{"version":3,"sources":["../src/ui/pieces/types.ts","../src/ui/pieces/pointer.ts","../src/ui/pieces/renderer.tsx","../src/ui/pieces/tokens.ts","../src/ui/pieces/dom/_shared.ts","../src/ui/pieces/dom/layout.ts","../src/ui/pieces/dom/content.ts","../src/ui/pieces/dom/data.ts","../src/ui/pieces/dom/inputs.ts","../src/ui/pieces/dom/actions.ts","../src/ui/pieces/dom/feedback.ts","../src/ui/pieces/dom/slot.ts","../src/ui/pieces/dom/index.ts","../src/ui/pieces/dom-renderer.ts","../src/ui/pieces/builtin/_shared.tsx","../src/ui/pieces/builtin/layout.tsx","../src/ui/pieces/builtin/content.tsx","../src/ui/pieces/builtin/data.tsx","../src/ui/pieces/builtin/inputs.tsx","../src/ui/pieces/builtin/actions.tsx","../src/ui/pieces/builtin/feedback.tsx","../src/ui/pieces/builtin/selection.tsx","../src/ui/pieces/builtin/slot.tsx","../src/ui/pieces/builtin/index.ts","../src/ui/pieces/builtin.ts","../src/ui/pieces/surface-bridge.ts","../src/ui/pieces/index.ts","../src/agent/webagent/cursor.ts","../src/agent/webagent/dom-reader.ts","../src/agent/webagent/runtime/streaming-envelope.ts","../src/index.ts","../src/triggers/space-gesture.ts","../src/utils/dom.ts","../src/utils/sdk-i18n.ts","../src/utils/selector.ts","../src/triggers/command-palette/styles.ts","../src/triggers/command-palette/prefix.ts","../src/triggers/command-palette/fuzzy.ts","../src/utils/id.ts","../src/triggers/command-palette/chip-bar.ts","../src/triggers/command-palette/qa.ts","../src/triggers/command-palette/screenshot.ts","../src/triggers/command-palette/index.ts","../src/triggers/spotter.ts","../src/skills/registry.ts","../src/prompts/registry.ts","../src/utils/llm-parse.ts","../src/agent/inline/parse.ts","../src/agent/plan/markdown.ts","../src/modules/immersive-translate/prompt.ts","../src/modules/voice/prompt.ts","../src/triggers/dwell/prompt.ts","../src/agent/sitemap/helpers.ts","../src/agent/webagent/prompt.ts","../src/agent/plan/prompt.ts","../src/prompts/defaults.ts","../src/triggers/panel-runtime.ts","../src/ui/placement.ts","../src/modules/pinned-panel.ts","../src/toolbox/common/types.ts","../src/utils/storage/memory.ts","../src/utils/storage/local-storage.ts","../src/utils/storage/indexeddb.ts","../src/utils/storage/index.ts","../src/utils/text/tokenize.ts","../src/utils/text/bm25.ts","../src/toolbox/search/store.ts","../src/toolbox/search/builtin.ts","../src/toolbox/search/index.ts","../src/toolbox/recommend/index.ts","../src/tools-registry.ts","../src/skills/preferences.ts","../src/ui/subtitle/styles.ts","../src/ui/subtitle/markdown.ts","../src/ui/subtitle/touch.ts","../src/ui/subtitle/paging.ts","../src/ui/subtitle/dismiss.ts","../src/ui/subtitle/streaming.ts","../src/ui/subtitle/choice.ts","../src/ui/subtitle/indicator.ts","../src/ui/subtitle/index.ts","../src/event-emitter.ts","../src/agent/webagent/session.ts","../src/agent/webagent/overlay.ts","../src/agent/webagent/actions.ts","../src/agent/webagent/actions-workflow.ts","../src/agent/webagent/cross-tab.ts","../src/agent/webagent/destructive.ts","../src/agent/webagent/cot.ts","../src/agent/webagent/execute-action.ts","../src/agent/webagent/runtime/helpers.ts","../src/agent/webagent/runtime/debug.ts","../src/agent/llm/router.ts","../src/agent/webagent/runtime/messages.ts","../src/agent/webagent/screenshot.ts","../src/agent/webagent/runtime/loops.ts","../src/agent/webagent/context-providers/url.ts","../src/agent/webagent/context-providers/page-summary.ts","../src/agent/webagent/context-providers/dom.ts","../src/agent/webagent/context-providers/screenshot.ts","../src/agent/webagent/context-providers/history.ts","../src/agent/webagent/context-providers/selection.ts","../src/agent/webagent/context-providers/index.ts","../src/agent/webagent/webagent.ts","../src/agent/index.ts","../src/agent/webagent/form-widgets.ts","../src/ui/inline-effects/styles.ts","../src/ui/inline-effects/inlineDiff.ts","../src/ui/inline-effects/chatSession.ts","../src/agent/inline/i18n.ts","../src/agent/inline/styles.ts","../src/agent/inline/scoping.ts","../src/agent/inline/index.ts","../src/agent/task/index.ts","../src/agent/cursor.ts","../src/agent/sitemap/learner.ts","../src/agent/memory/core.ts","../src/agent/memory/episodic.ts","../src/agent/memory/semantic.ts","../src/agent/memory/pii.ts","../src/agent/memory/drawer.ts","../src/agent/memory/unified.ts","../src/agent/memory/index.ts","../src/agent/plan/todos.ts","../src/agent/plan/index.ts","../src/orchestrator/agent-lifecycle.ts","../src/orchestrator/helpers.ts","../src/orchestrator/sessions-registry.ts","../src/orchestrator/agents-registry.ts","../src/orchestrator/skill-dispatcher.ts","../src/triggers/dwell/styles.ts","../src/orchestrator/highlight.ts","../src/orchestrator/intent-buffer.ts","../src/orchestrator/index.ts","../src/skills/evals.ts","../src/triggers/mobile-hero-greeting.ts","../src/triggers/mobile.ts","../src/init-sprite-urls.ts","../src/auto-install.ts","../src/triggers/dwell/index.ts","../src/triggers/action-panel.ts","../src/agent/llm/stream.ts","../src/utils/redact.ts","../src/agent/llm/openai.ts","../src/agent/llm/google/transform.ts","../src/agent/llm/google/stream.ts","../src/agent/llm/google/provider.ts","../src/agent/llm/proxy.ts","../src/agent/llm/adapters/registry.ts","../src/agent/llm/adapters/openai.ts","../src/agent/llm/adapters/google.ts","../src/agent/llm/adapters/proxy.ts","../src/agent/llm/adapters/agnes.ts","../src/agent/llm/adapters/index.ts","../src/skills/transaction.ts","../src/ui/dock-state.ts","../src/modules/immersive-translate/index.ts","../src/modules/voice/voice.ts","../src/modules/voice/tts.ts","../src/modules/voice/module.ts","../src/modules/theme-toggle.ts","../src/modules/language-switcher.ts","../src/modules/form-assist.ts","../src/modules/onboarding/index.ts","../src/utils/platform.ts","../src/cache.ts","../src/utils/heat-rank.ts","../src/ingest/schema.ts","../src/ingest/transport.ts","../src/analytics/store.ts","../src/analytics/sql-schema.ts","../src/analytics/mapper.ts","../src/analytics/export.ts"],"sourcesContent":["/**\n * Pieces — dddk's UI primitive system.\n *\n * Like HTML elements, but a curated set covering common SaaS UI patterns,\n * plus a `Slot` escape hatch for host-supplied components.\n *\n * Two ways to author the same UI:\n *   1. Direct API:  Pieces.Card({ children: [Pieces.Heading({ text: 'Hi' })] })\n *   2. Flat envelope (id-keyed component list): { component: 'Card', children: [{ component: 'Heading', text: 'Hi' }] }\n *\n * Both paths resolve through the same PieceRenderer with the same catalog.\n */\n\nimport type { ReactNode } from 'react';\n\n// ─── core shapes ───────────────────────────────────────────────────\n\n/** Discriminated piece — `kind` selects the catalog entry. */\nexport interface PieceNode {\n  kind: string;\n  /** Optional id, used to address nodes for partial updates. */\n  id?: string;\n  /** Optional binding path (JSON Pointer or simple key) into the data model. */\n  bind?: string;\n  /** Catalog-specific props. */\n  [key: string]: unknown;\n}\n\nexport interface PieceContext {\n  /** Reactive data model (mutated by inputs, read by `bind`). */\n  data: Record<string, unknown>;\n  /** Update a bound value. */\n  setBinding(path: string, value: unknown): void;\n  /** Fire a named action — e.g. 'submit', 'cancel', or any custom string. */\n  trigger(actionName: string, payload?: unknown): void;\n  /** Render a child PieceNode (recursive). */\n  render(node: PieceNode): ReactNode;\n}\n\nexport interface PieceDefinition<P = Record<string, unknown>> {\n  kind: string;\n  /**\n   * Render function. Returns React node OR a DOM element factory for\n   * non-React hosts (advanced — most users return JSX).\n   */\n  render(props: P & PieceNode, ctx: PieceContext): ReactNode;\n  /**\n   * Optional JSON Schema for props — useful when an LLM agent authors the\n   * piece from an envelope (the schema gives the LLM a contract).\n   */\n  propsSchema?: Record<string, unknown>;\n  /**\n   * Optional display metadata for tooling (palette previews, docs).\n   */\n  meta?: {\n    category: 'layout' | 'content' | 'data' | 'input' | 'action' | 'feedback' | 'slot';\n    description?: string;\n  };\n}\n\n// ─── catalog ───────────────────────────────────────────────────────\n\nexport class PieceCatalog {\n  private pieces = new Map<string, PieceDefinition>();\n\n  constructor(initial: PieceDefinition[] = []) {\n    for (const p of initial) this.register(p);\n  }\n\n  register(piece: PieceDefinition): void {\n    if (this.pieces.has(piece.kind)) {\n      console.warn(`[Pieces] kind \"${piece.kind}\" already registered — replacing.`);\n    }\n    this.pieces.set(piece.kind, piece);\n  }\n\n  get(kind: string): PieceDefinition | undefined {\n    return this.pieces.get(kind);\n  }\n\n  list(): PieceDefinition[] {\n    return Array.from(this.pieces.values());\n  }\n\n  /**\n   * Merge another catalog into this one. Host's custom catalog wins on\n   * conflict — lets enterprises extend / override built-ins.\n   */\n  extend(other: PieceCatalog | PieceDefinition[]): void {\n    const incoming = Array.isArray(other) ? other : other.list();\n    for (const p of incoming) this.register(p);\n  }\n}\n\n// ─── tree / surface ────────────────────────────────────────────────\n\n/**\n * A complete UI surface — root piece + optional initial data model.\n * Output of a skill, palette command, or external envelope translation.\n */\nexport interface PieceSurface {\n  root: PieceNode;\n  data?: Record<string, unknown>;\n}\n","/**\n * JSON Pointer (RFC 6901, simplified) helpers shared by both renderers.\n */\n\nexport function readPointer(data: Record<string, unknown>, path: string): unknown {\n  if (!path) return undefined;\n  if (!path.startsWith('/')) return data[path];\n  const parts = path.slice(1).split('/').map((p) => p.replace(/~1/g, '/').replace(/~0/g, '~'));\n  let cur: unknown = data;\n  for (const p of parts) {\n    if (cur && typeof cur === 'object' && p in (cur as object)) {\n      cur = (cur as Record<string, unknown>)[p];\n    } else {\n      return undefined;\n    }\n  }\n  return cur;\n}\n\nexport function applyPointer(\n  data: Record<string, unknown>,\n  path: string,\n  value: unknown,\n): Record<string, unknown> {\n  if (!path) return data;\n  if (!path.startsWith('/')) return { ...data, [path]: value };\n  const parts = path.slice(1).split('/').map((p) => p.replace(/~1/g, '/').replace(/~0/g, '~'));\n  const last = parts.pop();\n  const next: Record<string, unknown> = { ...data };\n  if (!last) return next;\n  let cur: Record<string, unknown> = next;\n  for (const p of parts) {\n    const existing = cur[p];\n    if (existing && typeof existing === 'object' && !Array.isArray(existing)) {\n      const cloned = { ...(existing as Record<string, unknown>) };\n      cur[p] = cloned;\n      cur = cloned;\n    } else {\n      const fresh: Record<string, unknown> = {};\n      cur[p] = fresh;\n      cur = fresh;\n    }\n  }\n  cur[last] = value;\n  return next;\n}\n","/**\r\n * PieceRenderer — unified React renderer for any catalog.\r\n * Drives direct authoring, flat envelopes, and palette detail views.\r\n */\r\n\r\nimport { useCallback, useMemo, useState, type ReactNode } from 'react';\r\nimport type { PieceCatalog, PieceContext, PieceNode, PieceSurface } from './types';\r\nimport { readPointer, applyPointer } from './pointer';\r\n\r\nexport { readPointer } from './pointer';\r\n\r\nexport interface PieceRendererProps {\r\n  surface: PieceSurface;\r\n  catalog: PieceCatalog;\r\n  onAction?: (name: string, payload: unknown, data: Record<string, unknown>) => void;\r\n  onDataChange?: (data: Record<string, unknown>) => void;\r\n}\r\n\r\nexport function PieceRenderer({\r\n  surface,\r\n  catalog,\r\n  onAction,\r\n  onDataChange,\r\n}: PieceRendererProps) {\r\n  const [data, setData] = useState<Record<string, unknown>>(surface.data ?? {});\r\n\r\n  const setBinding = useCallback((path: string, value: unknown) => {\r\n    setData((cur) => {\r\n      const next = applyPointer(cur, path, value);\r\n      onDataChange?.(next);\r\n      return next;\r\n    });\r\n  }, [onDataChange]);\r\n\r\n  const trigger = useCallback((name: string, payload?: unknown) => {\r\n    onAction?.(name, payload, data);\r\n  }, [onAction, data]);\r\n\r\n  const ctx: PieceContext = useMemo(() => {\r\n    const c: PieceContext = {\r\n      data,\r\n      setBinding,\r\n      trigger,\r\n      render: (node) => renderNode(node, c, catalog),\r\n    };\r\n    return c;\r\n  }, [data, setBinding, trigger, catalog]);\r\n\r\n  return <>{renderNode(surface.root, ctx, catalog)}</>;\r\n}\r\n\r\nfunction renderNode(node: PieceNode, ctx: PieceContext, catalog: PieceCatalog): ReactNode {\r\n  const def = catalog.get(node.kind);\r\n  if (!def) {\r\n    return (\r\n      <div data-dddk-ui=\"piece-unknown\" style={{ color: '#cc3333', padding: 8 }}>\r\n        Unknown piece: {node.kind}\r\n      </div>\r\n    );\r\n  }\r\n  return def.render(node, ctx);\r\n}\r\n\r\n/** Resolve a value via bind (preferred) or fallback to a literal prop. */\r\nexport function resolveValue<T>(\r\n  node: PieceNode,\r\n  ctx: PieceContext,\r\n  literalKey: string,\r\n  fallback?: T\r\n): T {\r\n  if (node.bind) {\r\n    const v = readPointer(ctx.data, node.bind);\r\n    if (v !== undefined) return v as T;\r\n  }\r\n  const lit = node[literalKey];\r\n  if (lit !== undefined) return lit as T;\r\n  return fallback as T;\r\n}\r\n","/**\n * Shared visual tokens for both React and DOM renderers.\n * Single source of truth — change once, propagates everywhere.\n */\n\nexport interface ToneColor {\n  bg: string;\n  fg: string;\n}\n\nexport const TONES: Record<string, ToneColor> = {\n  neutral: { bg: 'rgba(0,0,0,0.06)', fg: 'inherit' },\n  success: { bg: 'rgba(16,185,129,0.12)', fg: '#10b981' },\n  warning: { bg: 'rgba(245,158,11,0.12)', fg: '#f59e0b' },\n  error:   { bg: 'rgba(239,68,68,0.12)',  fg: '#ef4444' },\n  info:    { bg: 'rgba(59,130,246,0.12)', fg: '#3b82f6' },\n};\n\nexport function tone(name: unknown): ToneColor {\n  return TONES[String(name ?? 'neutral')] ?? TONES.neutral!;\n}\n\n/** CSS-property objects (React `style={}`-shaped) for button variants. */\nexport const BUTTON_VARIANTS_REACT: Record<string, React.CSSProperties> = {\n  primary:     { background: 'var(--dddk-accent, #3b82f6)', color: '#fff' },\n  secondary:   { background: 'transparent', color: 'inherit', border: '1px solid var(--dddk-border)' },\n  destructive: { background: '#ef4444', color: '#fff' },\n};\n\n/** CSS text strings for DOM renderer (style.cssText fragment). */\nexport const BUTTON_VARIANTS_CSS: Record<string, string> = {\n  primary:\n    'background:var(--dddk-accent, #6366f1);color:var(--dddk-text-on-accent, #fff);border:0;',\n  secondary:\n    'background:transparent;color:inherit;border:1px solid var(--dddk-border, rgba(0,0,0,0.15));',\n  destructive: 'background:#ef4444;color:#fff;border:0;',\n};\n\n/** Base input style (React form). */\nexport const BASE_INPUT_STYLE: React.CSSProperties = {\n  width: '100%',\n  padding: '6px 8px',\n  border: '1px solid var(--dddk-border, rgba(0,0,0,0.15))',\n  borderRadius: 6,\n  font: 'inherit',\n  background: 'var(--dddk-bg, #fff)',\n  color: 'inherit',\n};\n\n/** Base input style (DOM `cssText` form). */\nexport const BASE_INPUT_CSS =\n  'width:100%;padding:6px 8px;border:1px solid var(--dddk-border, rgba(0,0,0,0.15));' +\n  'border-radius:6px;font:inherit;background:var(--dddk-bg, #fff);color:inherit;box-sizing:border-box;';\n","/**\n * DOM-renderer shared helpers + the `DomHelpers` surface that each\n * per-category renderer module receives. Decouples sub-renderers from the\n * main class so they're testable and don't import it transitively.\n */\n\nimport type { PieceNode } from '../types';\nimport { BASE_INPUT_CSS } from '../tokens';\n\nexport interface DomHelpers {\n  /** Resolve `node.bind` first, then literal `node[key]`, then `fallback`. */\n  read<T>(node: PieceNode, key: string, fallback?: T): T;\n  /** Recursively render a child piece. */\n  renderNode(node: PieceNode): HTMLElement;\n  /** Render every `node.children` entry to an array of elements. */\n  renderChildren(node: PieceNode): HTMLElement[];\n  /** Mutate bound state path. */\n  setBinding(path: string, value: unknown): void;\n  /** Fire a named action. */\n  trigger(name: string, payload?: unknown): void;\n}\n\nexport function applyInputStyle(el: HTMLElement): void {\n  el.style.cssText = BASE_INPUT_CSS;\n}\n\nexport function px(value: unknown, fallback: number): string {\n  if (typeof value === 'number') return `${value}px`;\n  if (typeof value === 'string') return value;\n  return `${fallback}px`;\n}\n\nexport function escapeHtml(s: string): string {\n  return s.replace(/[&<>\"']/g, (c) =>\n    ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[c]!),\n  );\n}\n\nexport function appendAll(parent: HTMLElement, children: HTMLElement[]): void {\n  for (const c of children) parent.appendChild(c);\n}\n\nexport function fieldWrap(node: PieceNode): HTMLElement {\n  const wrap = document.createElement('label');\n  wrap.style.cssText = 'display:flex;flex-direction:column;gap:4px;font-size:13px;';\n  if (node.label != null) {\n    const span = document.createElement('span');\n    span.textContent = String(node.label);\n    wrap.appendChild(span);\n  }\n  return wrap;\n}\n","import type { PieceNode } from '../types';\nimport { appendAll, px, type DomHelpers } from './_shared';\n\nexport function renderStack(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  el.style.display = 'flex';\n  el.style.flexDirection = node.direction === 'horizontal' ? 'row' : 'column';\n  el.style.gap = px(node.gap, 8);\n  el.style.alignItems = String(node.align ?? 'stretch');\n  appendAll(el, h.renderChildren(node));\n  return el;\n}\n\nexport function renderGrid(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  el.style.display = 'grid';\n  el.style.gridTemplateColumns = `repeat(${Number(node.columns ?? 2)}, minmax(0,1fr))`;\n  el.style.gap = px(node.gap, 8);\n  appendAll(el, h.renderChildren(node));\n  return el;\n}\n\nexport function renderSplit(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  el.style.display = 'grid';\n  el.style.gridTemplateColumns = '1fr 1fr';\n  el.style.gap = '12px';\n  appendAll(el, h.renderChildren(node));\n  return el;\n}\n\nexport function renderCard(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  el.style.background = 'var(--dddk-bg-elevated, #fff)';\n  el.style.borderRadius = 'var(--dddk-radius, 12px)';\n  el.style.padding = '16px';\n  el.style.boxShadow = 'var(--dddk-shadow-md, 0 1px 3px rgba(0,0,0,0.05))';\n  el.style.display = 'flex';\n  el.style.flexDirection = 'column';\n  el.style.gap = '12px';\n  appendAll(el, h.renderChildren(node));\n  return el;\n}\n\nexport function renderGroup(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  el.style.display = 'flex';\n  el.style.flexDirection = node.direction === 'horizontal' ? 'row' : 'column';\n  el.style.gap = px(node.gap, 8);\n  el.style.alignItems = String(node.align ?? 'stretch');\n  appendAll(el, h.renderChildren(node));\n  return el;\n}\n\nexport function renderTabs(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  const tabs = (node.tabs as Array<{ id: string; label: string; content: PieceNode }>) ?? [];\n  const activeKey = node.bind ?? (node.id ? `__activeTab_${node.id}` : '__activeTab');\n  const active = (h.read<string>(\n    { kind: 'Tabs', bind: activeKey } as PieceNode,\n    'active',\n    tabs[0]?.id ?? '',\n  )) || tabs[0]?.id;\n\n  const bar = document.createElement('div');\n  bar.style.display = 'flex';\n  bar.style.gap = '8px';\n  bar.style.borderBottom = '1px solid var(--dddk-border, rgba(0,0,0,0.08))';\n  for (const t of tabs) {\n    const btn = document.createElement('button');\n    btn.type = 'button';\n    btn.textContent = t.label;\n    btn.style.padding = '6px 12px';\n    btn.style.background = 'transparent';\n    btn.style.border = '0';\n    btn.style.borderBottom = t.id === active\n      ? '2px solid var(--dddk-accent, #6366f1)'\n      : '2px solid transparent';\n    btn.style.cursor = 'pointer';\n    btn.style.font = 'inherit';\n    btn.addEventListener('click', () => h.setBinding(String(activeKey), t.id));\n    bar.appendChild(btn);\n  }\n  el.appendChild(bar);\n\n  const panel = document.createElement('div');\n  panel.style.padding = '12px';\n  const activeTab = tabs.find((t) => t.id === active) ?? tabs[0];\n  if (activeTab) panel.appendChild(h.renderNode(activeTab.content));\n  el.appendChild(panel);\n  return el;\n}\n","import type { PieceNode } from '../types';\nimport { tone } from '../tokens';\nimport type { DomHelpers } from './_shared';\n\nexport function renderHeading(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  const level = Math.min(6, Math.max(1, Number(node.level ?? 3)));\n  const tag = document.createElement(`h${level}`);\n  tag.style.margin = '0 0 8px 0';\n  tag.textContent = h.read<string>(node, 'text', '');\n  el.appendChild(tag);\n  return el;\n}\n\nexport function renderText(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  el.style.display = 'inline';\n  el.textContent = h.read<string>(node, 'text', '');\n  return el;\n}\n\nexport function renderMarkdown(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  el.style.whiteSpace = 'pre-wrap';\n  el.textContent = h.read<string>(node, 'text', '');\n  return el;\n}\n\nexport function renderCode(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  const pre = document.createElement('pre');\n  pre.style.cssText =\n    'background:var(--dddk-bg, #fafafa);padding:8px;border-radius:6px;' +\n    'font-family:var(--dddk-font-mono, ui-monospace, monospace);' +\n    'font-size:12px;margin:0;overflow-x:auto;';\n  pre.textContent = h.read<string>(node, 'code', '');\n  el.appendChild(pre);\n  return el;\n}\n\nexport function renderImage(el: HTMLElement, node: PieceNode): HTMLElement {\n  const img = document.createElement('img');\n  img.src = String(node.src ?? '');\n  img.alt = String(node.alt ?? '');\n  img.style.cssText = 'max-width:100%;border-radius:6px;';\n  el.appendChild(img);\n  return el;\n}\n\nexport function renderTag(el: HTMLElement, node: PieceNode): HTMLElement {\n  const c = tone(node.tone);\n  const span = document.createElement('span');\n  span.style.cssText =\n    `background:${c.bg};color:${c.fg};padding:2px 8px;border-radius:12px;` +\n    'font-size:11px;font-weight:500;display:inline-block;';\n  span.textContent = String(node.text ?? '');\n  el.appendChild(span);\n  return el;\n}\n\nexport function renderDivider(el: HTMLElement): HTMLElement {\n  const hr = document.createElement('hr');\n  hr.style.cssText = 'border:0;border-top:1px solid var(--dddk-border, rgba(0,0,0,0.08));margin:8px 0;';\n  el.appendChild(hr);\n  return el;\n}\n","import type { PieceNode } from '../types';\nimport { escapeHtml, type DomHelpers } from './_shared';\n\nexport function renderListing(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  type Item = { id: string; title: string; subtitle?: string; accessory?: string; icon?: string };\n  const items = h.read<Item[]>(node, 'items', []);\n  const ul = document.createElement('ul');\n  ul.style.cssText = 'list-style:none;margin:0;padding:0;';\n  for (const it of items) {\n    const li = document.createElement('li');\n    li.style.cssText =\n      'display:flex;gap:8px;padding:6px 8px;' +\n      'border-bottom:1px solid var(--dddk-border, rgba(0,0,0,0.05));';\n    if (it.icon) {\n      const ic = document.createElement('span');\n      ic.textContent = it.icon;\n      li.appendChild(ic);\n    }\n    const text = document.createElement('div');\n    text.style.cssText = 'flex:1;min-width:0;';\n    const t = document.createElement('div');\n    t.textContent = it.title;\n    text.appendChild(t);\n    if (it.subtitle) {\n      const s = document.createElement('small');\n      s.style.color = 'var(--dddk-text-muted, #6b6b6b)';\n      s.textContent = it.subtitle;\n      text.appendChild(s);\n    }\n    li.appendChild(text);\n    if (it.accessory) {\n      const a = document.createElement('span');\n      a.style.color = 'var(--dddk-text-muted, #6b6b6b)';\n      a.textContent = it.accessory;\n      li.appendChild(a);\n    }\n    ul.appendChild(li);\n  }\n  el.appendChild(ul);\n  return el;\n}\n\nexport function renderTable(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  const columns = (node.columns as Array<{ key: string; label: string }>) ?? [];\n  const rows = h.read<Array<Record<string, unknown>>>(node, 'rows', []);\n  const table = document.createElement('table');\n  table.style.cssText = 'width:100%;border-collapse:collapse;font-size:13px;';\n  const thead = document.createElement('thead');\n  const headRow = document.createElement('tr');\n  for (const c of columns) {\n    const th = document.createElement('th');\n    th.style.cssText =\n      'text-align:left;padding:6px;border-bottom:1px solid var(--dddk-border, rgba(0,0,0,0.08));';\n    th.textContent = c.label;\n    headRow.appendChild(th);\n  }\n  thead.appendChild(headRow);\n  table.appendChild(thead);\n  const tbody = document.createElement('tbody');\n  for (const r of rows) {\n    const tr = document.createElement('tr');\n    for (const c of columns) {\n      const td = document.createElement('td');\n      td.style.cssText =\n        'padding:6px;border-bottom:1px solid var(--dddk-border, rgba(0,0,0,0.05));';\n      td.textContent = String(r[c.key] ?? '');\n      tr.appendChild(td);\n    }\n    tbody.appendChild(tr);\n  }\n  table.appendChild(tbody);\n  el.appendChild(table);\n  return el;\n}\n\nexport function renderMetric(el: HTMLElement, node: PieceNode): HTMLElement {\n  const trend = String(node.trend ?? 'flat');\n  const color = trend === 'up' ? '#10b981' : trend === 'down' ? '#ef4444' : '#6b6b6b';\n  const arrow = trend === 'up' ? '▲' : trend === 'down' ? '▼' : '–';\n  const wrap = document.createElement('div');\n  wrap.style.cssText = 'display:flex;flex-direction:column;gap:2px;';\n  if (node.label) {\n    const lbl = document.createElement('span');\n    lbl.style.cssText = 'font-size:11px;color:var(--dddk-text-muted, #6b6b6b);';\n    lbl.textContent = String(node.label);\n    wrap.appendChild(lbl);\n  }\n  const row = document.createElement('div');\n  row.style.cssText = 'display:flex;align-items:baseline;gap:8px;';\n  const strong = document.createElement('strong');\n  strong.style.fontSize = '22px';\n  strong.textContent = String(node.value ?? '');\n  row.appendChild(strong);\n  if (node.delta != null) {\n    const d = document.createElement('span');\n    d.style.cssText = `color:${color};font-size:12px;`;\n    d.textContent = `${arrow} ${node.delta}`;\n    row.appendChild(d);\n  }\n  wrap.appendChild(row);\n  el.appendChild(wrap);\n  return el;\n}\n\nexport function renderTimeline(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  type Evt = { id: string; time: string; title: string; note?: string };\n  const events = h.read<Evt[]>(node, 'events', []);\n  const ol = document.createElement('ol');\n  ol.style.cssText =\n    'list-style:none;margin:0;padding:0;border-left:2px solid var(--dddk-border, rgba(0,0,0,0.08));';\n  for (const e of events) {\n    const li = document.createElement('li');\n    li.style.cssText = 'margin-left:12px;padding-left:12px;padding-bottom:12px;position:relative;';\n    li.innerHTML = `\n      <span style=\"position:absolute;left:-19px;top:6px;width:8px;height:8px;border-radius:50%;\n        background:var(--dddk-accent, #6366f1);\"></span>\n      <small style=\"color:var(--dddk-text-muted, #6b6b6b)\">${escapeHtml(e.time)}</small>\n      <div>${escapeHtml(e.title)}</div>\n      ${e.note ? `<small style=\"color:var(--dddk-text-muted, #6b6b6b)\">${escapeHtml(e.note)}</small>` : ''}\n    `;\n    ol.appendChild(li);\n  }\n  el.appendChild(ol);\n  return el;\n}\n","import type { PieceNode } from '../types';\nimport { applyInputStyle, fieldWrap, type DomHelpers } from './_shared';\n\nexport function renderTextInput(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  const f = fieldWrap(node);\n  const input = document.createElement('input');\n  input.type = node.kind === 'PasswordField' ? 'password' : 'text';\n  applyInputStyle(input);\n  input.value = String(h.read<string>(node, 'value', '') ?? '');\n  if (node.placeholder) input.placeholder = String(node.placeholder);\n  input.addEventListener('input', () => {\n    if (node.bind) h.setBinding(String(node.bind), input.value);\n  });\n  f.appendChild(input);\n  el.appendChild(f);\n  return el;\n}\n\nexport function renderTextArea(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  const f = fieldWrap(node);\n  const ta = document.createElement('textarea');\n  applyInputStyle(ta);\n  ta.rows = Number(node.rows ?? 3);\n  ta.value = String(h.read<string>(node, 'value', '') ?? '');\n  if (node.placeholder) ta.placeholder = String(node.placeholder);\n  ta.addEventListener('input', () => {\n    if (node.bind) h.setBinding(String(node.bind), ta.value);\n  });\n  f.appendChild(ta);\n  el.appendChild(f);\n  return el;\n}\n\nexport function renderNumberField(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  const f = fieldWrap(node);\n  const input = document.createElement('input');\n  input.type = 'number';\n  applyInputStyle(input);\n  input.value = String(h.read<number>(node, 'value', 0) ?? 0);\n  if (node.min != null) input.min = String(node.min);\n  if (node.max != null) input.max = String(node.max);\n  if (node.step != null) input.step = String(node.step);\n  input.addEventListener('input', () => {\n    if (node.bind) h.setBinding(String(node.bind), Number(input.value));\n  });\n  f.appendChild(input);\n  el.appendChild(f);\n  return el;\n}\n\nexport function renderCheckbox(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  const lbl = document.createElement('label');\n  lbl.style.cssText = 'display:flex;gap:6px;align-items:center;font-size:13px;cursor:pointer;';\n  const input = document.createElement('input');\n  input.type = 'checkbox';\n  input.checked = Boolean(h.read<boolean>(node, 'value', false));\n  input.addEventListener('change', () => {\n    if (node.bind) h.setBinding(String(node.bind), input.checked);\n  });\n  lbl.appendChild(input);\n  const span = document.createElement('span');\n  span.textContent = String(node.label ?? '');\n  lbl.appendChild(span);\n  el.appendChild(lbl);\n  return el;\n}\n\nexport function renderSwitch(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  const checked = Boolean(h.read<boolean>(node, 'value', false));\n  const lbl = document.createElement('label');\n  lbl.style.cssText = 'display:flex;gap:8px;align-items:center;font-size:13px;cursor:pointer;';\n  const track = document.createElement('span');\n  track.style.cssText =\n    'width:32px;height:18px;border-radius:9px;position:relative;display:inline-block;' +\n    `background:${checked ? 'var(--dddk-accent, #6366f1)' : 'rgba(0,0,0,0.2)'};` +\n    'transition:background 120ms;';\n  const knob = document.createElement('span');\n  knob.style.cssText =\n    `position:absolute;top:2px;left:${checked ? 16 : 2}px;` +\n    'width:14px;height:14px;border-radius:50%;background:#fff;transition:left 120ms;';\n  track.appendChild(knob);\n  track.addEventListener('click', () => {\n    if (node.bind) h.setBinding(String(node.bind), !checked);\n  });\n  lbl.appendChild(track);\n  if (node.label) {\n    const span = document.createElement('span');\n    span.textContent = String(node.label);\n    lbl.appendChild(span);\n  }\n  el.appendChild(lbl);\n  return el;\n}\n\nexport function renderPicker(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  const f = fieldWrap(node);\n  const sel = document.createElement('select');\n  applyInputStyle(sel);\n  const opts = (node.options as Array<string | { value: string; label: string }>) ?? [];\n  const current = String(h.read<string>(node, 'value', '') ?? '');\n  for (const o of opts) {\n    const v = typeof o === 'string' ? o : o.value;\n    const l = typeof o === 'string' ? o : o.label;\n    const opt = document.createElement('option');\n    opt.value = v;\n    opt.textContent = l;\n    if (v === current) opt.selected = true;\n    sel.appendChild(opt);\n  }\n  sel.addEventListener('change', () => {\n    if (node.bind) h.setBinding(String(node.bind), sel.value);\n  });\n  f.appendChild(sel);\n  el.appendChild(f);\n  return el;\n}\n\nexport function renderDatePicker(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  const f = fieldWrap(node);\n  const input = document.createElement('input');\n  input.type = 'datetime-local';\n  applyInputStyle(input);\n  input.value = String(h.read<string>(node, 'value', '') ?? '');\n  input.addEventListener('input', () => {\n    if (node.bind) h.setBinding(String(node.bind), input.value);\n  });\n  f.appendChild(input);\n  el.appendChild(f);\n  return el;\n}\n\nexport function renderSlider(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  const f = fieldWrap(node);\n  const input = document.createElement('input');\n  input.type = 'range';\n  input.min = String(node.min ?? 0);\n  input.max = String(node.max ?? 100);\n  input.step = String(node.step ?? 1);\n  input.value = String(h.read<number>(node, 'value', 0) ?? 0);\n  input.addEventListener('input', () => {\n    if (node.bind) h.setBinding(String(node.bind), Number(input.value));\n  });\n  f.appendChild(input);\n  el.appendChild(f);\n  return el;\n}\n\nexport function renderFilePicker(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  const f = fieldWrap(node);\n  const input = document.createElement('input');\n  input.type = 'file';\n  if (node.accept) input.accept = String(node.accept);\n  if (node.multiple) input.multiple = true;\n  input.addEventListener('change', () => {\n    if (!node.bind) return;\n    h.setBinding(String(node.bind), Array.from(input.files ?? []));\n  });\n  f.appendChild(input);\n  el.appendChild(f);\n  return el;\n}\n","import type { PieceNode } from '../types';\nimport { BUTTON_VARIANTS_CSS } from '../tokens';\nimport type { DomHelpers } from './_shared';\n\nexport function renderButton(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  const variant = String(node.variant ?? 'primary');\n  const btn = document.createElement('button');\n  btn.type = 'button';\n  const variantCss = BUTTON_VARIANTS_CSS[variant] ?? BUTTON_VARIANTS_CSS.primary!;\n  btn.style.cssText =\n    `${variantCss}` +\n    'padding:6px 14px;border-radius:6px;font:inherit;cursor:pointer;font-weight:500;';\n  btn.textContent = String(node.text ?? '');\n  btn.addEventListener('click', () => h.trigger(String(node.action ?? 'submit'), node.payload));\n  el.appendChild(btn);\n  return el;\n}\n\nexport function renderLink(el: HTMLElement, node: PieceNode): HTMLElement {\n  const a = document.createElement('a');\n  a.href = String(node.href ?? '#');\n  if (node.target) a.target = String(node.target);\n  a.style.cssText = 'color:var(--dddk-accent, #6366f1);text-decoration:underline;cursor:pointer;';\n  a.textContent = String(node.text ?? '');\n  el.appendChild(a);\n  return el;\n}\n\nexport function renderIconButton(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  const btn = document.createElement('button');\n  btn.type = 'button';\n  if (node.title) btn.title = String(node.title);\n  btn.style.cssText = 'background:transparent;border:0;cursor:pointer;padding:4px;font-size:16px;';\n  btn.textContent = String(node.icon ?? '');\n  btn.addEventListener('click', () => h.trigger(String(node.action ?? 'click'), node.payload));\n  el.appendChild(btn);\n  return el;\n}\n","import type { PieceNode } from '../types';\nimport type { DomHelpers } from './_shared';\n\nexport function renderSpinner(el: HTMLElement): HTMLElement {\n  el.textContent = '⋯';\n  return el;\n}\n\nexport function renderProgressBar(el: HTMLElement, node: PieceNode, h: DomHelpers): HTMLElement {\n  const v = Math.min(100, Math.max(0, Number(h.read<number>(node, 'value', 0) ?? 0)));\n  const track = document.createElement('div');\n  track.style.cssText = 'background:rgba(0,0,0,0.08);height:6px;border-radius:3px;overflow:hidden;';\n  const fill = document.createElement('div');\n  fill.style.cssText =\n    `width:${v}%;height:100%;background:var(--dddk-accent, #6366f1);transition:width 200ms;`;\n  track.appendChild(fill);\n  el.appendChild(track);\n  return el;\n}\n\nexport function renderEmptyState(el: HTMLElement, node: PieceNode): HTMLElement {\n  el.style.cssText = 'padding:24px;text-align:center;color:var(--dddk-text-muted, #6b6b6b);';\n  const icon = document.createElement('div');\n  icon.style.cssText = 'font-size:28px;margin-bottom:8px;';\n  icon.textContent = String(node.icon ?? '∅');\n  el.appendChild(icon);\n  const title = document.createElement('div');\n  title.textContent = String(node.title ?? '');\n  el.appendChild(title);\n  if (node.description) {\n    const small = document.createElement('small');\n    small.textContent = String(node.description);\n    el.appendChild(small);\n  }\n  return el;\n}\n\nexport function renderErrorState(el: HTMLElement, node: PieceNode): HTMLElement {\n  el.style.cssText =\n    'padding:16px;background:rgba(239,68,68,0.08);border:1px solid #ef4444;' +\n    'border-radius:6px;color:#991b1b;';\n  const strong = document.createElement('strong');\n  strong.textContent = String(node.title ?? 'Error');\n  el.appendChild(strong);\n  if (node.message) {\n    const msg = document.createElement('div');\n    msg.style.cssText = 'margin-top:4px;font-size:13px;';\n    msg.textContent = String(node.message);\n    el.appendChild(msg);\n  }\n  return el;\n}\n","import type { PieceNode } from '../types';\n\nexport function renderSlot(el: HTMLElement, node: PieceNode): HTMLElement {\n  const slotName = node.slotName;\n  if (typeof slotName === 'string') {\n    const map =\n      (typeof window !== 'undefined' &&\n        (window as unknown as { __dddkSlotElements?: Record<string, HTMLElement> }).__dddkSlotElements) ||\n      {};\n    const supplied = map[slotName];\n    if (supplied) {\n      el.appendChild(supplied);\n      return el;\n    }\n  }\n  el.style.cssText = 'padding:8px;background:rgba(0,0,0,0.04);border-radius:4px;font-size:11px;color:#6b6b6b;';\n  el.textContent = `Slot: ${slotName ?? '(inline)'}`;\n  return el;\n}\n","/**\n * PieceDomRenderer — vanilla-DOM, interactive renderer for `PieceSurface`.\n * Same tree shape as the React renderer, no React dependency.\n */\n\nimport type { PieceCatalog, PieceNode, PieceSurface } from '../types';\nimport { readPointer, applyPointer } from '../pointer';\nimport type { DomHelpers } from './_shared';\nimport * as L from './layout';\nimport * as C from './content';\nimport * as D from './data';\nimport * as I from './inputs';\nimport * as A from './actions';\nimport * as F from './feedback';\nimport { renderSlot } from './slot';\n\nexport interface PieceDomRendererOptions {\n  catalog?: PieceCatalog;\n  /** Read-only mode — inputs render but ignore changes. Default `false`. */\n  readOnly?: boolean;\n  /** Fired by Button / IconButton / Link clicks. */\n  onAction?: (name: string, payload: unknown, data: Record<string, unknown>) => void;\n  /** Fired on every data-model mutation. */\n  onDataChange?: (data: Record<string, unknown>) => void;\n}\n\nexport class PieceDomRenderer {\n  private opts: PieceDomRendererOptions;\n  private data: Record<string, unknown> = {};\n  private surface: PieceSurface | null = null;\n  private host: HTMLElement | null = null;\n\n  constructor(opts: PieceDomRendererOptions = {}) {\n    this.opts = opts;\n  }\n\n  mount(parent: HTMLElement, surface: PieceSurface): void {\n    this.host = parent;\n    this.surface = surface;\n    this.data = { ...(surface.data ?? {}) };\n    this.repaint();\n  }\n\n  update(surface: PieceSurface): void {\n    this.surface = surface;\n    // Preserve any user edits — merge incoming data on top of existing.\n    this.data = { ...this.data, ...(surface.data ?? {}) };\n    this.repaint();\n  }\n\n  setData(data: Record<string, unknown>): void {\n    this.data = { ...data };\n    this.opts.onDataChange?.(this.data);\n    this.repaint();\n  }\n\n  getData(): Record<string, unknown> {\n    return { ...this.data };\n  }\n\n  unmount(): void {\n    if (this.host) this.host.innerHTML = '';\n    this.host = null;\n    this.surface = null;\n  }\n\n  private repaint(): void {\n    if (!this.host || !this.surface) return;\n    this.host.innerHTML = '';\n    this.host.appendChild(this.renderNode(this.surface.root));\n  }\n\n  // QUICK FIX for focus-loss bug: each input rebuild via repaint() destroyed\n  // the focused element. Until per-binding patching is implemented, skip the\n  // repaint while the user is typing into a host-owned input — the input's\n  // own `input` event has already updated its DOM value, so visually nothing\n  // is lost. Any non-focused bindings re-resolve on the next repaint that\n  // does fire (blur / button click / external setData). Bound siblings that\n  // mirror the same value won't visually update mid-typing — accept that\n  // for now; a follow-up should add real DOM diffing.\n  private setBinding(path: string, value: unknown): void {\n    if (this.opts.readOnly || !path) return;\n    this.data = applyPointer(this.data, path, value);\n    this.opts.onDataChange?.(this.data);\n    const active = typeof document !== 'undefined' ? document.activeElement : null;\n    if (active && this.host?.contains(active)) return;\n    this.repaint();\n  }\n\n  private trigger(name: string, payload?: unknown): void {\n    this.opts.onAction?.(name, payload, this.data);\n  }\n\n  private read<T>(node: PieceNode, key: string, fallback?: T): T {\n    if (node.bind) {\n      const v = readPointer(this.data, String(node.bind));\n      if (v !== undefined) return v as T;\n    }\n    const lit = node[key];\n    if (lit !== undefined) return lit as T;\n    return fallback as T;\n  }\n\n  private renderChildren(node: PieceNode): HTMLElement[] {\n    const children = (node.children as PieceNode[] | undefined) ?? [];\n    return children.map((c) => this.renderNode(c));\n  }\n\n  private helpers(): DomHelpers {\n    return {\n      read: (n, k, f) => this.read(n, k, f),\n      renderNode: (n) => this.renderNode(n),\n      renderChildren: (n) => this.renderChildren(n),\n      setBinding: (p, v) => this.setBinding(p, v),\n      trigger: (n, p) => this.trigger(n, p),\n    };\n  }\n\n  private renderNode(node: PieceNode): HTMLElement {\n    const el = document.createElement('div');\n    el.setAttribute('data-dddk-piece', node.kind.toLowerCase());\n    const h = this.helpers();\n\n    switch (node.kind) {\n      // Layout\n      case 'Stack':         return L.renderStack(el, node, h);\n      case 'Grid':          return L.renderGrid(el, node, h);\n      case 'Split':         return L.renderSplit(el, node, h);\n      case 'Card':          return L.renderCard(el, node, h);\n      case 'Group':         return L.renderGroup(el, node, h);\n      case 'Tabs':          return L.renderTabs(el, node, h);\n\n      // Content\n      case 'Heading':       return C.renderHeading(el, node, h);\n      case 'Text':          return C.renderText(el, node, h);\n      case 'Markdown':      return C.renderMarkdown(el, node, h);\n      case 'Code':          return C.renderCode(el, node, h);\n      case 'Image':         return C.renderImage(el, node);\n      case 'Tag':           return C.renderTag(el, node);\n      case 'Divider':       return C.renderDivider(el);\n\n      // Data\n      case 'Listing':       return D.renderListing(el, node, h);\n      case 'Table':         return D.renderTable(el, node, h);\n      case 'Metric':        return D.renderMetric(el, node);\n      case 'Timeline':      return D.renderTimeline(el, node, h);\n\n      // Input\n      case 'TextField':\n      case 'PasswordField': return I.renderTextInput(el, node, h);\n      case 'TextArea':      return I.renderTextArea(el, node, h);\n      case 'NumberField':   return I.renderNumberField(el, node, h);\n      case 'Checkbox':      return I.renderCheckbox(el, node, h);\n      case 'Switch':        return I.renderSwitch(el, node, h);\n      case 'Picker':        return I.renderPicker(el, node, h);\n      case 'DatePicker':    return I.renderDatePicker(el, node, h);\n      case 'Slider':        return I.renderSlider(el, node, h);\n      case 'FilePicker':    return I.renderFilePicker(el, node, h);\n\n      // Action\n      case 'Button':        return A.renderButton(el, node, h);\n      case 'Link':          return A.renderLink(el, node);\n      case 'IconButton':    return A.renderIconButton(el, node, h);\n\n      // Feedback\n      case 'Spinner':       return F.renderSpinner(el);\n      case 'ProgressBar':   return F.renderProgressBar(el, node, h);\n      case 'EmptyState':    return F.renderEmptyState(el, node);\n      case 'ErrorState':    return F.renderErrorState(el, node);\n\n      // Slot\n      case 'Slot':          return renderSlot(el, node);\n\n      default: {\n        const def = this.opts.catalog?.get(node.kind);\n        el.style.cssText = 'padding:6px;background:rgba(0,0,0,0.03);border-radius:4px;font-size:12px;color:#6b6b6b;';\n        el.textContent = def ? `<${node.kind}>` : `Unknown piece: ${node.kind}`;\n        return el;\n      }\n    }\n  }\n}\n","/**\r\n * Back-compat shim — implementation lives in `./dom/index.ts`.\r\n * External imports of `pieces/dom-renderer` still resolve here.\r\n */\r\nexport { PieceDomRenderer } from './dom';\r\nexport type { PieceDomRendererOptions } from './dom';\r\n","/**\n * Shared helpers for React built-in pieces.\n */\n\nimport type { ReactNode } from 'react';\nimport type { PieceContext, PieceNode } from '../types';\n\nexport const UI = 'data-dddk-piece';\n\nexport function Frag({ children }: { children: ReactNode }) {\n  return <>{children}</>;\n}\n\nexport function renderChildren(node: PieceNode, ctx: PieceContext): ReactNode {\n  const children = node.children as PieceNode[] | undefined;\n  if (!children) return null;\n  return children.map((c, i) => <Frag key={c.id ?? i}>{ctx.render(c)}</Frag>);\n}\n\nexport function field(node: PieceNode, child: ReactNode) {\n  return (\n    <label style={{ display: 'flex', flexDirection: 'column', gap: 4, fontSize: 13 }}>\n      {node.label != null && <span>{node.label as string}</span>}\n      {child}\n    </label>\n  );\n}\n\n/**\n * Roving-tabindex keyboard handler shared by OptionGroup / ChoiceList.\n * Arrow keys move focus among siblings under the same parent; Enter/Space\n * confirms via the supplied `onConfirm`. Layout `row` swaps left/right with\n * up/down (the focused control is grid-shaped, both axes are valid).\n */\nexport function rovingTabindexKeyHandler<E extends HTMLElement>(\n  e: React.KeyboardEvent<E>,\n  idx: number,\n  total: number,\n  isRow: boolean,\n  onConfirm: () => void,\n): void {\n  const key = e.key;\n  if (key === 'Enter' || key === ' ') {\n    e.preventDefault();\n    onConfirm();\n    return;\n  }\n  let next = idx;\n  if (isRow) {\n    if (key === 'ArrowLeft' || key === 'ArrowUp') next = (idx - 1 + total) % total;\n    else if (key === 'ArrowRight' || key === 'ArrowDown') next = (idx + 1) % total;\n  } else {\n    if (key === 'ArrowUp' || key === 'ArrowLeft') next = (idx - 1 + total) % total;\n    else if (key === 'ArrowDown' || key === 'ArrowRight') next = (idx + 1) % total;\n  }\n  if (next !== idx) {\n    e.preventDefault();\n    const parent = e.currentTarget.parentElement;\n    const nextEl = parent?.children[next] as HTMLElement | undefined;\n    nextEl?.focus();\n  }\n}\n","import type { PieceDefinition, PieceNode } from '../types';\nimport { UI, renderChildren } from './_shared';\n\nexport const Stack: PieceDefinition = {\n  kind: 'Stack',\n  meta: { category: 'layout', description: '垂直 / 水平堆疊' },\n  render: (node, ctx) => (\n    <div\n      {...{ [UI]: 'stack' }}\n      data-direction={(node.direction as string) ?? 'vertical'}\n      style={{\n        display: 'flex',\n        flexDirection: node.direction === 'horizontal' ? 'row' : 'column',\n        gap: (node.gap as string | number) ?? 8,\n        alignItems: (node.align as string) ?? 'stretch',\n      }}\n    >\n      {renderChildren(node, ctx)}\n    </div>\n  ),\n};\n\nexport const Grid: PieceDefinition = {\n  kind: 'Grid',\n  meta: { category: 'layout', description: '網格佈局' },\n  render: (node, ctx) => (\n    <div\n      {...{ [UI]: 'grid' }}\n      style={{\n        display: 'grid',\n        gridTemplateColumns: `repeat(${(node.columns as number) ?? 2}, minmax(0, 1fr))`,\n        gap: (node.gap as string | number) ?? 8,\n      }}\n    >\n      {renderChildren(node, ctx)}\n    </div>\n  ),\n};\n\nexport const Split: PieceDefinition = {\n  kind: 'Split',\n  meta: { category: 'layout', description: '雙欄佈局' },\n  render: (node, ctx) => (\n    <div {...{ [UI]: 'split' }} style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>\n      {renderChildren(node, ctx)}\n    </div>\n  ),\n};\n\nexport const Card: PieceDefinition = {\n  kind: 'Card',\n  meta: { category: 'layout', description: '卡片容器' },\n  render: (node, ctx) => (\n    <div\n      {...{ [UI]: 'card' }}\n      style={{\n        background: 'var(--dddk-bg-elevated, #fff)',\n        borderRadius: 'var(--dddk-radius, 12px)',\n        padding: 16,\n        boxShadow: 'var(--dddk-shadow-md, 0 1px 3px rgba(0,0,0,0.05))',\n        display: 'flex', flexDirection: 'column', gap: 12,\n      }}\n    >\n      {renderChildren(node, ctx)}\n    </div>\n  ),\n};\n\nexport const Tabs: PieceDefinition = {\n  kind: 'Tabs',\n  meta: { category: 'layout', description: '頁籤' },\n  render: (node, ctx) => {\n    const tabs = (node.tabs as Array<{ id: string; label: string; content: PieceNode }>) ?? [];\n    const activeBind =\n      node.bind ?? (node.id ? `__activeTab_${node.id}` : '__activeTab');\n    const active = (ctx.data[activeBind] as string) ?? tabs[0]?.id;\n    const activeTab = tabs.find((t) => t.id === active) ?? tabs[0];\n    return (\n      <div {...{ [UI]: 'tabs' }}>\n        <div style={{ display: 'flex', gap: 8, borderBottom: '1px solid var(--dddk-border)' }}>\n          {tabs.map((t) => (\n            <button\n              key={t.id}\n              type=\"button\"\n              onClick={() => ctx.setBinding(activeBind, t.id)}\n              style={{\n                padding: '6px 12px', background: 'transparent', border: 0,\n                borderBottom: t.id === active ? '2px solid var(--dddk-accent)' : '2px solid transparent',\n                cursor: 'pointer', font: 'inherit',\n              }}\n            >\n              {t.label}\n            </button>\n          ))}\n        </div>\n        <div style={{ padding: 12 }}>{activeTab && ctx.render(activeTab.content)}</div>\n      </div>\n    );\n  },\n};\n\nexport const Group: PieceDefinition = {\n  kind: 'Group',\n  meta: { category: 'layout', description: 'Transparent flex container — no border / shadow / background. Use inside a Card to cluster children without stacking visual envelopes.' },\n  render: (node, ctx) => (\n    <div\n      {...{ [UI]: 'group' }}\n      style={{\n        display: 'flex',\n        flexDirection: (node.direction as string) === 'horizontal' ? 'row' : 'column',\n        gap: (node.gap as string | number) ?? 8,\n        alignItems: (node.align as string) ?? 'stretch',\n      }}\n    >\n      {renderChildren(node, ctx)}\n    </div>\n  ),\n};\n","import type { PieceDefinition } from '../types';\nimport { resolveValue } from '../renderer';\nimport { tone } from '../tokens';\nimport { UI } from './_shared';\n\nexport const Heading: PieceDefinition = {\n  kind: 'Heading',\n  meta: { category: 'content' },\n  render: (node, ctx) => {\n    const level = ((node.level as number) ?? 3) as 1 | 2 | 3 | 4 | 5 | 6;\n    const Tag = `h${level}` as const;\n    const text = resolveValue<string>(node, ctx, 'text', '');\n    return <Tag {...{ [UI]: 'heading' }} style={{ margin: '0 0 8px 0' }}>{text}</Tag>;\n  },\n};\n\nexport const Text: PieceDefinition = {\n  kind: 'Text',\n  meta: { category: 'content' },\n  render: (node, ctx) => {\n    const text = resolveValue<string>(node, ctx, 'text', '');\n    return <span {...{ [UI]: 'text' }}>{text}</span>;\n  },\n};\n\nexport const Code: PieceDefinition = {\n  kind: 'Code',\n  meta: { category: 'content' },\n  render: (node, ctx) => {\n    const code = resolveValue<string>(node, ctx, 'code', '');\n    return (\n      <pre {...{ [UI]: 'code' }} style={{\n        background: 'var(--dddk-bg, #fafafa)', padding: 8, borderRadius: 6,\n        fontFamily: 'var(--dddk-font-mono, ui-monospace, monospace)', fontSize: 12,\n        margin: 0, overflowX: 'auto',\n      }}>{code}</pre>\n    );\n  },\n};\n\nexport const Image: PieceDefinition = {\n  kind: 'Image',\n  meta: { category: 'content' },\n  render: (node) => (\n    <img {...{ [UI]: 'image' }} src={node.src as string} alt={(node.alt as string) ?? ''}\n      style={{ maxWidth: '100%', borderRadius: 6 }} />\n  ),\n};\n\nexport const Tag: PieceDefinition = {\n  kind: 'Tag',\n  meta: { category: 'content' },\n  render: (node) => {\n    const c = tone(node.tone);\n    return (\n      <span {...{ [UI]: 'tag' }} style={{\n        background: c.bg, color: c.fg, padding: '2px 8px', borderRadius: 12,\n        fontSize: 11, fontWeight: 500, display: 'inline-block',\n      }}>{node.text as string}</span>\n    );\n  },\n};\n\nexport const Divider: PieceDefinition = {\n  kind: 'Divider',\n  meta: { category: 'content' },\n  render: () => <hr {...{ [UI]: 'divider' }} style={{ border: 0, borderTop: '1px solid var(--dddk-border, rgba(0,0,0,0.1))', margin: '8px 0' }} />,\n};\n\nexport const Markdown: PieceDefinition = {\n  kind: 'Markdown',\n  meta: { category: 'content' },\n  render: (node, ctx) => {\n    const text = resolveValue<string>(node, ctx, 'text', '');\n    return <div {...{ [UI]: 'markdown' }} style={{ whiteSpace: 'pre-wrap' }}>{text}</div>;\n  },\n};\n","import type { PieceDefinition } from '../types';\nimport { resolveValue } from '../renderer';\nimport { UI } from './_shared';\n\nexport const Listing: PieceDefinition = {\n  kind: 'Listing',\n  meta: { category: 'data', description: '搜尋式清單' },\n  render: (node, ctx) => {\n    type Item = { id: string; title: string; subtitle?: string; accessory?: string; icon?: string };\n    const items = resolveValue<Item[]>(node, ctx, 'items', []);\n    return (\n      <ul {...{ [UI]: 'listing' }} style={{ listStyle: 'none', margin: 0, padding: 0 }}>\n        {items.map((it) => (\n          <li key={it.id} style={{\n            display: 'flex', gap: 8, padding: '6px 8px',\n            borderBottom: '1px solid var(--dddk-border, rgba(0,0,0,0.05))',\n          }}>\n            {it.icon && <span>{it.icon}</span>}\n            <div style={{ flex: 1, minWidth: 0 }}>\n              <div>{it.title}</div>\n              {it.subtitle && <small style={{ color: 'var(--dddk-text-muted, #6b6b6b)' }}>{it.subtitle}</small>}\n            </div>\n            {it.accessory && <span style={{ color: 'var(--dddk-text-muted, #6b6b6b)' }}>{it.accessory}</span>}\n          </li>\n        ))}\n      </ul>\n    );\n  },\n};\n\nexport const Table: PieceDefinition = {\n  kind: 'Table',\n  meta: { category: 'data' },\n  render: (node, ctx) => {\n    const columns = (node.columns as Array<{ key: string; label: string }>) ?? [];\n    const rows = resolveValue<Array<Record<string, unknown>>>(node, ctx, 'rows', []);\n    return (\n      <table {...{ [UI]: 'table' }} style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>\n        <thead>\n          <tr>{columns.map((c) => (\n            <th key={c.key} style={{ textAlign: 'left', padding: 6, borderBottom: '1px solid var(--dddk-border)' }}>\n              {c.label}\n            </th>\n          ))}</tr>\n        </thead>\n        <tbody>\n          {rows.map((r, i) => (\n            <tr key={i}>\n              {columns.map((c) => (\n                <td key={c.key} style={{ padding: 6, borderBottom: '1px solid var(--dddk-border, rgba(0,0,0,0.05))' }}>\n                  {String(r[c.key] ?? '')}\n                </td>\n              ))}\n            </tr>\n          ))}\n        </tbody>\n      </table>\n    );\n  },\n};\n\nexport const Metric: PieceDefinition = {\n  kind: 'Metric',\n  meta: { category: 'data', description: '單一數字 + 變動' },\n  render: (node) => {\n    const trend = (node.trend as string) ?? 'flat';\n    const trendColor = trend === 'up' ? '#10b981' : trend === 'down' ? '#ef4444' : '#6b6b6b';\n    const arrow = trend === 'up' ? '▲' : trend === 'down' ? '▼' : '–';\n    return (\n      <div {...{ [UI]: 'metric' }} style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n        {Boolean(node.label) && <span style={{ fontSize: 11, color: 'var(--dddk-text-muted, #6b6b6b)' }}>{node.label as string}</span>}\n        <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>\n          <strong style={{ fontSize: 22 }}>{node.value as string}</strong>\n          {node.delta != null && (\n            <span style={{ color: trendColor, fontSize: 12 }}>{arrow} {node.delta as string}</span>\n          )}\n        </div>\n      </div>\n    );\n  },\n};\n\nexport const Timeline: PieceDefinition = {\n  kind: 'Timeline',\n  meta: { category: 'data' },\n  render: (node, ctx) => {\n    type Event = { id: string; time: string; title: string; note?: string };\n    const events = resolveValue<Event[]>(node, ctx, 'events', []);\n    return (\n      <ol {...{ [UI]: 'timeline' }} style={{ listStyle: 'none', margin: 0, padding: 0, borderLeft: '2px solid var(--dddk-border)' }}>\n        {events.map((e) => (\n          <li key={e.id} style={{ marginLeft: 12, paddingLeft: 12, paddingBottom: 12, position: 'relative' }}>\n            <span style={{\n              position: 'absolute', left: -19, top: 6, width: 8, height: 8, borderRadius: '50%',\n              background: 'var(--dddk-accent, #3b82f6)',\n            }} />\n            <small style={{ color: 'var(--dddk-text-muted)' }}>{e.time}</small>\n            <div>{e.title}</div>\n            {e.note && <small style={{ color: 'var(--dddk-text-muted)' }}>{e.note}</small>}\n          </li>\n        ))}\n      </ol>\n    );\n  },\n};\n","import type { PieceDefinition } from '../types';\nimport { resolveValue } from '../renderer';\nimport { BASE_INPUT_STYLE } from '../tokens';\nimport { UI, field } from './_shared';\n\nexport const TextField: PieceDefinition = {\n  kind: 'TextField',\n  meta: { category: 'input' },\n  render: (node, ctx) => field(node, (\n    <input type=\"text\" {...{ [UI]: 'textfield' }} style={BASE_INPUT_STYLE}\n      value={String(resolveValue<string>(node, ctx, 'value', '') ?? '')}\n      placeholder={node.placeholder as string}\n      onChange={(e) => node.bind && ctx.setBinding(node.bind, e.target.value)} />\n  )),\n};\n\nexport const TextArea: PieceDefinition = {\n  kind: 'TextArea',\n  meta: { category: 'input' },\n  render: (node, ctx) => field(node, (\n    <textarea {...{ [UI]: 'textarea' }} style={BASE_INPUT_STYLE}\n      rows={(node.rows as number) ?? 3}\n      value={String(resolveValue<string>(node, ctx, 'value', '') ?? '')}\n      placeholder={node.placeholder as string}\n      onChange={(e) => node.bind && ctx.setBinding(node.bind, e.target.value)} />\n  )),\n};\n\nexport const NumberField: PieceDefinition = {\n  kind: 'NumberField',\n  meta: { category: 'input' },\n  render: (node, ctx) => field(node, (\n    <input type=\"number\" {...{ [UI]: 'numberfield' }} style={BASE_INPUT_STYLE}\n      value={Number(resolveValue<number>(node, ctx, 'value', 0)) || 0}\n      min={node.min as number} max={node.max as number} step={node.step as number}\n      onChange={(e) => node.bind && ctx.setBinding(node.bind, Number(e.target.value))} />\n  )),\n};\n\nexport const PasswordField: PieceDefinition = {\n  kind: 'PasswordField',\n  meta: { category: 'input' },\n  render: (node, ctx) => field(node, (\n    <input type=\"password\" {...{ [UI]: 'password' }} style={BASE_INPUT_STYLE}\n      value={String(resolveValue<string>(node, ctx, 'value', '') ?? '')}\n      onChange={(e) => node.bind && ctx.setBinding(node.bind, e.target.value)} />\n  )),\n};\n\nexport const Checkbox: PieceDefinition = {\n  kind: 'Checkbox',\n  meta: { category: 'input' },\n  render: (node, ctx) => (\n    <label style={{ display: 'flex', gap: 6, alignItems: 'center', fontSize: 13 }}>\n      <input type=\"checkbox\" checked={Boolean(resolveValue<boolean>(node, ctx, 'value', false))}\n        onChange={(e) => node.bind && ctx.setBinding(node.bind, e.target.checked)} />\n      <span>{node.label as string}</span>\n    </label>\n  ),\n};\n\nexport const Switch: PieceDefinition = {\n  kind: 'Switch',\n  meta: { category: 'input' },\n  render: (node, ctx) => {\n    const checked = Boolean(resolveValue<boolean>(node, ctx, 'value', false));\n    return (\n      <label style={{ display: 'flex', gap: 8, alignItems: 'center', fontSize: 13, cursor: 'pointer' }}>\n        <span\n          onClick={() => node.bind && ctx.setBinding(node.bind, !checked)}\n          style={{\n            width: 32, height: 18, borderRadius: 9, position: 'relative',\n            background: checked ? 'var(--dddk-accent)' : 'rgba(0,0,0,0.2)',\n            transition: 'background 120ms',\n          }}>\n          <span style={{\n            position: 'absolute', top: 2, left: checked ? 16 : 2,\n            width: 14, height: 14, borderRadius: '50%', background: '#fff',\n            transition: 'left 120ms',\n          }} />\n        </span>\n        {Boolean(node.label) && <span>{node.label as string}</span>}\n      </label>\n    );\n  },\n};\n\nexport const Picker: PieceDefinition = {\n  kind: 'Picker',\n  meta: { category: 'input' },\n  render: (node, ctx) => {\n    const options = (node.options as Array<string | { value: string; label: string }>) ?? [];\n    return field(node, (\n      <select style={BASE_INPUT_STYLE}\n        value={String(resolveValue<string>(node, ctx, 'value', '') ?? '')}\n        onChange={(e) => node.bind && ctx.setBinding(node.bind, e.target.value)}>\n        {options.map((o) => {\n          const v = typeof o === 'string' ? o : o.value;\n          const l = typeof o === 'string' ? o : o.label;\n          return <option key={v} value={v}>{l}</option>;\n        })}\n      </select>\n    ));\n  },\n};\n\nexport const DatePicker: PieceDefinition = {\n  kind: 'DatePicker',\n  meta: { category: 'input' },\n  render: (node, ctx) => field(node, (\n    <input type=\"datetime-local\" style={BASE_INPUT_STYLE}\n      value={String(resolveValue<string>(node, ctx, 'value', '') ?? '')}\n      onChange={(e) => node.bind && ctx.setBinding(node.bind, e.target.value)} />\n  )),\n};\n\nexport const Slider: PieceDefinition = {\n  kind: 'Slider',\n  meta: { category: 'input' },\n  render: (node, ctx) => field(node, (\n    <input type=\"range\"\n      min={(node.min as number) ?? 0}\n      max={(node.max as number) ?? 100}\n      step={(node.step as number) ?? 1}\n      value={Number(resolveValue<number>(node, ctx, 'value', 0)) || 0}\n      onChange={(e) => node.bind && ctx.setBinding(node.bind, Number(e.target.value))} />\n  )),\n};\n\nexport const FilePicker: PieceDefinition = {\n  kind: 'FilePicker',\n  meta: { category: 'input' },\n  render: (node, ctx) => field(node, (\n    <input type=\"file\" accept={node.accept as string}\n      multiple={Boolean(node.multiple)}\n      onChange={(e) => {\n        if (!node.bind) return;\n        const files = Array.from(e.target.files ?? []);\n        ctx.setBinding(node.bind, files);\n      }} />\n  )),\n};\n","import type { PieceDefinition } from '../types';\nimport { BUTTON_VARIANTS_REACT } from '../tokens';\nimport { UI } from './_shared';\n\nexport const Button: PieceDefinition = {\n  kind: 'Button',\n  meta: { category: 'action' },\n  render: (node, ctx) => {\n    const variant = (node.variant as string) ?? 'primary';\n    const style = BUTTON_VARIANTS_REACT[variant] ?? BUTTON_VARIANTS_REACT.primary!;\n    return (\n      <button type=\"button\" {...{ [UI]: 'button' }}\n        onClick={() => ctx.trigger((node.action as string) ?? 'submit', node.payload)}\n        style={{\n          ...style, padding: '6px 14px', borderRadius: 6, border: 0,\n          font: 'inherit', cursor: 'pointer', fontWeight: 500,\n        }}>\n        {node.text as string}\n      </button>\n    );\n  },\n};\n\nexport const Link: PieceDefinition = {\n  kind: 'Link',\n  meta: { category: 'action' },\n  render: (node) => (\n    <a {...{ [UI]: 'link' }} href={node.href as string} target={node.target as string}\n      style={{ color: 'var(--dddk-accent)', textDecoration: 'underline', cursor: 'pointer' }}>\n      {node.text as string}\n    </a>\n  ),\n};\n\nexport const IconButton: PieceDefinition = {\n  kind: 'IconButton',\n  meta: { category: 'action' },\n  render: (node, ctx) => (\n    <button type=\"button\" {...{ [UI]: 'icon-button' }}\n      title={node.title as string}\n      onClick={() => ctx.trigger((node.action as string) ?? 'click', node.payload)}\n      style={{ background: 'transparent', border: 0, cursor: 'pointer', padding: 4, fontSize: 16 }}>\n      {node.icon as string}\n    </button>\n  ),\n};\n","import type { PieceDefinition } from '../types';\nimport { resolveValue } from '../renderer';\nimport { UI } from './_shared';\n\nexport const Spinner: PieceDefinition = {\n  kind: 'Spinner',\n  meta: { category: 'feedback' },\n  render: () => <span {...{ [UI]: 'spinner' }}>⋯</span>,\n};\n\nexport const ProgressBar: PieceDefinition = {\n  kind: 'ProgressBar',\n  meta: { category: 'feedback' },\n  render: (node, ctx) => {\n    const v = Number(resolveValue<number>(node, ctx, 'value', 0)) || 0;\n    return (\n      <div style={{ background: 'rgba(0,0,0,0.08)', height: 6, borderRadius: 3, overflow: 'hidden' }}>\n        <div style={{\n          width: `${Math.min(100, Math.max(0, v))}%`, height: '100%',\n          background: 'var(--dddk-accent, #3b82f6)', transition: 'width 200ms',\n        }} />\n      </div>\n    );\n  },\n};\n\nexport const EmptyState: PieceDefinition = {\n  kind: 'EmptyState',\n  meta: { category: 'feedback' },\n  render: (node) => (\n    <div {...{ [UI]: 'empty-state' }} style={{\n      padding: 24, textAlign: 'center', color: 'var(--dddk-text-muted, #6b6b6b)',\n    }}>\n      <div style={{ fontSize: 28, marginBottom: 8 }}>{(node.icon as string) ?? '∅'}</div>\n      <div>{node.title as string ?? 'No data'}</div>\n      {Boolean(node.description) && <small>{node.description as string}</small>}\n    </div>\n  ),\n};\n\nexport const ErrorState: PieceDefinition = {\n  kind: 'ErrorState',\n  meta: { category: 'feedback' },\n  render: (node) => (\n    <div {...{ [UI]: 'error-state' }} style={{\n      padding: 16, background: 'rgba(239,68,68,0.08)', border: '1px solid #ef4444',\n      borderRadius: 6, color: '#991b1b',\n    }}>\n      <strong>{node.title as string ?? 'Error'}</strong>\n      {Boolean(node.message) && <div style={{ marginTop: 4, fontSize: 13 }}>{node.message as string}</div>}\n    </div>\n  ),\n};\n","/**\n * Rich selection pieces — MediaCard, OptionGroup, ChoiceList.\n *\n * MediaCard is a transparent presentation tile (image + text). OptionGroup\n * wraps MediaCard-shaped tiles into a keyboard-navigable radio group.\n * ChoiceList is its text-only sibling. Both share roving-tabindex semantics.\n */\n\nimport type { PieceDefinition } from '../types';\nimport { readPointer } from '../pointer';\nimport { UI, rovingTabindexKeyHandler } from './_shared';\n\nexport const MediaCard: PieceDefinition = {\n  kind: 'MediaCard',\n  meta: { category: 'layout', description: 'Image + text tile. Transparent; compose inside a Card or OptionGroup.' },\n  render: (node) => {\n    const orientation = (node.orientation as 'top' | 'left') ?? 'top';\n    const image = node.image as { src: string; alt?: string; aspectRatio?: string } | undefined;\n    const title = (node.title as string) ?? '';\n    const description = node.description as string | undefined;\n    const meta = (node.meta as string[]) ?? [];\n    const isLeft = orientation === 'left';\n    return (\n      <div\n        {...{ [UI]: 'media-card' }}\n        data-orientation={orientation}\n        style={{\n          display: 'flex',\n          flexDirection: isLeft ? 'row' : 'column',\n          gap: isLeft ? 12 : 8,\n          alignItems: isLeft ? 'flex-start' : 'stretch',\n        }}\n      >\n        {image?.src && (\n          <div style={{\n            flex: isLeft ? '0 0 96px' : '0 0 auto',\n            width: isLeft ? 96 : '100%',\n            aspectRatio: image.aspectRatio ?? (isLeft ? '1' : '16/9'),\n            overflow: 'hidden',\n            borderRadius: 'var(--dddk-radius-sm, 6px)',\n            background: 'var(--dddk-bg-subtle, rgba(0,0,0,0.04))',\n          }}>\n            <img\n              src={image.src}\n              alt={image.alt ?? ''}\n              style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}\n            />\n          </div>\n        )}\n        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 4, minWidth: 0 }}>\n          {title && <div style={{ fontWeight: 600, fontSize: 14, lineHeight: 1.3 }}>{title}</div>}\n          {description && (\n            <div style={{ fontSize: 13, color: 'var(--dddk-text-muted, #64748b)', lineHeight: 1.45 }}>{description}</div>\n          )}\n          {meta.length > 0 && (\n            <div style={{ display: 'flex', gap: 8, fontSize: 11.5, color: 'var(--dddk-text-muted, #64748b)', marginTop: 2 }}>\n              {meta.map((m, i) => <span key={i}>{m}</span>)}\n            </div>\n          )}\n        </div>\n      </div>\n    );\n  },\n};\n\ninterface OptionSpec {\n  value: string;\n  title: string;\n  description?: string;\n  meta?: string[];\n  image?: { src: string; alt?: string; aspectRatio?: string };\n}\n\nexport const OptionGroup: PieceDefinition = {\n  kind: 'OptionGroup',\n  meta: { category: 'input', description: 'Keyboard-navigable MediaCard-shaped radio group. Fires `trigger(\"choose\", { value, index })`.' },\n  render: (node, ctx) => {\n    const options = (node.options as OptionSpec[]) ?? [];\n    const bind = (node.bind as string) ?? '';\n    const layout = (node.layout as 'row' | 'column') ?? 'column';\n    const columns = node.columns as number | undefined;\n    const selected = bind ? readPointer(ctx.data, bind) : undefined;\n    const isRow = layout === 'row';\n    const gridCols = isRow ? (columns ?? options.length) : 1;\n\n    const choose = (i: number) => {\n      if (bind) ctx.setBinding(bind, options[i]!.value);\n      ctx.trigger('choose', { value: options[i]!.value, index: i });\n    };\n\n    return (\n      <div\n        {...{ [UI]: 'option-group' }}\n        role=\"radiogroup\"\n        data-layout={layout}\n        style={{\n          display: 'grid',\n          gridTemplateColumns: isRow ? `repeat(${gridCols}, minmax(0, 1fr))` : '1fr',\n          gap: 8,\n        }}\n      >\n        {options.map((opt, i) => {\n          const isSelected = opt.value === selected || (selected === undefined && i === 0);\n          return (\n            <div\n              key={opt.value}\n              role=\"radio\"\n              aria-checked={isSelected}\n              tabIndex={isSelected ? 0 : -1}\n              onClick={() => choose(i)}\n              onKeyDown={(e) => rovingTabindexKeyHandler(e, i, options.length, isRow, () => choose(i))}\n              style={{\n                display: 'flex',\n                flexDirection: 'column',\n                gap: 8,\n                padding: 12,\n                cursor: 'pointer',\n                outline: 'none',\n                borderRadius: 'var(--dddk-radius, 10px)',\n                border: '1px solid',\n                borderColor: isSelected ? 'var(--dddk-accent, #6366f1)' : 'var(--dddk-border, rgba(0,0,0,0.08))',\n                background: isSelected ? 'var(--dddk-accent-soft, rgba(99,102,241,0.08))' : 'transparent',\n                transition: 'border-color 120ms, background 120ms',\n              }}\n              onFocus={(e) => { (e.currentTarget as HTMLDivElement).style.boxShadow = '0 0 0 2px var(--dddk-accent-soft, rgba(99,102,241,0.2))'; }}\n              onBlur={(e) => { (e.currentTarget as HTMLDivElement).style.boxShadow = 'none'; }}\n            >\n              {opt.image?.src && (\n                <div style={{\n                  width: '100%',\n                  aspectRatio: opt.image.aspectRatio ?? '16/9',\n                  overflow: 'hidden',\n                  borderRadius: 'var(--dddk-radius-sm, 6px)',\n                  background: 'var(--dddk-bg-subtle, rgba(0,0,0,0.04))',\n                }}>\n                  <img src={opt.image.src} alt={opt.image.alt ?? ''} style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />\n                </div>\n              )}\n              <div style={{ fontWeight: 600, fontSize: 14 }}>{opt.title}</div>\n              {opt.description && (\n                <div style={{ fontSize: 13, color: 'var(--dddk-text-muted, #64748b)', lineHeight: 1.45 }}>{opt.description}</div>\n              )}\n              {opt.meta && opt.meta.length > 0 && (\n                <div style={{ display: 'flex', gap: 8, fontSize: 11.5, color: 'var(--dddk-text-muted, #64748b)' }}>\n                  {opt.meta.map((m, mi) => <span key={mi}>{m}</span>)}\n                </div>\n              )}\n            </div>\n          );\n        })}\n      </div>\n    );\n  },\n};\n\nexport const ChoiceList: PieceDefinition = {\n  kind: 'ChoiceList',\n  meta: { category: 'input', description: 'Text-only radio sibling of OptionGroup. Same keyboard model, denser.' },\n  render: (node, ctx) => {\n    const options = (node.options as Array<{ value: string; label: string; description?: string }>) ?? [];\n    const bind = (node.bind as string) ?? '';\n    const orientation = (node.orientation as 'row' | 'column') ?? 'column';\n    const selected = bind ? readPointer(ctx.data, bind) : undefined;\n    const isRow = orientation === 'row';\n\n    const choose = (i: number) => {\n      if (bind) ctx.setBinding(bind, options[i]!.value);\n      ctx.trigger('choose', { value: options[i]!.value, index: i });\n    };\n\n    return (\n      <div\n        {...{ [UI]: 'choice-list' }}\n        role=\"radiogroup\"\n        data-orientation={orientation}\n        style={{\n          display: 'flex',\n          flexDirection: isRow ? 'row' : 'column',\n          gap: 6,\n        }}\n      >\n        {options.map((opt, i) => {\n          const isSelected = opt.value === selected || (selected === undefined && i === 0);\n          return (\n            <div\n              key={opt.value}\n              role=\"radio\"\n              aria-checked={isSelected}\n              tabIndex={isSelected ? 0 : -1}\n              onClick={() => choose(i)}\n              onKeyDown={(e) => rovingTabindexKeyHandler(e, i, options.length, isRow, () => choose(i))}\n              style={{\n                flex: isRow ? '1 1 0' : '0 0 auto',\n                padding: '10px 14px',\n                cursor: 'pointer',\n                outline: 'none',\n                borderRadius: 'var(--dddk-radius-sm, 6px)',\n                border: '1px solid',\n                borderColor: isSelected ? 'var(--dddk-accent, #6366f1)' : 'var(--dddk-border, rgba(0,0,0,0.08))',\n                background: isSelected ? 'var(--dddk-accent-soft, rgba(99,102,241,0.08))' : 'transparent',\n                transition: 'border-color 120ms, background 120ms',\n              }}\n              onFocus={(e) => { (e.currentTarget as HTMLDivElement).style.boxShadow = '0 0 0 2px var(--dddk-accent-soft, rgba(99,102,241,0.2))'; }}\n              onBlur={(e) => { (e.currentTarget as HTMLDivElement).style.boxShadow = 'none'; }}\n            >\n              <div style={{ fontWeight: 500, fontSize: 14 }}>{opt.label}</div>\n              {opt.description && (\n                <div style={{ fontSize: 12.5, color: 'var(--dddk-text-muted, #64748b)', marginTop: 2 }}>{opt.description}</div>\n              )}\n            </div>\n          );\n        })}\n      </div>\n    );\n  },\n};\n","import type { ReactNode } from 'react';\nimport type { PieceDefinition } from '../types';\nimport { UI } from './_shared';\n\nexport const Slot: PieceDefinition = {\n  kind: 'Slot',\n  meta: { category: 'slot', description: '渲染 host 提供的 React/Web component' },\n  render: (node, ctx) => {\n    if (typeof node.render === 'function') {\n      return (node.render as (data: Record<string, unknown>) => ReactNode)(ctx.data);\n    }\n    if (typeof node.slotName === 'string') {\n      const map = (typeof window !== 'undefined' &&\n        (window as unknown as { __dddkSlots?: Record<string, ReactNode> }).__dddkSlots) || {};\n      return map[node.slotName] ?? <div {...{ [UI]: 'slot-empty' }}>(slot:{node.slotName})</div>;\n    }\n    return null;\n  },\n};\n","/**\n * 33 built-in Pieces, organized by category.\n * See ../../docs/13-pieces.md for the full design.\n */\n\nimport type { PieceDefinition } from '../types';\nimport { PieceCatalog as Catalog } from '../types';\n\nimport { Stack, Grid, Split, Card, Tabs, Group } from './layout';\nimport { Heading, Text, Code, Image, Tag, Divider, Markdown } from './content';\nimport { Listing, Table, Metric, Timeline } from './data';\nimport {\n  TextField, TextArea, NumberField, PasswordField,\n  Checkbox, Switch, Picker, DatePicker, Slider, FilePicker,\n} from './inputs';\nimport { Button, Link, IconButton } from './actions';\nimport { Spinner, ProgressBar, EmptyState, ErrorState } from './feedback';\nimport { MediaCard, OptionGroup, ChoiceList } from './selection';\nimport { Slot } from './slot';\n\nexport const builtinPieces: PieceDefinition[] = [\n  // layout\n  Stack, Grid, Split, Card, Tabs, Group,\n  // content\n  Heading, Text, Code, Image, Tag, Divider, Markdown,\n  // data\n  Listing, Table, Metric, Timeline,\n  // input\n  TextField, TextArea, NumberField, PasswordField,\n  Checkbox, Switch, Picker, DatePicker, Slider, FilePicker,\n  // rich layout + selection\n  MediaCard, OptionGroup, ChoiceList,\n  // action\n  Button, Link, IconButton,\n  // feedback\n  Spinner, ProgressBar, EmptyState, ErrorState,\n  // slot\n  Slot,\n];\n\nexport function createBuiltinCatalog(): Catalog {\n  return new Catalog(builtinPieces);\n}\n","/**\n * Back-compat shim — implementation lives in `./builtin/index.ts`.\n */\nexport { builtinPieces, createBuiltinCatalog } from './builtin/index';\n","/**\n * Surface envelope ↔ Pieces bridge.\n *\n * The flat envelope shape (a list of components keyed by id + a data model)\n * is the on-the-wire format some agent runtimes emit. Our PieceSurface uses\n * a tree of PieceNodes with inline children. Same underlying primitives,\n * different wire shape. This file converts between them.\n */\n\nimport type { PieceSurface, PieceNode } from './types';\n\ninterface EnvelopeComponent {\n  id: string;\n  component: string;\n  children?: string[];\n  [key: string]: unknown;\n}\n\ninterface SurfaceEnvelope {\n  version: 'v0.10';\n  updateComponents?: {\n    surfaceId?: string;\n    catalogId?: string;\n    components: EnvelopeComponent[];\n  };\n  updateDataModel?: {\n    surfaceId?: string;\n    data: Record<string, unknown>;\n  };\n}\n\n/**\n * Convert a flat envelope into a PieceSurface our renderer can consume.\n * Uses the component with id 'root' (or the first one) as the tree root,\n * recursively expanding `children` ids into nested PieceNodes.\n */\nexport function envelopeToSurface(envelope: SurfaceEnvelope): PieceSurface | null {\n  const components = envelope.updateComponents?.components ?? [];\n  if (components.length === 0) return null;\n\n  const byId = new Map<string, EnvelopeComponent>();\n  for (const c of components) byId.set(c.id, c);\n\n  const rootComp = byId.get('root') ?? components[0];\n  if (!rootComp) return null;\n\n  const root = expand(rootComp, byId, new Set());\n\n  return {\n    root,\n    data: envelope.updateDataModel?.data ?? {},\n  };\n}\n\nfunction expand(\n  comp: EnvelopeComponent,\n  byId: Map<string, EnvelopeComponent>,\n  visited: Set<string>,\n): PieceNode {\n  const { id, component, children, ...rest } = comp;\n  const node: PieceNode = {\n    kind: component,\n    id,\n    ...rest,\n  };\n  // Cycle guard: an envelope where component A lists B as a child and B lists\n  // A back would recurse forever. Mark this id before descending, unmark after\n  // (siblings can still reference the same component non-cyclically).\n  if (visited.has(id)) return node;\n  visited.add(id);\n  if (Array.isArray(children) && children.length > 0) {\n    const childNodes: PieceNode[] = [];\n    for (const childId of children) {\n      if (visited.has(childId)) continue;\n      const child = byId.get(childId);\n      if (child) childNodes.push(expand(child, byId, visited));\n    }\n    node.children = childNodes;\n  }\n  visited.delete(id);\n  return node;\n}\n\n/**\n * Reverse — turn a PieceSurface into a flat envelope. Useful when the agent\n * authors UI imperatively and needs to send it cross-process.\n */\nexport function surfaceToEnvelope(surface: PieceSurface, surfaceId = 'default'): SurfaceEnvelope {\n  const components: EnvelopeComponent[] = [];\n  let nextAuto = 1;\n\n  function visit(node: PieceNode, suggestedId?: string): string {\n    const id = node.id ?? suggestedId ?? `auto_${nextAuto++}`;\n    const childIds: string[] = [];\n    if (Array.isArray(node.children)) {\n      for (const child of node.children as PieceNode[]) {\n        childIds.push(visit(child));\n      }\n    }\n    const { kind, id: _drop, children: _drop2, ...rest } = node;\n    const comp: EnvelopeComponent = {\n      id,\n      component: kind,\n      ...(childIds.length > 0 ? { children: childIds } : {}),\n      ...(rest as Record<string, unknown>),\n    };\n    components.push(comp);\n    return id;\n  }\n\n  visit(surface.root, 'root');\n\n  return {\n    version: 'v0.10',\n    updateComponents: { surfaceId, components },\n    ...(surface.data ? { updateDataModel: { surfaceId, data: surface.data } } : {}),\n  };\n}\n","/**\n * @perhapxin/dddk Pieces — unified UI primitive system.\n * See ../../docs/13-pieces.md for the full design.\n */\n\nexport type {\n  PieceNode,\n  PieceContext,\n  PieceDefinition,\n  PieceSurface,\n} from './types';\nexport { PieceCatalog } from './types';\n\nexport { PieceRenderer, readPointer, resolveValue } from './renderer';\nexport type { PieceRendererProps } from './renderer';\n\nexport { PieceDomRenderer } from './dom-renderer';\nexport type { PieceDomRendererOptions } from './dom-renderer';\n\nexport { builtinPieces, createBuiltinCatalog } from './builtin';\n\nexport { envelopeToSurface, surfaceToEnvelope } from './surface-bridge';\n","/**\n * Synthetic cursor overlay.\n *\n * When the agent runs `click`, it normally calls `el.click()` instantly —\n * which from the user's POV looks like the button just got pressed by a\n * ghost. The synthetic cursor smooths this over:\n *\n *   1. A small arrow overlay is rendered above the page chrome.\n *   2. It slides from its last position (or window centre on first use)\n *      to the target element's centre — CSS transition, ~350ms ease-in-out.\n *   3. A short \"press\" tap animation runs (scale down/up).\n *   4. THEN we call `el.click()`.\n *\n * The cursor is purely visual — DOM events are still synthesised by\n * `el.click()`, not by simulating mousedown / mouseup at coordinates.\n * The point is human-paced visual feedback, not bypassing event handlers.\n *\n * Off by default. Host opts in via `new WebAgent({ cursorTrail: true })`.\n * Respects `prefers-reduced-motion` (skip the slide, still flashes briefly\n * so users know SOMETHING happened).\n */\n\nconst CURSOR_ID = 'webagent-cursor';\nconst CURSOR_STYLE_ID = 'webagent-cursor-style';\n\nconst CURSOR_CSS = `\n  #${CURSOR_ID} {\n    position: fixed;\n    top: 0; left: 0;\n    z-index: var(--webagent-z-overlay, 9100);\n    pointer-events: none;\n    transition:\n      transform var(--webagent-cursor-glide-ms, 360ms) cubic-bezier(0.4, 0, 0.2, 1),\n      opacity 160ms ease;\n    will-change: transform;\n    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.25));\n  }\n  #${CURSOR_ID}.tapping {\n    transition: transform 90ms ease-in;\n    transform-origin: top left;\n  }\n  #${CURSOR_ID}.pulsing::after {\n    content: '';\n    position: absolute;\n    top: 0; left: 0;\n    width: 18px; height: 18px;\n    border-radius: 50%;\n    border: 2px solid var(--webagent-cursor-fill, #111);\n    opacity: 0.55;\n    pointer-events: none;\n    animation: ${CURSOR_ID}-pulse 600ms ease-out forwards;\n  }\n  @keyframes ${CURSOR_ID}-pulse {\n    0%   { transform: scale(0.4); opacity: 0.6; }\n    100% { transform: scale(2.2); opacity: 0; }\n  }\n  #${CURSOR_ID}.hidden { opacity: 0; }\n  @media (prefers-reduced-motion: reduce) {\n    #${CURSOR_ID} { transition: opacity 80ms linear; }\n    #${CURSOR_ID}.pulsing::after { animation: none; opacity: 0; }\n  }\n`;\n\n/** Visual mode of the cursor. v0.2.0 — broader UX coverage. */\nexport type CursorMode = 'pointer' | 'scroll' | 'reading';\n\n/**\n * The `pointer` mode is a bitmap sprite by default — a duck riding a\n * paper airplane, sharp origami tip at the top-left as the click\n * origin. Host swaps the whole sprite via `--dddk-cursor-url`. Scroll\n * / reading modes stay SVG so they remain themeable via\n * `--webagent-cursor-fill` / `-stroke`.\n *\n * Sizing note: the sprite is rendered inside a 34×34 wrapper so the\n * hotspot (top-left corner) aligns with the previous SVG cursor's\n * click origin. Non-square PNG assets scale to fit.\n */\nconst CURSOR_SPRITE_HTML = `\n    <img\n      alt=\"\"\n      draggable=\"false\"\n      style=\"display:block; width:34px; height:34px; object-fit:contain; object-position:top left;\n             pointer-events:none; -webkit-user-drag:none;\"\n      src=\"\"\n    />\n  `;\n\nconst CURSOR_SVG_BY_MODE: Record<Exclude<CursorMode, 'pointer'>, string> = {\n  scroll: `\n    <svg width=\"22\" height=\"22\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <rect x=\"6\" y=\"2\" width=\"8\" height=\"14\" rx=\"4\"\n        fill=\"var(--webagent-cursor-fill, #111)\"\n        stroke=\"var(--webagent-cursor-stroke, #fff)\" stroke-width=\"1\" />\n      <line x1=\"10\" y1=\"5\" x2=\"10\" y2=\"9\"\n        stroke=\"var(--webagent-cursor-stroke, #fff)\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n    </svg>\n  `,\n  reading: `\n    <svg width=\"22\" height=\"22\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <circle cx=\"10\" cy=\"10\" r=\"7\"\n        fill=\"none\"\n        stroke=\"var(--webagent-cursor-fill, #111)\" stroke-width=\"1.8\" />\n      <circle cx=\"10\" cy=\"10\" r=\"2.2\"\n        fill=\"var(--webagent-cursor-fill, #111)\" />\n    </svg>\n  `,\n};\n\nlet cursorEl: HTMLDivElement | null = null;\nlet lastX = -1;\nlet lastY = -1;\nlet currentMode: CursorMode = 'pointer';\n\n/**\n * Anchored target. Once a move call lands on this element, a RAF\n * loop keeps the cursor's viewport position in sync with the\n * element's `getBoundingClientRect()` on every frame — so the\n * cursor follows the element when the user scrolls, the page\n * relayouts, or content reflows. Calling `hideCursor` /\n * `setCursorAnchor(null)` releases the lock.\n */\nlet anchorEl: Element | null = null;\nlet anchorRafId: number | null = null;\n\nfunction ensureCursor(): HTMLDivElement {\n  if (cursorEl && document.body.contains(cursorEl)) return cursorEl;\n  if (!document.getElementById(CURSOR_STYLE_ID)) {\n    const style = document.createElement('style');\n    style.id = CURSOR_STYLE_ID;\n    style.textContent = CURSOR_CSS;\n    document.head.appendChild(style);\n  }\n  const wrap = document.createElement('div');\n  wrap.id = CURSOR_ID;\n  wrap.className = 'hidden';\n  wrap.setAttribute('aria-hidden', 'true');\n  // Default mode is the bitmap pointer (duck-on-paper-airplane sprite).\n  // setCursorMode() swaps in scroll / reading SVGs at runtime.\n  renderPointerSprite(wrap);\n  document.body.appendChild(wrap);\n  cursorEl = wrap;\n  return wrap;\n}\n\n/**\n * Fill `wrap` with the pointer sprite `<img>` reading its source from\n * `--dddk-cursor-url` (falls back to `--dddk-avatar-url` for hosts\n * that haven't wired the cursor sprite). Kept as a helper so `setCursorMode`\n * can restore it cleanly when swapping back from scroll / reading.\n */\nfunction renderPointerSprite(wrap: HTMLDivElement): void {\n  wrap.innerHTML = CURSOR_SPRITE_HTML;\n  const img = wrap.querySelector<HTMLImageElement>('img');\n  if (!img) return;\n  // Read the URL from :root computed style so hosts can override with\n  // one CSS declaration and swap the whole sprite. Fallback chain:\n  //   --dddk-cursor-url → --dddk-avatar-url → hard-coded transparent 1×1\n  //   (the last keeps the wrapper positioned even if no sprite is wired).\n  const rootStyle = getComputedStyle(document.documentElement);\n  const raw = (rootStyle.getPropertyValue('--dddk-cursor-url')\n    || rootStyle.getPropertyValue('--dddk-avatar-url')\n    || '').trim();\n  const match = raw.match(/url\\([\"']?(.+?)[\"']?\\)/);\n  img.src = match?.[1] ?? 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';\n}\n\nfunction setPosition(el: HTMLDivElement, x: number, y: number): void {\n  el.style.transform = `translate(${x}px, ${y}px)`;\n  lastX = x;\n  lastY = y;\n}\n\nfunction getStartPoint(): { x: number; y: number } {\n  if (lastX >= 0 && lastY >= 0) return { x: lastX, y: lastY };\n  // First use — start from off-screen-left so the entrance slide is visible.\n  return {\n    x: -32,\n    y: Math.max(40, window.innerHeight / 2),\n  };\n}\n\nfunction reducedMotion(): boolean {\n  try {\n    return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Glide the synthetic cursor to `target` and play a tap animation.\n * Returns when the tap animation has finished (so the caller can fire\n * the real `el.click()` immediately after).\n *\n * `targetEl` is the DOM element you're about to click. We sample its\n * centre as the destination point. If the target is offscreen, the cursor\n * still slides — pair with a `scrollTo` action first if you want the\n * user to see the click happen.\n */\nexport async function moveCursorAndTap(targetEl: Element): Promise<void> {\n  if (typeof document === 'undefined' || !document.body) return;\n\n  // Release any prior anchor BEFORE the glide animation — otherwise\n  // the RAF loop keeps pulling the cursor back to the old target\n  // mid-transition.\n  setCursorAnchor(null);\n\n  const wrap = ensureCursor();\n  await ensureInView(targetEl);\n  const { destX, destY } = cursorAnchor(targetEl);\n\n  const reduced = reducedMotion();\n  const glideMs = reduced ? 0 : 360;\n\n  // Place at start point (or last point) BEFORE setting transition target.\n  const start = getStartPoint();\n  if (wrap.classList.contains('hidden')) {\n    // Reflow trick: assign start with transition disabled, then enable\n    // and assign destination so the browser interpolates between them.\n    wrap.style.transition = 'none';\n    setPosition(wrap, start.x, start.y);\n    // Force a reflow so the next transform change tweens.\n    void wrap.offsetWidth;\n    wrap.style.transition = '';\n    wrap.classList.remove('hidden');\n  }\n\n  setPosition(wrap, destX, destY);\n  await sleep(glideMs);\n\n  // Tap: scale down + scale back up.\n  wrap.classList.add('tapping');\n  wrap.style.transform = `translate(${destX}px, ${destY}px) scale(0.78)`;\n  await sleep(reduced ? 0 : 90);\n  wrap.style.transform = `translate(${destX}px, ${destY}px) scale(1)`;\n  await sleep(reduced ? 0 : 90);\n  wrap.classList.remove('tapping');\n\n  // Glide done — anchor the cursor TO the element. From now on the\n  // RAF loop keeps the cursor's viewport coords aligned with the\n  // element's rect so scrolls / layout shifts don't desync it.\n  setCursorAnchor(targetEl);\n}\n\n/**\n * Center of the target's current viewport rect. No heuristics — the\n * cursor anchor mechanism below keeps recomputing this every frame\n * so layout shifts / scrolls follow naturally. If the model picked a\n * giant element as the target, that's a model-side problem\n * (`narrate.about` should be the specific element it's referring to,\n * not the section wrapper), not something for this function to\n * smooth over.\n */\nfunction cursorAnchor(targetEl: Element): { destX: number; destY: number } {\n  const rect = targetEl.getBoundingClientRect();\n  const destX = rect.left + rect.width  / 2;\n  const destY = rect.top  + rect.height / 2;\n  return { destX, destY };\n}\n\n/**\n * Anchor the cursor to `el` and start a RAF loop that keeps the\n * cursor's viewport position in sync with `el`'s rect every frame.\n * Stops automatically when `setCursorAnchor(null)` is called, when\n * a new anchor replaces it, or when the cursor hides.\n *\n * Without this, the cursor's position was a snapshot taken at the\n * moment of `moveCursorAndTap` — page scrolls AFTER the move left\n * the cursor pointing at whatever happened to be at that viewport\n * coordinate, totally disconnected from the element the agent had\n * gestured at.\n */\nfunction setCursorAnchor(el: Element | null): void {\n  anchorEl = el;\n  if (anchorRafId !== null) {\n    cancelAnimationFrame(anchorRafId);\n    anchorRafId = null;\n  }\n  if (!el) return;\n  const tick = (): void => {\n    if (!anchorEl || anchorEl !== el || !cursorEl) {\n      anchorRafId = null;\n      return;\n    }\n    // Element disconnected (removed from DOM) — release the anchor.\n    if (!el.isConnected) {\n      anchorEl = null;\n      anchorRafId = null;\n      return;\n    }\n    const rect = el.getBoundingClientRect();\n    const x = rect.left + rect.width  / 2;\n    const y = rect.top  + rect.height / 2;\n    // Skip transform update if nothing changed — avoids triggering\n    // unnecessary repaints and lets the existing CSS transition\n    // (used during the initial glide) play out.\n    if (x !== lastX || y !== lastY) {\n      // Direct write WITHOUT animation — keeps cursor stuck to\n      // the moving target instead of trailing behind on scroll.\n      cursorEl.style.transition = 'none';\n      cursorEl.style.transform = `translate(${x}px, ${y}px)`;\n      lastX = x;\n      lastY = y;\n    }\n    anchorRafId = requestAnimationFrame(tick);\n  };\n  anchorRafId = requestAnimationFrame(tick);\n}\n\n/**\n * If the target is meaningfully off-screen, smooth-scroll it into\n * view BEFORE moving the cursor. Without this the cursor \"lands\"\n * at a viewport coordinate that no longer corresponds to where the\n * user sees the element after a layout shift.\n */\nasync function ensureInView(targetEl: Element): Promise<void> {\n  if (typeof window === 'undefined') return;\n  try {\n    const rect = targetEl.getBoundingClientRect();\n    const vh = window.innerHeight;\n    const vw = window.innerWidth;\n    // Offscreen vertically (top above viewport or bottom below + a\n    // 40px buffer) OR offscreen horizontally → scroll center.\n    const offY = rect.bottom < 40 || rect.top > vh - 40;\n    const offX = rect.right  < 40 || rect.left > vw - 40;\n    if (offY || offX) {\n      (targetEl as HTMLElement).scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' });\n      // Wait for the smooth-scroll to settle. ~360ms covers typical\n      // browser smooth-scroll timing.\n      await sleep(reducedMotion() ? 0 : 380);\n    }\n  } catch { /* nicety; positioning will fall back to whatever rect we get */ }\n}\n\n/**\n * Glide the cursor onto `targetEl` WITHOUT tapping — used by actions\n * that visualize attention (border / highlight / scrollTo / narrate-\n * about) but don't synthesize a click. A short pulse plays on\n * arrival so the user gets a clear \"I'm focused HERE now\" beat.\n *\n * Same gating + reduced-motion semantics as `moveCursorAndTap`.\n */\nexport async function moveCursorTo(targetEl: Element): Promise<void> {\n  if (typeof document === 'undefined' || !document.body) return;\n  setCursorAnchor(null);\n  const wrap = ensureCursor();\n  await ensureInView(targetEl);\n  const { destX, destY } = cursorAnchor(targetEl);\n  const reduced = reducedMotion();\n  const glideMs = reduced ? 0 : 360;\n\n  const start = getStartPoint();\n  if (wrap.classList.contains('hidden')) {\n    wrap.style.transition = 'none';\n    setPosition(wrap, start.x, start.y);\n    void wrap.offsetWidth;\n    wrap.style.transition = '';\n    wrap.classList.remove('hidden');\n  }\n\n  setPosition(wrap, destX, destY);\n  await sleep(glideMs);\n  cursorPulse();\n\n  // Anchor the cursor to the element so scrolls / layout shifts\n  // keep it visually attached.\n  setCursorAnchor(targetEl);\n}\n\n/**\n * Trigger the arrival-pulse animation independent of arrival —\n * useful for the moment a narration starts or a highlight lands.\n */\nexport function cursorPulse(): void {\n  if (!cursorEl) return;\n  cursorEl.classList.remove('pulsing');\n  // Reflow to restart the CSS animation.\n  void cursorEl.offsetWidth;\n  cursorEl.classList.add('pulsing');\n  setTimeout(() => cursorEl?.classList.remove('pulsing'), 700);\n}\n\n/**\n * Swap the cursor glyph between visual modes.\n *   - `pointer` (default): OS-style arrow, for clicks / general use.\n *   - `scroll`: mouse-wheel icon, for `scroll_to` action.\n *   - `reading`: target reticle, for `narrate`-with-`about` beats.\n *\n * Idempotent — calling with the current mode is a no-op.\n */\nexport function setCursorMode(mode: CursorMode): void {\n  if (mode === currentMode) return;\n  currentMode = mode;\n  const wrap = ensureCursor();\n  if (mode === 'pointer') {\n    renderPointerSprite(wrap);\n  } else {\n    wrap.innerHTML = CURSOR_SVG_BY_MODE[mode];\n  }\n}\n\n/**\n * Hide the cursor (e.g. when the agent run ends). Does not destroy the\n * element — next call to `moveCursorAndTap` re-shows it.\n *\n * Resets `lastX / lastY` to the \"first use\" sentinel so the NEXT\n * agent run starts the entrance glide from off-screen-left, not from\n * wherever the previous run's last action happened to land. Without\n * this, the cursor would visibly fly across the page from a stale\n * position before reaching the new target.\n */\nexport function hideCursor(): void {\n  setCursorAnchor(null);\n  if (cursorEl) cursorEl.classList.add('hidden');\n  lastX = -1;\n  lastY = -1;\n}\n\n/** Remove the cursor DOM entirely. Call on `dddk.destroy()`. */\nexport function destroyCursor(): void {\n  setCursorAnchor(null);\n  if (cursorEl && cursorEl.parentElement) cursorEl.parentElement.removeChild(cursorEl);\n  cursorEl = null;\n  lastX = -1;\n  lastY = -1;\n}\n\nfunction sleep(ms: number): Promise<void> {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * DOM Reader — indexed tabbed-tree serialiser.\n *\n * Every addressable element (interactive control, section-level\n * container, heading, image, code block) gets a monotonic numeric\n * index. The agent calls tools with that index directly\n * (`click(\"[3]\")` / `border(\"[5]\")`) — no CSS selectors, no\n * `:nth-of-type(4)`, no string-matching guesswork. The runtime keeps\n * an index→Element map for one turn and resolves indices on the next\n * tool dispatch.\n *\n * What gets indexed:\n *   - INTERACTIVE_TAGS — A, BUTTON, INPUT, SELECT, TEXTAREA, LABEL,\n *     SUMMARY, plus ANY element with an interactive ARIA role\n *     (button / link / tab / menuitem / option / checkbox / radio /\n *     switch / combobox / textbox / slider / spinbutton) or a\n *     keyboard-focusable tabindex with an accessible label.\n *   - HEADING_TAGS — H1..H6.\n *   - SECTION_TAGS — SECTION, ARTICLE, ASIDE, FIELDSET, MAIN, NAV,\n *     HEADER, FOOTER, HGROUP, TABLE, TR, FORM, DETAILS, DL, DIALOG.\n *     These also bump indentation so the tree shape is visible.\n *   - MEDIA_TAGS — IMG (emits alt text or filename hint).\n *   - PRE_TAGS — PRE (preserves newlines, capped).\n *\n * What gets emitted as flat content lines (no index):\n *   - NAMED_CONTENT_TAGS — P, LI, TD, TH, DT, DD, BLOCKQUOTE,\n *     FIGCAPTION, CAPTION, LEGEND, OUTPUT, METER, PROGRESS.\n *\n * What gets dropped entirely:\n *   - SKIP_TAGS — SCRIPT, STYLE, NOSCRIPT, TEMPLATE, IFRAME, SVG,\n *     CANVAS, SOURCE, TRACK, HEAD, META, LINK.\n *   - Elements with `class=\"dddk-skip\"` or `data-dddk-skip` (host\n *     structural opt-out — site chrome, etc.).\n *   - Elements failing `isVisible` (display:none / visibility:hidden\n *     / zero box) — `display: contents` is a SPECIAL CASE: the wrapper\n *     has no box but children render, so we descend without depth bump.\n *\n * Output shape:\n *\n *   URL: https://example.com/commercial\n *   TITLE: Commercial — example\n *\n *   [1]<a href=\"/\">Home</a>\n *   [2]<a href=\"/commercial\">Commercial</a>\n *   [3]<section>\n *     <h1>Commercial cooperation</h1>\n *     <p>AGPL covers most teams …</p>\n *     [4]<section>\n *       01 · COMMERCIAL LICENSE\n *       <h2>Using dotdotduck in closed-source products</h2>\n *       <p>AGPL-3.0 requires …</p>\n *       <td>Personal</td>\n *       <td>Solo dev / <US$100K</td>\n *       <td>Free</td>\n *\n * Indentation is one tab per logical container (`<section>`,\n * `<article>`, `<aside>`, `<fieldset>`). Other wrappers (`<div>`,\n * `<span>`) don't add indentation — they're noise.\n *\n * Filtering opt-outs (and opt-ins) for hosts:\n *   - Element with class `dddk-skip` or attribute `data-dddk-skip`\n *     drops that element AND its subtree.\n *   - The `WebAgentConfig.domFilter` function applies on top of the\n *     class-based skip.\n */\n\nconst DEFAULT_MAX_LENGTH = 12000;\nconst MAX_TEXT_PER_ITEM = 120;\nconst MAX_LINK_TEXT = 80;\nconst MAX_CELL_TEXT = 160;\n\nconst INTERACTIVE_TAGS = new Set([\n  'A',\n  'BUTTON',\n  'INPUT',\n  'SELECT',\n  'TEXTAREA',\n  'LABEL',\n  'SUMMARY',\n]);\n\n/** ARIA roles that turn any element (including `<div>` / `<span>`) into\n *  an interactive control. Custom widget libraries rely on these — without\n *  role-based detection the agent can't click their components. */\nconst INTERACTIVE_ROLES = new Set([\n  'button',\n  'link',\n  'tab',\n  'menuitem',\n  'menuitemcheckbox',\n  'menuitemradio',\n  'option',\n  'checkbox',\n  'radio',\n  'switch',\n  'combobox',\n  'searchbox',\n  'textbox',\n  'slider',\n  'spinbutton',\n]);\n\nconst HEADING_TAGS = new Set(['H1', 'H2', 'H3', 'H4', 'H5', 'H6']);\n\n/** Tags whose text content is emitted directly as a labelled line. */\nconst NAMED_CONTENT_TAGS = new Set([\n  'P',\n  'LI',\n  'TD',\n  'TH',\n  'DT',\n  'DD',\n  'BLOCKQUOTE',\n  'FIGCAPTION',\n  'CAPTION',\n  'LEGEND',\n  'OUTPUT',\n  'METER',\n  'PROGRESS',\n]);\n\n/** Media tags handled with their own emit shape (alt text / src). */\nconst MEDIA_TAGS = new Set(['IMG']);\n\n/** Tags whose `textContent` should be emitted verbatim, preserving line\n *  breaks (capped). Used for code / preformatted content. */\nconst PRE_TAGS = new Set(['PRE']);\n\n/**\n * Logical-group tags — emit a wrapper line + a numeric index so the\n * agent can border the whole group as one subject. These also bump\n * the indentation level for their descendants so structure is visible.\n *\n * `<tr>` is included so each table row is its own addressable subject\n * — without this, pricing / comparison tables collapse to a flat list\n * of `<td>` lines that the agent can't frame row-by-row.\n */\nconst SECTION_TAGS = new Set([\n  'SECTION',\n  'ARTICLE',\n  'ASIDE',\n  'FIELDSET',\n  'MAIN',\n  'NAV',\n  'HEADER',\n  'FOOTER',\n  'HGROUP',\n  'TABLE',\n  'TR',\n  'FORM',\n  'DETAILS',\n  'DL',\n  'DIALOG',\n]);\n\nconst SKIP_TAGS = new Set([\n  'SCRIPT',\n  'STYLE',\n  'NOSCRIPT',\n  'TEMPLATE',\n  'IFRAME',\n  'SVG',\n  'CANVAS',\n  'SOURCE',\n  'TRACK',\n  'HEAD',\n  'META',\n  'LINK',\n]);\n\nexport interface DomReadOptions {\n  maxLength?: number;\n  includeInvisible?: boolean;\n  scope?: HTMLElement;\n  /**\n   * Host-supplied subtraction filter. Called for every visible element\n   * the walker considers; return `false` to drop the element AND its\n   * subtree.\n   *\n   * Composes on top of the built-in class-based skip (elements with\n   * `class=\"dddk-skip\"` or `data-dddk-skip` are always dropped — hosts\n   * use those for fast structural opt-outs without writing a function).\n   */\n  filter?: (el: Element) => boolean;\n}\n\nexport interface IndexedDomResult {\n  /** Tab-indented text dump for the LLM. */\n  text: string;\n  /** Map from emitted stable ID → live DOM element. Tool handlers look\n   *  up here when the LLM passes an `[id]` reference as the target.\n   *  IDs are short alphanumeric hashes (e.g. `e4f3a`) computed from the\n   *  element's tag + role + sibling position + first 30 chars of text,\n   *  so the same element keeps the same ID across turns — fixing the\n   *  cross-turn drift where `[5]` in turn N pointed at a different\n   *  element than `[5]` in turn N+1. */\n  indexMap: Map<string, Element>;\n  /** Total bytes emitted (post-truncation). */\n  bytes: number;\n}\n\n/**\n * Build the indexed-tabbed-tree dump + the index→element map for the\n * current document. Called once per agent turn — the map only needs to\n * live until the next tool dispatch, after which a fresh readDOM\n * overwrites it.\n */\nexport function readDOM(opts: DomReadOptions = {}): IndexedDomResult {\n  if (typeof document === 'undefined') {\n    return { text: '(no DOM available)', indexMap: new Map(), bytes: 0 };\n  }\n\n  const maxLength = opts.maxLength ?? DEFAULT_MAX_LENGTH;\n  const scope = opts.scope ?? document.body;\n\n  // Scroll context — tells the agent \"what slice of the page is the user\n  // looking at right now\". The agent uses this to decide between bordering\n  // an already-visible element vs. calling scroll_to first.\n  const vh = typeof window !== 'undefined' ? window.innerHeight : 0;\n  const scrollY = typeof window !== 'undefined' ? window.scrollY : 0;\n  const docHeight = typeof document !== 'undefined'\n    ? Math.max(document.body.scrollHeight, document.documentElement.scrollHeight)\n    : 0;\n  const above = Math.round(scrollY);\n  const below = Math.max(0, Math.round(docHeight - scrollY - vh));\n\n  const lines: string[] = [];\n  lines.push(`URL: ${location.href}`);\n  lines.push(`TITLE: ${truncate(document.title, 100)}`);\n  if (vh > 0 && docHeight > 0) {\n    lines.push(`VIEWPORT: ${above}px above · ${vh}px visible · ${below}px below`);\n  }\n  lines.push('');\n\n  const ctx: WalkCtx = {\n    indexMap: new Map(),\n    seenLinkSigs: new Set(),\n    seenContentSigs: new Set(),\n    viewportTop: 0,\n    viewportBottom: vh,\n  };\n  walk(scope, lines, 0, opts.includeInvisible ?? false, opts.filter, ctx);\n\n  let out = lines.join('\\n');\n  if (out.length > maxLength) {\n    out = out.slice(0, maxLength) + '\\n[...truncated]';\n  }\n\n  // Debug exposure — devs can inspect window.__dddkDebug to see what\n  // the agent saw at any given turn.\n  if (typeof window !== 'undefined') {\n    const w = window as unknown as {\n      __dddkDebug?: { lastDom?: string; lastDomAt?: string; lastDomBytes?: number; lastIndexMap?: Map<string, Element> };\n    };\n    w.__dddkDebug = w.__dddkDebug ?? {};\n    w.__dddkDebug.lastDom = out;\n    w.__dddkDebug.lastDomAt = new Date().toISOString();\n    w.__dddkDebug.lastDomBytes = out.length;\n    w.__dddkDebug.lastIndexMap = ctx.indexMap;\n  }\n\n  return { text: out, indexMap: ctx.indexMap, bytes: out.length };\n}\n\ninterface WalkCtx {\n  indexMap: Map<string, Element>;\n  /** href|text — second occurrence of the same link is skipped. */\n  seenLinkSigs: Set<string>;\n  /** tag|text — second occurrence of the same content line is skipped\n   *  (kills duplicates from wrapper divs that emit the same text). */\n  seenContentSigs: Set<string>;\n  /** Viewport bounds in CSS px (relative to layout viewport). Used to\n   *  prefix each emitted line with ↑ / ↓ when the element sits above /\n   *  below what the user can currently see. */\n  viewportTop: number;\n  viewportBottom: number;\n}\n\n/**\n * Position of `node` relative to the current viewport:\n *   '↑' — above (user must scroll up to see it)\n *   ''  — at least partially in view\n *   '↓' — below (user must scroll down to see it)\n */\nfunction viewportMarker(node: Element, ctx: WalkCtx): string {\n  if (typeof window === 'undefined') return '';\n  const rect = (node as HTMLElement).getBoundingClientRect();\n  if (rect.bottom <= ctx.viewportTop) return '↑';\n  if (rect.top >= ctx.viewportBottom) return '↓';\n  return '';\n}\n\nfunction walk(\n  node: Element,\n  lines: string[],\n  depth: number,\n  includeInvisible: boolean,\n  filter: ((el: Element) => boolean) | undefined,\n  ctx: WalkCtx,\n): void {\n  if (SKIP_TAGS.has(node.tagName)) return;\n  // Built-in class-based opt-out. Hosts use this for fast structural\n  // skips — no filter function required.\n  if (hasSkipMarker(node)) return;\n  if (!includeInvisible && !isVisible(node)) return;\n  if (filter && !filter(node)) return;\n\n  const indent = depth > 0 ? '\\t'.repeat(depth) : '';\n\n  // `display: contents` — the element has no box, but its children\n  // render normally. Descend WITHOUT increasing depth.\n  if (typeof window !== 'undefined' && window.getComputedStyle(node).display === 'contents') {\n    for (const child of Array.from(node.children)) walk(child, lines, depth, includeInvisible, filter, ctx);\n    return;\n  }\n\n  // Interactive — by tag name OR by ARIA role. Custom widgets are\n  // usually `<div role=\"button\">`; without the role check, the agent\n  // can't click them.\n  if (INTERACTIVE_TAGS.has(node.tagName) || hasInteractiveRole(node)) {\n    emitInteractive(node, lines, indent, ctx);\n    return;\n  }\n\n  // Image — emit alt text (or filename fallback) so the agent can\n  // narrate icons / illustrations / logos. Index it so the agent can\n  // border specific images (e.g. \"the duck logo top-left\").\n  if (MEDIA_TAGS.has(node.tagName)) {\n    emitImage(node as HTMLImageElement, lines, indent, ctx);\n    return;\n  }\n\n  // Preformatted / code block — emit textContent preserving newlines\n  // (capped). Otherwise multi-line code collapses into one giant line\n  // through the normal whitespace-squash path.\n  if (PRE_TAGS.has(node.tagName)) {\n    emitPre(node, lines, indent, ctx);\n    return;\n  }\n\n  // Heading — emit with index so the agent can border / scroll_to it.\n  if (HEADING_TAGS.has(node.tagName)) {\n    const text = textOf(node, MAX_TEXT_PER_ITEM);\n    if (text) {\n      const idx = takeIndex(node, ctx);\n      const v = viewportMarker(node, ctx);\n      lines.push(`${indent}${v}[${idx}]<${node.tagName.toLowerCase()}>${text}</${node.tagName.toLowerCase()}>`);\n    }\n    return;\n  }\n\n  // Logical group — emit a wrapper line WITH index, then recurse with\n  // depth + 1 so children visually nest underneath.\n  if (SECTION_TAGS.has(node.tagName)) {\n    const label = sectionLabel(node);\n    const idx = takeIndex(node, ctx);\n    const tag = node.tagName.toLowerCase();\n    const v = viewportMarker(node, ctx);\n    lines.push(`${indent}${v}[${idx}]<${tag}>${label ? ` ${label}` : ''}`);\n    for (const child of Array.from(node.children)) {\n      walk(child, lines, depth + 1, includeInvisible, filter, ctx);\n    }\n    return;\n  }\n\n  // Modal — emit marker + descend at same depth (modal contents are\n  // important to read but don't deserve indentation).\n  if (isModalLike(node)) {\n    const idx = takeIndex(node, ctx);\n    const v = viewportMarker(node, ctx);\n    lines.push(`${indent}${v}[${idx}]<dialog>`);\n    for (const child of Array.from(node.children)) {\n      walk(child, lines, depth + 1, includeInvisible, filter, ctx);\n    }\n    return;\n  }\n\n  // Named content tag — emit text when leaf-like; otherwise recurse.\n  if (NAMED_CONTENT_TAGS.has(node.tagName)) {\n    if (!hasBlockDescendants(node)) {\n      const cap = node.tagName === 'TD' || node.tagName === 'TH' ? MAX_CELL_TEXT : MAX_TEXT_PER_ITEM;\n      const text = textOf(node, cap);\n      if (text) {\n        const sig = node.tagName + '|' + text;\n        if (!ctx.seenContentSigs.has(sig)) {\n          ctx.seenContentSigs.add(sig);\n          lines.push(`${indent}<${node.tagName.toLowerCase()}>${text}</${node.tagName.toLowerCase()}>`);\n        }\n      }\n      return;\n    }\n    // Has block descendants — recurse without depth bump.\n  }\n\n  // Generic visible element. If it's a leaf with text content, emit\n  // as plain text. Otherwise recurse without bumping depth (most\n  // intermediate divs / spans / wrappers are noise).\n  if (!hasBlockDescendants(node)) {\n    const text = textOf(node, MAX_TEXT_PER_ITEM);\n    if (text) {\n      const sig = node.tagName + '|' + text;\n      if (!ctx.seenContentSigs.has(sig)) {\n        ctx.seenContentSigs.add(sig);\n        lines.push(`${indent}${text}`);\n      }\n      return;\n    }\n  }\n\n  for (const child of Array.from(node.children)) {\n    walk(child, lines, depth, includeInvisible, filter, ctx);\n  }\n}\n\n/** Assign + record a stable ID for `node`. Tool handlers later look\n *  this up to resolve `[id]` references to real elements. The ID is\n *  a short alphanumeric hash derived from the element's structural +\n *  textual signature, so the same element keeps the same ID across\n *  turns. Collisions (rare but possible) get a `-2`, `-3` suffix. */\nfunction takeIndex(node: Element, ctx: WalkCtx): string {\n  const base = stableElementId(node);\n  let id = base;\n  let n = 2;\n  while (ctx.indexMap.has(id)) {\n    id = `${base}-${n++}`;\n  }\n  ctx.indexMap.set(id, node);\n  return id;\n}\n\n/** Compute a stable 5-char ID for an element. Inputs that make this\n *  cross-turn stable: tag, ARIA role, sibling position among same-tag\n *  siblings, first 30 chars of text content, and href for anchors.\n *  Outputs of the form `e<4 base36 chars>` so the ID never starts\n *  with a digit (keeps it distinguishable from legacy numeric refs). */\nfunction stableElementId(node: Element): string {\n  const tag = node.tagName;\n  const role = node.getAttribute('role') ?? '';\n  const text = (node.textContent ?? '').slice(0, 30).replace(/\\s+/g, ' ').trim();\n  const href = node instanceof HTMLAnchorElement ? node.getAttribute('href') ?? '' : '';\n  let siblingIdx = 0;\n  const parent = node.parentElement;\n  if (parent) {\n    const same = Array.from(parent.children).filter((c) => c.tagName === tag);\n    siblingIdx = same.indexOf(node);\n  }\n  const sig = `${tag}|${role}|${siblingIdx}|${text}|${href}`;\n  return 'e' + fnv1a32(sig).toString(36).padStart(4, '0').slice(-4);\n}\n\n/** FNV-1a 32-bit hash. Deterministic, fast, no crypto needs. */\nfunction fnv1a32(s: string): number {\n  let h = 0x811c9dc5;\n  for (let i = 0; i < s.length; i++) {\n    h ^= s.charCodeAt(i);\n    h = Math.imul(h, 0x01000193);\n  }\n  return h >>> 0;\n}\n\n/** Last-resort accessible name for icon-only buttons / image-only links:\n *  aria-label → title → inner <img>'s alt → empty. */\nfunction accessibleLabel(node: Element): string {\n  const ariaLabel = node.getAttribute('aria-label');\n  if (ariaLabel?.trim()) return truncate(ariaLabel.trim(), MAX_TEXT_PER_ITEM);\n  const title = node.getAttribute('title');\n  if (title?.trim()) return truncate(title.trim(), MAX_TEXT_PER_ITEM);\n  const img = node.querySelector('img[alt]');\n  if (img) {\n    const alt = (img.getAttribute('alt') ?? '').trim();\n    if (alt) return truncate(alt, MAX_TEXT_PER_ITEM);\n  }\n  return '';\n}\n\nfunction hasInteractiveRole(node: Element): boolean {\n  const role = node.getAttribute('role');\n  if (role && INTERACTIVE_ROLES.has(role.toLowerCase())) return true;\n  // tabindex>=0 on a non-native element strongly implies \"this is\n  // keyboard-focusable, treat it as interactive\". Skip for native tags\n  // that are already handled by INTERACTIVE_TAGS.\n  if (!INTERACTIVE_TAGS.has(node.tagName)) {\n    const ti = node.getAttribute('tabindex');\n    if (ti !== null && parseInt(ti, 10) >= 0) {\n      // Only count tabindex when there's a non-trivial accessible label —\n      // otherwise we'd index every scrollable container.\n      const label = (node as HTMLElement).getAttribute('aria-label')\n        ?? (node.textContent ?? '').trim();\n      if (label) return true;\n    }\n  }\n  return false;\n}\n\nfunction emitImage(node: HTMLImageElement, lines: string[], indent: string, ctx: WalkCtx): void {\n  const alt = (node.getAttribute('alt') ?? '').trim();\n  const src = node.getAttribute('src') ?? '';\n  // Decorative image with no alt and no useful src — drop.\n  if (!alt && !src) return;\n  const v = viewportMarker(node, ctx);\n  const idx = takeIndex(node, ctx);\n  if (alt) {\n    lines.push(`${indent}${v}[${idx}]<img alt=\"${escapeAttr(truncate(alt, MAX_TEXT_PER_ITEM))}\" />`);\n  } else {\n    // Strip URL down to a filename hint — full URLs are dump-bloating noise.\n    const file = src.split('?')[0]!.split('#')[0]!.split('/').pop() ?? '';\n    lines.push(`${indent}${v}[${idx}]<img src=\"${escapeAttr(truncate(file, 60))}\" />`);\n  }\n}\n\nfunction emitPre(node: Element, lines: string[], indent: string, ctx: WalkCtx): void {\n  // Preserve newlines but cap so a 500-line code dump doesn't blow the\n  // whole budget on one element.\n  const raw = (node.textContent ?? '').replace(/\\r\\n/g, '\\n');\n  const PRE_MAX = 600;\n  const text = raw.length > PRE_MAX ? raw.slice(0, PRE_MAX) + '\\n…[pre truncated]' : raw;\n  if (!text.trim()) return;\n  const v = viewportMarker(node, ctx);\n  const idx = takeIndex(node, ctx);\n  // Re-indent each line so the block sits under the section that owns it.\n  const indented = text.split('\\n').map((l, i) => i === 0 ? l : indent + '  ' + l).join('\\n');\n  lines.push(`${indent}${v}[${idx}]<pre>${indented}</pre>`);\n}\n\nfunction emitInteractive(node: Element, lines: string[], indent: string, ctx: WalkCtx): void {\n  const v = viewportMarker(node, ctx);\n  switch (node.tagName) {\n    case 'A': {\n      const href = node.getAttribute('href') ?? '';\n      const text = textOf(node, MAX_LINK_TEXT) || accessibleLabel(node);\n      if (!text && !href) return;\n      const sig = `${href}|${text}`;\n      if (ctx.seenLinkSigs.has(sig)) return;\n      ctx.seenLinkSigs.add(sig);\n      const idx = takeIndex(node, ctx);\n      lines.push(`${indent}${v}[${idx}]<a href=\"${escapeAttr(href)}\">${text}</a>`);\n      return;\n    }\n    case 'BUTTON': {\n      const text = textOf(node, MAX_TEXT_PER_ITEM) || accessibleLabel(node);\n      const disabled = (node as HTMLButtonElement).disabled ? ' disabled' : '';\n      const idx = takeIndex(node, ctx);\n      lines.push(`${indent}${v}[${idx}]<button${disabled}>${text || '(no label)'}</button>`);\n      return;\n    }\n    case 'INPUT': {\n      const input = node as HTMLInputElement;\n      const type = input.type || 'text';\n      if (type === 'hidden') return;\n      const isSensitive = type === 'password' || type === 'tel';\n      const attrs: string[] = [`type=\"${type}\"`];\n      if (input.placeholder) attrs.push(`placeholder=\"${escapeAttr(truncate(input.placeholder, 60))}\"`);\n      const liveValue = isSensitive\n        ? (input.value ? '[redacted]' : '')\n        : (input.value ? truncate(input.value, 200) : '');\n      if (liveValue) attrs.push(`value=\"${escapeAttr(liveValue)}\"`);\n      const idx = takeIndex(node, ctx);\n      lines.push(`${indent}${v}[${idx}]<input ${attrs.join(' ')} />`);\n      return;\n    }\n    case 'SELECT': {\n      const select = node as HTMLSelectElement;\n      const opts = Array.from(select.options).map((o) => o.text).slice(0, 8).join(' | ');\n      const idx = takeIndex(node, ctx);\n      lines.push(`${indent}${v}[${idx}]<select>options: ${truncate(opts, 100)}</select>`);\n      return;\n    }\n    case 'TEXTAREA': {\n      const ta = node as HTMLTextAreaElement;\n      const attrs: string[] = [];\n      if (ta.placeholder) attrs.push(`placeholder=\"${escapeAttr(truncate(ta.placeholder, 60))}\"`);\n      const liveValue = ta.value ? truncate(ta.value, 400) : '';\n      if (liveValue) attrs.push(`value=\"${escapeAttr(liveValue)}\"`);\n      const idx = takeIndex(node, ctx);\n      lines.push(`${indent}${v}[${idx}]<textarea${attrs.length ? ' ' + attrs.join(' ') : ''} />`);\n      return;\n    }\n    case 'LABEL':\n    case 'SUMMARY': {\n      const text = textOf(node, MAX_TEXT_PER_ITEM);\n      if (!text) return;\n      const idx = takeIndex(node, ctx);\n      lines.push(`${indent}${v}[${idx}]<${node.tagName.toLowerCase()}>${text}</${node.tagName.toLowerCase()}>`);\n      return;\n    }\n    default: {\n      // Role-based interactive (e.g. <div role=\"button\">). Use the role\n      // name as the rendered tag so the agent sees what kind of widget\n      // it is, and fall back to \"control\" when no role is set.\n      const role = node.getAttribute('role')?.toLowerCase();\n      const label = node.getAttribute('aria-label')\n        ?? textOf(node, MAX_TEXT_PER_ITEM);\n      if (!label) return;\n      const idx = takeIndex(node, ctx);\n      lines.push(`${indent}${v}[${idx}]<${role ?? 'control'}>${truncate(label, MAX_TEXT_PER_ITEM)}</${role ?? 'control'}>`);\n      return;\n    }\n  }\n}\n\n/** Pick a short summary for a section's wrapper line — first heading\n *  text, or first paragraph text, or the trimmed full text. */\nfunction sectionLabel(node: Element): string {\n  const heading = node.querySelector('h1, h2, h3, h4, h5, h6');\n  if (heading && heading.textContent) {\n    const t = heading.textContent.trim().replace(/\\s+/g, ' ');\n    if (t) return truncate(t, 80);\n  }\n  const p = node.querySelector('p, .section-label, [class*=\"label\"]');\n  if (p && p.textContent) {\n    const t = p.textContent.trim().replace(/\\s+/g, ' ');\n    if (t) return truncate(t, 80);\n  }\n  const text = (node.textContent ?? '').trim().replace(/\\s+/g, ' ');\n  return truncate(text, 80);\n}\n\n/** True when this node contains a block-level descendant that would\n *  emit its own line. */\nfunction hasBlockDescendants(node: Element): boolean {\n  for (const desc of Array.from(node.querySelectorAll('*'))) {\n    if (SKIP_TAGS.has(desc.tagName)) continue;\n    if (HEADING_TAGS.has(desc.tagName)) return true;\n    if (NAMED_CONTENT_TAGS.has(desc.tagName)) return true;\n    if (INTERACTIVE_TAGS.has(desc.tagName)) return true;\n    if (SECTION_TAGS.has(desc.tagName)) return true;\n    if (MEDIA_TAGS.has(desc.tagName)) return true;\n    if (PRE_TAGS.has(desc.tagName)) return true;\n    if (hasInteractiveRole(desc)) return true;\n  }\n  return false;\n}\n\nfunction textOf(el: Element, max: number): string {\n  return truncate((el.textContent ?? '').trim().replace(/\\s+/g, ' '), max);\n}\n\nfunction truncate(s: string, n: number): string {\n  return s.length > n ? s.slice(0, n - 1) + '…' : s;\n}\n\nfunction escapeAttr(s: string): string {\n  return s.replace(/\"/g, '&quot;');\n}\n\n/** Class- or attribute-based opt-out. */\nfunction hasSkipMarker(el: Element): boolean {\n  if (el.hasAttribute('data-dddk-skip')) return true;\n  const cls = (el as HTMLElement).className;\n  if (typeof cls === 'string' && /\\bdddk-skip\\b/.test(cls)) return true;\n  return false;\n}\n\n/**\n * \"Is this element visible to the user\".\n *\n * Rules (in order):\n *   1. display: none                   → hidden\n *   2. visibility: hidden              → hidden\n *   3. display: contents               → VISIBLE (descend)\n *   4. has bounding box (width|height) → visible\n *   5. otherwise                       → hidden\n *\n * `display: contents` is the framework-wrapper case — walker MUST\n * descend or the whole site disappears.\n */\nfunction isVisible(el: Element): boolean {\n  if (typeof window === 'undefined' || typeof window.getComputedStyle !== 'function') return true;\n  const style = window.getComputedStyle(el as HTMLElement);\n  if (style.display === 'none') return false;\n  if (style.visibility === 'hidden') return false;\n  if (style.display === 'contents') return true;\n  const rect = (el as HTMLElement).getBoundingClientRect();\n  return rect.width > 0 && rect.height > 0;\n}\n\nfunction isModalLike(el: Element): boolean {\n  const role = el.getAttribute('role');\n  if (role === 'dialog' || role === 'alertdialog') return true;\n  return el.getAttribute('aria-modal') === 'true';\n}\n\n","/**\n * Streaming envelope parser — scanner-based.\n *\n * The previous state-machine version bailed permanently the first time a\n * field's value spanned two SSE fragments (the readers returned `null` on\n * \"incomplete\" but the dispatcher treated null as a permanent failure).\n * In practice that meant nano — which emits the JSON char-by-char — bailed\n * on the very first long string (memory), so streaming \"looked\" enabled\n * but every turn fell back to JSON-parse-when-done.\n *\n * This rewrite is a forward-only buffer scanner. Every call to `feed()`:\n *\n *   1. Appends the new chars to `buf`.\n *   2. Walks the outer envelope object at depth=1, looking for `\"<key>\":`\n *      pairs we haven't emitted yet.\n *   3. For each known top-level key (memory / turn_planning / todo_adjust\n *      / todos_remaining / is_final), tries to read its value. If the\n *      value isn't fully in `buf` yet, leaves it alone — next `feed()`\n *      will see it grown and try again.\n *   4. For `actions`, scans the array element-by-element:\n *      - For each new partial action object (`{...` open, no `}` close\n *        yet), emits `narrate_delta` chars from inside its `\"narrate\":\"...\"`\n *        field as they arrive — that's the LIVE subtitle stream.\n *      - When the object's `}` lands, JSON.parse the slice, emit\n *        `action_start` + `about_complete` + `narrate_complete` +\n *        `tool_args_complete` synchronously, and advance past it.\n *   5. When the outer envelope's `}` lands, emits `envelope_complete`.\n *\n * There is NO bail. Malformed JSON triggers a single bail at the action\n * parse site and surfaces as `null` from `feed()` so the loop can fall\n * back to the JSON-parse path; otherwise the scanner is fully resumable.\n *\n * Performance: each `feed()` only re-scans from `scanPos` (cached\n * position), so cost is linear in TOTAL stream length even though the\n * full `buf` grows.\n */\n\nexport type EnvelopeStreamEvent =\n  | { kind: 'memory_complete'; value: string }\n  | { kind: 'turn_planning_complete'; value: { evaluation_previous_goal: string; next_goal: string } }\n  | { kind: 'todo_adjust_complete'; value: unknown }\n  | { kind: 'todos_remaining_complete'; value: string[] }\n  | { kind: 'action_start'; index: number }\n  | { kind: 'about_complete'; index: number; value: string }\n  | { kind: 'narrate_delta'; index: number; delta: string }\n  | { kind: 'narrate_complete'; index: number; full: string }\n  | { kind: 'tool_args_complete'; index: number; tool: string; args: Record<string, unknown> }\n  | { kind: 'is_final_complete'; value: boolean }\n  | { kind: 'envelope_complete' };\n\nconst TOP_LEVEL_KEYS = ['memory', 'turn_planning', 'todo_adjust', 'todos_remaining', 'actions', 'is_final'] as const;\n\nexport class StreamingEnvelopeParser {\n  private buf = '';\n  private envelopeOpenedAt = -1; // position right after the outer `{`\n  private envelopeClosed = false;\n  private envelopeCompleteEmitted = false;\n  private bailed = false;\n  private readonly emittedKeys = new Set<string>();\n\n  // Action tracking — actions are dispatched one at a time as their\n  // closing `}` lands. For the action currently being streamed (still\n  // open), we emit narrate chars as they arrive via `partialActionStart`.\n  private actionsArrayOpenAt = -1; // position right after `[`\n  private actionsArrayClosed = false;\n  private nextActionIdx = 0;\n  // Where to resume scanning the array on next entry to scanActions.\n  // Advances past each consumed action's closing `}`. -1 = use\n  // actionsArrayOpenAt (first entry).\n  private actionsScanCursor = -1;\n  private partialActionStart = -1; // pos of `{` for the currently-streaming action, -1 if between actions\n  private partialActionStarted = false; // emitted action_start for partialActionStart\n  private partialNarrateEmittedLen = 0;\n\n  feed(delta: string): EnvelopeStreamEvent[] | null {\n    if (this.bailed) return null;\n    this.buf += delta;\n    const events: EnvelopeStreamEvent[] = [];\n    try {\n      this.scan(events);\n    } catch (err) {\n      this.bailed = true;\n      return null;\n    }\n    return events;\n  }\n\n  finish(): EnvelopeStreamEvent[] | null {\n    if (this.bailed) return null;\n    const events: EnvelopeStreamEvent[] = [];\n    // Final scan to flush anything we can pick up.\n    try {\n      this.scan(events);\n    } catch {\n      this.bailed = true;\n      return null;\n    }\n    if (this.envelopeClosed && !this.envelopeCompleteEmitted) {\n      events.push({ kind: 'envelope_complete' });\n      this.envelopeCompleteEmitted = true;\n    }\n    return events;\n  }\n\n  hasBailed(): boolean {\n    return this.bailed;\n  }\n\n  // ─── scanner ────────────────────────────────────────────────────\n\n  private scan(events: EnvelopeStreamEvent[]): void {\n    if (this.envelopeClosed) return;\n\n    // Locate the outer `{`. Provider/SSE quirks can deliver fragments\n    // out of order — sometimes the opening `{\"` lands AFTER a chunk\n    // like `memory` in the visible delta. Scan forward for the FIRST\n    // `{` anywhere in the buffer rather than asserting it's at the\n    // head. If not present yet, wait for more chars.\n    if (this.envelopeOpenedAt < 0) {\n      const i = this.buf.indexOf('{');\n      if (i < 0) return;\n      this.envelopeOpenedAt = i + 1;\n    }\n\n    // For each known top-level key not yet emitted, try to read it.\n    for (const key of TOP_LEVEL_KEYS) {\n      if (this.emittedKeys.has(key)) continue;\n      if (key === 'actions') {\n        // actions has its own streaming logic\n        this.scanActions(events);\n        continue;\n      }\n      this.tryEmitTopLevelKey(key, events);\n    }\n\n    // Once actions array closed AND we've reached outer `}`, fire\n    // envelope_complete.\n    if (!this.envelopeClosed) {\n      const closePos = this.findOuterCloseBrace();\n      if (closePos >= 0) {\n        this.envelopeClosed = true;\n        events.push({ kind: 'envelope_complete' });\n        this.envelopeCompleteEmitted = true;\n      }\n    }\n  }\n\n  private tryEmitTopLevelKey(key: string, events: EnvelopeStreamEvent[]): void {\n    const valueStart = this.locateTopLevelValueStart(key);\n    if (valueStart < 0) return;\n\n    switch (key) {\n      case 'memory': {\n        const value = this.readStringAt(valueStart);\n        if (value === null) return;\n        events.push({ kind: 'memory_complete', value: value.text });\n        this.emittedKeys.add('memory');\n        return;\n      }\n      case 'turn_planning': {\n        const obj = this.readBalancedAt(valueStart, '{', '}');\n        if (obj === null) return;\n        try {\n          events.push({\n            kind: 'turn_planning_complete',\n            value: JSON.parse(obj.raw) as { evaluation_previous_goal: string; next_goal: string },\n          });\n        } catch {\n          throw new Error('turn_planning JSON.parse failed');\n        }\n        this.emittedKeys.add('turn_planning');\n        return;\n      }\n      case 'todo_adjust': {\n        const obj = this.readBalancedAt(valueStart, '{', '}');\n        if (obj === null) return;\n        try {\n          events.push({ kind: 'todo_adjust_complete', value: JSON.parse(obj.raw) });\n        } catch {\n          throw new Error('todo_adjust JSON.parse failed');\n        }\n        this.emittedKeys.add('todo_adjust');\n        return;\n      }\n      case 'todos_remaining': {\n        const arr = this.readBalancedAt(valueStart, '[', ']');\n        if (arr === null) return;\n        try {\n          events.push({ kind: 'todos_remaining_complete', value: JSON.parse(arr.raw) as string[] });\n        } catch {\n          throw new Error('todos_remaining JSON.parse failed');\n        }\n        this.emittedKeys.add('todos_remaining');\n        return;\n      }\n      case 'is_final': {\n        const bool = this.readBoolAt(valueStart);\n        if (bool === null) return;\n        events.push({ kind: 'is_final_complete', value: bool });\n        this.emittedKeys.add('is_final');\n        return;\n      }\n    }\n  }\n\n  /**\n   * Walk the actions array. Emits action_start + per-field events for\n   * each new complete action. While an action is still streaming open,\n   * scans inside its narrate field and emits narrate_delta chars as\n   * they arrive.\n   */\n  private scanActions(events: EnvelopeStreamEvent[]): void {\n    if (this.actionsArrayClosed) return;\n    if (this.actionsArrayOpenAt < 0) {\n      const valueStart = this.locateTopLevelValueStart('actions');\n      if (valueStart < 0) return;\n      if (this.buf.charAt(valueStart) !== '[') return;\n      this.actionsArrayOpenAt = valueStart + 1;\n    }\n\n    let pos = this.partialActionStart >= 0\n      ? this.partialActionStart\n      : (this.actionsScanCursor >= 0 ? this.actionsScanCursor : this.actionsArrayOpenAt);\n\n    while (true) {\n      pos = this.skipWhitespaceAndCommas(pos);\n      if (pos >= this.buf.length) {\n        this.partialActionStart = -1;\n        return;\n      }\n      const c = this.buf.charAt(pos);\n      if (c === ']') {\n        this.actionsArrayClosed = true;\n        this.emittedKeys.add('actions');\n        return;\n      }\n      if (c !== '{') {\n        // Unexpected — wait for more chars (might be partial whitespace).\n        this.partialActionStart = -1;\n        return;\n      }\n\n      // Action object starts. Mark + emit action_start if not yet.\n      if (this.partialActionStart !== pos) {\n        this.partialActionStart = pos;\n        this.partialActionStarted = false;\n        this.partialNarrateEmittedLen = 0;\n      }\n      if (!this.partialActionStarted) {\n        events.push({ kind: 'action_start', index: this.nextActionIdx });\n        this.partialActionStarted = true;\n      }\n\n      // Try to find balanced `}` to complete this action.\n      const balanced = this.readBalancedAt(pos, '{', '}');\n      if (balanced === null) {\n        // Incomplete action — but we can still stream narrate chars\n        // from inside it as they arrive.\n        this.streamPartialNarrate(pos, events);\n        return;\n      }\n\n      // Complete action — JSON.parse and emit per-field events.\n      let parsed: { about?: string; narrate?: string; tool?: string; args?: Record<string, unknown> };\n      try {\n        parsed = JSON.parse(balanced.raw);\n      } catch {\n        throw new Error('action JSON.parse failed');\n      }\n      const idx = this.nextActionIdx;\n      if (typeof parsed.about === 'string' && parsed.about) {\n        events.push({ kind: 'about_complete', index: idx, value: parsed.about });\n      }\n      if (typeof parsed.narrate === 'string') {\n        // Flush any narrate chars we haven't streamed yet via the partial\n        // scan (covers actions whose narrate field arrived in one chunk\n        // OR where partial scan missed something).\n        const already = this.partialNarrateEmittedLen;\n        if (already < parsed.narrate.length) {\n          events.push({\n            kind: 'narrate_delta',\n            index: idx,\n            delta: parsed.narrate.slice(already),\n          });\n        }\n        events.push({ kind: 'narrate_complete', index: idx, full: parsed.narrate });\n      }\n      if (typeof parsed.tool === 'string') {\n        events.push({\n          kind: 'tool_args_complete',\n          index: idx,\n          tool: parsed.tool,\n          args: (parsed.args ?? {}) as Record<string, unknown>,\n        });\n      }\n      this.nextActionIdx += 1;\n      this.partialActionStart = -1;\n      this.partialActionStarted = false;\n      this.partialNarrateEmittedLen = 0;\n      pos = balanced.end + 1;\n      this.actionsScanCursor = pos; // resume here on next scan\n    }\n  }\n\n  /**\n   * For the partial action object at `pos`, look for `\"narrate\":\"...\"`\n   * inside it and emit narrate_delta for any chars we haven't yet.\n   *\n   * Doesn't matter if we mis-find narrate boundaries inside other fields\n   * — the readBalancedAt path is brace-aware, so when the full action\n   * arrives we'll JSON.parse correctly and any over/under streaming\n   * gets reconciled via the `partialNarrateEmittedLen` accounting (see\n   * the action-complete path above).\n   */\n  private streamPartialNarrate(actionStart: number, events: EnvelopeStreamEvent[]): void {\n    // Search for `\"narrate\"` inside the partial action.\n    const slice = this.buf.slice(actionStart);\n    const m = slice.match(/\"narrate\"\\s*:\\s*\"/);\n    if (!m) return;\n    const valueStart = actionStart + m.index! + m[0].length;\n    // Walk chars to find closing `\"` (respect escapes). Emit deltas\n    // for chars between `partialNarrateEmittedLen` and the current\n    // scanned position.\n    let i = valueStart + this.partialNarrateEmittedLen;\n    let inEscape = false;\n    let consumed = this.partialNarrateEmittedLen;\n    let decoded = '';\n    while (i < this.buf.length) {\n      const ch = this.buf.charAt(i);\n      if (inEscape) {\n        inEscape = false;\n        // Translate basic escape sequences for display.\n        switch (ch) {\n          case 'n': decoded += '\\n'; break;\n          case 't': decoded += '\\t'; break;\n          case 'r': decoded += '\\r'; break;\n          case '\"': decoded += '\"'; break;\n          case '\\\\': decoded += '\\\\'; break;\n          case '/': decoded += '/'; break;\n          case 'u': {\n            // Need 4 hex digits — if not yet in buf, stop here.\n            if (i + 4 >= this.buf.length) break;\n            const hex = this.buf.slice(i + 1, i + 5);\n            const code = parseInt(hex, 16);\n            if (!isNaN(code)) {\n              decoded += String.fromCharCode(code);\n              i += 4;\n            }\n            break;\n          }\n          default: decoded += ch;\n        }\n        consumed += 1;\n        i += 1;\n        continue;\n      }\n      if (ch === '\\\\') {\n        inEscape = true;\n        consumed += 1;\n        i += 1;\n        continue;\n      }\n      if (ch === '\"') {\n        // Closing of narrate. Don't include in delta; let the\n        // action-complete path emit narrate_complete.\n        break;\n      }\n      decoded += ch;\n      consumed += 1;\n      i += 1;\n    }\n    if (decoded) {\n      events.push({\n        kind: 'narrate_delta',\n        index: this.nextActionIdx,\n        delta: decoded,\n      });\n      this.partialNarrateEmittedLen = consumed;\n    }\n  }\n\n  // ─── primitives ────────────────────────────────────────────────\n\n  private findFirstNonWhitespace(from: number): number {\n    for (let i = from; i < this.buf.length; i++) {\n      const c = this.buf.charAt(i);\n      if (c !== ' ' && c !== '\\n' && c !== '\\r' && c !== '\\t') return i;\n    }\n    return -1;\n  }\n\n  private skipWhitespaceAndCommas(from: number): number {\n    let i = from;\n    while (i < this.buf.length) {\n      const c = this.buf.charAt(i);\n      if (c === ' ' || c === '\\n' || c === '\\r' || c === '\\t' || c === ',') {\n        i += 1;\n      } else {\n        return i;\n      }\n    }\n    return i;\n  }\n\n  /**\n   * Find `\"<key>\":` at depth=1 (i.e. directly inside the envelope's outer\n   * `{`). Returns the position right after the `:` (with whitespace\n   * skipped), or -1 if not found yet. Depth-aware so we don't match\n   * keys-with-the-same-name nested inside object/array values.\n   */\n  private locateTopLevelValueStart(key: string): number {\n    if (this.envelopeOpenedAt < 0) return -1;\n    const target = `\"${key}\"`;\n    let depth = 1; // we're inside outer `{`\n    let i = this.envelopeOpenedAt;\n    let inStr = false;\n    let inEscape = false;\n    while (i < this.buf.length) {\n      const ch = this.buf.charAt(i);\n      if (inEscape) { inEscape = false; i += 1; continue; }\n      if (inStr) {\n        if (ch === '\\\\') { inEscape = true; i += 1; continue; }\n        if (ch === '\"') { inStr = false; i += 1; continue; }\n        i += 1; continue;\n      }\n      // not in string\n      if (ch === '\"') {\n        if (depth === 1 && this.buf.startsWith(target, i)) {\n          // Verify it's a key — must be followed by `:` (possibly w/ ws).\n          let j = i + target.length;\n          while (j < this.buf.length && /\\s/.test(this.buf.charAt(j))) j += 1;\n          if (j < this.buf.length && this.buf.charAt(j) === ':') {\n            j += 1;\n            while (j < this.buf.length && /\\s/.test(this.buf.charAt(j))) j += 1;\n            if (j >= this.buf.length) return -1; // value not yet\n            return j;\n          }\n          // Not followed by `:` yet — wait for more chars.\n          return -1;\n        }\n        // Some other string at depth=1 — skip it\n        inStr = true;\n        i += 1;\n        continue;\n      }\n      if (ch === '{' || ch === '[') depth += 1;\n      else if (ch === '}' || ch === ']') depth -= 1;\n      i += 1;\n    }\n    return -1;\n  }\n\n  private findOuterCloseBrace(): number {\n    if (this.envelopeOpenedAt < 0) return -1;\n    let depth = 1;\n    let i = this.envelopeOpenedAt;\n    let inStr = false;\n    let inEscape = false;\n    while (i < this.buf.length) {\n      const ch = this.buf.charAt(i);\n      if (inEscape) { inEscape = false; i += 1; continue; }\n      if (inStr) {\n        if (ch === '\\\\') { inEscape = true; i += 1; continue; }\n        if (ch === '\"') inStr = false;\n        i += 1; continue;\n      }\n      if (ch === '\"') { inStr = true; i += 1; continue; }\n      if (ch === '{' || ch === '[') depth += 1;\n      else if (ch === '}' || ch === ']') {\n        depth -= 1;\n        if (depth === 0) return i;\n      }\n      i += 1;\n    }\n    return -1;\n  }\n\n  private readStringAt(start: number): { text: string; end: number } | null {\n    if (this.buf.charAt(start) !== '\"') return null;\n    let i = start + 1;\n    let inEscape = false;\n    while (i < this.buf.length) {\n      const ch = this.buf.charAt(i);\n      if (inEscape) { inEscape = false; i += 1; continue; }\n      if (ch === '\\\\') { inEscape = true; i += 1; continue; }\n      if (ch === '\"') {\n        const raw = this.buf.slice(start, i + 1);\n        try {\n          return { text: JSON.parse(raw) as string, end: i };\n        } catch {\n          return null;\n        }\n      }\n      i += 1;\n    }\n    return null; // incomplete\n  }\n\n  private readBalancedAt(start: number, open: '{' | '[', close: '}' | ']'): { raw: string; end: number } | null {\n    if (this.buf.charAt(start) !== open) return null;\n    let depth = 1;\n    let i = start + 1;\n    let inStr = false;\n    let inEscape = false;\n    while (i < this.buf.length) {\n      const ch = this.buf.charAt(i);\n      if (inEscape) { inEscape = false; i += 1; continue; }\n      if (inStr) {\n        if (ch === '\\\\') { inEscape = true; i += 1; continue; }\n        if (ch === '\"') inStr = false;\n        i += 1; continue;\n      }\n      if (ch === '\"') { inStr = true; i += 1; continue; }\n      if (ch === open || (open === '{' && ch === '[') || (open === '[' && ch === '{')) depth += 1;\n      else if (ch === close || (close === '}' && ch === ']') || (close === ']' && ch === '}')) {\n        depth -= 1;\n        if (depth === 0) {\n          return { raw: this.buf.slice(start, i + 1), end: i };\n        }\n      }\n      i += 1;\n    }\n    return null; // incomplete\n  }\n\n  private readBoolAt(start: number): boolean | null {\n    if (this.buf.startsWith('true', start)) return true;\n    if (this.buf.startsWith('false', start)) return false;\n    // Partial 't'/'f' at end means incomplete — return null.\n    return null;\n  }\n}\n","/**\n * @perhapxin/dddk — Command palette + voice + Dwell + inline AI + DOM-grounded agent SDK.\n *\n * Public root entry. Tree-shake-friendly partial entries also available:\n *   - `@perhapxin/dddk/agent`  — WebAgent + InlineAgent + LLM router + sitemap\n *   - `@perhapxin/dddk/llm`    — providers, router, adapter registry only\n *   - `@perhapxin/dddk/ui`     — Subtitle, placement, dock-state, Pieces\n *   - `@perhapxin/dddk/skills` — SkillRegistry, evals\n *   - `@perhapxin/dddk/toolbox/*` — search / qa / classify / recommend ...\n */\n\n// ─── orchestrator ──────────────────────────────────────────────────\n\nexport { DotDotDuck, searchPageText, SessionsRegistry, AgentsRegistry } from './orchestrator';\nexport type { DotDotDuckConfig, SessionRegistration, RegisterableAgent } from './orchestrator';\n\n// ─── one-line install ─────────────────────────────────────────────\n// autoInstall(overrides?) — zero-config on-ramp for hosts who want the\n// SDK running with sensible defaults before wiring the details.\nexport { autoInstall, type AutoInstallOptions } from './auto-install';\nexport { initSpriteDefaults, type SpriteOverrides } from './init-sprite-urls';\n\n// ─── prompt registry ──────────────────────────────────────────────\n// Central override surface for every LLM system prompt the SDK ships.\n// Hosts localise per-locale, append site-wide reminders, or list what's\n// registered — one API for the whole prompt surface.\nexport {\n  PromptRegistry,\n  PROMPT_IDS,\n  promptRegistry,\n  type PromptId,\n  type PromptRender,\n} from './prompts/registry';\n\n// ─── tools registry ────────────────────────────────────────────────\n\nexport { ToolsRegistry } from './tools-registry';\nexport type { ToolSpec, RegisterQAOpts, QAToolItem } from './tools-registry';\n\n// ─── triggers (input surfaces) ─────────────────────────────────────\n\nexport {\n  GestureManager,\n} from './triggers/space-gesture';\nexport type { GestureCallbacks, GestureManagerOptions } from './triggers/space-gesture';\n\nexport {\n  CommandPalette,\n  listPrefixMatches,\n  displayPrefix,\n} from './triggers/command-palette';\nexport type {\n  PaletteItem,\n  PaletteItemPrefix,\n  PaletteAgentTool,\n  PaletteHandle,\n  PaletteAttachment,\n  PaletteContext,\n  PaletteCategory,\n  ResultSurface,\n  CameraOptions,\n  CommandPaletteOptions,\n} from './triggers/command-palette';\n\nexport { Spotter } from './triggers/spotter';\nexport type { SpotterOptions, SpotterState } from './triggers/spotter';\n\nexport { PanelRuntime } from './triggers/panel-runtime';\nexport type { PanelRuntimeHost, PanelRuntimeOptions } from './triggers/panel-runtime';\n\nexport { Dwell, type DwellConfig } from './triggers/dwell';\nexport {\n  MobileTrigger,\n  type MobileTriggerConfig,\n  type MobileFABConfig,\n  type HeroGreetingConfig,\n  type HeroGreetingRow,\n} from './triggers/mobile';\n\n// ─── ActionDeck (typed action system on palette items) ────────────\n\nexport {\n  runAction,\n  defaultIconFor,\n} from './triggers/action-panel';\nexport type {\n  PaletteAction,\n  CopyAction,\n  InsertAction,\n  OpenUrlAction,\n  NavigateAction,\n  AgentTaskAction,\n  RenderSurfaceAction,\n  RunSkillAction,\n  CustomAction,\n  ActionRunContext,\n} from './triggers/action-panel';\n\n// ─── Agent subsystem (LLM engines + LLM layer + sitemap) ───────────\n\nexport {\n  WebAgent,\n  InlineAgent,\n  TaskAgent,\n  AgentCursor,\n  StreamingEnvelopeParser,\n  Memory,\n  CoreMemory,\n  EpisodicMemory,\n  SemanticMemory,\n  DrawerMemory,\n  createDrawerMemory,\n  // unified memory facade\n  UnifiedMemory,\n  createUnifiedMemory,\n  Plan,\n  TodosArtifact,\n  MarkdownArtifact,\n  border,\n  highlight,\n  spotlight,\n  inject,\n  removeOverlay,\n  clearOverlays,\n  listOverlays,\n  readDOM,\n  // v0.2.0 action bundles — default install = `coreActions`; pass the\n  // other bundles to `customActions` to opt in.\n  coreActions,\n  formActions,\n  flowActions,\n  extraActions,\n  builtinActions,\n  // Opt-in action exports — host opts in via `customActions: [...]`.\n  escalateToHuman,\n  trackIntent,\n  workflowActions,\n  validateForm,\n  waitUntil,\n  serializeSitemap,\n  resolvePath,\n  searchSitemap,\n  listAuthGatedPaths,\n  SAAS_SITEMAP_TEMPLATE,\n  SitemapLearner,\n} from './agent';\nexport type {\n  PlanConfig,\n  PlanInput,\n  TaskPlan,\n  TodoItem,\n  MarkdownDoc,\n  PlanSnapshot,\n  PlanStorageAdapter,\n} from './agent';\nexport type {\n  WebAgentConfig,\n  AgentSession,\n  AgentTurn,\n  UserTurn,\n  AgentStepTurn,\n  AgentFinalTurn,\n  AgentStatus,\n  AgentEvent,\n  ActionDefinition,\n  ActionResult,\n  ActionFailureReason,\n  ActionContext,\n  SitemapEntry,\n  SitemapConfig,\n  OverlayItem,\n  OverlayType,\n  PiecePlacement,\n  RunOptions,\n  SelectionContext,\n  BrandPrompt,\n  PromptContext,\n  SystemPromptOverride,\n  DomReadOptions,\n  InlineAgentConfig,\n  InlineAction,\n  ToolHandle,\n  ContextProvider,\n  ContextProviderHandle,\n  ContextRole,\n  ContextRequest,\n  TaskAgentConfig,\n  TaskRunOptions,\n  TaskTool,\n  InlineScopeConfig,\n  ScopeHandle,\n  ScopeResolver,\n  AgentCursorConfig,\n  SitemapNode,\n  SitemapResolution,\n  SitemapLearnerOptions,\n  SitemapLearnerStorage,\n  Drawer,\n  DrawerMemoryOpts,\n  DrawerSearchOpts,\n  // unified memory facade types\n  UnifiedMemoryConfig,\n  RememberOpts,\n  RecallResult,\n  MemoryConfig,\n  CoreMemoryConfig,\n  CoreMemorySchema,\n  CoreFieldType,\n  EpisodicMemoryConfig,\n  EpisodicEntry,\n  SemanticMemoryConfig,\n  SemanticMemoryEntry,\n  MemoryProvider,\n  MemoryPrivacyConfig,\n  EnvelopeStreamEvent,\n} from './agent';\n\n// ─── LLM (providers, router, adapter registry) ─────────────────────\n\nexport {\n  OpenAIProvider,\n  GoogleProvider,\n  ProxyProvider,\n  resolveLLM,\n  isLLMRouter,\n} from './agent/llm';\nexport type {\n  LLMRouter,\n  LLMSource,\n  LLMRouterRole,\n  LLMProvider,\n  CompleteOptions,\n  CompleteResult,\n  LLMMessage,\n  LLMRole,\n  ContentPart,\n  ToolDefinition,\n  ToolCall,\n  OpenAIProviderConfig,\n  GoogleProviderConfig,\n  ProxyProviderConfig,\n} from './agent/llm';\n\n// Adapter registry — explicit `seedDefaultAdapters()` required (tsup\n// tree-shakes pure side-effect imports).\nexport {\n  seedDefaultAdapters,\n  registerAdapter,\n  getAdapter,\n  listAdapters,\n  unregisterAdapter,\n  createProvider,\n  openaiAdapter,\n  googleAdapter,\n  proxyAdapter,\n  agnesAdapter,\n} from './agent/llm';\nexport type { LLMAdapter, AdapterConfig } from './agent/llm';\n\n// ─── skills (registry only — zero built-ins) ───────────────────────\n\nexport { SkillRegistry } from './skills/registry';\nexport type {\n  Skill,\n  BaseSkill,\n  ScriptSkill,\n  ScriptStep,\n  PromptSkill,\n  ActionSkill,\n  ActionSkillContext,\n  SurfaceSkill,\n  SurfaceSkillContext,\n  PanelSkill,\n  PanelSkillContext,\n  SkillTools,\n  SurfacePlacement,\n} from './skills/types';\n\nexport { PreferenceStore } from './skills/preferences';\nexport type {\n  PreferenceField,\n  PreferenceKind,\n  PreferenceSchema,\n  PreferenceContext,\n} from './skills/preferences';\n\nexport {\n  defineEval,\n  runEvals,\n  MockLLM,\n  mockToolCall,\n} from './skills/evals';\n\n// multi-step transaction with rollback\nexport { runTransaction } from './skills/transaction';\nexport type {\n  TransactionStep,\n  TransactionOpts,\n  TransactionOutcome,\n} from './skills/transaction';\n\n// form widget adapter registry\nexport {\n  registerFormWidget,\n  unregisterFormWidget,\n  listFormWidgets,\n  findFormWidget,\n} from './agent/webagent/form-widgets';\nexport type {\n  FormWidgetAdapter,\n  FormWidgetFillContext,\n} from './agent/webagent/form-widgets';\nexport type {\n  EvalSpec,\n  EvalAssertion,\n  EvalTrace,\n  EvalResult,\n  EvalReport,\n  RunEvalsOptions,\n  MockLLMOptions,\n} from './skills/evals';\n\n// ─── UI primitives ─────────────────────────────────────────────────\n\nexport { Subtitle } from './ui/subtitle';\nexport { createDockState } from './ui/dock-state';\nexport type { DockState, DockStateValue, DockStateOpts } from './ui/dock-state';\n\n// Canonical screen placement slots — every transient piece of UI\n// (subtitle bar, voice indicator, palette, dock, modal, banner, FAB,\n// toast) routes through this stylesheet so positions are defined once\n// and stay consistent.\nexport {\n  Placements,\n  ensurePlacementStyles,\n  applyPlacement,\n  clearPlacement,\n  PLACEMENT_ATTR,\n} from './ui/placement';\nexport type { PlacementSlot, PlacementHandle } from './ui/placement';\n\n// Pieces — declarative UI primitives system (lives at ui/pieces/).\nexport {\n  PieceCatalog,\n  PieceRenderer,\n  PieceDomRenderer,\n  readPointer,\n  resolveValue,\n  builtinPieces,\n  createBuiltinCatalog,\n  envelopeToSurface,\n  surfaceToEnvelope,\n} from './ui/pieces';\nexport type {\n  PieceNode,\n  PieceContext,\n  PieceDefinition,\n  PieceSurface,\n  PieceRendererProps,\n  PieceDomRendererOptions,\n} from './ui/pieces';\n\n// ─── built-in feature modules ──────────────────────────────────────\n\nexport {\n  ImmersiveTranslate,\n  VoiceModule,\n  ThemeToggleModule,\n  LanguageSwitcherModule,\n  FormAssistModule,\n  OnboardingModule,\n  PinnedPanelRegistry,\n  inspectForm,\n} from './modules';\nexport type {\n  VoiceModuleConfig,\n  AudioTranscriber,\n  ThemeToggleConfig,\n  LanguageSwitcherConfig,\n  FormAssistConfig,\n  FormAssistInfo,\n  OnboardingConfig,\n  ImmersiveTranslateConfig,\n  PinnedPanelHandle,\n  PinnedPanelSpec,\n  PinnedPanelPlacement,\n} from './modules';\n\n// ─── platform helpers ──────────────────────────────────────────────\n\nexport {\n  isMac,\n  paletteShortcutLabel,\n  paletteShortcutLabelPlus,\n} from './utils/platform';\n\n// ─── utilities ─────────────────────────────────────────────────────\n\nexport { Cache } from './cache';\nexport type { CacheOptions, CacheTier } from './cache';\n\nexport {\n  HeatRank,\n  makeCacheAdapter,\n} from './utils/heat-rank';\nexport type {\n  HeatRankOptions,\n  HeatRankAdapter,\n} from './utils/heat-rank';\n\n// ─── v0.2.0 ingest layer ──────────────────────────────────────────────\n\nexport {\n  EVENT_SCHEMA_VERSION,\n  makeEvent,\n  Transport,\n  HttpSink,\n  DebugSink,\n  MultiSink,\n} from './ingest';\nexport type {\n  EventCategory,\n  BaseEvent,\n  ClickEventProps,\n  ScrollEventProps,\n  HoverEventProps,\n  FocusEventProps,\n  RoutingEventProps,\n  PerformanceEventProps,\n  SessionStartProps,\n  PageViewProps,\n  CustomEventProps,\n  EventSink,\n  TransportOptions,\n} from './ingest';\n\n// ─── analytics (self-hosted store + export + SQL schema) ──────────\nexport {\n  EventStore,\n  defaultMapper,\n  fieldMapper,\n  filterEvents,\n  eventToRow,\n  rowToEvent,\n  dddkEventsDDL,\n  DDDK_EVENTS_COLUMNS,\n  DDDK_EVENTS_DDL_SQLITE,\n  DDDK_EVENTS_DDL_POSTGRES,\n  DDDK_EVENTS_DDL_MYSQL,\n  toCSV,\n  toNDJSON,\n  toSQL,\n} from './analytics';\nexport type {\n  Cap,\n  CapInfo,\n  EventStoreOpts,\n  EventQuery,\n  OnFullPolicy,\n  NotifyHostHandler,\n  SqlSchemaMapper,\n  DddkEventRow,\n  SqlDialect,\n  ToCSVOptions,\n  ToNDJSONOptions,\n  ToSQLOptions,\n} from './analytics';\n\n// ─── shared types ──────────────────────────────────────────────────\n\nexport type {\n  Locale,\n  SubtitleType,\n  SubtitleShowOptions,\n  StorageAdapter,\n  I18nDict,\n  DddkEventName,\n  DddkEventMap,\n  DddkEventHandler,\n  IntentEvent,\n} from './types';\n","/**\r\n * GestureManager — unified space-based gesture system.\r\n * See ../../docs/02-space-gesture.md for the full design.\r\n *\r\n * Detects:\r\n *   - Single space tap (<150ms hold, 350ms gap) → accept\r\n *   - Double space tap (two taps <350ms) → reject\r\n *   - Long space press (>150ms) → voice start\r\n *   - Tab → accept next line (when subtitle showing)\r\n *   - Escape → dismiss\r\n *   - Ctrl+K / Cmd+K → command palette\r\n *   - Ctrl+Space (in input) → accept while typing\r\n *\r\n * Space is ONLY intercepted when shouldIntercept() returns true\r\n * (i.e. there's a pending UI awaiting user response).\r\n */\r\n\r\n// Long-press threshold for voice. 250ms keeps the gesture snappy\r\n// (anything longer felt sluggish) while staying clear of the natural\r\n// space-tap range (~80-200ms in fast typing). If you hit accidental\r\n// voice triggers on fast prose typing, push this back up to 350-400ms.\r\nconst DEFAULT_HOLD_THRESHOLD_MS = 250;\r\n// Default window for double-tap-reject detection. Two space taps\r\n// completing within this window are treated as \"reject\". Configurable\r\n// via `GestureManagerOptions.doubleTapWindowMs`.\r\nconst DEFAULT_DOUBLE_TAP_WINDOW_MS = 350;\r\n\r\nexport interface GestureCallbacks {\r\n  onAccept: () => void;\r\n  onReject: () => void;\r\n  onAcceptLine: () => void;\r\n  onVoiceStart: (selection: string, images: string[]) => void;\r\n  onVoiceEnd: () => void;\r\n  onPaletteToggle: (selection: string) => void;\r\n  onEscape: () => void;\r\n}\r\n\r\nexport interface GestureManagerOptions {\r\n  callbacks: GestureCallbacks;\r\n  /** Function called on every space keydown to decide whether to intercept. */\r\n  shouldIntercept?: () => boolean;\r\n  /** Legacy: use 'ctrl' for backwards-compat with old Ctrl-based UI. Default 'space'. */\r\n  gestureKey?: 'space' | 'ctrl';\r\n  /**\r\n   * How long the user must hold the gesture key before voice_start fires.\r\n   * Default 250ms. Lower = more responsive but easier to mis-trigger on\r\n   * fast prose typing; higher = less mis-trigger but voice feels laggy.\r\n   */\r\n  holdThresholdMs?: number;\r\n  /**\r\n   * Window for \"two taps in this many ms → reject\" detection. Default\r\n   * 350ms. Raise if users with slower fingers can't reliably double-tap;\r\n   * lower for power users who want reject to fire snappier.\r\n   */\r\n  doubleTapWindowMs?: number;\r\n}\r\n\r\nexport class GestureManager {\r\n  private callbacks: GestureCallbacks;\r\n  private shouldIntercept: () => boolean;\r\n  private gestureKey: 'space' | 'ctrl';\r\n  private holdThresholdMs: number;\r\n  private doubleTapWindowMs: number;\r\n\r\n  private holdTimer: ReturnType<typeof setTimeout> | null = null;\r\n  private tapTimer: ReturnType<typeof setTimeout> | null = null;\r\n  private lastTapAt = 0;\r\n  private isHolding = false;\r\n  /**\r\n   * Set on space-keydown inside an input field. If user releases before the\r\n   * hold threshold, we insert the missing space character manually (since we\r\n   * preventDefault'd the keydown to keep voice-hold possible). If the hold\r\n   * threshold fires, voice triggers without any space being inserted —\r\n   * which is the desired behavior for \"long-press to dictate\".\r\n   */\r\n  private pendingSpaceInput: HTMLElement | null = null;\r\n\r\n  /**\r\n   * Disposer for the per-hold reactive guard that watches the focused\r\n   * input for unexpected value changes during voice. Set when voice\r\n   * triggers, called from `handleKeyUp` when the user releases. The\r\n   * guard's job is to revert any character the OS-level IME slips into\r\n   * the input despite `readOnly = true` — bullet-proofing against Edge\r\n   * + Microsoft Bopomofo, which on some builds writes one stray space\r\n   * AFTER readOnly is set (in-flight queued keystroke from the 250ms\r\n   * detection window).\r\n   */\r\n  private holdRevertDispose: (() => void) | null = null;\r\n\r\n  private cleanups: Array<() => void> = [];\r\n\r\n  /** Set by host when a suggestion/subtitle/surface is visible. Enables accept/reject/tab. */\r\n  hasSuggestion = false;\r\n\r\n  constructor(opts: GestureManagerOptions) {\r\n    this.callbacks = opts.callbacks;\r\n    this.shouldIntercept = opts.shouldIntercept ?? (() => this.hasSuggestion);\r\n    this.gestureKey = opts.gestureKey ?? 'space';\r\n    this.holdThresholdMs = opts.holdThresholdMs ?? DEFAULT_HOLD_THRESHOLD_MS;\r\n    this.doubleTapWindowMs = opts.doubleTapWindowMs ?? DEFAULT_DOUBLE_TAP_WINDOW_MS;\r\n  }\r\n\r\n  start(): void {\r\n    if (typeof document === 'undefined') return;\r\n\r\n    const onKeyDown = (e: KeyboardEvent) => this.handleKeyDown(e);\r\n    const onKeyUp = (e: KeyboardEvent) => this.handleKeyUp(e);\r\n\r\n    // Edge + Microsoft IME (Bopomofo / Pinyin) inserts characters at\r\n    // the OS level BEFORE our document-capture keydown handler runs,\r\n    // so `preventDefault` on keydown is too late — a stream of literal\r\n    // spaces leaks into the input while the user is holding space for\r\n    // voice. `beforeinput` fires after keydown but right BEFORE the\r\n    // input's value mutates, and `preventDefault` here is honoured\r\n    // even for IME-mediated inserts. Block input mutations while we\r\n    // are detecting (`holdTimer` set) or actively voice-holding\r\n    // (`isHolding`). Normal taps still type a space via the\r\n    // `insertSpaceAt` path on keyup.\r\n    const onBeforeInput = (e: InputEvent) => {\r\n      if (this.isHolding || this.holdTimer !== null) {\r\n        // Only block space-character inserts so other input (paste of\r\n        // pre-existing text, deletion, etc.) keeps working.\r\n        if (e.data === ' ' || e.inputType === 'insertText' && e.data === ' ') {\r\n          e.preventDefault();\r\n          e.stopImmediatePropagation();\r\n        }\r\n      }\r\n    };\r\n\r\n    // Use capture phase for keys so we get Ctrl+K BEFORE the browser's\r\n    // own search-bar focus shortcut. Without capture, some browsers (Chrome\r\n    // on certain platforms / extensions) intercept Ctrl+K at the window\r\n    // level before our bubble-phase listener runs.\r\n    document.addEventListener('keydown', onKeyDown, true);\r\n    document.addEventListener('keyup', onKeyUp, true);\r\n    document.addEventListener('beforeinput', onBeforeInput, true);\r\n\r\n    this.cleanups.push(\r\n      () => document.removeEventListener('keydown', onKeyDown, true),\r\n      () => document.removeEventListener('keyup', onKeyUp, true),\r\n      () => document.removeEventListener('beforeinput', onBeforeInput, true),\r\n    );\r\n  }\r\n\r\n  destroy(): void {\r\n    this.cancelHold();\r\n    if (this.tapTimer) clearTimeout(this.tapTimer);\r\n    this.cleanups.forEach((fn) => fn());\r\n    this.cleanups = [];\r\n  }\r\n\r\n  /**\r\n   * Read currently selected text (live, from DOM/input). Always queried\r\n   * at the moment of the gesture — no cached state. Previously we kept\r\n   * a `lastSelection` mirror updated by selectionchange / mouseup, but\r\n   * that cache survived SPA navigation and leaked the previous page's\r\n   * selection into the next page's first Ctrl+K. The fix is to never\r\n   * cache: if the browser has live selection at gesture time, use it;\r\n   * otherwise the gesture has no selection context.\r\n   */\r\n  captureSelection(): string {\r\n    return this.readSelection();\r\n  }\r\n\r\n  captureImages(): string[] {\r\n    const sel = window.getSelection?.();\r\n    if (!sel || sel.rangeCount === 0) return [];\r\n    const out: string[] = [];\r\n    const range = sel.getRangeAt(0);\r\n    range.cloneContents().querySelectorAll('img').forEach((img) => {\r\n      const src = img.getAttribute('src');\r\n      if (src) out.push(src);\r\n    });\r\n    return out;\r\n  }\r\n\r\n  // ─── private ────────────────────────────────────────────────────\r\n\r\n  private handleKeyDown(e: KeyboardEvent): void {\r\n    // IME composition guard. When a CJK user is actively composing a\r\n    // character, `e.isComposing` is true; space pressed in that state\r\n    // is committing the candidate, NOT a voice gesture. Bail so the\r\n    // IME owns the keystroke.\r\n    //\r\n    // We intentionally DO NOT also check `keyCode === 229`: on Edge\r\n    // with Bopomofo / Microsoft Pinyin IME selected, *every* keydown\r\n    // (including autorepeat space outside composition) reports\r\n    // keyCode 229. Returning on that signal blocks our preventDefault\r\n    // and the OS leaks a stream of literal spaces into the focused\r\n    // input when the user holds space for voice. `isComposing` alone\r\n    // is the reliable per-keystroke \"this is composition\" signal.\r\n    if (e.isComposing) {\r\n      return;\r\n    }\r\n\r\n    // Always: Ctrl+K toggles palette regardless of intercept state.\r\n    if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'k') {\r\n      e.preventDefault();\r\n      e.stopPropagation();\r\n      e.stopImmediatePropagation();\r\n      const sel = this.captureSelection();\r\n      this.cancelHold();\r\n      this.callbacks.onPaletteToggle(sel);\r\n      return;\r\n    }\r\n\r\n    // Escape always dismisses.\r\n    if (e.key === 'Escape') {\r\n      this.callbacks.onEscape();\r\n      return;\r\n    }\r\n\r\n    // Tab accepts a line when suggestion is showing.\r\n    if (e.key === 'Tab' && this.hasSuggestion) {\r\n      e.preventDefault();\r\n      this.callbacks.onAcceptLine();\r\n      return;\r\n    }\r\n\r\n    // The main gesture key.\r\n    if (!this.matchesGestureKey(e)) {\r\n      // Any other key combined with gesture key → cancel hold (it's a chord).\r\n      if (this.isHolding && (e.ctrlKey || e.metaKey || e.altKey)) {\r\n        this.cancelHold();\r\n      }\r\n      return;\r\n    }\r\n\r\n    // Decide whether to intercept space at all.\r\n    const inInput = isInInputField(e.target);\r\n\r\n    // In an input AND user holds ctrl+space → that's the explicit accept shortcut,\r\n    // not the start of a long-press voice. Treat as accept and don't preventDefault\r\n    // (browser will insert a normal space if there's no intercept).\r\n    if (this.gestureKey === 'space' && inInput && e.ctrlKey) {\r\n      if (this.hasSuggestion) {\r\n        e.preventDefault();\r\n        this.callbacks.onAccept();\r\n      }\r\n      return;\r\n    }\r\n\r\n    // Space inside an input field — special handling:\r\n    //   1. preventDefault on keydown so the space character isn't immediately\r\n    //      inserted (otherwise voice-hold would always leave a stray space)\r\n    //   2. Start the hold timer\r\n    //   3. If keyup before threshold → insert space manually (it was a normal tap)\r\n    //   4. If hold threshold fires → trigger voice (no stray space)\r\n    //\r\n    // This preserves \"long-press to dictate\" even when typing in the palette\r\n    // input / textarea / contenteditable, while keeping normal space typing\r\n    // smooth (imperceptible 150ms delay).\r\n    if (this.gestureKey === 'space' && inInput) {\r\n      e.preventDefault();\r\n      if (e.repeat || this.holdTimer) return;\r\n      this.pendingSpaceInput = e.target as HTMLElement;\r\n      const targetInput = e.target as HTMLElement;\r\n\r\n      // Snapshot the input's pre-hold state. Edge's IME can still leak\r\n      // 1-2 literal spaces into the input during the detection window\r\n      // (between this keydown and the hold timer firing) — the OS path\r\n      // runs ahead of our preventDefault. When voice triggers, we\r\n      // restore this snapshot so the input is in its ORIGINAL state.\r\n      const isFormInput =\r\n        targetInput instanceof HTMLInputElement ||\r\n        targetInput instanceof HTMLTextAreaElement;\r\n      const snapshotValue = isFormInput\r\n        ? (targetInput as HTMLInputElement | HTMLTextAreaElement).value\r\n        : null;\r\n      const snapshotStart = isFormInput\r\n        ? (targetInput as HTMLInputElement | HTMLTextAreaElement).selectionStart\r\n            ?? (snapshotValue as string).length\r\n        : 0;\r\n      const snapshotEnd = isFormInput\r\n        ? (targetInput as HTMLInputElement | HTMLTextAreaElement).selectionEnd\r\n            ?? (snapshotValue as string).length\r\n        : 0;\r\n\r\n      const selection = this.captureSelection();\r\n      const images = this.captureImages();\r\n\r\n      this.holdTimer = setTimeout(() => {\r\n        this.holdTimer = null;\r\n        this.isHolding = true;\r\n        if (this.tapTimer) {\r\n          clearTimeout(this.tapTimer);\r\n          this.tapTimer = null;\r\n        }\r\n        this.pendingSpaceInput = null;\r\n        this.callbacks.onVoiceStart(selection, images);\r\n\r\n        // Set readOnly FIRST so the snapshot restore can't get\r\n        // immediately re-written by an in-flight IME insert.\r\n        //   - <input> / <textarea> → `readOnly = true`\r\n        //   - contentEditable → `contentEditable = 'false'`\r\n        // Caret stays visible; consecutive voice gestures on the same\r\n        // field keep appending. voice-handler flips these back right\r\n        // before insertion.\r\n        const isInputLike =\r\n          targetInput instanceof HTMLInputElement ||\r\n          targetInput instanceof HTMLTextAreaElement;\r\n        if (isInputLike) {\r\n          try { (targetInput as HTMLInputElement | HTMLTextAreaElement).readOnly = true; } catch { /* detached */ }\r\n        } else if (targetInput.isContentEditable) {\r\n          try { targetInput.contentEditable = 'false'; } catch { /* detached */ }\r\n        }\r\n\r\n        // Wipe any stray characters the IME leaked during the 250ms\r\n        // detection window (before readOnly was set).\r\n        if (\r\n          snapshotValue !== null &&\r\n          (targetInput instanceof HTMLInputElement || targetInput instanceof HTMLTextAreaElement) &&\r\n          targetInput.value !== snapshotValue\r\n        ) {\r\n          targetInput.value = snapshotValue;\r\n          try { targetInput.setSelectionRange(snapshotStart, snapshotEnd); } catch { /* detached */ }\r\n          targetInput.dispatchEvent(new Event('input', { bubbles: true }));\r\n        }\r\n\r\n        // REACTIVE guard. Edge + Microsoft Bopomofo IME can still flush\r\n        // one in-flight space into the input AFTER readOnly is set (the\r\n        // OS path queues the keystroke ahead of our JS handler). Listen\r\n        // for `input` events on the target — anytime the value drifts\r\n        // from the snapshot while voice is active, revert. Disposer is\r\n        // called on keyup.\r\n        if (isInputLike) {\r\n          const inputEl = targetInput as HTMLInputElement | HTMLTextAreaElement;\r\n          const onUnwantedInput = () => {\r\n            if (inputEl.value !== snapshotValue) {\r\n              inputEl.value = snapshotValue as string;\r\n              try { inputEl.setSelectionRange(snapshotStart, snapshotEnd); } catch { /* detached */ }\r\n            }\r\n          };\r\n          inputEl.addEventListener('input', onUnwantedInput, true);\r\n          this.holdRevertDispose = () => {\r\n            inputEl.removeEventListener('input', onUnwantedInput, true);\r\n            this.holdRevertDispose = null;\r\n          };\r\n        }\r\n      }, this.holdThresholdMs);\r\n      return;\r\n    }\r\n\r\n    // Page-level space (not in an input). Always intercept so the browser\r\n    // doesn't scroll the page on space-down.\r\n    e.preventDefault();\r\n\r\n    if (e.repeat || this.holdTimer) return;\r\n\r\n    const selection = this.captureSelection();\r\n    const images = this.captureImages();\r\n\r\n    this.holdTimer = setTimeout(() => {\r\n      this.holdTimer = null;\r\n      this.isHolding = true;\r\n      if (this.tapTimer) {\r\n        clearTimeout(this.tapTimer);\r\n        this.tapTimer = null;\r\n      }\r\n      this.callbacks.onVoiceStart(selection, images);\r\n    }, this.holdThresholdMs);\r\n  }\r\n\r\n  private handleKeyUp(e: KeyboardEvent): void {\r\n    if (!this.matchesGestureKey(e)) return;\r\n\r\n    // Cancel hold if released before threshold\r\n    if (this.holdTimer) {\r\n      clearTimeout(this.holdTimer);\r\n      this.holdTimer = null;\r\n    }\r\n\r\n    // If this was a short tap inside an input, the space character was\r\n    // suppressed by handleKeyDown — insert it now manually so the user sees\r\n    // a normal space land in their text.\r\n    if (this.pendingSpaceInput && !this.isHolding) {\r\n      insertSpaceAt(this.pendingSpaceInput);\r\n      this.pendingSpaceInput = null;\r\n      // Don't trigger accept/reject — this was a text edit, not a UI gesture.\r\n      return;\r\n    }\r\n    this.pendingSpaceInput = null;\r\n\r\n    if (!this.isHolding) {\r\n      // Tap (no voice). Check double-tap window.\r\n      const now = Date.now();\r\n      if (now - this.lastTapAt < this.doubleTapWindowMs) {\r\n        if (this.tapTimer) {\r\n          clearTimeout(this.tapTimer);\r\n          this.tapTimer = null;\r\n        }\r\n        this.lastTapAt = 0;\r\n        this.callbacks.onReject();\r\n      } else {\r\n        this.lastTapAt = now;\r\n        if (this.tapTimer) clearTimeout(this.tapTimer);\r\n        this.tapTimer = setTimeout(() => {\r\n          this.tapTimer = null;\r\n          if (this.hasSuggestion) this.callbacks.onAccept();\r\n        }, this.doubleTapWindowMs);\r\n      }\r\n      return;\r\n    }\r\n\r\n    // Was holding → voice end. Tear down the reactive input-revert\r\n    // guard (it's no-op once host clears readOnly anyway, but freeing\r\n    // the listener now avoids a leak across sessions).\r\n    this.isHolding = false;\r\n    this.holdRevertDispose?.();\r\n    this.callbacks.onVoiceEnd();\r\n  }\r\n\r\n  private matchesGestureKey(e: KeyboardEvent): boolean {\r\n    if (this.gestureKey === 'space') {\r\n      return e.key === ' ' || e.code === 'Space';\r\n    }\r\n    return e.key === 'Control' || e.key === 'Meta';\r\n  }\r\n\r\n  private cancelHold(): void {\r\n    if (this.holdTimer) {\r\n      clearTimeout(this.holdTimer);\r\n      this.holdTimer = null;\r\n    }\r\n    this.holdRevertDispose?.();\r\n    if (this.isHolding) {\r\n      this.isHolding = false;\r\n      this.callbacks.onVoiceEnd();\r\n    }\r\n  }\r\n\r\n  private readSelection(): string {\r\n    let sel = window.getSelection?.()?.toString().trim() ?? '';\r\n    if (!sel) {\r\n      const active = document.activeElement as HTMLElement | null;\r\n      if (active && (active.tagName === 'TEXTAREA' || active.tagName === 'INPUT')) {\r\n        const input = active as HTMLInputElement | HTMLTextAreaElement;\r\n        const s = input.selectionStart ?? 0;\r\n        const e = input.selectionEnd ?? 0;\r\n        if (e > s) sel = input.value.substring(s, e);\r\n      }\r\n    }\r\n    return sel;\r\n  }\r\n}\r\n\r\nfunction isInInputField(target: EventTarget | null): boolean {\r\n  const el = target as HTMLElement | null;\r\n  if (!el) return false;\r\n  const tag = el.tagName;\r\n  return tag === 'TEXTAREA' || tag === 'INPUT' || el.isContentEditable;\r\n}\r\n\r\n/**\r\n * Insert a literal space at the caret position of the given input/textarea/\r\n * contenteditable. Used by GestureManager when a short space tap inside an\r\n * input was suppressed (to allow voice-hold to also work in inputs).\r\n */\r\nfunction insertSpaceAt(el: HTMLElement): void {\r\n  if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {\r\n    const start = el.selectionStart ?? el.value.length;\r\n    const end = el.selectionEnd ?? el.value.length;\r\n    el.value = el.value.slice(0, start) + ' ' + el.value.slice(end);\r\n    const caret = start + 1;\r\n    el.setSelectionRange(caret, caret);\r\n    el.dispatchEvent(new Event('input', { bubbles: true }));\r\n  } else if (el.isContentEditable) {\r\n    try {\r\n      document.execCommand('insertText', false, ' ');\r\n    } catch {\r\n      // execCommand deprecated in some envs; fall back silently\r\n    }\r\n  }\r\n}\r\n","/**\r\n * Tiny DOM helpers shared across dddk modules.\r\n */\r\n\r\n/** Canonical attribute every dddk-owned UI element carries. */\r\nexport const UI_ATTR = 'data-dddk-ui';\r\n\r\n/**\r\n * Escape a string for safe injection into an HTML attribute or text node via\r\n * innerHTML. Covers `&`, `<`, `>`, `\"`, and `'` — the full set documented at\r\n * https://owasp.org/www-community/attacks/xss/.\r\n */\r\nexport function escapeHtml(s: string): string {\r\n  return s\r\n    .replace(/&/g, '&amp;')\r\n    .replace(/</g, '&lt;')\r\n    .replace(/>/g, '&gt;')\r\n    .replace(/\"/g, '&quot;')\r\n    .replace(/'/g, '&#39;');\r\n}\r\n\r\n/**\r\n * Build a compact `<tag#id.class> inner` signature for an element — the\r\n * same short-form descriptor used by the chip-bar and the Dwell capture\r\n * flow when surfacing \"what is selected\" to the user / LLM. Truncates\r\n * inner text at `maxInner` (default 1000) so we never paste a paragraph\r\n * into a chip / context blob.\r\n *\r\n * Returns just `<tag#id.class>` when the element has no readable inner\r\n * text — keeps the signature meaningful even for icon-only buttons.\r\n */\r\nexport function formatElementSignature(\r\n  el: HTMLElement,\r\n  opts: { maxInner?: number } = {},\r\n): string {\r\n  const maxInner = opts.maxInner ?? 1000;\r\n  const tag = el.tagName.toLowerCase();\r\n  const id = el.id ? `#${el.id}` : '';\r\n  const classList = el.classList ? Array.from(el.classList).slice(0, 3) : [];\r\n  const cls = classList.length ? '.' + classList.join('.') : '';\r\n  const sig = `<${tag}${id}${cls}>`;\r\n  const inner = ((el as HTMLElement).innerText ?? el.textContent ?? '').trim().slice(0, maxInner);\r\n  return inner ? `${sig} ${inner}` : sig;\r\n}\r\n\r\n/**\r\n * Idempotently inject a `<style>` element with the given id and CSS text. If\r\n * an element with the same id already exists, this is a no-op (so modules can\r\n * call it from every constructor without worrying about duplication).\r\n *\r\n * Returns `true` if a new element was created, `false` otherwise — useful for\r\n * tests that want to assert \"this only happens once\".\r\n */\r\nexport function injectScopedStyle(id: string, css: string): boolean {\r\n  if (typeof document === 'undefined') return false;\r\n  if (document.getElementById(id)) return false;\r\n  const style = document.createElement('style');\r\n  style.id = id;\r\n  style.textContent = css;\r\n  document.head.appendChild(style);\r\n  return true;\r\n}\r\n","/**\n * SDK-wide UI string table. Centralises the user-visible labels that\n * modules render directly (palette item names, button captions, the\n * agent status indicator) so they pick up the host's locale instead of\n * defaulting to a hardcoded language. Bundled languages are `en` and\n * `zh-TW`; any other locale falls back to `en` so a Japanese / Spanish\n * site never breaks — those hosts override per-module via config.\n *\n * NOT a general-purpose i18n framework. dddk's module-level i18n\n * (subtitle hints, inline-agent menu) lives next to each module. This\n * file is only for the small set of strings that DotDotDuck itself\n * renders without going through a module.\n */\nconst STRINGS = {\n  en: {\n    'agent.thinking': 'Thinking…',\n    'agent.running': 'Agent running…',\n    'agent.processing': 'Working…',\n    'agent.loading': 'Loading the page…',\n    'agent.done': '✓ Done',\n    'agent.press_space_close': 'press space to close',\n    'agent.press_space_continue': 'space → next · double space → exit',\n    'agent.tap_to_continue': 'tap → next · double-tap → exit',\n    'agent.space_continue_reject': 'space → next · double space → exit',\n    'agent.tap_to_dismiss': 'tap to dismiss',\n    'agent.stop_close': 'Agent stopped — say something new when you\\'re ready',\n    'agent.stop_esc': 'Esc received — agent stopped',\n    'agent.stop_reject': 'Double-tap reject received — agent stopped',\n    // Confirmation copy for destructive / requireConfirmation tool calls.\n    // `{target}` / `{path}` / `{action}` placeholders interpolated at call time.\n    'agent.confirm.suffix': '— press space to confirm',\n    'agent.confirm.navigate.with_path': 'Take you to {path}',\n    'agent.confirm.navigate.no_path': 'Switch page',\n    'agent.confirm.click.with_target': 'Click {target}',\n    'agent.confirm.click.no_target': 'Click',\n    'agent.confirm.fill_input.with_target': 'Fill {target}',\n    'agent.confirm.fill_input.no_target': 'Fill field',\n    'agent.confirm.delete.with_target': 'Delete {target}',\n    'agent.confirm.delete.no_target': 'Delete',\n    'agent.confirm.generic.with_target': 'Run {action} → {target}',\n    'agent.confirm.generic.no_target': 'Run {action}',\n    'palette.theme.light': 'Theme: light',\n    'palette.theme.dark': 'Theme: dark',\n    'palette.theme.system': 'Theme: follow system',\n    'palette.language.current': '✓ Active',\n    'palette.onboarding.replay': 'Replay tour',\n    'form.required': 'This field is required',\n    'form.submit': 'Submit',\n    'form.assist.fill': '✦ AI fill',\n    'proactive.yes': 'Yes',\n    'proactive.no': 'No',\n    'fallback.empty': 'No data',\n    'fallback.error': 'Error',\n    'palette.placeholder': 'Search commands or page…',\n    'palette.footer.navigate': 'to navigate',\n    'palette.footer.select': 'to select',\n    'palette.footer.close': 'to close',\n    'palette.footer.back': 'to go back',\n    'palette.footer.touch.pick': 'Tap a row to pick',\n    'palette.footer.touch.dismiss': 'Tap outside to close',\n    'palette.footer.touch.back': 'Tap × to go back',\n    'palette.section.settings': 'Settings',\n    'palette.section.go_to': 'Go to',\n    'palette.section.ai': 'AI',\n    'palette.section.commands': 'Commands',\n    'palette.section.docs': 'Docs',\n    'palette.screenshot.hint': 'Drag to select · Esc cancels',\n    'form.assist.scanning': 'Scanning {count} fields…',\n    'prefs.title': 'Settings: {skill}',\n    // voice module labels in the SDK i18n fallback\n    'voice.listening': 'Listening',\n    'voice.unsupported': 'Voice input not supported',\n    'voice.failed': 'Voice input failed',\n  },\n  'zh-TW': {\n    'agent.thinking': '思考中…',\n    'agent.running': 'Agent 執行中…',\n    'agent.processing': '處理中…',\n    'agent.loading': '頁面載入中…',\n    'agent.done': '✓ 執行完畢',\n    'agent.press_space_close': '按 space 關閉',\n    'agent.press_space_continue': 'space 下一步 ｜ 兩下 space 直接結束',\n    'agent.tap_to_continue': '點一下下一步 ｜ 兩下直接結束',\n    'agent.space_continue_reject': 'space 下一步 ｜ 兩下 space 直接結束',\n    'agent.tap_to_dismiss': '點一下關閉',\n    'agent.stop_close': 'Agent 已停下，想到新的就直接打或按住 space',\n    'agent.stop_esc': '收到 esc，agent 已停下',\n    'agent.stop_reject': '收到雙擊 space 拒絕，agent 已停下',\n    'agent.confirm.suffix': '— 按 space 確認',\n    'agent.confirm.navigate.with_path': '帶你到 {path}',\n    'agent.confirm.navigate.no_path': '切換頁面',\n    'agent.confirm.click.with_target': '點擊 {target}',\n    'agent.confirm.click.no_target': '點擊',\n    'agent.confirm.fill_input.with_target': '填寫 {target}',\n    'agent.confirm.fill_input.no_target': '填寫欄位',\n    'agent.confirm.delete.with_target': '刪除 {target}',\n    'agent.confirm.delete.no_target': '刪除',\n    'agent.confirm.generic.with_target': '執行 {action} → {target}',\n    'agent.confirm.generic.no_target': '執行 {action}',\n    'palette.theme.light': '主題:亮色',\n    'palette.theme.dark': '主題:暗色',\n    'palette.theme.system': '主題:跟隨系統',\n    'palette.language.current': '✓ 目前',\n    'palette.onboarding.replay': '重看導覽',\n    'form.required': '此欄位必填',\n    'form.submit': '儲存',\n    'form.assist.fill': '✦ AI 填寫',\n    'proactive.yes': '是',\n    'proactive.no': '否',\n    'fallback.empty': '無資料',\n    'fallback.error': '錯誤',\n    'palette.placeholder': '搜尋指令或頁面…',\n    'palette.footer.navigate': '上下移動',\n    'palette.footer.select': '選取',\n    'palette.footer.close': '關閉',\n    'palette.footer.back': '上一頁',\n    'palette.footer.touch.pick': '點列項選擇',\n    'palette.footer.touch.dismiss': '點外側關閉',\n    'palette.footer.touch.back': '點 × 返回',\n    'palette.section.settings': '設定',\n    'palette.section.go_to': '前往',\n    'palette.section.ai': 'AI',\n    'palette.section.commands': '指令',\n    'palette.section.docs': '文件',\n    'palette.screenshot.hint': '拖曳框選 · Esc 取消',\n    'form.assist.scanning': '正在分析 {count} 個欄位…',\n    'prefs.title': '設定：{skill}',\n    'voice.listening': '聽取中',\n    'voice.unsupported': '此瀏覽器不支援語音輸入',\n    'voice.failed': '語音輸入失敗',\n  },\n} as const;\n\nexport type SdkI18nKey = keyof typeof STRINGS['en'];\n\n/**\n * Look up the bundled string for `key` in the given locale. Falls back\n * to English when the locale isn't bundled. Hosts that want native\n * strings for `ja` / `es` / `fr` etc. should NOT call this — they\n * override at the module config level (e.g. WebAgentConfig.confirmStrings).\n *\n * `vars` interpolates `{name}` placeholders, e.g.\n *   sdkString('en', 'agent.confirm.click.with_target', { target: 'button[3]' })\n *   → \"Click button[3]\"\n */\nexport function sdkString(\n  locale: string | undefined,\n  key: SdkI18nKey,\n  vars?: Record<string, string | number>,\n): string {\n  const dict = (STRINGS as unknown as Record<string, Record<string, string>>)[locale ?? 'en'];\n  let s = dict?.[key] ?? STRINGS.en[key];\n  if (vars) {\n    for (const [k, v] of Object.entries(vars)) {\n      s = s.replaceAll(`{${k}}`, String(v));\n    }\n  }\n  return s;\n}\n","/**\n * Best-effort CSS selector inference for a DOM element.\n *\n * Strategy:\n *   1. honor explicit hooks first: `data-dddk-id`, then `data-testid`\n *   2. then `id` if globally unique (escaped via CSS.escape so weird ids are safe)\n *   3. otherwise build a short ancestry path with :nth-child positions,\n *      bounded to 5 levels deep so we don't generate selectors that bind to\n *      structural noise.\n *\n * `asAttribute: true` returns the selector wrapped as ` selector=\"...\"` for\n * inline annotation inside LLM-facing DOM summaries (see agent/dom-reader.ts).\n */\n\nexport interface InferSelectorOptions {\n  /** Include ` selector=\"...\"` decorator string suitable for inline annotation. Default false. */\n  asAttribute?: boolean;\n  /** Max depth for the nth-child fallback path. Default 5. */\n  maxDepth?: number;\n}\n\nexport function inferSelector(el: Element, opts: InferSelectorOptions = {}): string {\n  const maxDepth = opts.maxDepth ?? 5;\n  const wrap = (sel: string) => (opts.asAttribute ? ` selector=\"${sel}\"` : sel);\n\n  if (typeof document === 'undefined') return '';\n  if (el instanceof HTMLElement && el.dataset.dddkId) {\n    return wrap(`[data-dddk-id=\"${cssAttrEscape(el.dataset.dddkId)}\"]`);\n  }\n  if (el.id) {\n    try {\n      const escaped = CSS.escape(el.id);\n      if (document.querySelectorAll(`#${escaped}`).length === 1) {\n        return wrap(`#${escaped}`);\n      }\n    } catch {\n      /* CSS.escape unavailable (very old browsers) — fall through. */\n    }\n  }\n  if (el instanceof HTMLElement && el.dataset.testid) {\n    return wrap(`[data-testid=\"${cssAttrEscape(el.dataset.testid)}\"]`);\n  }\n\n  const path: string[] = [];\n  let cur: Element | null = el;\n  while (cur && cur !== document.body && path.length < maxDepth) {\n    const idx = Array.from(cur.parentElement?.children ?? []).indexOf(cur) + 1;\n    path.unshift(`${cur.tagName.toLowerCase()}:nth-child(${idx})`);\n    cur = cur.parentElement;\n  }\n  return wrap(path.join('>'));\n}\n\nfunction cssAttrEscape(s: string): string {\n  return s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n}\n","import { injectScopedStyle, UI_ATTR } from '../../utils/dom';\n\nexport { UI_ATTR };\nexport const STYLE_ID = 'dddk-palette-style';\n\nexport function ensurePaletteStyles(): void {\n  injectScopedStyle(STYLE_ID, `\n    [${UI_ATTR}=\"palette-backdrop\"] {\n      position: fixed; inset: 0;\n      background: var(--dddk-bg-overlay, rgba(15, 23, 42, 0.42));\n      backdrop-filter: blur(var(--dddk-blur, 20px));\n      -webkit-backdrop-filter: blur(var(--dddk-blur, 20px));\n      z-index: var(--dddk-z-palette, 9900);\n      display: flex; align-items: flex-start; justify-content: center;\n      padding-top: 10vh;\n      animation: dddk-fade 140ms ease-out;\n    }\n    /* Inline mount: palette embedded in a host (no overlay/backdrop). The box\n       fills the host width and drops the elevation/animation of the modal. */\n    [${UI_ATTR}=\"palette-inline\"] { position: static; display: block; width: 100%; }\n    [${UI_ATTR}=\"palette-inline\"] [${UI_ATTR}=\"palette\"] {\n      width: 100%; max-width: none;\n      max-height: var(--dddk-palette-inline-max-height, 460px);\n      box-shadow: var(--dddk-palette-inline-shadow, none);\n      animation: none;\n    }\n    [${UI_ATTR}=\"palette\"] {\n      width: var(--dddk-palette-width, 760px); max-width: 92vw;\n      max-height: var(--dddk-palette-max-height, 78vh);\n      background: var(--dddk-bg-elevated, #ffffff);\n      color: var(--dddk-text, #1a1a1a);\n      border-radius: var(--dddk-radius, 18px);\n      border: 1px solid var(--dddk-border, rgba(0, 0, 0, 0.06));\n      box-shadow: var(--dddk-shadow-lg, 0 28px 72px -16px rgba(0, 0, 0, 0.38), 0 4px 18px rgba(0, 0, 0, 0.08));\n      font-family: var(--dddk-font, system-ui, -apple-system, \"Segoe UI\", \"PingFang TC\", \"Microsoft JhengHei\", sans-serif);\n      /* Self-containment: these properties INHERIT from the host page. The modal\n         renders against a neutral backdrop so it never noticed, but inline mounts\n         live inside arbitrary host CSS (e.g. a centered hero). Reset them on the\n         root so the palette looks identical wherever it is embedded. */\n      text-align: left; letter-spacing: normal; line-height: normal;\n      text-transform: none; font-style: normal; white-space: normal;\n      word-spacing: normal; text-indent: 0; direction: ltr;\n      display: flex; flex-direction: column; overflow: hidden;\n      animation: dddk-palette-rise 200ms cubic-bezier(0.2, 0, 0, 1);\n    }\n    @keyframes dddk-palette-rise {\n      from { transform: translateY(8px) scale(0.985); opacity: 0; }\n      to   { transform: translateY(0)    scale(1);     opacity: 1; }\n    }\n    [${UI_ATTR}=\"palette-input-row\"] {\n      display: flex; align-items: center;\n      padding-right: 14px;\n      border-bottom: 1px solid var(--dddk-border, rgba(0, 0, 0, 0.06));\n    }\n    /* Back / close chrome shared with PanelRuntime — the panel skill\n       UI reuses the same input row so the user sees one continuous\n       palette experience, with a back arrow appearing only when\n       there's somewhere to go. */\n    [${UI_ATTR}=\"panel-back\"],\n    [${UI_ATTR}=\"panel-close\"] {\n      flex-shrink: 0;\n      width: 32px; height: 32px;\n      margin: 0 4px;\n      display: inline-flex; align-items: center; justify-content: center;\n      background: transparent;\n      color: var(--dddk-text-muted, #64748b);\n      border: 0;\n      border-radius: 8px;\n      font-size: 18px; line-height: 1;\n      cursor: pointer;\n      padding: 0;\n      transition: background 0.12s, color 0.12s;\n      -webkit-tap-highlight-color: transparent;\n    }\n    [${UI_ATTR}=\"panel-back\"] { margin-left: 8px; }\n    [${UI_ATTR}=\"panel-close\"] { margin-right: 0; }\n    [${UI_ATTR}=\"panel-back\"]:hover,\n    [${UI_ATTR}=\"panel-close\"]:hover {\n      background: var(--dddk-row-hover, rgba(0, 0, 0, 0.06));\n      color: var(--dddk-text, #1a1a1a);\n    }\n    [${UI_ATTR}=\"panel-back\"]:focus-visible,\n    [${UI_ATTR}=\"panel-close\"]:focus-visible {\n      outline: 2px solid var(--dddk-accent, #6366f1);\n      outline-offset: 2px;\n    }\n    [${UI_ATTR}=\"panel-back\"]:active,\n    [${UI_ATTR}=\"panel-close\"]:active { transform: scale(0.94); }\n    [${UI_ATTR}=\"palette-input\"] {\n      border: 0; outline: 0; padding: 18px 22px;\n      font-size: var(--dddk-font-size-lg, 16.5px);\n      font-weight: 400;\n      background: transparent; color: inherit; width: 100%;\n      flex: 1; min-width: 0;\n      letter-spacing: 0.002em;\n      /* Long placeholders truncate with an ellipsis instead of being clipped flush. */\n      text-overflow: ellipsis;\n    }\n    [${UI_ATTR}=\"palette-input\"]::placeholder {\n      color: var(--dddk-text-muted, #94a3b8);\n      font-weight: 400;\n    }\n    [${UI_ATTR}=\"palette-camera\"] {\n      flex-shrink: 0;\n      width: 32px; height: 32px;\n      background: transparent; border: 0;\n      border-radius: var(--dddk-radius-sm, 6px);\n      color: var(--dddk-text-muted, #71717a);\n      cursor: pointer;\n      display: inline-flex; align-items: center; justify-content: center;\n      transition: background 0.15s, color 0.15s;\n    }\n    [${UI_ATTR}=\"palette-camera\"]:hover {\n      background: var(--dddk-accent-soft, rgba(139,115,85,0.1));\n      color: var(--dddk-text, #18181b);\n    }\n    /* Submit / send button — circular accent button at the right edge of input. */\n    [${UI_ATTR}=\"palette-submit\"] {\n      flex-shrink: 0; margin-right: 10px;\n      width: var(--dddk-palette-submit-size, 36px); height: var(--dddk-palette-submit-size, 36px);\n      border: 0; border-radius: 999px; cursor: pointer;\n      background: var(--dddk-palette-submit-bg, var(--dddk-accent, #a94064));\n      color: var(--dddk-palette-submit-color, #fff);\n      display: inline-flex; align-items: center; justify-content: center;\n      transition: opacity 0.15s, transform 0.1s;\n    }\n    [${UI_ATTR}=\"palette-submit\"]:hover { opacity: 0.9; }\n    [${UI_ATTR}=\"palette-submit\"]:active { transform: scale(0.93); }\n    /* Multi-line row: vertical text column (name on top, then one el per line). */\n    [${UI_ATTR}=\"palette-item-textcol\"] {\n      display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto;\n    }\n    [${UI_ATTR}=\"palette-item-line\"] {\n      font-size: var(--dddk-palette-line-font-size, 13px);\n      line-height: 1.35; min-width: 0;\n      color: var(--dddk-palette-line-color, var(--dddk-text-muted, #6b6b6b));\n      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n    }\n    [${UI_ATTR}=\"palette-item\"][data-active=\"true\"] [${UI_ATTR}=\"palette-item-line\"] {\n      color: var(--dddk-palette-line-color-active, var(--dddk-palette-desc-color-active, inherit));\n    }\n    [${UI_ATTR}=\"palette-context\"] {\n      display: flex; flex-wrap: wrap; gap: 6px;\n      padding: 8px 14px;\n      background: var(--dddk-accent-soft, rgba(139,115,85,0.06));\n      font-size: 12px;\n    }\n    [${UI_ATTR}=\"palette-context\"] .pal-chip {\n      display: inline-flex; align-items: center; gap: 6px;\n      padding: 4px 8px; border-radius: 12px;\n      background: var(--dddk-bg-elevated, #fff);\n      border: 1px solid var(--dddk-border, rgba(0,0,0,0.1));\n      max-width: 360px;\n    }\n    [${UI_ATTR}=\"palette-context\"] .pal-chip-label {\n      font-size: 9px; font-weight: 700; letter-spacing: 0.08em;\n      text-transform: uppercase;\n      color: var(--dddk-accent, #ec4899);\n    }\n    [${UI_ATTR}=\"palette-context\"] .pal-chip-text {\n      font-size: 12px;\n      color: var(--dddk-text, #18181b);\n      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n      max-width: 280px;\n    }\n    /* DOM chip — uses a slightly different label color so users can tell at\n       a glance \"I pinned an element\" vs \"I selected some text\". */\n    [${UI_ATTR}=\"palette-context\"] .pal-chip-dom .pal-chip-label {\n      color: var(--dddk-accent-strong, var(--dddk-accent, #ec4899));\n    }\n    [${UI_ATTR}=\"palette-context\"] .pal-chip-dom .pal-chip-text {\n      font-family: var(--dddk-font-mono, ui-monospace, monospace);\n      font-size: 11px;\n    }\n    /* Image-attachment chip — shows the preview big enough to recognise. */\n    [${UI_ATTR}=\"palette-context\"] .pal-chip-att {\n      padding: 4px;\n      position: relative;\n    }\n    [${UI_ATTR}=\"palette-context\"] .pal-chip-img {\n      display: block;\n      width: 64px; height: 64px; border-radius: 6px;\n      object-fit: cover;\n    }\n    [${UI_ATTR}=\"palette-context\"] .pal-chip-att .pal-chip-x {\n      position: absolute;\n      top: 2px; right: 2px;\n      width: 18px; height: 18px;\n      border-radius: 50%;\n      background: var(--dddk-bg-elevated, #fff);\n      border: 1px solid var(--dddk-border);\n      box-shadow: var(--dddk-shadow-sm, 0 1px 3px rgba(0,0,0,0.1));\n      display: flex; align-items: center; justify-content: center;\n      cursor: pointer;\n      color: var(--dddk-text-muted, #71717a);\n      font-size: 11px;\n      padding: 0;\n    }\n    [${UI_ATTR}=\"palette-context\"] .pal-chip-x {\n      background: transparent; border: 0; cursor: pointer;\n      color: var(--dddk-text-muted, #71717a);\n      font-size: 11px; padding: 0 2px;\n    }\n    [${UI_ATTR}=\"palette-context\"] .pal-chip-x:hover {\n      color: var(--dddk-text, #18181b);\n    }\n    [${UI_ATTR}=\"palette-screenshot-overlay\"] {\n      position: fixed; inset: 0;\n      z-index: calc(var(--dddk-z-palette, 9600) + 1);\n      cursor: crosshair;\n      background: rgba(0, 0, 0, 0.18);\n    }\n    [${UI_ATTR}=\"palette-screenshot-rect\"] {\n      position: fixed;\n      display: none;\n      border: 2px solid var(--dddk-accent, #6366f1);\n      background: var(--dddk-accent-soft, rgba(99,102,241,0.18));\n      pointer-events: none;\n    }\n    [${UI_ATTR}=\"palette-screenshot-hint\"] {\n      position: fixed; left: 50%; bottom: 32px;\n      transform: translateX(-50%);\n      padding: 8px 16px;\n      background: var(--dddk-bg-elevated, rgba(255,255,255,0.96));\n      color: var(--dddk-text, #18181b);\n      border-radius: 8px;\n      font-family: var(--dddk-font);\n      font-size: 12px;\n      box-shadow: var(--dddk-shadow-md);\n      pointer-events: none;\n    }\n    [${UI_ATTR}=\"palette-footer\"] {\n      display: flex; align-items: center; gap: 18px;\n      padding: 10px 16px;\n      border-top: 1px solid var(--dddk-border, rgba(0,0,0,0.06));\n      font-size: 11px;\n      color: var(--dddk-text-muted, #71717a);\n      background: var(--dddk-bg-elevated, transparent);\n      /* Footer MUST NOT shrink or get clipped when the results list\n         grows tall — it holds the keyboard hints + Powered-by mark\n         and the whole point is it always shows at the bottom of the\n         panel. min-height: 0 on the middle flex children makes sure\n         they scroll internally instead of pushing us out. */\n      flex-shrink: 0;\n    }\n    [${UI_ATTR}=\"palette-categories\"] {\n      display: flex; align-items: center; gap: 6px;\n      padding: 8px 14px;\n      border-bottom: 1px solid var(--dddk-border, rgba(0,0,0,0.06));\n      overflow-x: auto;\n      scrollbar-width: none;\n    }\n    [${UI_ATTR}=\"palette-categories\"]::-webkit-scrollbar { display: none; }\n    [${UI_ATTR}=\"palette-category\"] {\n      flex: 0 0 auto;\n      appearance: none;\n      border: 0;\n      padding: 4px 11px;\n      border-radius: 999px;\n      font-family: inherit;\n      font-size: 12px;\n      line-height: 1.4;\n      color: var(--dddk-palette-category-color, var(--dddk-text-muted, #71717a));\n      background: var(--dddk-palette-category-bg, transparent);\n      cursor: pointer;\n      transition: background 80ms ease, color 80ms ease;\n    }\n    [${UI_ATTR}=\"palette-category\"]:hover {\n      background: var(--dddk-palette-category-bg-hover, rgba(0,0,0,0.04));\n      color: var(--dddk-text, #18181b);\n    }\n    [${UI_ATTR}=\"palette-category\"][data-active=\"true\"] {\n      background: var(--dddk-palette-category-bg-active, var(--dddk-accent, #6366f1));\n      color: var(--dddk-palette-category-color-active, var(--dddk-text-on-accent, #fff));\n    }\n    [${UI_ATTR}=\"palette-footer-group\"] {\n      display: inline-flex; align-items: center; gap: 6px;\n    }\n    /* Touch-variant hint groups. Hidden on hover-capable devices; the\n       media query below flips their visibility with the kbd groups so\n       touch users see actionable hints instead of un-pressable kbd\n       symbols. */\n    [${UI_ATTR}=\"palette-footer-group-touch\"] {\n      display: none; align-items: center; gap: 4px;\n      color: var(--dddk-text-muted, #71717a);\n    }\n    /* Powered-by brand mark — pinned to the far right of the footer.\n       All three keyboard-hint groups stay grouped on the left; the\n       brand pill takes over as the true last child of the footer. */\n    [${UI_ATTR}=\"palette-footer-brand\"] {\n      margin-left: auto;\n      display: inline-flex;\n      align-items: center;\n      gap: 4px;\n      font-size: 11px;\n      opacity: 0.7;\n      user-select: none;\n    }\n    [${UI_ATTR}=\"palette-footer-brand\"] a {\n      color: inherit;\n      text-decoration: none;\n      font-weight: 600;\n      opacity: 0.95;\n    }\n    [${UI_ATTR}=\"palette-footer-brand\"] a:hover {\n      text-decoration: underline;\n      opacity: 1;\n    }\n    [${UI_ATTR}=\"palette-footer-brand-text\"] {\n      opacity: 0.75;\n    }\n    /* Tiny duck watermark next to the brand text. Uses the same CSS\n       variable as other dddk surfaces so hosts wire the URL once. */\n    [${UI_ATTR}=\"palette-footer-brand-mark\"] {\n      display: inline-block;\n      width: 16px; height: 16px;\n      background-image: var(--dddk-brand-mark-url, var(--dddk-avatar-url, none));\n      background-size: contain;\n      background-repeat: no-repeat;\n      background-position: center;\n      vertical-align: middle;\n      margin-left: 2px;\n      animation: dddk-brand-mark-bob var(--dddk-brand-mark-bob-duration, 3.2s) ease-in-out infinite;\n    }\n    @keyframes dddk-brand-mark-bob {\n      0%, 100% { transform: translateY(0); }\n      50%      { transform: translateY(-2px); }\n    }\n    /* Borderless, lower-contrast kbd chips — a subtle filled tile\n       rather than a button-with-border so the row of hints reads as\n       ambient help, not a toolbar. */\n    [${UI_ATTR}=\"palette-footer\"] kbd {\n      display: inline-flex; align-items: center; justify-content: center;\n      min-width: 16px; height: 16px;\n      padding: 0 4px;\n      background: var(--dddk-palette-kbd-bg, rgba(0,0,0,0.05));\n      border: 0;\n      border-radius: 3px;\n      font-family: inherit;\n      font-size: 10px;\n      line-height: 1;\n      color: var(--dddk-palette-kbd-color, var(--dddk-text-muted, #71717a));\n    }\n    [${UI_ATTR}=\"palette-result\"] {\n      /* Zero internal padding — host content owns its own layout. The\n         outer palette shell provides the visual frame; custom panels\n         live edge-to-edge inside, so there's no \"box inside a box\"\n         feel when a host's split-view / image preview / chip grid\n         mounts here. Hosts that want padded content add their own\n         padding to the surface they emit (.dddk-panel-section etc). */\n      padding: 0;\n      overflow-y: auto;\n      overscroll-behavior: contain;\n      /* flex: 1 1 auto — basis auto means the list's natural\n         intrinsic height is the starting point, and it can grow to\n         fill remaining space. basis: 0 (my earlier fix attempt)\n         collapsed the list to 0 when the panel didn't have a\n         definite height, breaking the palette entirely. Combined\n         with the footer's flex-shrink: 0, the footer stays pinned\n         at the bottom even when the list is tall. */\n      flex: 1 1 auto;\n      max-height: 60vh;\n      min-height: 0;\n      font-size: var(--dddk-font-size-md, 14px);\n      line-height: 1.65;\n      color: var(--dddk-text, #18181b);\n    }\n    [${UI_ATTR}=\"palette-split\"] {\n      display: flex; flex: 1 1 auto; min-height: 0;\n    }\n    [${UI_ATTR}=\"palette-list\"] {\n      list-style: none; margin: 0; padding: 6px 8px 8px;\n      overflow-y: auto;\n      overscroll-behavior: contain;       /* same — captures wheel on overflow */\n      flex: 1; min-width: 0;\n    }\n    /* Inline accordion: appended INSIDE the active row so the whole option grows\n       taller. flex-basis:100% drops it onto a new full-width line under the\n       icon + text; it inherits the row's active background (one expanded card). */\n    [${UI_ATTR}=\"palette-detail\"] {\n      flex-basis: 100%;\n      width: 100%;\n      padding: 6px 8px 4px 50px;\n      overflow-y: auto;\n      overscroll-behavior: contain;\n      font-size: var(--dddk-font-size-sm, 13px);\n      color: var(--dddk-text, #18181b);\n    }\n    /* Palette-scoped text-selection — high-contrast on both themes. */\n    [${UI_ATTR}=\"palette\"] ::selection,\n    [${UI_ATTR}=\"palette-result\"] ::selection {\n      background: var(--dddk-accent, #6366f1);\n      color: var(--dddk-text-on-accent, #fff);\n    }\n    [${UI_ATTR}=\"palette-section\"] {\n      padding: var(--dddk-palette-section-padding, 14px 16px 6px);\n      font-size: var(--dddk-palette-section-font-size, 12px);\n      color: var(--dddk-palette-section-color, var(--dddk-text-muted, #6b6b6b));\n      text-transform: var(--dddk-palette-section-text-transform, none);\n      letter-spacing: var(--dddk-palette-section-letter-spacing, 0);\n      font-weight: var(--dddk-palette-section-font-weight, 500);\n      /* Section headers default to STATIC — they scroll away with\n         their rows. Sticky was the old default; user feedback: reads\n         as clutter, a section title should feel like a paragraph\n         heading, not a docked chip. Hosts can opt back in via\n         --dddk-palette-section-position: sticky per surface. */\n      position: var(--dddk-palette-section-position, static);\n      z-index: 1;\n      background: var(--dddk-palette-section-bg, transparent);\n    }\n    [${UI_ATTR}=\"palette-item\"] {\n      position: relative;\n      padding: var(--dddk-palette-row-padding, 9px 16px);\n      /* Reserve right-edge space for the focus arrow on EVERY row so the\n         text columns don't shift when focus moves. Without this the arrow\n         would overlap any shortcut text on the active row. */\n      padding-right: calc(28px + var(--dddk-palette-row-padding-right, 8px));\n      cursor: pointer;\n      display: flex; align-items: center;\n      /* wrap so an inline detail host (appended into the active row) drops onto\n         a new full-width line under the icon + text — the whole option grows. */\n      flex-wrap: wrap;\n      gap: var(--dddk-palette-row-gap, 12px);\n      border-radius: var(--dddk-palette-row-radius, 6px);\n    }\n    [${UI_ATTR}=\"palette-item\"]:hover {\n      background: var(--dddk-palette-row-bg-hover, rgba(0,0,0,0.04));\n    }\n    [${UI_ATTR}=\"palette-item\"][data-active=\"true\"] {\n      background: var(--dddk-palette-row-bg-active, rgba(0,0,0,0.06));\n    }\n    /* Right-edge arrow on the focused row — affordance telling the\n       user \"Enter activates this row\". Quiet on hover, fully visible\n       on the active row only. */\n    [${UI_ATTR}=\"palette-item\"][data-active=\"true\"]::after {\n      content: '→';\n      position: absolute;\n      right: 16px;\n      top: 50%;\n      transform: translateY(-50%);\n      color: var(--dddk-palette-row-arrow-color, var(--dddk-text-muted, #71717a));\n      font-size: 14px;\n      pointer-events: none;\n    }\n    [${UI_ATTR}=\"palette-item-icon\"] {\n      width: var(--dddk-palette-icon-size, 18px);\n      text-align: center; flex-shrink: 0;\n      color: var(--dddk-palette-icon-color, var(--dddk-text-muted, #6b6b6b));\n    }\n    [${UI_ATTR}=\"palette-item\"][data-active=\"true\"] [${UI_ATTR}=\"palette-item-icon\"] {\n      color: var(--dddk-palette-icon-color-active, var(--dddk-text-on-accent, #fff));\n    }\n    /* Image thumbnail row (item.image): cover-fit, slightly larger than glyph slot. */\n    [${UI_ATTR}=\"palette-item-icon-img\"] {\n      width: var(--dddk-palette-image-w, 26px);\n      height: var(--dddk-palette-image-h, 34px);\n      flex-shrink: 0;\n    }\n    [${UI_ATTR}=\"palette-item-icon-img\"] img {\n      width: 100%; height: 100%; object-fit: cover; display: block;\n      border-radius: var(--dddk-palette-image-radius, 3px);\n      box-shadow: 0 1px 3px rgba(0,0,0,0.18);\n    }\n    [${UI_ATTR}=\"palette-item-name\"] {\n      flex-shrink: 0;\n      color: var(--dddk-palette-name-color, var(--dddk-text, #18181b));\n      font-size: var(--dddk-palette-name-font-size, var(--dddk-font-size-md, 14px));\n      font-weight: var(--dddk-palette-name-font-weight, 500);\n    }\n    [${UI_ATTR}=\"palette-item\"][data-active=\"true\"] [${UI_ATTR}=\"palette-item-name\"] {\n      color: var(--dddk-palette-name-color-active, var(--dddk-text-on-accent, #fff));\n    }\n    [${UI_ATTR}=\"palette-item-dash\"] {\n      color: var(--dddk-palette-dash-color, var(--dddk-text-muted, #6b6b6b));\n      opacity: var(--dddk-palette-dash-opacity, 0.55);\n    }\n    [${UI_ATTR}=\"palette-item-desc\"] {\n      flex: 1; min-width: 0;\n      color: var(--dddk-palette-desc-color, var(--dddk-text-muted, #6b6b6b));\n      font-size: var(--dddk-palette-desc-font-size, var(--dddk-font-size-sm, 13px));\n      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n    }\n    [${UI_ATTR}=\"palette-item\"][data-active=\"true\"] [${UI_ATTR}=\"palette-item-desc\"] {\n      color: var(--dddk-palette-desc-color-active, var(--dddk-text-on-accent, #fff));\n      opacity: var(--dddk-palette-desc-opacity-active, 0.85);\n    }\n    [${UI_ATTR}=\"palette-item\"][data-active=\"true\"] [${UI_ATTR}=\"palette-item-dash\"] {\n      color: var(--dddk-palette-desc-color-active, var(--dddk-text-on-accent, #fff));\n      opacity: 0.5;\n    }\n    [${UI_ATTR}=\"palette-item-shortcut\"] {\n      font-family: var(--dddk-palette-shortcut-font, var(--dddk-font-mono, ui-monospace, monospace));\n      font-size: var(--dddk-palette-shortcut-font-size, var(--dddk-font-size-sm, 12px));\n      color: var(--dddk-palette-shortcut-color, var(--dddk-text-muted, #6b6b6b));\n      opacity: var(--dddk-palette-shortcut-opacity, 0.6);\n    }\n    [${UI_ATTR}=\"palette-item-prefix\"] {\n      font-family: var(--dddk-palette-prefix-font, inherit);\n      font-size: var(--dddk-palette-prefix-font-size, var(--dddk-font-size-md, 14px));\n      padding: var(--dddk-palette-prefix-padding, 0);\n      border-radius: var(--dddk-palette-prefix-radius, 0);\n      background: var(--dddk-palette-prefix-bg, transparent);\n      color: var(--dddk-palette-prefix-color, var(--dddk-text-muted, #71717a));\n      font-weight: var(--dddk-palette-name-font-weight, 500);\n    }\n    /* Query-match highlight inside row name / description. Warm yellow\n       marker on light bg, soft amber on dark — meant to read as a\n       search-hit signal distinct from the brand accent. */\n    [${UI_ATTR}=\"palette-match\"] {\n      background: var(--dddk-palette-match-bg, rgba(250, 204, 21, 0.35));\n      color: var(--dddk-palette-match-color, inherit);\n      border-radius: var(--dddk-palette-match-radius, 2px);\n      padding: 0 1px;\n      font-weight: var(--dddk-palette-match-weight, 600);\n    }\n    @keyframes dddk-fade { from { opacity: 0; } to { opacity: 1; } }\n\n    /* ─────────────────────────────────────────────────────────────\n       Panel-surface utilities — opt-in classes hosts can compose\n       inside any palette result / panel runtime content area.\n       The point is to give custom UIs a consistent visual language\n       without each host writing its own CSS (or pulling Tailwind).\n       All classes use the dddk-panel- prefix so they never collide\n       with the host's own styles.\n       ───────────────────────────────────────────────────────────── */\n\n    /* Section — generous-padding container for prose / hero content. */\n    .dddk-panel-section {\n      padding: 18px 22px;\n    }\n    .dddk-panel-section + .dddk-panel-section {\n      border-top: 1px solid var(--dddk-border, rgba(0, 0, 0, 0.06));\n    }\n\n    /* Split — left rail (list) + right detail panel. */\n    .dddk-panel-split {\n      display: grid;\n      grid-template-columns: minmax(220px, 38%) 1fr;\n      min-height: 320px;\n    }\n    .dddk-panel-split > :first-child {\n      border-right: 1px solid var(--dddk-border, rgba(0, 0, 0, 0.06));\n      overflow-y: auto; min-height: 0;\n    }\n    .dddk-panel-split > :last-child {\n      overflow-y: auto; min-height: 0;\n    }\n    @media (max-width: 640px) {\n      .dddk-panel-split { grid-template-columns: 1fr; min-height: 240px; }\n      .dddk-panel-split > :first-child {\n        border-right: 0;\n        border-bottom: 1px solid var(--dddk-border, rgba(0, 0, 0, 0.06));\n      }\n    }\n\n    /* Section heading — small, muted, generous letter-spacing. */\n    .dddk-panel-section-label {\n      font-size: 11px;\n      font-weight: 600;\n      letter-spacing: 0.08em;\n      text-transform: uppercase;\n      color: var(--dddk-text-muted, #64748b);\n      padding: 12px 16px 4px;\n    }\n\n    /* List rows — Raycast-style hoverable list. */\n    .dddk-panel-list {\n      list-style: none;\n      margin: 0;\n      padding: 4px 8px 8px;\n    }\n    .dddk-panel-row {\n      display: flex; align-items: center; gap: 10px;\n      padding: 9px 12px;\n      border-radius: 8px;\n      cursor: pointer;\n      color: var(--dddk-text, #1a1a1a);\n      transition: background 80ms ease;\n    }\n    .dddk-panel-row:hover {\n      background: var(--dddk-row-hover, rgba(0, 0, 0, 0.04));\n    }\n    .dddk-panel-row[data-active=\"true\"] {\n      background: var(--dddk-row-active, rgba(0, 0, 0, 0.06));\n    }\n    .dddk-panel-row-icon {\n      flex: 0 0 28px;\n      width: 28px; height: 28px;\n      display: inline-flex; align-items: center; justify-content: center;\n      border-radius: 8px;\n      background: var(--dddk-bg-elevated, rgba(0, 0, 0, 0.04));\n      color: var(--dddk-text-muted, #64748b);\n      font-size: 13px;\n    }\n    .dddk-panel-row-icon img,\n    .dddk-panel-row-icon svg { width: 100%; height: 100%; border-radius: 8px; object-fit: cover; }\n    .dddk-panel-row-main {\n      flex: 1; min-width: 0;\n      display: flex; flex-direction: column;\n    }\n    .dddk-panel-row-title {\n      font-size: 14px;\n      font-weight: 500;\n      color: var(--dddk-text, #1a1a1a);\n      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n    }\n    .dddk-panel-row-sub {\n      font-size: 12px;\n      color: var(--dddk-text-muted, #64748b);\n      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n      margin-top: 2px;\n    }\n    .dddk-panel-row-meta {\n      font-size: 11.5px;\n      color: var(--dddk-text-muted, #64748b);\n      flex: 0 0 auto;\n      margin-left: 8px;\n    }\n\n    /* Detail panel — hero block + info table. */\n    .dddk-panel-detail {\n      padding: 22px 24px;\n      display: flex; flex-direction: column; gap: 18px;\n    }\n    .dddk-panel-detail-hero {\n      display: flex; align-items: center; justify-content: center;\n      min-height: 160px;\n      border-radius: 12px;\n      background: var(--dddk-bg-elevated, rgba(0, 0, 0, 0.03));\n      overflow: hidden;\n    }\n    .dddk-panel-detail-hero img {\n      max-width: 100%; max-height: 240px; object-fit: contain;\n      border-radius: 12px;\n    }\n    .dddk-panel-detail-title {\n      font-size: 16px; font-weight: 600;\n      color: var(--dddk-text, #1a1a1a);\n      text-align: center;\n    }\n\n    /* Info table — key/value rows. */\n    .dddk-panel-info {\n      display: flex; flex-direction: column;\n      border-top: 1px solid var(--dddk-border, rgba(0, 0, 0, 0.06));\n      padding-top: 12px;\n    }\n    .dddk-panel-info-row {\n      display: flex; align-items: baseline; justify-content: space-between;\n      padding: 9px 0;\n      border-bottom: 1px solid var(--dddk-border-subtle, rgba(0, 0, 0, 0.04));\n      font-size: 13px;\n    }\n    .dddk-panel-info-row:last-child { border-bottom: 0; }\n    .dddk-panel-info-key {\n      color: var(--dddk-text-muted, #64748b);\n      font-weight: 500;\n    }\n    .dddk-panel-info-value {\n      color: var(--dddk-text, #1a1a1a);\n      text-align: right;\n      max-width: 70%;\n      word-break: break-word;\n    }\n    .dddk-panel-info-value code {\n      font-family: var(--dddk-mono, ui-monospace, \"SF Mono\", Menlo, monospace);\n      font-size: 12.5px;\n      background: var(--dddk-row-hover, rgba(0, 0, 0, 0.05));\n      padding: 1px 5px;\n      border-radius: 4px;\n    }\n\n    /* Pill / tag chip. */\n    .dddk-panel-pill {\n      display: inline-flex; align-items: center;\n      padding: 3px 10px;\n      border-radius: 999px;\n      background: var(--dddk-row-hover, rgba(0, 0, 0, 0.06));\n      color: var(--dddk-text, #1a1a1a);\n      font-size: 12px;\n      font-weight: 500;\n      line-height: 1.4;\n    }\n    .dddk-panel-pill[data-tone=\"accent\"] {\n      background: var(--dddk-accent-soft, rgba(99, 102, 241, 0.12));\n      color: var(--dddk-accent, #4f46e5);\n    }\n    .dddk-panel-pill[data-tone=\"success\"] {\n      background: rgba(34, 197, 94, 0.12);\n      color: rgb(21, 128, 61);\n    }\n    .dddk-panel-pill[data-tone=\"warning\"] {\n      background: rgba(245, 158, 11, 0.14);\n      color: rgb(180, 83, 9);\n    }\n\n    /* Card grid — responsive product / item gallery. */\n    .dddk-panel-card-grid {\n      display: grid;\n      grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));\n      gap: 12px;\n      padding: 14px 16px 18px;\n    }\n    .dddk-panel-card {\n      display: flex; flex-direction: column; gap: 8px;\n      padding: 14px;\n      border-radius: 12px;\n      background: var(--dddk-bg-elevated, rgba(0, 0, 0, 0.02));\n      border: 1px solid var(--dddk-border, rgba(0, 0, 0, 0.06));\n      cursor: pointer;\n      transition: transform 120ms ease, box-shadow 120ms ease, background 120ms ease;\n    }\n    .dddk-panel-card:hover {\n      transform: translateY(-2px);\n      box-shadow: 0 10px 24px -10px rgba(0, 0, 0, 0.2);\n      background: var(--dddk-row-hover, rgba(0, 0, 0, 0.04));\n    }\n    .dddk-panel-card-hero {\n      height: 96px;\n      border-radius: 8px;\n      background: var(--dddk-accent-soft, rgba(99, 102, 241, 0.1));\n      display: flex; align-items: center; justify-content: center;\n      font-size: 28px;\n      color: var(--dddk-accent, #4f46e5);\n    }\n    .dddk-panel-card-title {\n      font-size: 14px; font-weight: 600;\n      color: var(--dddk-text, #1a1a1a);\n    }\n    .dddk-panel-card-sub {\n      font-size: 12.5px;\n      color: var(--dddk-text-muted, #64748b);\n      line-height: 1.5;\n    }\n\n    /* Empty state — for \"no results\" / first-time content. */\n    .dddk-panel-empty {\n      display: flex; flex-direction: column; align-items: center; justify-content: center;\n      gap: 8px;\n      padding: 48px 24px;\n      text-align: center;\n      color: var(--dddk-text-muted, #64748b);\n      font-size: 13.5px;\n    }\n    .dddk-panel-empty-icon {\n      font-size: 28px;\n      opacity: 0.5;\n    }\n\n\n    /* ── Mobile / coarse-pointer overrides ─────────────────────────\n       The default chrome (centered modal, keyboard-shortcut footer, 14px\n       fonts) is desktop-shaped. On touch devices we (1) hide the keyboard\n       footer (↑ ↓ ⏎ esc are not reachable), (2) bottom-anchor the panel\n       sheet-style with a safe-area inset, and (3) bump tap targets so\n       fingers can hit list rows cleanly. */\n    @media (max-width: 640px), (pointer: coarse) {\n      /* Mobile palette is a FLOATING dialog, NOT a fullscreen sheet.\n         The previous fullscreen layout felt like a takeover app, not\n         like a command palette. We keep ~88% viewport width, max-height\n         70vh, rounded on all sides, and centered with backdrop visible\n         around it — the user can still see hints of the page behind so\n         the palette feels like an overlay control, not a destination. */\n      [${UI_ATTR}=\"palette-backdrop\"] {\n        padding: 16px;\n        padding-top: 12vh;\n        align-items: flex-start;\n      }\n      [${UI_ATTR}=\"palette\"] {\n        width: 100%;\n        max-width: 100%;\n        max-height: 70vh;\n        border-radius: var(--dddk-radius, 14px);\n        animation: dddk-sheet-up 180ms cubic-bezier(0.2, 0, 0, 1);\n      }\n      [${UI_ATTR}=\"palette-input\"] {\n        font-size: 16px;       /* prevents iOS auto-zoom on focus */\n        padding: 12px 14px;\n      }\n      [${UI_ATTR}=\"palette-list\"] li {\n        padding: 12px 16px;    /* tap target ~44dp */\n      }\n      [${UI_ATTR}=\"palette-result\"] { max-height: 55vh; }\n    }\n    /* Touch-only devices (phones, tablets — NOT touch laptops with a\n       trackpad, those still get hover: hover). Flip the footer hints:\n       hide the kbd groups (un-pressable) and reveal the touch groups\n       so the strip stays useful. Brand mark shows on every form. */\n    @media (hover: none) and (pointer: coarse) {\n      [${UI_ATTR}=\"palette-footer-group\"] { display: none; }\n      [${UI_ATTR}=\"palette-footer-group-touch\"] { display: inline-flex; }\n    }\n    @keyframes dddk-sheet-up {\n      from { transform: translateY(24px); opacity: 0; }\n      to   { transform: translateY(0);    opacity: 1; }\n    }\n  `);\n}\n","/**\n * Prefix routing helpers — pure functions that operate on `PaletteItem.prefix`\n * specs and the current input string. No class state, no DOM.\n */\n\nimport type { PaletteItem, PaletteItemPrefix } from './types';\n\n/** Normalize PrefixSpec to a list of matchable strings. */\nexport function listPrefixMatches(spec: PaletteItemPrefix | undefined): string[] {\n  if (!spec) return [];\n  if (typeof spec === 'string') return [spec];\n  if (Array.isArray(spec)) return spec;\n  if (typeof spec === 'object') {\n    return Array.isArray(spec.match) ? spec.match : [spec.match];\n  }\n  return [];\n}\n\n/** What to render in the prefix slot for an item. */\nexport function displayPrefix(spec: PaletteItemPrefix | undefined): string | undefined {\n  if (!spec) return undefined;\n  if (typeof spec === 'string') return spec;\n  if (Array.isArray(spec)) return spec[0];\n  if (typeof spec === 'object') {\n    return spec.label ?? (Array.isArray(spec.match) ? spec.match[0] : spec.match);\n  }\n  return undefined;\n}\n\n/**\n * Find the item whose prefix matches the input.\n *   - Longest prefix wins (so `ask ai:` beats a hypothetical `ask:`).\n *   - Non-Tips items beat Tips items at the same length (a Tip is a hint\n *     row that lives in section `'Tips'`; the real command in another\n *     section is what should actually fire when the user types the prefix).\n */\nexport function matchPrefix(\n  items: PaletteItem[],\n  input: string,\n): { item: PaletteItem; arg: string } | null {\n  // Case-insensitive: `Docs:`, `DOCS:`, `docs:` all route to the same item.\n  const loweredInput = input.toLowerCase();\n  let best: { item: PaletteItem; arg: string; prefixLen: number; isTip: boolean } | null = null;\n  for (const item of items) {\n    const isTip = item.section === 'Tips';\n    const matches = listPrefixMatches(item.prefix);\n    for (const m of matches) {\n      if (loweredInput.startsWith(m.toLowerCase())) {\n        const len = m.length;\n        const better =\n          !best ||\n          (best.isTip && !isTip) ||\n          (best.isTip === isTip && len > best.prefixLen);\n        if (better) {\n          best = { item, arg: input.slice(len).trim(), prefixLen: len, isTip };\n        }\n      }\n    }\n  }\n  return best ? { item: best.item, arg: best.arg } : null;\n}\n\n/**\n * True when the user has typed the START of a registered prefix but not\n * the whole thing — e.g. `/`, `/t`, `nav`, `ask`. In that state we want\n * to filter the palette to commands whose prefix begins with the input,\n * NOT run a fuzzy / page-text search.\n */\nexport function looksLikePrefixAttempt(items: PaletteItem[], input: string): boolean {\n  if (input.length === 0) return false;\n  const lowered = input.toLowerCase();\n  for (const item of items) {\n    for (const p of listPrefixMatches(item.prefix)) {\n      const pl = p.toLowerCase();\n      if (pl === lowered) return false; // exact match already routes via matchPrefix\n      if (pl.startsWith(lowered) && p.length > input.length) return true;\n    }\n  }\n  return false;\n}\n","/**\n * Fuzzy filter + match-highlight helpers — pure, item-shape-agnostic.\n * The hay-cache mutates the item in place (lazy `__searchHay` /\n * `__searchNameLower`); setItems() invalidates by replacing the array.\n */\n\nimport { escapeHtml } from '../../utils/dom';\nimport type { PaletteItem } from './types';\n\n/**\n * Lazy hay-cache for fuzzy lookup. Concatenating name + description +\n * keywords on every keystroke for every item is O(N * L) per char with\n * non-trivial constants on hundreds of items, so we stash the lowercased\n * haystack on the item once and reuse it. setItems() invalidates by\n * replacing the item array entirely.\n */\nexport interface PaletteItemWithHay extends PaletteItem {\n  __searchHay?: string;\n  __searchNameLower?: string;\n}\n\nexport function truncate(s: string, max: number): string {\n  return s.length <= max ? s : s.slice(0, max - 1) + '…';\n}\n\n/**\n * Wrap EVERY contiguous occurrence of `query` in `text` with a\n * `<mark data-dddk-ui=\"palette-match\">` so it renders with the highlight\n * style (warm yellow / themed). Case-insensitive, non-overlapping. Falls\n * back to plain escaped text when the query is empty or has no match.\n *\n * Only contiguous substring matches highlight — fuzzy character matches\n * don't, because per-char highlights read as visual noise.\n */\nexport function highlightMatch(text: string, query: string): string {\n  if (!query) return escapeHtml(text);\n  const haystack = text.toLowerCase();\n  const needle = query.toLowerCase();\n  const segments: string[] = [];\n  let cursor = 0;\n  let hit = haystack.indexOf(needle, cursor);\n  if (hit < 0) return escapeHtml(text);\n  while (hit >= 0) {\n    if (hit > cursor) segments.push(escapeHtml(text.slice(cursor, hit)));\n    segments.push(\n      `<mark data-dddk-ui=\"palette-match\">${escapeHtml(text.slice(hit, hit + needle.length))}</mark>`,\n    );\n    cursor = hit + needle.length;\n    hit = haystack.indexOf(needle, cursor);\n  }\n  if (cursor < text.length) segments.push(escapeHtml(text.slice(cursor)));\n  return segments.join('');\n}\n\nexport function fuzzyScore(item: PaletteItem, query: string): number {\n  // Substring-only — require a contiguous match. Hosts that want\n  // typo tolerance should add alternate keywords on the item itself.\n  const it = item as PaletteItemWithHay;\n  let hay = it.__searchHay;\n  if (hay == null) {\n    hay = `${item.name} ${item.description ?? ''} ${(item.keywords ?? []).join(' ')}`.toLowerCase();\n    it.__searchHay = hay;\n  }\n  if (!hay.includes(query)) return 0;\n  // Boost for prefix match on name — also tolerate a leading symbol\n  // (`/`, `#`, `>`) so `/language` ranks high on query `lan` / `language`.\n  let nameLower = it.__searchNameLower;\n  if (nameLower == null) {\n    nameLower = item.name.toLowerCase();\n    it.__searchNameLower = nameLower;\n  }\n  if (nameLower.startsWith(query)) return 10;\n  // Strip a single leading non-alphanumeric character and retry — handles\n  // skill-style names like `/language` against bare-word queries.\n  if (/^[^a-z0-9]/.test(nameLower) && nameLower.slice(1).startsWith(query)) return 9;\n  return 5;\n}\n\n/**\n * Shared \"fuzzy-score + sort desc + slice\" helper. Three call sites in\n * the refilter pipeline (browse-mode, prefixAcceptsAnyArg secondary\n * results, free-text search) all do the same thing — keep them in lockstep.\n */\nexport function fuzzyTopN(items: PaletteItem[], query: string, limit: number): PaletteItem[] {\n  const q = query.toLowerCase();\n  return items\n    .map((i) => ({ i, score: fuzzyScore(i, q) }))\n    .filter((x) => x.score > 0)\n    .sort((a, b) => b.score - a.score)\n    .map((x) => x.i)\n    .slice(0, limit);\n}\n","/**\n * Small id generator.\n *\n * Not collision-proof (we're not crypto.randomUUID here — that pulls in\n * different polyfills for SSR), but the combination of a millisecond\n * timestamp + a 6-char base36 random suffix is enough for any in-memory\n * uniqueness need (palette attachments, mock tool calls, etc).\n */\nexport function genId(prefix?: string): string {\n  const suffix = `${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;\n  return prefix ? `${prefix}_${suffix}` : suffix;\n}\n","/**\n * Chip-bar rendering + pinned-context bookkeeping. The CommandPalette class\n * owns the state slots (`contextSelectionText`, `contextAttachments`,\n * `pinnedContextEl` …) and forwards to these helpers via a small host\n * adapter so this file can stay state-free (modulo the host it operates on).\n *\n * Why an adapter instead of importing CommandPalette directly: avoids a\n * circular import (CommandPalette imports this file) and keeps the helper's\n * surface explicit.\n */\n\nimport { genId } from '../../utils/id';\nimport { formatElementSignature } from '../../utils/dom';\nimport { inferSelector } from '../../utils/selector';\nimport type { PaletteAttachment } from './types';\nimport { truncate } from './fuzzy';\nimport { UI_ATTR } from './styles';\n\nexport type SelectionKind = 'dom' | 'text';\n\n/**\n * State slots the chip-bar helpers read / mutate on the palette.\n * Implemented as accessor pairs so the CommandPalette class can keep the\n * private fields where they live today without exposing them.\n */\nexport interface ChipBarHost {\n  /** Backing DOM node of the chip strip (between input row and list). */\n  getChipBarHost(): HTMLDivElement | null;\n\n  /** Live text-selection state. */\n  getSelectionText(): string;\n  setSelectionText(value: string): void;\n  getSelectionElement(): string | undefined;\n  setSelectionElement(value: string | undefined): void;\n  getSelectionKind(): SelectionKind;\n  setSelectionKind(value: SelectionKind): void;\n\n  /** Image attachments queued in the palette context. */\n  getAttachments(): PaletteAttachment[];\n  setAttachments(value: PaletteAttachment[]): void;\n\n  /** Sticky pinned-context state — survives palette open/close cycles. */\n  getPinnedEl(): Element | null;\n  setPinnedEl(el: Element | null): void;\n  getPinnedText(): string;\n  setPinnedText(text: string): void;\n  getPinnedKind(): SelectionKind;\n  setPinnedKind(kind: SelectionKind): void;\n\n  /** Render orchestration. Helper calls these whenever its mutations\n   *  could change the chip-bar / list. */\n  isOpen(): boolean;\n  renderChipBar(): void;\n  refilter(): void;\n}\n\n/**\n * Render or refresh the chip-bar above the palette input. Shows a context\n * chip (text or DOM selection) when one is captured, then one preview chip\n * per image attachment.\n */\nexport function renderChipBar(host: ChipBarHost): void {\n  const el = host.getChipBarHost();\n  if (!el) return;\n  const selectionText = host.getSelectionText();\n  const attachments = host.getAttachments();\n  const hasSel = !!selectionText;\n  const hasAtt = attachments.length > 0;\n  if (!hasSel && !hasAtt) {\n    el.style.display = 'none';\n    el.innerHTML = '';\n    return;\n  }\n  el.style.display = 'flex';\n  el.innerHTML = '';\n\n  if (hasSel) {\n    const chip = document.createElement('div');\n    const isDom = host.getSelectionKind() === 'dom';\n    chip.className = isDom ? 'pal-chip pal-chip-sel pal-chip-dom' : 'pal-chip pal-chip-sel';\n    chip.innerHTML = `\n      <span class=\"pal-chip-label\">${isDom ? 'DOM' : 'CONTEXT'}</span>\n      <span class=\"pal-chip-text\"></span>\n      <button type=\"button\" class=\"pal-chip-x\" aria-label=\"Clear selection\">✕</button>\n    `;\n    const textEl = chip.querySelector('.pal-chip-text');\n    // DOM chips are usually short (`<tag#id.class> inner`); 80 chars keeps\n    // the chip compact. Text chips can show more (120) since longer prose\n    // selections benefit from extra preview.\n    if (textEl) textEl.textContent = truncate(selectionText, isDom ? 80 : 120);\n    const xBtn = chip.querySelector<HTMLButtonElement>('.pal-chip-x');\n    if (xBtn) xBtn.onclick = () => {\n      host.setSelectionText('');\n      host.setSelectionElement(undefined);\n      host.setSelectionKind('text');\n      renderChipBar(host);\n    };\n    el.appendChild(chip);\n  }\n\n  for (const att of attachments) {\n    const chip = document.createElement('div');\n    chip.className = 'pal-chip pal-chip-att';\n    // Image chips show the actual preview (no filename clutter).\n    chip.innerHTML = `\n      <img class=\"pal-chip-img\" alt=\"\" />\n      <button type=\"button\" class=\"pal-chip-x\" aria-label=\"Remove\">✕</button>\n    `;\n    const img = chip.querySelector<HTMLImageElement>('.pal-chip-img');\n    if (img) img.src = att.thumbnailUrl;\n    const xBtn = chip.querySelector<HTMLButtonElement>('.pal-chip-x');\n    if (xBtn) xBtn.onclick = () => removeAttachment(host, att.id);\n    el.appendChild(chip);\n  }\n}\n\n/**\n * Read the current text of the pinned element AT THIS MOMENT. Returns\n * '' if the pinned element has been unmounted (SPA route change, list\n * virtualised, etc.) — no caching, no selector re-matching across\n * pages, just \"is this exact element still in the document\".\n *\n * `withSignature: true` prepends a human-readable `<tag#id.classes>`\n * tag — used by the chip bar so the user sees WHICH element is pinned.\n * The agent path must use `withSignature: false` so the LLM gets clean\n * prose to operate on.\n */\nexport function readPinnedTextLive(\n  host: ChipBarHost,\n  opts: { withSignature?: boolean } = {},\n): string {\n  const el = host.getPinnedEl();\n  if (!el) return host.getPinnedText();\n  if (typeof document === 'undefined') return host.getPinnedText();\n  if (!el.isConnected || !document.contains(el)) return '';\n  const inner = ((el as HTMLElement).innerText ?? el.textContent ?? '').trim().slice(0, 1000);\n  if (host.getPinnedKind() === 'dom' && opts.withSignature) {\n    return formatElementSignature(el as HTMLElement);\n  }\n  return inner || (el.textContent ?? host.getPinnedText()).trim();\n}\n\n/**\n * Host pins a context (typically the DOM region the user just selected via\n * Dwell / Spotter / a manual selection) for the next palette open. Cleared\n * automatically after the palette opens once.\n */\nexport function setPinnedContext(\n  host: ChipBarHost,\n  text: string,\n  elementOrSelector?: Element | string | null,\n  opts?: { kind?: SelectionKind },\n): void {\n  const kind: SelectionKind = opts?.kind ?? 'text';\n  host.setPinnedKind(kind);\n\n  // Resolve to an element REFERENCE. If host passes an Element we\n  // store it directly (no selector indirection). If they pass a\n  // selector string, resolve it NOW — the selector is only a\n  // bootstrapping hint, not stored. Anything else → no element pin.\n  if (elementOrSelector instanceof Element) {\n    host.setPinnedEl(elementOrSelector);\n  } else if (typeof elementOrSelector === 'string' && elementOrSelector.length > 0) {\n    try { host.setPinnedEl(document.querySelector(elementOrSelector)); }\n    catch { host.setPinnedEl(null); }\n  } else {\n    host.setPinnedEl(null);\n  }\n\n  // Text fallback only for non-DOM pins. DOM pins always re-read from\n  // the live element at open time so navigation auto-invalidates them.\n  host.setPinnedText(kind === 'dom' ? '' : text);\n\n  // Pinning is a deliberate \"this is the context now\" — clear any\n  // earlier text selection so the two don't coexist.\n  if (typeof window !== 'undefined') {\n    try { window.getSelection?.()?.removeAllRanges(); } catch { /* cross-origin / SSR */ }\n  }\n}\n\n/**\n * Capture selection / dwell context at palette-open time. Pure live scan —\n * NO trust in any cached state. Every open re-queries the document for\n * \"what is selected RIGHT NOW\" and \"what element carries the Dwell marker\n * RIGHT NOW\". Stored vars are only consulted as a last-resort legacy\n * fallback for hosts that pin programmatically without using Dwell.\n */\nexport function captureContextOnOpen(host: ChipBarHost, seed: string | undefined): void {\n  let text = (seed ?? '').trim();\n  let elementSel: string | undefined;\n  // Kind defaults to 'text' for live window selections; the dwell\n  // pathway carries 'dom'.\n  let kind: SelectionKind = 'text';\n\n  // 1) LIVE window text selection.\n  if (!text && typeof window !== 'undefined') {\n    const sel = window.getSelection?.();\n    const fromBrowser = sel?.toString().trim() ?? '';\n    if (fromBrowser && sel && sel.rangeCount > 0) {\n      const node = sel.getRangeAt(0).startContainer;\n      const anchor = node instanceof Element ? node : node.parentElement;\n      if (anchor && anchor.isConnected && document.contains(anchor)) {\n        text = fromBrowser;\n        elementSel = inferSelector(anchor) || undefined;\n      }\n    }\n  }\n\n  // 2) LIVE dwell marker — query the DOM for the element currently\n  //    carrying `[data-dddk-dwell-target]`. No stored Element ref to\n  //    go stale; if the marked element was unmounted by an SPA route\n  //    change, `querySelector` simply doesn't find it on the new\n  //    page and there is no pin to mis-attribute. This is the\n  //    canonical path for Dwell pins.\n  if (!text && typeof document !== 'undefined') {\n    const marked = document.querySelector<HTMLElement>('[data-dddk-dwell-target]');\n    if (marked) {\n      const inner = (marked.innerText ?? marked.textContent ?? '').trim().slice(0, 1000);\n      if (inner) {\n        text = formatElementSignature(marked);\n        elementSel = inferSelector(marked) || undefined;\n        kind = 'dom';\n      }\n    }\n  }\n\n  // 3) LEGACY programmatic pin via setPinnedContext (rare; only hosts\n  //    that pin outside of the Dwell module). Kept for back-compat\n  //    but cleared aggressively if its element has detached.\n  if (!text && host.getPinnedEl()) {\n    const liveText = readPinnedTextLive(host, { withSignature: true });\n    if (liveText) {\n      text = liveText;\n      elementSel = inferSelector(host.getPinnedEl() as Element) || undefined;\n      kind = host.getPinnedKind();\n    } else {\n      host.setPinnedEl(null);\n      host.setPinnedText('');\n      host.setPinnedKind('text');\n    }\n  }\n  if (!text && host.getPinnedText() && !host.getPinnedEl()) {\n    text = host.getPinnedText();\n    kind = host.getPinnedKind();\n  }\n\n  host.setSelectionText(text);\n  host.setSelectionElement(elementSel);\n  host.setSelectionKind(kind);\n  // Image attachments persist across palette opens until user removes /\n  // activates. Cleared from the orchestrator after webagent consumes them.\n}\n\n/** Public: add an image attachment to the palette context. */\nexport function addAttachment(\n  host: ChipBarHost,\n  att: Omit<PaletteAttachment, 'id'>,\n): PaletteAttachment {\n  const full: PaletteAttachment = { id: genId('att'), ...att };\n  host.setAttachments([...host.getAttachments(), full]);\n  if (host.isOpen()) {\n    host.renderChipBar();\n    // Re-filter so contextPromotesFallback (default ON) pulls the Ask AI\n    // row to the top now that there's something attached.\n    host.refilter();\n  }\n  return full;\n}\n\nexport function removeAttachment(host: ChipBarHost, id: string): void {\n  host.setAttachments(host.getAttachments().filter((a) => a.id !== id));\n  if (host.isOpen()) {\n    host.renderChipBar();\n    host.refilter();\n  }\n}\n\nexport function clearAttachments(host: ChipBarHost): void {\n  host.setAttachments([]);\n  if (host.isOpen()) {\n    host.renderChipBar();\n    host.refilter();\n  }\n}\n","/**\n * QA palette helpers — locale-resolving wrappers around `addItem`. The\n * palette instance is passed in so the public `addQAItems` method on the\n * class stays a one-liner delegating here.\n */\n\nimport type {\n  LocalizedText,\n  PaletteItem,\n  QAItemsOpts,\n  QAPaletteItem,\n} from './types';\n\nexport function resolveLocalized(value: LocalizedText, locale: string): string {\n  if (typeof value === 'string') return value;\n  const v = value[locale];\n  if (v) return v;\n  const en = value['en'];\n  if (en) return en;\n  for (const k of Object.keys(value)) return value[k]!;\n  return '';\n}\n\nexport function defaultQAAnswerSurface(ctx: {\n  question: string;\n  answer: string;\n}): import('../../ui/pieces').PieceSurface {\n  // Minimal Pieces tree — Stack { Heading, Body }. Hosts that want\n  // richer formatting (markdown, code blocks, links) override via\n  // `renderAnswer`.\n  return {\n    root: {\n      kind: 'Stack',\n      gap: 8,\n      children: [\n        { kind: 'Heading', text: ctx.question, level: 4 },\n        { kind: 'Body', text: ctx.answer },\n      ],\n    },\n  };\n}\n\n/**\n * Add a batch of QA items via the palette's `addItem`. Receives an\n * adder callback so the helper stays independent of the class shape.\n */\nexport function addQAItems(\n  addItem: (item: PaletteItem) => void,\n  items: QAPaletteItem[],\n  opts: QAItemsOpts = {},\n): void {\n  const locale = opts.locale ?? 'en';\n  const section = opts.section ?? 'QA';\n  const icon = opts.icon ?? '?';\n  const idPrefix = opts.idPrefix ?? 'qa-';\n  const renderAnswer = opts.renderAnswer ?? defaultQAAnswerSurface;\n  for (const item of items) {\n    const question = resolveLocalized(item.question, locale);\n    const answer = resolveLocalized(item.answer, locale);\n    if (!question || !answer) continue;\n    addItem({\n      id: `${idPrefix}${item.id}`,\n      name: question,\n      description: item.description\n        ? resolveLocalized(item.description, locale)\n        : undefined,\n      section,\n      icon,\n      category: item.category,\n      detail: () => renderAnswer({ question, answer, meta: item.meta }),\n      handler: (p) => p.close(),\n    });\n  }\n}\n","/**\n * Screenshot capture mode — host-rendered crosshair overlay + drag rect.\n * The palette's camera button delegates here when `camera.mode === 'screenshot'`.\n *\n * No `getDisplayMedia` — we hand the host a viewport rect and they turn it\n * into a Blob (typically via html2canvas / modern-screenshot in their bundle).\n */\n\nimport { sdkString } from '../../utils/sdk-i18n';\nimport type { CameraOptions, PaletteAttachment } from './types';\nimport { UI_ATTR } from './styles';\n\n/**\n * Host adapter — the screenshot module only needs three handles on the\n * palette instance: the backdrop root (to dim while the overlay is up),\n * the chrome locale (to label the hint), and the queue-attachment method.\n */\nexport interface ScreenshotHost {\n  /** The palette's root backdrop element — null when the palette is closed. */\n  getRoot(): HTMLDivElement | null;\n  /** Current chrome locale, forwarded to the hint i18n string. */\n  getLocale(): string | undefined;\n  /** Adds the captured blob to the palette context (renders a chip). */\n  addAttachment(att: Omit<PaletteAttachment, 'id'>): PaletteAttachment;\n}\n\n/**\n * Screenshot UX (re-implemented — no `getDisplayMedia`):\n *  1. Hide the palette panel (kept in DOM so re-opening is fast)\n *  2. Show a fullscreen crosshair overlay\n *  3. User drags a rectangle on the visible page\n *  4. Pass the rect to the host's `captureRect()` — host returns a Blob\n *  5. Attach the Blob, re-show the palette\n *\n * Esc / right-click / outside-mousedown cancels at any point.\n */\nexport function openScreenshot(host: ScreenshotHost, cfg: CameraOptions): void {\n  if (!cfg.captureRect) {\n    console.warn('[palette] screenshot mode requires a `captureRect` callback (e.g. via html2canvas).');\n    return;\n  }\n  if (typeof document === 'undefined') return;\n  const root = host.getRoot();\n  if (!root) return;\n\n  // Stash the panel so we can hide-then-restore without losing state.\n  const panel = root.querySelector<HTMLElement>(`[${UI_ATTR}=\"palette\"]`);\n  if (panel) panel.style.visibility = 'hidden';\n  root.style.background = 'transparent';\n  root.style.backdropFilter = 'none';\n\n  const overlay = document.createElement('div');\n  overlay.setAttribute(UI_ATTR, 'palette-screenshot-overlay');\n  const hintText = sdkString(host.getLocale(), 'palette.screenshot.hint');\n  overlay.innerHTML = `\n    <div data-dddk-ui=\"palette-screenshot-rect\"></div>\n    <div data-dddk-ui=\"palette-screenshot-hint\">${hintText}</div>\n  `;\n  document.body.appendChild(overlay);\n  const rectEl = overlay.querySelector<HTMLElement>('[data-dddk-ui=\"palette-screenshot-rect\"]')!;\n\n  let startX = 0, startY = 0;\n  let dragging = false;\n  let finalRect: { x: number; y: number; width: number; height: number } | null = null;\n\n  const cleanup = () => {\n    overlay.remove();\n    document.removeEventListener('keydown', onKey, true);\n    if (panel) panel.style.visibility = '';\n    const r = host.getRoot();\n    if (r) {\n      r.style.background = '';\n      r.style.backdropFilter = '';\n    }\n  };\n\n  const onKey = (e: KeyboardEvent) => {\n    if (e.key === 'Escape') {\n      e.preventDefault();\n      cleanup();\n    }\n  };\n  document.addEventListener('keydown', onKey, true);\n\n  overlay.addEventListener('mousedown', (e) => {\n    e.preventDefault();\n    dragging = true;\n    startX = e.clientX;\n    startY = e.clientY;\n    rectEl.style.display = 'block';\n    rectEl.style.left = `${startX}px`;\n    rectEl.style.top = `${startY}px`;\n    rectEl.style.width = '0px';\n    rectEl.style.height = '0px';\n  });\n  overlay.addEventListener('mousemove', (e) => {\n    if (!dragging) return;\n    const x = Math.min(startX, e.clientX);\n    const y = Math.min(startY, e.clientY);\n    const w = Math.abs(e.clientX - startX);\n    const h = Math.abs(e.clientY - startY);\n    rectEl.style.left = `${x}px`;\n    rectEl.style.top = `${y}px`;\n    rectEl.style.width = `${w}px`;\n    rectEl.style.height = `${h}px`;\n  });\n  overlay.addEventListener('mouseup', async (e) => {\n    if (!dragging) return;\n    dragging = false;\n    const x = Math.min(startX, e.clientX);\n    const y = Math.min(startY, e.clientY);\n    const w = Math.abs(e.clientX - startX);\n    const h = Math.abs(e.clientY - startY);\n    if (w < 8 || h < 8) {\n      cleanup();\n      return;\n    }\n    finalRect = { x, y, width: w, height: h };\n    cleanup();\n    try {\n      const blob = await cfg.captureRect!(finalRect);\n      if (!blob) return;\n      host.addAttachment({\n        kind: 'image',\n        blob,\n        thumbnailUrl: URL.createObjectURL(blob),\n        source: 'screenshot',\n        sourceUrl: typeof window !== 'undefined' ? window.location.href : undefined,\n        // No filename — UI doesn't show one; downstream agent gets the\n        // source URL instead, which is more useful than `screenshot-12345`.\n      });\n      cfg.onCapture(blob, 'screenshot');\n    } catch (err) {\n      console.warn('[palette] screenshot captureRect failed:', err);\n    }\n  });\n  // Right-click cancels.\n  overlay.addEventListener('contextmenu', (e) => {\n    e.preventDefault();\n    cleanup();\n  });\n}\n","/**\n * CommandPalette — Ctrl/⌘+K input overlay rendered into the DOM.\n *\n * This file is the shell: lifecycle (open/close), DOM scaffolding (render),\n * keyboard handling, list rendering, and the public class surface. The\n * sub-files in this folder own:\n *   - styles.ts      — injected CSS + shared `UI_ATTR` / `STYLE_ID`\n *   - types.ts       — all public type / interface contracts\n *   - prefix.ts      — prefix routing helpers (pure functions)\n *   - fuzzy.ts       — fuzzy filter + match-highlight\n *   - chip-bar.ts    — chip strip + pinned-context lifecycle\n *   - qa.ts          — locale-resolved QA item registration\n *   - screenshot.ts  — drag-rect screenshot overlay\n */\n\nimport { escapeHtml } from '../../utils/dom';\nimport { sdkString, type SdkI18nKey } from '../../utils/sdk-i18n';\nimport { inferSelector } from '../../utils/selector';\nimport { ensurePaletteStyles, UI_ATTR } from './styles';\nimport type {\n  CameraOptions,\n  CommandPaletteOptions,\n  PaletteAttachment,\n  PaletteCategory,\n  PaletteContext,\n  PaletteHandle,\n  PaletteItem,\n  QAItemsOpts,\n  QAPaletteItem,\n  ResultChunk,\n  ResultSurface,\n  StreamingResultSurface,\n} from './types';\nimport {\n  displayPrefix,\n  listPrefixMatches,\n  looksLikePrefixAttempt,\n  matchPrefix,\n} from './prefix';\nimport { fuzzyTopN, highlightMatch } from './fuzzy';\nimport {\n  addAttachment as chipAddAttachment,\n  captureContextOnOpen as chipCaptureContextOnOpen,\n  type ChipBarHost,\n  clearAttachments as chipClearAttachments,\n  readPinnedTextLive as chipReadPinnedTextLive,\n  removeAttachment as chipRemoveAttachment,\n  renderChipBar as chipRenderChipBar,\n  type SelectionKind,\n  setPinnedContext as chipSetPinnedContext,\n} from './chip-bar';\nimport { addQAItems as helperAddQAItems } from './qa';\nimport { openScreenshot as helperOpenScreenshot, type ScreenshotHost } from './screenshot';\n\n// Re-export public types / values so import paths\n// (`./triggers/command-palette`, `@perhapxin/dddk`) keep working unchanged.\nexport type {\n  CameraOptions,\n  CommandPaletteOptions,\n  LocalizedText,\n  PaletteAgentTool,\n  PaletteAttachment,\n  PaletteCategory,\n  PaletteContext,\n  PaletteHandle,\n  PaletteItem,\n  PaletteItemPrefix,\n  QAItemsOpts,\n  QAPaletteItem,\n  ResultChunk,\n  ResultSurface,\n  StreamingResultSurface,\n} from './types';\nexport { displayPrefix, listPrefixMatches } from './prefix';\n\nexport class CommandPalette {\n  /**\n   * `rootItems` is the canonical list — what `addItem` / `removeItem` operate\n   * on. It survives sub-menu navigation. `items` is the *currently displayed*\n   * set; when a handler calls `handle.replace([...])`, the previous `items` is\n   * pushed onto `subMenuStack` and `items` becomes the new set. Esc pops back\n   * one level; if the stack is empty, Esc closes the palette. Re-opening via\n   * `open()` always resets `items` to `rootItems.slice()`.\n   */\n  private rootItems: PaletteItem[];\n  private detailRenderToken = 0;\n  private items: PaletteItem[];\n  private subMenuStack: PaletteItem[][] = [];\n  private placeholder: string;\n  /** True while the palette is embedded inline in a host (vs the Ctrl/⌘+K modal). */\n  private inlineMounted = false;\n  /** Saved inline surface refs while a modal (Ctrl/⌘+K) is opened on top of it. */\n  private suspendedInline: {\n    root: HTMLDivElement | null; input: HTMLInputElement | null; list: HTMLUListElement | null;\n    detailHost: HTMLDivElement | null; chipBarHost: HTMLDivElement | null;\n    categoryBarHost: HTMLDivElement | null; resultHost: HTMLDivElement | null;\n    listSplit: HTMLDivElement | null; listeners: Array<() => void>;\n  } | null = null;\n  /** Locale for the bundled chrome strings. Read at construction; can\n   *  be flipped at runtime via `setLocale()` — the next render picks\n   *  up the new strings (footer hints + placeholder). */\n  private locale: string | undefined;\n  private searchPage?: CommandPaletteOptions['searchPage'];\n  private contextPromotesFallback = true;\n\n  private root: HTMLDivElement | null = null;\n  private input: HTMLInputElement | null = null;\n  private list: HTMLUListElement | null = null;\n  private filtered: PaletteItem[] = [];\n  private cursor = 0;\n  private currentArg = '';\n  private listeners: Array<() => void> = [];\n\n  private heatRank?: import('../../utils/heat-rank').HeatRank;\n  private pieceCatalog?: import('../../ui/pieces').PieceCatalog;\n  private detailHost: HTMLDivElement | null = null;\n  private categoryBarHost: HTMLDivElement | null = null;\n  private categories: PaletteCategory[] = [];\n  private allCategoriesLabel = 'All';\n  private activeCategoryId: string | null = null;\n  private camera?: CameraOptions;\n  private submitButton?: boolean;\n  private onActivate?: CommandPaletteOptions['onActivate'];\n  // PaletteContext fields — populated on open / camera capture.\n  private contextSelectionText = '';\n  private contextSelectionElement?: string;\n  private contextSelectionKind: SelectionKind = 'text';\n  private contextAttachments: PaletteAttachment[] = [];\n\n  /**\n   * Host-supplied pinned context. Set by `setPinnedContext()` and consumed\n   * on each `open()`. Used by modules like Dwell that pin an element\n   * BEFORE the palette opens — when the palette eventually opens, this is\n   * what its chipbar surfaces.\n   *\n   * `pinnedContextEl` stores the ELEMENT REFERENCE directly (not a CSS\n   * selector). At open time we check `el.isConnected && document.contains(el)`\n   * — if the element has been unmounted (SPA route change, list virtualised,\n   * etc.) the pin is auto-invalidated WITHOUT having to trust any selector\n   * lookup. Structural selectors (`body>main>section:nth-child(3)`) match\n   * different content on different pages; element references can't.\n   */\n  private pinnedContextEl: Element | null = null;\n  private pinnedContextText = '';\n  private pinnedContextKind: SelectionKind = 'text';\n\n  // ─── in-place result mode ──────────────────────────────────────\n  private resultHost: HTMLDivElement | null = null;\n  private listSplit: HTMLDivElement | null = null;\n  private resultMode = false;\n\n  // ─── chip-bar host element ────────────────────────────────────\n  private chipBarHost: HTMLDivElement | null = null;\n\n  // ─── Input-context override ─────────────────────────────────────\n  // A sub-tool (chat panel, search box for a specific dataset, ...) can\n  // hijack the palette's top input — change its placeholder + redirect\n  // Enter to a custom handler — without spawning a second input box. The\n  // override clears automatically on Esc-back or palette close.\n  private inputContext: {\n    placeholder: string;\n    onSubmit: (value: string, handle: PaletteHandle) => void;\n    onInput?: (value: string, handle: PaletteHandle) => void;\n    clearOnSubmit?: boolean;\n    hideList?: boolean;\n  } | null = null;\n\n  constructor(opts: CommandPaletteOptions = {}) {\n    this.rootItems = opts.initialItems ?? [];\n    this.items = this.rootItems.slice();\n    this.locale = opts.locale;\n    this.placeholder = opts.placeholder ?? sdkString(this.locale, 'palette.placeholder');\n    this.searchPage = opts.searchPage;\n    this.heatRank = opts.heatRank;\n    this.pieceCatalog = opts.pieceCatalog;\n    this.contextPromotesFallback = opts.contextPromotesFallback ?? true;\n    this.camera = opts.camera;\n    this.submitButton = opts.submitButton;\n    this.onActivate = opts.onActivate;\n    this.categories = opts.categories ?? [];\n    this.allCategoriesLabel = opts.allCategoriesLabel ?? 'All';\n  }\n\n  /**\n   * Replace the category chip set. Pass an empty array to remove the\n   * chip row entirely. Active category resets to \"All\".\n   */\n  setCategories(categories: PaletteCategory[], allLabel?: string): void {\n    this.categories = categories;\n    if (allLabel !== undefined) this.allCategoriesLabel = allLabel;\n    this.activeCategoryId = null;\n    if (this.isOpen()) {\n      this.renderCategoryBar();\n      this.refilter();\n    }\n  }\n\n  /** Runtime toggle of the camera icon's mode (upload ↔ screenshot). */\n  setCameraMode(mode: 'upload' | 'screenshot'): void {\n    if (this.camera) this.camera.mode = mode;\n  }\n\n  isOpen(): boolean {\n    return this.root !== null;\n  }\n\n  /** Update the locale for the bundled chrome strings (placeholder,\n   *  footer hints). Next palette open picks up the new strings. The\n   *  open-right-now palette is patched in place too. */\n  setLocale(locale: string): void {\n    this.locale = locale;\n    this.placeholder = sdkString(locale, 'palette.placeholder');\n    if (this.input) this.input.placeholder = this.placeholder;\n    this.refreshFooter();\n  }\n\n  /** Produce the current footer HTML — kbd hints + touch hints + brand\n   *  mark. Kept as a pure builder so it can be used both for the initial\n   *  mount (before `this.root` is set) and for later refreshes triggered\n   *  by locale / esc-mode / result-mode changes. Both paths converge on\n   *  the same output; drift here becomes drift users see. */\n  private buildFooterHTML(): string {\n    const escKey: SdkI18nKey = this.hasInternalEsc() ? 'palette.footer.back' : 'palette.footer.close';\n    const touchDismissKey: SdkI18nKey = this.hasInternalEsc()\n      ? 'palette.footer.touch.back'\n      : 'palette.footer.touch.dismiss';\n    return `\n      <span data-dddk-ui=\"palette-footer-group\">\n        <kbd>↑</kbd><kbd>↓</kbd> <span>${escapeHtml(sdkString(this.locale, 'palette.footer.navigate'))}</span>\n      </span>\n      <span data-dddk-ui=\"palette-footer-group\">\n        <kbd>↵</kbd> <span>${escapeHtml(sdkString(this.locale, 'palette.footer.select'))}</span>\n      </span>\n      <span data-dddk-ui=\"palette-footer-group\">\n        <kbd>esc</kbd> <span>${escapeHtml(sdkString(this.locale, escKey))}</span>\n      </span>\n      <span data-dddk-ui=\"palette-footer-group-touch\">\n        <span>${escapeHtml(sdkString(this.locale, 'palette.footer.touch.pick'))}</span>\n      </span>\n      <span data-dddk-ui=\"palette-footer-group-touch\">\n        <span>${escapeHtml(sdkString(this.locale, touchDismissKey))}</span>\n      </span>\n      <span data-dddk-ui=\"palette-footer-brand\">\n        <span data-dddk-ui=\"palette-footer-brand-text\">Powered by</span>\n        <a href=\"https://dddk.perhapxin.com\" target=\"_blank\" rel=\"noopener noreferrer\">dotdotduck</a>\n        <span data-dddk-ui=\"palette-footer-brand-mark\" aria-hidden=\"true\"></span>\n      </span>\n    `;\n  }\n\n  /** Rebuild the footer to match the current locale + state. Wipes and\n   *  re-writes the whole strip — the brand mark on the right is\n   *  intentionally re-rendered every call so a partial repaint can't\n   *  leave it lopped off. */\n  private refreshFooter(): void {\n    if (!this.root) return;\n    const footer = this.root.querySelector<HTMLElement>(`[${UI_ATTR}=\"palette-footer\"]`);\n    if (!footer) return;\n    footer.innerHTML = this.buildFooterHTML();\n  }\n\n  toggle(initialSelection?: string): void {\n    // A modal that is open (and not sitting over an inline mount) → close it.\n    // Otherwise open the modal. When inline-mounted, opening suspends the inline\n    // surface and shows the full modal on top; closing restores the inline.\n    if (this.isOpen() && !this.inlineMounted) this.close();\n    else this.open(initialSelection);\n  }\n\n  /** Programmatically set the palette's search input value (and refilter\n   *  the visible list). Used by hosts driving the palette from outside —\n   *  e.g. the webagent's `open_palette({ initialInput })` tool seeds a\n   *  prefix command like `docs:` so the user lands on the right sub-list. */\n  setInputValue(value: string): void {\n    if (this.input) {\n      this.input.value = value;\n      this.refilter();\n    }\n  }\n\n  open(initialSelection?: string, opts?: { focusInput?: boolean }): void {\n    if (this.inlineMounted) {\n      // Suspend the inline surface and render the full modal on top of it. The\n      // inline DOM stays in the host (hidden behind the backdrop) and is restored\n      // by close(). This is what lets Ctrl/⌘+K open the modal from a page that\n      // already shows the palette inline.\n      this.suspendedInline = {\n        root: this.root, input: this.input, list: this.list,\n        detailHost: this.detailHost, chipBarHost: this.chipBarHost,\n        categoryBarHost: this.categoryBarHost, resultHost: this.resultHost,\n        listSplit: this.listSplit, listeners: this.listeners,\n      };\n      this.listeners = [];\n      this.inlineMounted = false;\n      if (this.suspendedInline.root) this.suspendedInline.root.style.display = 'none';\n    } else if (this.isOpen()) return;\n    ensurePaletteStyles();\n    // Every open is a fresh root-state palette — discard any sub-menu the\n    // user left behind on a previous open.\n    this.items = this.rootItems.slice();\n    this.subMenuStack = [];\n    // Capture selection context (text + element selector) BEFORE we render —\n    // because rendering the palette steals focus from the originating element.\n    this.captureContextOnOpen(initialSelection);\n    this.render();\n    this.refilter();\n    // Default behaviour: auto-focus the input on desktop so the user can\n    // start typing immediately. On MOBILE (touch device) we DON'T focus\n    // by default — focus triggers the OS soft keyboard which pops up\n    // over the palette and pushes the content around, ruining the\n    // \"browse commands\" flow. Mobile users can tap the input field\n    // itself when they actually want to type. Programmatic openers\n    // (the webagent's `open_palette` tool) pass `focusInput: false`\n    // to keep focus on body regardless.\n    const isTouch = typeof window !== 'undefined'\n      && window.matchMedia?.('(hover: none) and (pointer: coarse)').matches;\n    const defaultFocus = !isTouch;\n    const focusInput = opts?.focusInput ?? defaultFocus;\n    if (focusInput) {\n      requestAnimationFrame(() => this.input?.focus());\n    }\n  }\n\n  close(): void {\n    // Inline-mounted palette is PERSISTENT — a handler calling handle.close()\n    // (e.g. after navigating or starting the agent) must NOT tear the embedded\n    // palette out of the page. Reset it to its root state instead. Actual\n    // teardown only happens via the cleanup fn returned by mountInline().\n    if (this.inlineMounted) {\n      if (this.resultMode) this.clearResult();\n      this.clearInputContext();\n      this.subMenuStack = [];\n      this.items = this.rootItems.slice();\n      if (this.input) this.input.value = '';\n      this.clearContext();\n      this.refilter();\n      this.refreshFooter();\n      return;\n    }\n    if (!this.root) return;\n    this.listeners.forEach((fn) => fn());\n    this.listeners = [];\n    this.root.remove();\n    // If this modal was covering an inline mount, restore the inline surface\n    // instead of tearing the palette down entirely.\n    if (this.suspendedInline) {\n      const s = this.suspendedInline;\n      this.suspendedInline = null;\n      this.root = s.root;\n      this.input = s.input;\n      this.list = s.list;\n      this.detailHost = s.detailHost;\n      this.chipBarHost = s.chipBarHost;\n      this.categoryBarHost = s.categoryBarHost;\n      this.resultHost = s.resultHost;\n      this.listSplit = s.listSplit;\n      this.listeners = s.listeners;\n      this.inlineMounted = true;\n      if (this.root) this.root.style.display = '';\n      this.clearContext();\n      this.inputContext = null;\n      // Keep the inline input's own placeholder (host-configured) — only clear text.\n      if (this.input) this.input.value = '';\n      this.items = this.rootItems.slice();\n      this.subMenuStack = [];\n      this.refilter();\n      return;\n    }\n    this.root = null;\n    this.input = null;\n    this.list = null;\n    // Clear context — next open re-captures fresh.\n    this.clearContext();\n    // Drop any sub-tool input override so the next open starts at the\n    // default search placeholder, not whatever the last tool installed.\n    this.inputContext = null;\n  }\n\n  /**\n   * Mount the palette INLINE inside a host element, persistently visible —\n   * no backdrop, no outside-click dismissal. It shares the exact same items,\n   * filtering, keyboard navigation and row rendering as the Ctrl/⌘+K modal,\n   * so the host writes ONE set of palette items and gets both surfaces.\n   * While inline-mounted, `open()` / `toggle()` (e.g. Ctrl+K) just focus the\n   * embedded input instead of spawning the modal.\n   *\n   * Returns a teardown function — call it when the host element unmounts\n   * (e.g. SPA route change) to detach the palette and its listeners.\n   */\n  mountInline(host: HTMLElement, opts?: { placeholder?: string; focus?: boolean }): () => void {\n    if (this.isOpen()) this.close();\n    ensurePaletteStyles();\n    this.items = this.rootItems.slice();\n    this.subMenuStack = [];\n    this.inlineMounted = true;\n    this.render(host);\n    if (opts?.placeholder && this.input) this.input.placeholder = opts.placeholder;\n    this.refilter();\n    if (opts?.focus) requestAnimationFrame(() => this.input?.focus());\n    return () => {\n      this.inlineMounted = false;\n      this.close();\n    };\n  }\n\n  // ─── palette context (selection text + image attachments) ──────\n\n  /**\n   * Pin a DOM element (or a free-text snippet) as context for the NEXT\n   * palette open. Detection is done at open time by re-reading the live\n   * DOM — we don't snapshot a copy of the text here. If the selector\n   * stops resolving (page navigation, element removed, scroll-virtualised\n   * list) the context auto-clears with no work from the host.\n   *\n   * The `text` argument is kept only as a fallback for `kind: 'text'`\n   * pins where there is no element to read from (rare).\n   */\n  setPinnedContext(\n    text: string,\n    elementOrSelector?: Element | string | null,\n    opts?: { kind?: SelectionKind },\n  ): void {\n    chipSetPinnedContext(this.chipBarHostAdapter, text, elementOrSelector, opts);\n  }\n\n  clearPinnedContext(): void {\n    this.pinnedContextEl = null;\n    this.pinnedContextText = '';\n    this.pinnedContextKind = 'text';\n  }\n\n  /**\n   * Read-only snapshot of the sticky pinned context. Unlike `context`, this\n   * survives palette `close()` — useful for `dddk.startAgent()` called from a\n   * palette handler. The text is read live from the pinned element when\n   * possible so navigation invalidates stale pins.\n   */\n  get pinnedContext(): { text: string; element?: string; kind: SelectionKind } {\n    // Agent-facing: NO `<tag.class>` signature prefix. The signature is a\n    // debug affordance for the chip bar; feeding it into selection.text\n    // confuses the LLM (it reads `<section.section>` as a literal HTML\n    // reference and starts inspecting the DOM via tools instead of just\n    // operating on the inner text).\n    return {\n      text: chipReadPinnedTextLive(this.chipBarHostAdapter, { withSignature: false }),\n      element: this.pinnedContextEl ? inferSelector(this.pinnedContextEl) || undefined : undefined,\n      kind: this.pinnedContextKind,\n    };\n  }\n\n  private captureContextOnOpen(seed?: string): void {\n    chipCaptureContextOnOpen(this.chipBarHostAdapter, seed);\n  }\n\n  private clearContext(): void {\n    this.contextSelectionText = '';\n    this.contextSelectionElement = undefined;\n    this.contextSelectionKind = 'text';\n    // Don't drop attachments — user may have queued one and not yet activated.\n  }\n\n  /** Public: add an image attachment to the palette context. */\n  addAttachment(att: Omit<PaletteAttachment, 'id'>): PaletteAttachment {\n    return chipAddAttachment(this.chipBarHostAdapter, att);\n  }\n\n  removeAttachment(id: string): void {\n    chipRemoveAttachment(this.chipBarHostAdapter, id);\n  }\n\n  clearAttachments(): void {\n    chipClearAttachments(this.chipBarHostAdapter);\n  }\n\n  /** Read-only snapshot of the current context. */\n  get context(): PaletteContext {\n    return {\n      selectionText: this.contextSelectionText,\n      selectionElement: this.contextSelectionElement,\n      attachments: this.contextAttachments.slice(),\n    };\n  }\n\n  // ─── result mode (showResult / clearResult) ──────────────────────\n\n  async showResult(surface: ResultSurface): Promise<void> {\n    if (!this.resultHost) return;\n    this.resultMode = true;\n    this.resultHost.style.display = 'block';\n    this.resultHost.textContent = '';\n    if (this.listSplit) this.listSplit.style.display = 'none';\n    this.refreshFooter();\n\n    let value: Awaited<Exclude<ResultSurface, (...args: never) => unknown>>;\n    try {\n      value = typeof surface === 'function' ? await surface() : surface;\n    } catch (err) {\n      this.resultHost.textContent = `Error: ${(err as Error).message}`;\n      return;\n    }\n\n    if (value instanceof HTMLElement) {\n      this.resultHost.appendChild(value);\n      return;\n    }\n    if (typeof value === 'string') {\n      this.resultHost.textContent = value;\n      return;\n    }\n    // Streaming surface { mount, stream } — host owns the DOM, gets the\n    // root back as a writable handle. Mount first so the element is in\n    // the document before the stream callback fires.\n    if (isStreamingSurface(value)) {\n      const root = value.mount;\n      this.resultHost.appendChild(root);\n      try {\n        await value.stream(root);\n      } catch (err) {\n        const errLine = document.createElement('div');\n        errLine.style.color = 'var(--error, #c11)';\n        errLine.style.marginTop = '8px';\n        errLine.textContent = `Error: ${(err as Error).message}`;\n        root.appendChild(errLine);\n      }\n      return;\n    }\n    // AsyncIterable path — accepts plain strings (legacy delta-append\n    // contract) OR structured ResultChunks (text / html / node / clear).\n    if (value && typeof (value as AsyncIterable<unknown>)[Symbol.asyncIterator] === 'function') {\n      const out = document.createElement('div');\n      this.resultHost.appendChild(out);\n      try {\n        for await (const chunk of value as AsyncIterable<string | ResultChunk>) {\n          applyResultChunk(out, chunk);\n        }\n      } catch (err) {\n        const errLine = document.createElement('div');\n        errLine.style.color = 'var(--error, #c11)';\n        errLine.style.marginTop = '8px';\n        errLine.textContent = `Error: ${(err as Error).message}`;\n        out.appendChild(errLine);\n      }\n    }\n  }\n\n  clearResult(): void {\n    this.resultMode = false;\n    if (this.resultHost) {\n      this.resultHost.style.display = 'none';\n      this.resultHost.textContent = '';\n    }\n    if (this.listSplit) this.listSplit.style.display = 'flex';\n    this.refreshFooter();\n  }\n\n  /**\n   * True when the palette is open AND in a state where Esc has its own\n   * meaning (back out of result-mode / pop a sub-menu). External\n   * keyboard handlers (orchestrator's GestureManager Esc) should defer\n   * to the palette in that case — otherwise the global \"Esc closes the\n   * whole palette\" rule kills the back-step the user expected.\n   */\n  hasInternalEsc(): boolean {\n    return this.isOpen() && (this.resultMode || this.subMenuStack.length > 0);\n  }\n\n  /** Snapshot of the currently-registered root items. Read-only — use\n   *  `addItem` / `removeItem` / `setItems` to mutate. */\n  getItems(): readonly PaletteItem[] {\n    return this.rootItems.slice();\n  }\n\n  /** Replace the canonical root-level items. Public hosts use this for full\n   *  re-registration; if the palette is open at a sub-menu level, the change\n   *  takes effect on next open. */\n  setItems(items: PaletteItem[]): void {\n    this.rootItems = items.slice();\n    if (this.subMenuStack.length === 0) {\n      this.items = this.rootItems.slice();\n      if (this.isOpen()) this.refilter();\n    }\n  }\n\n  /**\n   * Add or replace a palette item. If an item with the same `id` is already\n   * registered, the new one REPLACES it in-place (preserving its position\n   * in the list). This is what makes the i18n re-registration pattern work:\n   *\n   *   onLocaleChange((loc) => {\n   *     palette.addItem({ id: 'theme', name: t(loc, 'theme.name'), ... });\n   *     // ↑ replaces the previous 'theme' item, HeatRank usage carries over.\n   *   });\n   *\n   * For full-replace registration, use `setItems()` instead.\n   */\n  addItem(item: PaletteItem): void {\n    const existingRoot = this.rootItems.findIndex((i) => i.id === item.id);\n    if (existingRoot >= 0) {\n      this.rootItems[existingRoot] = item;\n    } else {\n      this.rootItems.push(item);\n    }\n    if (this.subMenuStack.length === 0) {\n      const existing = this.items.findIndex((i) => i.id === item.id);\n      if (existing >= 0) {\n        this.items[existing] = item;\n      } else {\n        this.items.push(item);\n      }\n      if (this.isOpen()) this.refilter();\n    }\n  }\n\n  removeItem(id: string): void {\n    this.rootItems = this.rootItems.filter((i) => i.id !== id);\n    if (this.subMenuStack.length === 0) {\n      this.items = this.items.filter((i) => i.id !== id);\n      if (this.isOpen()) this.refilter();\n    }\n  }\n\n  /**\n   * Register a batch of FAQ-style items so the user can browse the\n   * answer right inside the palette — arrow keys land on a question,\n   * the detail pane auto-renders the answer. Replaces the old\n   * `toolbox/qa` module for UI flows.\n   *\n   * Each item's `question` / `answer` accepts a plain string OR a\n   * locale-keyed dict (`{ en, 'zh-TW', ja, … }`). The palette resolves\n   * the right string at registration time via `opts.locale` (falls back\n   * to `en` then the first defined locale). Re-call on locale change\n   * to refresh labels — same id replaces in place.\n   *\n   * The agent-tool counterpart lives at `dddk.tools.registerQA(...)` —\n   * use that one to let the LLM look up answers itself.\n   */\n  addQAItems(items: QAPaletteItem[], opts: QAItemsOpts = {}): void {\n    helperAddQAItems((it) => this.addItem(it), items, opts);\n  }\n\n  // ─── render ─────────────────────────────────────────────────────\n\n  private render(inlineHost?: HTMLElement): void {\n    const inline = !!inlineHost;\n    const root = document.createElement('div');\n    root.setAttribute(UI_ATTR, inline ? 'palette-inline' : 'palette-backdrop');\n\n    const panel = document.createElement('div');\n    panel.setAttribute(UI_ATTR, 'palette');\n\n    const inputEl = document.createElement('input');\n    inputEl.type = 'text';\n    inputEl.placeholder = this.placeholder;\n    inputEl.setAttribute(UI_ATTR, 'palette-input');\n    inputEl.spellcheck = false;\n    inputEl.autocomplete = 'off';\n    inputEl.addEventListener('input', () => {\n      // If a skill has hijacked the input via setInputContext({ onInput }),\n      // route keystrokes there instead of the normal filter pipeline.\n      if (this.inputContext?.onInput) {\n        this.inputContext.onInput(this.input?.value ?? '', this.buildHandle());\n      } else {\n        this.refilter();\n      }\n    });\n\n    const onKey = (e: KeyboardEvent) => this.onInputKey(e);\n    inputEl.addEventListener('keydown', onKey);\n    this.listeners.push(() => inputEl.removeEventListener('keydown', onKey));\n\n    // Optional camera icon at right edge of input row.\n    const inputRow = document.createElement('div');\n    inputRow.setAttribute(UI_ATTR, 'palette-input-row');\n    inputRow.appendChild(inputEl);\n    if (this.camera) {\n      const cameraBtn = this.buildCameraButton();\n      inputRow.appendChild(cameraBtn);\n    }\n    if (this.submitButton) {\n      inputRow.appendChild(this.buildSubmitButton());\n    }\n\n    const listEl = document.createElement('ul');\n    listEl.setAttribute(UI_ATTR, 'palette-list');\n\n    // Right-side detail pane (only visible when active item has .detail).\n    const detailEl = document.createElement('div');\n    detailEl.setAttribute(UI_ATTR, 'palette-detail');\n    detailEl.style.display = 'none';\n\n    const splitEl = document.createElement('div');\n    splitEl.setAttribute(UI_ATTR, 'palette-split');\n    splitEl.appendChild(listEl);\n    splitEl.appendChild(detailEl);\n\n    // Chip-bar between input and list — shows selection text + image attachments.\n    const chipBar = document.createElement('div');\n    chipBar.setAttribute(UI_ATTR, 'palette-context');\n    chipBar.style.display = 'none';\n\n    // Category chip row — rendered between the input and the list when the\n    // host has configured `categories`. Each chip narrows the visible items\n    // to those whose `category` matches its id.\n    const categoryBar = document.createElement('div');\n    categoryBar.setAttribute(UI_ATTR, 'palette-categories');\n    categoryBar.style.display = 'none';\n\n    // Result-mode host: when a handler calls `palette.showResult(...)` this\n    // takes over the area below the input. Hidden in regular list mode.\n    const resultEl = document.createElement('div');\n    resultEl.setAttribute(UI_ATTR, 'palette-result');\n    resultEl.style.display = 'none';\n\n    // Footer strip: kbd hints (desktop) OR touch hints (touch-only) on\n    // the left, brand mark on the right. Content is filled inline via\n    // the same buildFooterHTML() builder that `refreshFooter()` reuses\n    // on later state transitions — the two paths converge so the\n    // footer can't drift out of sync (previously the initial mount had\n    // its own inline HTML and refreshFooter had a divergent copy).\n    const footerEl = document.createElement('div');\n    footerEl.setAttribute(UI_ATTR, 'palette-footer');\n    footerEl.innerHTML = this.buildFooterHTML();\n\n    // Layout: chipbar SITS ABOVE the input (context-first reading order).\n    // [chipbar] [input] [category-bar] [list/result] [footer]\n    panel.appendChild(chipBar);\n    panel.appendChild(inputRow);\n    panel.appendChild(categoryBar);\n    panel.appendChild(splitEl);\n    panel.appendChild(resultEl);\n    panel.appendChild(footerEl);\n    root.appendChild(panel);\n    this.detailHost = detailEl;\n    this.chipBarHost = chipBar;\n    this.categoryBarHost = categoryBar;\n    this.resultHost = resultEl;\n    this.listSplit = splitEl;\n    this.renderCategoryBar();\n    this.refreshFooter();\n\n    // ── Outside-click dismissal ────────────────────────────────\n    // Use `mousedown` (not `click`) so the dismissal beats focus-stealing on\n    // the page behind. We close whenever the press lands anywhere outside the\n    // panel — robust to clicks on the empty area to the side of the panel,\n    // below the panel, or any non-panel descendant of the backdrop.\n    const onBackdropDown = (e: MouseEvent) => {\n      if (!(e.target instanceof Node)) return;\n      if (panel.contains(e.target)) return;\n      // Defensive belt — if the row handler mutated the DOM (e.g. via\n      // `p.replace(...)` from a sub-menu activation) the target may have\n      // been detached BEFORE this bubbled handler runs, so it's no longer\n      // in document. Treat detached targets as \"originated inside the\n      // palette\" so we don't wrongly close. (The row's own mousedown also\n      // stopPropagation's now, so this is suspenders + belt.)\n      if (!document.contains(e.target)) return;\n      // Narrow exemption — ONLY the subtitle bar. The agent narrates\n      // while the user interacts with the palette, and clicking the\n      // narration to read it should NOT kill the palette mid-task.\n      // Other outside clicks (page body, other dddk UI) close as\n      // normal — that's the user signalling \"I'm moving on\".\n      if (e.target instanceof Element && e.target.closest('[data-dddk-ui=\"bar\"]')) return;\n      e.preventDefault();\n      this.close();\n    };\n    // Inline mode: the palette lives embedded in a host container and stays\n    // visible, so it must NOT close on outside clicks or trap document keys.\n    if (!inline) {\n      root.addEventListener('mousedown', onBackdropDown);\n      this.listeners.push(() => root.removeEventListener('mousedown', onBackdropDown));\n    }\n\n    // ── Focus trap ─────────────────────────────────────────────\n    // Catch keyboard nav at document level too, so arrow keys never bubble\n    // through to the page underneath after the user clicked something inside\n    // the panel that wasn't the input. We re-focus the input on any inside\n    // mousedown that lands on a non-button surface to keep typing alive.\n    const onDocKey = (e: KeyboardEvent) => {\n      if (!this.isOpen()) return;\n      const t = e.target;\n      // If keystroke originated outside the palette panel, intercept and route\n      // to our handler instead — this prevents arrows from scrolling the page\n      // behind the (blurred) backdrop after focus has leaked.\n      if (t instanceof Node && !panel.contains(t)) {\n        if (e.key === 'Escape' || e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.key === 'Enter') {\n          e.preventDefault();\n          e.stopPropagation();\n          this.onInputKey(e);\n          this.input?.focus();\n        }\n      }\n    };\n    if (!inline) {\n      document.addEventListener('keydown', onDocKey, true);\n      this.listeners.push(() => document.removeEventListener('keydown', onDocKey, true));\n    }\n\n    const onPanelMouseDown = (e: MouseEvent) => {\n      const t = e.target;\n      if (!(t instanceof HTMLElement)) return;\n      // Refocus the input whenever the press lands on non-interactive panel\n      // chrome (list rows, headers, chip-bar background) so the next keystroke\n      // hits our keydown listener rather than nothing.\n      const tag = t.tagName;\n      if (tag !== 'INPUT' && tag !== 'BUTTON' && tag !== 'TEXTAREA') {\n        // Defer to next tick so the click on a list item runs first.\n        setTimeout(() => this.input?.focus(), 0);\n      }\n    };\n    panel.addEventListener('mousedown', onPanelMouseDown);\n    this.listeners.push(() => panel.removeEventListener('mousedown', onPanelMouseDown));\n\n    if (inline) inlineHost!.appendChild(root);\n    else document.body.appendChild(root);\n\n    this.root = root;\n    this.input = inputEl;\n    this.list = listEl;\n\n    // Render chip-bar now in case we opened with selection / attachments already.\n    this.renderChipBar();\n  }\n\n  // ─── chip-bar host adapter ─────────────────────────────────────\n  // Exposed as a getter so it can capture the live `this` after class\n  // fields have been initialised (chip-bar.ts mutates via these hooks).\n  private get chipBarHostAdapter(): ChipBarHost {\n    return {\n      getChipBarHost: () => this.chipBarHost,\n      getSelectionText: () => this.contextSelectionText,\n      setSelectionText: (v) => { this.contextSelectionText = v; },\n      getSelectionElement: () => this.contextSelectionElement,\n      setSelectionElement: (v) => { this.contextSelectionElement = v; },\n      getSelectionKind: () => this.contextSelectionKind,\n      setSelectionKind: (v) => { this.contextSelectionKind = v; },\n      getAttachments: () => this.contextAttachments,\n      setAttachments: (v) => { this.contextAttachments = v; },\n      getPinnedEl: () => this.pinnedContextEl,\n      setPinnedEl: (v) => { this.pinnedContextEl = v; },\n      getPinnedText: () => this.pinnedContextText,\n      setPinnedText: (v) => { this.pinnedContextText = v; },\n      getPinnedKind: () => this.pinnedContextKind,\n      setPinnedKind: (v) => { this.pinnedContextKind = v; },\n      isOpen: () => this.isOpen(),\n      renderChipBar: () => this.renderChipBar(),\n      refilter: () => this.refilter(),\n    };\n  }\n\n  private renderChipBar(): void {\n    chipRenderChipBar(this.chipBarHostAdapter);\n  }\n\n  private onInputKey(e: KeyboardEvent): void {\n    if (e.key === 'Escape') {\n      e.preventDefault();\n      // Hierarchical back: Esc unwinds ONE layer at a time, only\n      // closing the palette when no layers remain. Order matters —\n      // result-mode (the rendered panel from showResult / a chat or\n      // QA surface) sits on top of any sub-menu stack, so we exit it\n      // first.\n      //\n      // 1. In result mode  → close result, restore list (parent menu)\n      // 2. Sub-menu pushed → pop one\n      // 3. Root level      → close the palette\n      if (this.resultMode) {\n        this.clearResult();\n        this.clearInputContext();\n        if (this.input) this.input.value = '';\n        this.refilter();\n      } else if (this.subMenuStack.length > 0) {\n        const previous = this.subMenuStack.pop()!;\n        this.items = previous;\n        this.clearInputContext();\n        if (this.input) this.input.value = '';\n        this.refilter();\n        this.refreshFooter();\n      } else {\n        this.close();\n      }\n    } else if (e.key === 'ArrowDown') {\n      e.preventDefault();\n      this.move(1);\n    } else if (e.key === 'ArrowUp') {\n      e.preventDefault();\n      this.move(-1);\n    } else if (e.key === 'Enter') {\n      // If a sub-tool has hijacked the input (chat box, etc.) hand off to\n      // its onSubmit and short-circuit the default \"activate selected row\"\n      // behaviour. Empty input still bubbles up so users don't accidentally\n      // fire a chat message by hitting Enter twice.\n      if (this.inputContext) {\n        e.preventDefault();\n        const value = this.input?.value ?? '';\n        if (value.trim().length === 0) return;\n        this.inputContext.onSubmit(value, this.buildHandle());\n        if (this.inputContext?.clearOnSubmit !== false && this.input) {\n          this.input.value = '';\n        }\n        return;\n      }\n      e.preventDefault();\n      this.activate(this.cursor);\n    }\n  }\n\n  setInputContext(ctx: {\n    placeholder?: string;\n    onSubmit: (value: string, handle: PaletteHandle) => void;\n    /** Fires on every keystroke. Use for live-filter panels. */\n    onInput?: (value: string, handle: PaletteHandle) => void;\n    /** Clear the input after onSubmit fires. Default true. */\n    clearOnSubmit?: boolean;\n    /** Hide the list / typeahead while in this context. Default false. */\n    hideList?: boolean;\n  }): void {\n    this.inputContext = {\n      placeholder: ctx.placeholder ?? this.placeholder,\n      onSubmit: ctx.onSubmit,\n      onInput: ctx.onInput,\n      clearOnSubmit: ctx.clearOnSubmit,\n      hideList: ctx.hideList,\n    };\n    if (this.input) {\n      this.input.placeholder = this.inputContext.placeholder;\n      this.input.value = '';\n    }\n    if (this.inputContext.hideList && this.list) {\n      this.list.style.display = 'none';\n    }\n  }\n\n  clearInputContext(): void {\n    if (!this.inputContext) return;\n    this.inputContext = null;\n    if (this.input) this.input.placeholder = this.placeholder;\n    if (this.list) this.list.style.display = '';\n  }\n\n  // ─── camera icon ────────────────────────────────────────────────\n\n  /** Circular submit/send button at the right edge of the input row. */\n  private buildSubmitButton(): HTMLButtonElement {\n    const btn = document.createElement('button');\n    btn.type = 'button';\n    btn.setAttribute(UI_ATTR, 'palette-submit');\n    btn.title = sdkString(this.locale, 'palette.footer.select');\n    btn.setAttribute('aria-label', btn.title);\n    btn.innerHTML = `\n      <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\"\n           stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n        <path d=\"M12 19V5M5 12l7-7 7 7\"/>\n      </svg>\n    `;\n    btn.addEventListener('click', (e) => {\n      e.stopPropagation();\n      this.submitInput();\n      this.input?.focus();\n    });\n    return btn;\n  }\n\n  /**\n   * Submit the current query — same effect as pressing Enter. Routes to the\n   * active input-context's onSubmit, else fires the single registered fallback\n   * (e.g. Ask AI) with the typed text, else activates the focused row.\n   */\n  private submitInput(): void {\n    if (this.inputContext) {\n      const value = this.input?.value ?? '';\n      if (value.trim().length === 0) return;\n      this.inputContext.onSubmit(value, this.buildHandle());\n      if (this.inputContext?.clearOnSubmit !== false && this.input) this.input.value = '';\n      return;\n    }\n    const raw = this.input?.value.trim() ?? '';\n    if (!raw) { this.input?.focus(); return; }\n    const fallbacks = this.rootItems.filter((i) => i.fallback);\n    if (fallbacks.length >= 1 && fallbacks[0]!.handler) {\n      this.currentArg = raw;\n      this.heatRank?.visit(fallbacks[0]!.id);\n      fallbacks[0]!.handler(this.buildHandle(), raw);\n      return;\n    }\n    this.activate(this.cursor);\n  }\n\n  private buildCameraButton(): HTMLButtonElement {\n    const cfg = this.camera!;\n    const btn = document.createElement('button');\n    btn.type = 'button';\n    btn.setAttribute(UI_ATTR, 'palette-camera');\n    btn.title = cfg.title ?? 'Attach image';\n    btn.setAttribute('aria-label', btn.title);\n    btn.innerHTML = `\n      <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\"\n           stroke-width=\"1.75\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n        <path d=\"M3 7h3l2-2h8l2 2h3a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1z\"/>\n        <circle cx=\"12\" cy=\"13\" r=\"4\"/>\n      </svg>\n    `;\n    btn.addEventListener('click', (e) => {\n      e.stopPropagation();\n      if (cfg.mode === 'upload') this.openUpload();\n      else this.openScreenshot();\n    });\n    return btn;\n  }\n\n  private openUpload(): void {\n    const cfg = this.camera;\n    if (!cfg) return;\n    const input = document.createElement('input');\n    input.type = 'file';\n    input.accept = cfg.accept ?? 'image/*';\n    if (cfg.capture) input.setAttribute('capture', 'environment');\n    input.style.display = 'none';\n    input.addEventListener('change', () => {\n      const file = input.files?.[0];\n      if (file) {\n        // Auto-queue as a palette attachment so it shows in chip-bar.\n        this.addAttachment({\n          kind: 'image',\n          blob: file,\n          thumbnailUrl: URL.createObjectURL(file),\n          source: 'upload',\n          filename: file.name,\n          sourceUrl: typeof window !== 'undefined' ? window.location.href : undefined,\n        });\n        cfg.onCapture(file, 'upload');\n      }\n      input.remove();\n    });\n    document.body.appendChild(input);\n    input.click();\n  }\n\n  /** See `./screenshot.ts` for the drag-rect overlay implementation. */\n  private openScreenshot(): void {\n    const cfg = this.camera;\n    if (!cfg) return;\n    const host: ScreenshotHost = {\n      getRoot: () => this.root,\n      getLocale: () => this.locale,\n      addAttachment: (att) => this.addAttachment(att),\n    };\n    helperOpenScreenshot(host, cfg);\n  }\n\n  private refilter(): void {\n    const raw = this.input?.value ?? '';\n    const q = raw.trim().toLowerCase();\n\n    // 1. Prefix routing — detect items whose `prefix` matches the input start.\n    const prefixMatch = matchPrefix(this.items, raw);\n\n    if (prefixMatch) {\n      const { item, arg } = prefixMatch;\n      this.currentArg = arg;\n      if (item.browse) {\n        // Browse mode — host-supplied resource list under this prefix.\n        // Section is overridable so a Tips-anchored parent can display\n        // its children under a different heading.\n        const sectionName =\n          item.browseSection ??\n          (item.section && item.section !== 'Tips' ? item.section : undefined) ??\n          String(item.prefix);\n        let browseItems: PaletteItem[] = [];\n        try {\n          browseItems = item.browse(arg) ?? [];\n        } catch {\n          browseItems = [];\n        }\n        if (arg) {\n          browseItems = fuzzyTopN(browseItems, arg, 50);\n        } else {\n          browseItems = browseItems.slice(0, 50);\n        }\n        this.filtered = browseItems.map((i) => ({\n          ...i,\n          section: i.section ?? sectionName,\n        }));\n        if (arg) {\n          const echo = arg;\n          for (const fb of this.items.filter((x) => x.fallback)) {\n            this.filtered.push({ ...fb, description: `“${echo}”` });\n          }\n        }\n      } else if (item.prefixAcceptsAnyArg) {\n        // Show this item as the single top result. Optionally also show items\n        // that fuzzy-match the arg (excluding Tips — they're hints, not picks).\n        const others = arg\n          ? fuzzyTopN(\n              this.items.filter((i) => i.id !== item.id && i.section !== 'Tips'),\n              arg,\n              10,\n            )\n          : [];\n        this.filtered = [item, ...others];\n      } else {\n        // Items sharing the same prefix (Tips excluded).\n        const sameGroup = this.items.filter((i) => i.prefix === item.prefix && i.section !== 'Tips');\n        this.filtered = arg\n          ? fuzzyTopN(sameGroup, arg, 50)\n          : sameGroup.slice(0, 50);\n      }\n    } else if (!q) {\n      this.currentArg = '';\n      // Empty state — show everything EXCEPT items whose prefix is already\n      // represented by a Tips row. So `/theme` (a Tip) shows once under\n      // Tips; the underlying `theme-toggle` command (same prefix, sits in\n      // Settings) is hidden to avoid duplication. Items WITHOUT a prefix\n      // (Skills, Go to navigation rows, …) always show because they have\n      // no Tip surrogate that could replace them. Fallbacks stay hidden.\n      const tipPrefixes = new Set<string>();\n      for (const i of this.items) {\n        if (i.section === 'Tips' && i.prefix) {\n          for (const p of listPrefixMatches(i.prefix)) {\n            tipPrefixes.add(p.toLowerCase());\n          }\n        }\n      }\n      this.filtered = this.items.filter((i) => {\n        if (i.fallback) return false;\n        if (i.searchOnly) return false;\n        if (i.searchAction) return false;\n        if (i.section === 'Tips') return true;\n        if (!i.prefix) return true;\n        return !listPrefixMatches(i.prefix).some((p) => tipPrefixes.has(p.toLowerCase()));\n      }).slice(0, 100);\n    } else if (looksLikePrefixAttempt(this.items, raw)) {\n      // Partial-prefix typing — user has typed `/`, `nav`, `ask` etc. but\n      // hasn't completed any registered prefix. Show ONLY the commands whose\n      // declared prefix starts with what they've typed. No page-text search,\n      // no AI fallback (yet — they're trying to pick a command). Items\n      // tagged `section: 'Tips'` are empty-state discovery rows — drop them\n      // here so they don't duplicate the real commands.\n      // currentArg holds the raw input so highlightMatch can mark the typed\n      // characters inside the matched command name (e.g. user types `/them`,\n      // `/theme` row shows `/them` in highlight + trailing `e`).\n      this.currentArg = raw.trim();\n      const partial = raw.toLowerCase();\n      this.filtered = this.items\n        .filter((i) => !i.fallback)\n        .filter((i) => !i.searchOnly)\n        .filter((i) => !i.searchAction)\n        .filter((i) => i.section !== 'Tips')\n        .filter((i) => listPrefixMatches(i.prefix).some((p) => p.toLowerCase().startsWith(partial)))\n        .slice(0, 50);\n    } else {\n      // Use raw-trimmed input for currentArg so fallback handlers (Ask AI etc.)\n      // receive the user's original casing. Fuzzy scoring still uses `q`\n      // (lowercased) for matching, which is what we want for search.\n      this.currentArg = raw.trim();\n      // Prefixed items ARE included in free-text search — typing `lan`\n      // surfaces `/language` via substring match on the name. Excluding\n      // them previously meant prefix commands were unreachable from a\n      // plain-text query (the user had to know the leading symbol first).\n      // The prefix routing earlier branches already short-circuit on exact\n      // / partial prefix typing, so this only fires when the user's query\n      // does NOT look like any registered prefix.\n      const candidates = this.items\n        .filter((i) => !i.fallback)\n        .filter((i) => !i.searchAction)\n        .filter((i) => i.section !== 'Tips');\n      this.filtered = fuzzyTopN(candidates, q, 50);\n\n      // Search-action rows: pinned to the TOP the moment anything is typed,\n      // regardless of fuzzy match, with the live query substituted for `{q}`.\n      const echoQ = raw.trim();\n      const searchActions = this.items\n        .filter((i) => i.searchAction)\n        .map((s) => ({\n          ...s,\n          name: (s.name ?? '').replace(/\\{q\\}/g, echoQ),\n          description: (s.description ?? '').replace(/\\{q\\}/g, echoQ),\n        }));\n      if (searchActions.length) this.filtered = [...searchActions, ...this.filtered];\n\n      // (Body-text page search is no longer auto-fired here. The host can\n      // gate it behind a prefix tip like `#` whose `browse()` calls into\n      // its own DOM-text search — keeps free-text typing strictly about\n      // matching registered palette items + the Ask AI fallback.)\n\n      // Fallback rows are appended whenever the user has typed something\n      // real, so an \"Ask AI — '<query>'\" row stays discoverable at the\n      // bottom of the list. Each registered fallback becomes one row with\n      // the live query echoed in the description.\n      const fallbacks = this.items.filter((i) => i.fallback);\n      const echo = raw.trim();\n      for (const f of fallbacks) {\n        this.filtered.push({\n          ...f,\n          description: `“${echo}”`,\n        });\n      }\n    }\n    // Category-chip filter — when the host configured `categories` and the\n    // user clicked a chip other than \"All\", drop items whose `category`\n    // doesn't match. Tips rows are kept either way so the discovery row\n    // stays visible regardless of which chip is active.\n    if (this.activeCategoryId) {\n      const active = this.activeCategoryId;\n      this.filtered = this.filtered.filter(\n        (i) => i.section === 'Tips' || i.fallback || i.category === active,\n      );\n    }\n\n    // Apply HeatRank sort (stable: keeps original tie-break order)\n    if (this.heatRank && this.filtered.length > 1) {\n      const rank = this.heatRank;\n      this.filtered = rank.sort(this.filtered, (i) => i.id, () => 0);\n    }\n\n    // Context promotion — when chip-bar has anything attached (selection\n    // text, pinned element, image), pull the registered fallback rows to\n    // the TOP so pressing Enter immediately routes the captured context to\n    // the agent. Skip when the user is actively drilling into a registered\n    // prefix (their intent is \"browse / pick from this resource\", not\n    // \"ask AI about my selection\"). Host can opt out via\n    // `contextPromotesFallback: false`.\n    if (!prefixMatch && this.contextPromotesFallback && this.hasChipContext()) {\n      const fbItems = this.items.filter((i) => i.fallback);\n      if (fbItems.length > 0) {\n        // Drop any fallback rows the earlier branches already appended at\n        // the bottom — we'll re-add them at the top instead.\n        this.filtered = this.filtered.filter((i) => !i.fallback);\n        const echo = raw.trim();\n        const promoted = fbItems.map((fb) => ({\n          ...fb,\n          description: echo\n            ? `“${echo}”`\n            : (fb.description ?? '送選取的內容給 AI · use captured context'),\n        }));\n        this.filtered = [...promoted, ...this.filtered];\n      }\n    }\n\n    this.cursor = 0;\n    this.renderList();\n  }\n\n  /** True when the chip bar has any user-pinned context attached. */\n  private hasChipContext(): boolean {\n    return this.contextSelectionText.trim().length > 0\n      || this.contextAttachments.length > 0;\n  }\n\n  /**\n   * Render or refresh the category chip row. Hidden when no categories\n   * were configured. Active chip is highlighted via `data-active=\"true\"`.\n   */\n  private renderCategoryBar(): void {\n    const host = this.categoryBarHost;\n    if (!host) return;\n    if (this.categories.length === 0) {\n      host.style.display = 'none';\n      host.innerHTML = '';\n      return;\n    }\n    host.style.display = '';\n    host.innerHTML = '';\n    const chips: PaletteCategory[] = [\n      { id: '', label: this.allCategoriesLabel },\n      ...this.categories,\n    ];\n    for (const c of chips) {\n      const btn = document.createElement('button');\n      btn.type = 'button';\n      btn.setAttribute(UI_ATTR, 'palette-category');\n      btn.dataset.id = c.id;\n      const isActive = (this.activeCategoryId ?? '') === c.id;\n      btn.setAttribute('data-active', String(isActive));\n      btn.textContent = c.label;\n      btn.addEventListener('mousedown', (e) => { e.preventDefault(); });\n      btn.addEventListener('click', () => {\n        this.activeCategoryId = c.id ? c.id : null;\n        this.renderCategoryBar();\n        this.refilter();\n        this.input?.focus();\n      });\n      host.appendChild(btn);\n    }\n  }\n\n  /**\n   * Render the filtered item list. Each `<li>` carries a `data-idx` matching\n   * its index in `this.filtered`, so:\n   *  - hover does NOT rebuild the DOM — it just toggles `data-active` on the\n   *    existing nodes. (Critical: rebuilding the `<li>` during a press\n   *    destroys the click target and the click bubbles to the `<ul>` instead,\n   *    making items appear unclickable.)\n   *  - the click handler reads `data-idx` from the row at click-time, so it\n   *    survives any re-renders triggered by other events.\n   *\n   * If `tipsItems` is present we also prepend a `Tips` section showing the\n   * prefixes the user can type to filter (ask: / find: / go: hints at the top).\n   */\n  private renderList(): void {\n    if (!this.list) return;\n    this.list.innerHTML = '';\n    // Shared across this render's row listeners: real clicks fire mousedown AND\n    // click; the mousedown handler sets this so the trailing click is a no-op\n    // (only programmatic clicks — no preceding mousedown — fall through).\n    let pressHandled = false;\n\n    // (Tips rows are now part of `this.filtered` in empty-state — see\n    // `refilter()` + `buildTipItems()`. The section header gets emitted by\n    // the normal lastSection logic below since they all have `section: 'Tips'`.)\n\n    // Group items by section header to avoid duplicate headers when\n    // HeatRank / context-promotion scatters same-section items across\n    // the filtered array. The lastSection toggle below only collapses\n    // ADJACENT same-section rows; with HeatRank, the [Go to, Settings,\n    // ..., Go to, ...] order would emit \"前往\" twice.\n    //\n    // Section order is derived from REGISTRATION ORDER (this.rootItems),\n    // NOT from filtered order — otherwise a HeatRank-promoted item drags\n    // its whole section to the top, violating the host's hand-curated\n    // section sequence (host registered Settings then Go-to → Settings\n    // must render above Go-to even when Go-to has the hottest item).\n    // Within a section, HeatRank ordering of items is preserved.\n    const sectionRegOrder = new Map<string, number>();\n    for (const it of this.rootItems) {\n      const s = it.section ?? 'Commands';\n      if (!sectionRegOrder.has(s)) sectionRegOrder.set(s, sectionRegOrder.size);\n    }\n    // Sections that appear in filtered but were never in rootItems\n    // (post-mount additions / fallbacks / Tips) tail-append in their\n    // first-seen order.\n    this.filtered.forEach((it) => {\n      const s = it.section ?? 'Commands';\n      if (!sectionRegOrder.has(s)) sectionRegOrder.set(s, sectionRegOrder.size);\n    });\n    this.filtered.sort((a, b) => {\n      const sa = a.section ?? 'Commands';\n      const sb = b.section ?? 'Commands';\n      if (sa === sb) return 0;\n      return sectionRegOrder.get(sa)! - sectionRegOrder.get(sb)!;\n    });\n\n    let lastSection = '';\n    this.filtered.forEach((item, idx) => {\n      const section = item.section ?? 'Commands';\n      if (section !== lastSection) {\n        const header = document.createElement('li');\n        header.setAttribute(UI_ATTR, 'palette-section');\n        header.textContent = section;\n        this.list!.appendChild(header);\n        lastSection = section;\n      }\n\n      const li = document.createElement('li');\n      li.setAttribute(UI_ATTR, 'palette-item');\n      // `role=\"option\"` is what makes the row clickable from the webagent's\n      // perspective — without it the DOM walker treats <li> as a content\n      // line (no index, no hash id), and the agent has no handle to call\n      // `click` on. With role=option, the walker indexes it like any\n      // other interactive element and the agent can drive the palette\n      // exactly like a user would. Also semantically correct: the palette\n      // panel is a listbox of options.\n      li.setAttribute('role', 'option');\n      li.dataset.idx = String(idx);\n      if (idx === this.cursor) li.setAttribute('data-active', 'true');\n      const prefixLabel = displayPrefix(item.prefix);\n\n      // Layout rule: hide the bold `name` slot when it would just repeat the\n      // prefix pill (case-insensitive). Two flavours of prefix items:\n      //   - `/theme` registered with `name: '/theme'`  →  pill is the name;\n      //     row reads as `[/theme] — toggle light/dark`. No duplication.\n      //   - `nav:` items registered with `name: 'Home'` →  pill is the\n      //     family, name is the destination; both shown.\n      const showName = !prefixLabel\n        || prefixLabel.toLowerCase() !== item.name.toLowerCase();\n      // Highlight query matches in name + description. Fallback items render\n      // the user's query inside their description (e.g. Ask AI — “foo”) — we\n      // intentionally skip highlighting on them so the echoed query stays\n      // visually clean as a single token.\n      const hl = item.fallback ? '' : (this.currentArg ?? '');\n      // Icon: glyph string is escaped; inline SVG (starts with `<svg`) is\n      // passed through so hosts can use lucide / heroicons / custom SVG\n      // without an SDK API change. Host controls the icon string, so this\n      // is not an injection vector — it's the same trust boundary as\n      // `agentTool.description` etc.\n      // Image thumbnail takes precedence over the glyph/SVG icon. Renders an\n      // <img> in the icon slot so hosts can build rich rows (book cover etc.).\n      // src is attribute-escaped; host controls the URL (same trust boundary as\n      // `icon`). Falls back to glyph icon, then nothing.\n      // Some renderers (e.g. Svelte 5's `mount()`) prefix a `<!---->`\n      // HTML comment before the actual `<svg>` root — strip leading\n      // comments before deciding \"raw HTML vs plain text\" so those\n      // don't fall through to escapeHtml and render as visible code.\n      const iconStripped = item.icon?.replace(/^\\s*(<!--[\\s\\S]*?-->\\s*)+/, '') ?? '';\n      const iconHtml = item.image\n        ? `<img data-dddk-ui=\"palette-item-image\" src=\"${escapeHtml(item.image)}\" alt=\"\" loading=\"lazy\" />`\n        : item.icon\n          ? (iconStripped.startsWith('<svg') || iconStripped.startsWith('<')\n              ? item.icon\n              : escapeHtml(item.icon))\n          : '';\n      // NOTE: `data-dddk-ui` is matched with EXACT `[attr=\"...\"]` selectors, so it\n      // must hold a SINGLE token (not space-separated like a className) — otherwise\n      // neither the base nor the modifier rule matches and the thumbnail renders at\n      // its natural (huge) size. The image variant is fully self-contained in CSS.\n      const iconClass = item.image ? 'palette-item-icon-img' : 'palette-item-icon';\n      // Text block: when the host supplies `lines`, stack them vertically as a\n      // multi-line row (name on top, then one element per line). Otherwise use\n      // the default inline `name — description` layout.\n      const hasLines = Array.isArray(item.lines) && item.lines.length > 0;\n      const textHtml = hasLines\n        ? `<span data-dddk-ui=\"palette-item-textcol\">\n             ${showName ? `<span data-dddk-ui=\"palette-item-name\">${highlightMatch(item.name, hl)}</span>` : ''}\n             ${item.lines!.map((ln, li2) => `<span data-dddk-ui=\"palette-item-line\" data-line=\"${li2}\">${highlightMatch(ln, hl)}</span>`).join('')}\n           </span>`\n        : `${showName ? `<span data-dddk-ui=\"palette-item-name\">${highlightMatch(item.name, hl)}</span>` : ''}\n           ${item.description ? `<span data-dddk-ui=\"palette-item-dash\">—</span><span data-dddk-ui=\"palette-item-desc\">${highlightMatch(item.description, hl)}</span>` : ''}`;\n      li.innerHTML = `\n        ${iconHtml ? `<span data-dddk-ui=\"${iconClass}\">${iconHtml}</span>` : ''}\n        ${prefixLabel ? `<span data-dddk-ui=\"palette-item-prefix\">${highlightMatch(prefixLabel, hl)}</span>` : ''}\n        ${textHtml}\n        ${item.shortcut ? `<span data-dddk-ui=\"palette-item-shortcut\">${escapeHtml(item.shortcut)}</span>` : ''}\n      `;\n      // Two-stage press: hover NO LONGER auto-selects (so the wheel scrolls the\n      // list smoothly under the pointer instead of every row stealing focus and\n      // re-expanding). A press on a row that HAS a `detail` and isn't already\n      // active just EXPANDS it; pressing the already-expanded row COMMITS\n      // (navigates). Rows without detail commit on the first press, as before.\n      const press = (): void => {\n        const it = this.filtered[idx];\n        // First press on a \"rich\" row — one that expands when active, i.e. has a\n        // `detail` pane OR an `image` thumbnail that enlarges — just selects it;\n        // pressing the already-active row commits. Plain rows commit immediately.\n        if ((it?.detail || it?.image) && this.cursor !== idx) this.setCursor(idx);\n        else this.activate(idx);\n      };\n      // Use mousedown so it happens before any blur side-effects, and\n      // stopPropagation so a handler that detaches THIS li mid-event doesn't\n      // bubble to the backdrop close handler (which would wrongly close).\n      li.addEventListener('mousedown', (e) => {\n        e.preventDefault();    // keep input focus\n        e.stopPropagation();\n        pressHandled = true;   // swallow the trailing real `click`\n        press();\n      });\n      // `click` only acts for PROGRAMMATIC invocations (webagent `el.click()` —\n      // no preceding mousedown). Real clicks already handled by mousedown above.\n      li.addEventListener('click', (e) => {\n        if (pressHandled) { pressHandled = false; return; }\n        if (!li.isConnected) return;\n        e.preventDefault();\n        e.stopPropagation();\n        press();\n      });\n      this.list!.appendChild(li);\n    });\n    // After a re-render the cursor row exists again but its inline detail was\n    // wiped by `innerHTML = ''` — re-render it so the expanded description /\n    // table under the active row survives filtering.\n    this.renderDetailFor(this.filtered[this.cursor]);\n  }\n\n  /** Set the highlighted row without re-rendering. */\n  private setCursor(idx: number): void {\n    if (this.cursor === idx) return;\n    this.cursor = idx;\n    if (!this.list) return;\n    const rows = this.list.querySelectorAll<HTMLLIElement>('[data-idx]');\n    rows.forEach((row) => {\n      if (Number(row.dataset.idx) === idx) row.setAttribute('data-active', 'true');\n      else row.removeAttribute('data-active');\n    });\n    this.renderDetailFor(this.filtered[idx]);\n  }\n\n  // (Tips are now host-defined: the host registers items with\n  //  `section: 'Tips'` directly. The SDK does not generate them.)\n\n  private move(delta: number): void {\n    const next = Math.max(0, Math.min(this.filtered.length - 1, this.cursor + delta));\n    this.setCursor(next);\n    // Keep the active row's HEADER (title line) visible. A row with an expanded\n    // inline detail (e.g. orders / cart preview) can be taller than the list\n    // viewport — plain `scrollIntoView({block:'nearest'})` then aligns the row's\n    // BOTTOM and clips the title line off the top edge. Scroll on the next frame\n    // (after the async detail has laid out) and prioritise the row's TOP: if the\n    // row is taller than the viewport or its top is above the fold, align the top.\n    requestAnimationFrame(() => {\n      const active = this.list?.querySelector('[data-active]') as HTMLElement | null;\n      if (!active || !this.list) return;\n      const list = this.list;\n      const lr = list.getBoundingClientRect();\n      const ar = active.getBoundingClientRect();\n      if (ar.top < lr.top || ar.height >= list.clientHeight) list.scrollTop += ar.top - lr.top;\n      else if (ar.bottom > lr.bottom) list.scrollTop += ar.bottom - lr.bottom;\n    });\n  }\n\n  /** Render the right detail pane if the active item provides `detail()`. */\n  private async renderDetailFor(item: PaletteItem | undefined): Promise<void> {\n    if (!this.detailHost) return;\n    const token = ++this.detailRenderToken;\n    if (!item?.detail) {\n      this.detailHost.innerHTML = '';\n      this.detailHost.style.display = 'none';\n      return;\n    }\n    // Inline accordion: render the detail INSIDE the active row so the whole\n    // selected option grows taller (one expanded, highlighted card) rather than\n    // spawning a separate block. The host is appended as the last child of the\n    // active <li>; the row is `flex-wrap` so this full-width host drops onto a\n    // new line under the icon + text. The host has no `data-idx`, so the cursor\n    // logic never lands on it.\n    const activeLi = this.list?.querySelector('[data-active]');\n    if (activeLi && this.detailHost.parentElement !== activeLi) {\n      activeLi.appendChild(this.detailHost);\n    }\n    this.detailHost.style.display = 'block';\n    this.detailHost.innerHTML = '<div data-dddk-ui=\"palette-detail-loading\">…</div>';\n\n    try {\n      const surface = await item.detail(this.currentArg || undefined);\n      if (token !== this.detailRenderToken || !this.detailHost) return;\n      if (!this.pieceCatalog) {\n        const { createBuiltinCatalog } = await import('../../ui/pieces');\n        if (token !== this.detailRenderToken) return;\n        this.pieceCatalog = createBuiltinCatalog();\n      }\n      const { PieceDomRenderer } = await import('../../ui/pieces/dom-renderer');\n      if (token !== this.detailRenderToken || !this.detailHost) return;\n      this.detailHost.innerHTML = '';\n      const renderer = new PieceDomRenderer({ catalog: this.pieceCatalog, readOnly: true });\n      renderer.mount(this.detailHost, surface);\n    } catch (err) {\n      if (token !== this.detailRenderToken || !this.detailHost) return;\n      this.detailHost.innerHTML = `<div data-dddk-ui=\"palette-detail-error\">${String((err as Error).message)}</div>`;\n    }\n  }\n\n  /**\n   * Public — activate a palette item by id. Returns true if found and\n   * fired, false if no matching item is currently in the filtered list\n   * (e.g. caller passed a sub-menu id before opening the parent).\n   *\n   * Used by host-registered \"semantic\" webagent tools that wrap multi-\n   * level palette flows: the tool can `open()` the palette, await a\n   * frame, `activateById('parent')` to expand the sub-menu, await, then\n   * `activateById('child')` to commit. Saves the agent from having to\n   * model the palette as a 2-step click sequence.\n   */\n  activateById(id: string): boolean {\n    const idx = this.filtered.findIndex((item) => item.id === id);\n    if (idx < 0) return false;\n    this.activate(idx);\n    return true;\n  }\n\n  private activate(idx: number): void {\n    const item = this.filtered[idx];\n    if (!item) {\n      // Implicit fallback — list is empty and the user pressed Enter on a\n      // non-empty query. If exactly one fallback item is registered, fire\n      // it with the raw input as arg. Lets `plain text + Enter → webagent`\n      // Just Work without ever rendering an \"Ask AI\" row.\n      const raw = this.input?.value.trim() ?? '';\n      if (!raw) return;\n      const fallbacks = this.rootItems.filter((i) => i.fallback);\n      if (fallbacks.length === 1) {\n        const fb = fallbacks[0]!;\n        this.heatRank?.visit(fb.id);\n        this.onActivate?.({\n          itemId: fb.id,\n          arg: raw,\n          selectionText: this.contextSelectionText || undefined,\n          attachmentsCount: this.contextAttachments.length,\n        });\n        fb.handler?.(this.buildHandle(), raw);\n      }\n      return;\n    }\n\n    // Record usage in HeatRank so it floats up next time.\n    this.heatRank?.visit(item.id);\n\n    // Notify host (orchestrator) — used for `intent` event emission.\n    this.onActivate?.({\n      itemId: item.id,\n      arg: this.currentArg || undefined,\n      selectionText: this.contextSelectionText || undefined,\n      attachmentsCount: this.contextAttachments.length,\n    });\n\n    if (!item.handler) {\n      // Detail-only items don't need to do anything on activate.\n      return;\n    }\n    item.handler(this.buildHandle(), this.currentArg || undefined);\n  }\n\n  private buildHandle(): PaletteHandle {\n    const self = this;\n    const inputRef = this.input;\n    return {\n      close: () => this.close(),\n      replace: (items) => {\n        // Push the current visible set onto the sub-menu stack so Esc can\n        // pop back to it. (The user's `addItem`-registered root list lives\n        // separately in `rootItems` and is restored on next `open()`.)\n        this.subMenuStack.push(this.items);\n        this.items = items;\n        if (this.input) this.input.value = '';\n        this.refilter();\n        this.refreshFooter();\n      },\n      get input() {\n        return inputRef?.value ?? '';\n      },\n      setInput: (value) => {\n        if (self.input) {\n          self.input.value = value;\n          self.refilter();\n        }\n      },\n      get context(): PaletteContext {\n        return {\n          selectionText: self.contextSelectionText,\n          selectionElement: self.contextSelectionElement,\n          attachments: self.contextAttachments.slice(),\n        };\n      },\n      showResult: (surface) => self.showResult(surface),\n      clearResult: () => self.clearResult(),\n      setInputContext: (ctx) => self.setInputContext(ctx),\n      clearInputContext: () => self.clearInputContext(),\n    };\n  }\n}\n\n// ─── streaming result helpers ─────────────────────────────────────\n\nfunction isStreamingSurface(v: unknown): v is StreamingResultSurface {\n  return (\n    !!v &&\n    typeof v === 'object' &&\n    'mount' in v &&\n    'stream' in v &&\n    (v as StreamingResultSurface).mount instanceof HTMLElement &&\n    typeof (v as StreamingResultSurface).stream === 'function'\n  );\n}\n\n/**\n * Apply one streamed chunk to the running content frame.\n * Plain strings keep the legacy \"yield deltas, get appended\" contract\n * so existing callers don't break.\n */\nfunction applyResultChunk(out: HTMLElement, chunk: string | ResultChunk): void {\n  if (typeof chunk === 'string') {\n    out.textContent = (out.textContent ?? '') + chunk;\n    return;\n  }\n  if ('clear' in chunk) {\n    out.textContent = '';\n    return;\n  }\n  if ('delta' in chunk) {\n    out.textContent = (out.textContent ?? '') + chunk.delta;\n    return;\n  }\n  if ('text' in chunk) {\n    out.textContent = chunk.text;\n    return;\n  }\n  if ('html' in chunk) {\n    if (chunk.append) out.insertAdjacentHTML('beforeend', chunk.html);\n    else out.innerHTML = chunk.html;\n    return;\n  }\n  if ('node' in chunk) {\n    if (chunk.append) out.appendChild(chunk.node);\n    else {\n      out.textContent = '';\n      out.appendChild(chunk.node);\n    }\n  }\n}\n","/**\r\n * Spotter — pointer follow + deictic lock + region lasso.\r\n * See ../../docs/04-spotter.md for the full design.\r\n */\r\n\r\nimport { inferSelector } from '../utils/selector';\r\nimport { injectScopedStyle, UI_ATTR } from '../utils/dom';\r\n\r\nconst RING_DELAY_MS = 200;\r\nconst MIN_LASSO_PX = 5;\r\nconst STYLE_ID = 'dddk-spotter-style';\r\n\r\nexport type SpotterState = 'idle' | 'ring' | 'lock' | 'lasso';\r\n\r\nexport interface SpotterOptions {\r\n  ringDelay?: number;\r\n  enableLasso?: boolean;\r\n  enableRing?: boolean;\r\n  /** Elements with this selector are ignored (e.g. dddk's own UI). */\r\n  ignoreSelector?: string;\r\n  onRingShow?: (info: { selector: string; element: HTMLElement; rect: DOMRect }) => void;\r\n  onRingHide?: () => void;\r\n  onLock?: (info: { selector: string; element: HTMLElement }) => void;\r\n  onLassoComplete?: (info: {\r\n    elements: HTMLElement[];\r\n    bounds: DOMRect;\r\n  }) => void;\r\n}\r\n\r\nexport class Spotter {\r\n  private state: SpotterState = 'idle';\r\n  private opts: Required<Pick<SpotterOptions, 'ringDelay' | 'enableLasso' | 'enableRing'>> &\r\n    SpotterOptions;\r\n\r\n  private hoverTimer: ReturnType<typeof setTimeout> | null = null;\r\n  private lastHoverElement: HTMLElement | null = null;\r\n  private lastHoverPos = { x: 0, y: 0 };\r\n\r\n  private ringEl: HTMLElement | null = null;\r\n  private lassoEl: HTMLElement | null = null;\r\n  private lassoStart: { x: number; y: number } | null = null;\r\n  private lockedElement: HTMLElement | null = null;\r\n\r\n  private cleanups: Array<() => void> = [];\r\n\r\n  constructor(opts: SpotterOptions = {}) {\r\n    this.opts = {\r\n      ringDelay: RING_DELAY_MS,\r\n      enableLasso: true,\r\n      enableRing: true,\r\n      ...opts,\r\n    };\r\n  }\r\n\r\n  start(): void {\r\n    if (typeof document === 'undefined') return;\r\n    ensureStyles();\r\n\r\n    const onMove = (e: MouseEvent) => this.handleMove(e);\r\n    document.addEventListener('mousemove', onMove);\r\n    this.cleanups.push(() => document.removeEventListener('mousemove', onMove));\r\n  }\r\n\r\n  destroy(): void {\r\n    this.cleanups.forEach((fn) => fn());\r\n    this.cleanups = [];\r\n    this.hideRing();\r\n    this.endLasso(false);\r\n    this.state = 'idle';\r\n  }\r\n\r\n  getState(): SpotterState {\r\n    return this.state;\r\n  }\r\n\r\n  /**\r\n   * Called by GestureManager when user starts a long-press while\r\n   * something is hovered. If ring is shown → lock. Otherwise → just signal voice mode.\r\n   */\r\n  lockCurrent(): { selector: string; element: HTMLElement } | null {\r\n    if (!this.opts.enableRing) return null;\r\n    if (!this.lastHoverElement) return null;\r\n    if (this.shouldIgnore(this.lastHoverElement)) return null;\r\n\r\n    this.state = 'lock';\r\n    this.lockedElement = this.lastHoverElement;\r\n    const selector = inferSelector(this.lockedElement);\r\n    this.opts.onLock?.({ selector, element: this.lockedElement });\r\n    return { selector, element: this.lockedElement };\r\n  }\r\n\r\n  /** Start drawing a lasso from current pointer position. */\r\n  beginLasso(startX: number, startY: number): void {\r\n    if (!this.opts.enableLasso) return;\r\n    this.state = 'lasso';\r\n    this.lassoStart = { x: startX, y: startY };\r\n    this.lassoEl = document.createElement('div');\r\n    this.lassoEl.setAttribute(UI_ATTR, 'spotter-lasso');\r\n    this.lassoEl.style.left = `${startX}px`;\r\n    this.lassoEl.style.top = `${startY}px`;\r\n    document.body.appendChild(this.lassoEl);\r\n  }\r\n\r\n  updateLasso(x: number, y: number): void {\r\n    if (!this.lassoEl || !this.lassoStart) return;\r\n    const left = Math.min(this.lassoStart.x, x);\r\n    const top = Math.min(this.lassoStart.y, y);\r\n    const w = Math.abs(x - this.lassoStart.x);\r\n    const h = Math.abs(y - this.lassoStart.y);\r\n    this.lassoEl.style.left = `${left}px`;\r\n    this.lassoEl.style.top = `${top}px`;\r\n    this.lassoEl.style.width = `${w}px`;\r\n    this.lassoEl.style.height = `${h}px`;\r\n  }\r\n\r\n  endLasso(commit: boolean): { elements: HTMLElement[]; bounds: DOMRect } | null {\r\n    if (!this.lassoEl || !this.lassoStart) return null;\r\n\r\n    const result = commit ? this.collectLassoElements() : null;\r\n    this.lassoEl.remove();\r\n    this.lassoEl = null;\r\n    this.lassoStart = null;\r\n    this.state = 'idle';\r\n\r\n    if (result) this.opts.onLassoComplete?.(result);\r\n    return result;\r\n  }\r\n\r\n  unlock(): void {\r\n    this.lockedElement = null;\r\n    this.state = 'idle';\r\n    this.hideRing();\r\n  }\r\n\r\n  // ─── private ────────────────────────────────────────────────────\r\n\r\n  private handleMove(e: MouseEvent): void {\r\n    if (this.state === 'lasso') {\r\n      this.updateLasso(e.pageX, e.pageY);\r\n      return;\r\n    }\r\n\r\n    this.lastHoverPos = { x: e.pageX, y: e.pageY };\r\n\r\n    const target = e.target as HTMLElement | null;\r\n    if (!target || target === this.lastHoverElement) return;\r\n\r\n    // Hovering changed → cancel timer, hide ring, restart.\r\n    if (this.hoverTimer) clearTimeout(this.hoverTimer);\r\n    if (this.state === 'ring') this.hideRing();\r\n\r\n    if (!this.opts.enableRing) return;\r\n    if (this.shouldIgnore(target)) return;\r\n\r\n    this.lastHoverElement = target;\r\n    this.hoverTimer = setTimeout(() => {\r\n      if (this.lastHoverElement !== target) return;\r\n      this.showRing(target);\r\n    }, this.opts.ringDelay);\r\n  }\r\n\r\n  private showRing(el: HTMLElement): void {\r\n    this.state = 'ring';\r\n    const rect = el.getBoundingClientRect();\r\n    if (!this.ringEl) {\r\n      this.ringEl = document.createElement('div');\r\n      this.ringEl.setAttribute(UI_ATTR, 'spotter-ring');\r\n      document.body.appendChild(this.ringEl);\r\n    }\r\n    this.ringEl.style.left = `${rect.left + window.scrollX}px`;\r\n    this.ringEl.style.top = `${rect.top + window.scrollY}px`;\r\n    this.ringEl.style.width = `${rect.width}px`;\r\n    this.ringEl.style.height = `${rect.height}px`;\r\n    this.ringEl.style.display = 'block';\r\n\r\n    const selector = inferSelector(el);\r\n    this.opts.onRingShow?.({ selector, element: el, rect });\r\n  }\r\n\r\n  private hideRing(): void {\r\n    if (this.ringEl) {\r\n      this.ringEl.style.display = 'none';\r\n    }\r\n    if (this.state === 'ring') this.state = 'idle';\r\n    this.opts.onRingHide?.();\r\n  }\r\n\r\n  private collectLassoElements(): { elements: HTMLElement[]; bounds: DOMRect } | null {\r\n    if (!this.lassoEl || !this.lassoStart) return null;\r\n\r\n    const rect = this.lassoEl.getBoundingClientRect();\r\n    if (rect.width < MIN_LASSO_PX || rect.height < MIN_LASSO_PX) return null;\r\n\r\n    const elements: HTMLElement[] = [];\r\n    // Lasso runs once on mouseup, so an O(n) full-DOM walk is acceptable.\r\n    document.body.querySelectorAll<HTMLElement>('*').forEach((el) => {\r\n      if (this.shouldIgnore(el)) return;\r\n      const r = el.getBoundingClientRect();\r\n      if (\r\n        r.left >= rect.left &&\r\n        r.right <= rect.right &&\r\n        r.top >= rect.top &&\r\n        r.bottom <= rect.bottom &&\r\n        r.width > 0 &&\r\n        r.height > 0\r\n      ) {\r\n        elements.push(el);\r\n      }\r\n    });\r\n\r\n    return { elements, bounds: rect };\r\n  }\r\n\r\n  private shouldIgnore(el: HTMLElement): boolean {\r\n    if (el.closest(`[${UI_ATTR}]`)) return true;\r\n    if (this.opts.ignoreSelector && el.closest(this.opts.ignoreSelector)) return true;\r\n    return false;\r\n  }\r\n}\r\n\r\n// ─── helpers ────────────────────────────────────────────────────────\r\n\r\nfunction ensureStyles(): void {\r\n  injectScopedStyle(STYLE_ID, `\r\n    [${UI_ATTR}=\"spotter-ring\"] {\r\n      position: absolute; pointer-events: none;\r\n      z-index: var(--dddk-z-pointer, 9800);\r\n      border: 2px solid var(--dddk-accent, #ec4899);\r\n      border-radius: var(--dddk-radius, 12px);\r\n      box-shadow: 0 0 0 4px color-mix(in srgb, var(--dddk-accent, #ec4899) 20%, transparent);\r\n      transition: all 80ms ease-out;\r\n      animation: dddk-ring-pulse 2s ease-in-out infinite;\r\n      display: none;\r\n    }\r\n    [${UI_ATTR}=\"spotter-lasso\"] {\r\n      position: absolute; pointer-events: none;\r\n      z-index: var(--dddk-z-pointer, 9800);\r\n      border: 2px dashed var(--dddk-accent, #ec4899);\r\n      background: color-mix(in srgb, var(--dddk-accent, #ec4899) 15%, transparent);\r\n      border-radius: 4px;\r\n    }\r\n    @keyframes dddk-ring-pulse {\r\n      0%, 100% { opacity: 0.8; }\r\n      50%      { opacity: 1.0; }\r\n    }\r\n  `);\r\n}\r\n","/**\n * SkillRegistry — register / lookup / match skills by id or `/command`.\n */\n\nimport type { Skill, PromptSkill } from './types';\n\nexport class SkillRegistry {\n  private skills: Map<string, Skill> = new Map();\n\n  constructor(initial: Skill[] = []) {\n    for (const s of initial) this.skills.set(s.id, s);\n  }\n\n  register(skill: Skill): void {\n    this.skills.set(skill.id, skill);\n  }\n\n  unregister(id: string): void {\n    this.skills.delete(id);\n  }\n\n  get(id: string): Skill | undefined {\n    return this.skills.get(id);\n  }\n\n  list(): Skill[] {\n    return Array.from(this.skills.values()).filter((s) => !s.hidden);\n  }\n\n  listAll(): Skill[] {\n    return Array.from(this.skills.values());\n  }\n\n  /** Match palette input like `/introduce` or `/translate en` to a skill id. */\n  match(input: string): Skill | undefined {\n    const id = input.startsWith('/') ? input.slice(1).split(/\\s+/)[0] : input.split(/\\s+/)[0];\n    return id ? this.skills.get(id) : undefined;\n  }\n\n  /** Extract args after the skill name. e.g. `/translate en` → 'en' */\n  parseArgs(input: string): string {\n    const parts = (input.startsWith('/') ? input.slice(1) : input).split(/\\s+/);\n    return parts.slice(1).join(' ');\n  }\n\n  /** Resolve `{{var}}` placeholders in a PromptSkill template. */\n  resolvePrompt(skill: PromptSkill, vars: Record<string, string> = {}): string {\n    const merged = { ...skill.variables, ...vars };\n    let out = skill.prompt;\n    for (const [k, v] of Object.entries(merged)) {\n      out = out.replace(new RegExp(`\\\\{\\\\{\\\\s*${escapeRegex(k)}\\\\s*\\\\}\\\\}`, 'g'), v);\n    }\n    return out;\n  }\n}\n\nfunction escapeRegex(s: string): string {\n  return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n","/**\n * Prompt registry — one place to see, override, and localise every LLM\n * system prompt the SDK ships.\n *\n * Motivation. Before this file, prompts lived inline in ~10 subsystem\n * modules (webagent narrator, planner, InlineAgent, markdown-edit,\n * immersive-translate, voice-cleanup, Dwell classifier, task runner).\n * A host that wanted \"Japanese prompts\" or \"no persona line\" had to\n * spelunk each module. The registry consolidates all defaults behind\n * stable IDs and gives hosts three levers:\n *\n *   - `override(id, locale, render)` — full replace for one locale.\n *   - `append(id, render)`           — extra content stitched on the end.\n *   - `list()` / `has(id)`           — introspection.\n *\n * Locale fallback. `render(id, ctx, locale)` prefers a locale-specific\n * override, falls back to the `'en'` override, then to the SDK-registered\n * default. So a host can localise EN + zh-TW + ja without touching the\n * defaults for locales they don't care about.\n *\n * Non-goals. The registry does NOT parse or execute the prompt; it just\n * assembles the string. Runtime message plumbing (system role, temp,\n * tool schemas) stays in the subsystem callsites.\n */\n\n/**\n * A prompt renderer. Receives an arbitrary context object (subsystem-\n * specific — e.g. the WebAgent narrator gets `PromptContext` with brand\n * + persona + sitemap; the InlineAgent gets nothing) and the effective\n * locale. Returns the full system prompt string.\n */\nexport type PromptRender<Ctx = unknown> = (ctx: Ctx, locale: string) => string;\n\n/**\n * Stable IDs for every prompt the SDK ships. Consumers reference these\n * by string via the registry so hosts can override without importing\n * subsystem internals. Add here when introducing a new prompt.\n */\nexport const PROMPT_IDS = {\n  /** InlineAgent — replaces a text fragment inside a longer body. */\n  INLINE_EDIT: 'inline-edit.system',\n  /** Markdown-doc edit tool (used by Plan runner). */\n  MARKDOWN_EDIT: 'markdown-edit.system',\n  /** Voice STT cleanup — turns raw transcript into polished prose. */\n  VOICE_CLEANUP: 'voice-cleanup.system',\n  /** Immersive-translate — inline machine translation of visible copy. */\n  TRANSLATE: 'translate.system',\n  /** Dwell classifier — labels the long-pressed element + suggests actions. */\n  DWELL_CLASSIFY: 'dwell-classify.system',\n  /** Planner — writes the CoT / task plan for the WebAgent to execute. */\n  PLANNER: 'planner.system',\n  /** WebAgent narrator — the huge everything-prompt for the agentic loop. */\n  WEBAGENT_NARRATOR: 'webagent-narrator.system',\n  /** WebAgent CoT variant — thinking-mode narrator. */\n  WEBAGENT_COT: 'webagent-cot.system',\n  /** Task runner — free-form task execution prompt (host-supplied by default). */\n  TASK: 'task.system',\n} as const;\n\nexport type PromptId = (typeof PROMPT_IDS)[keyof typeof PROMPT_IDS];\n\n/** Fallback locale when a specific locale has no override. */\nconst FALLBACK_LOCALE = 'en';\n\nexport class PromptRegistry {\n  private defaults = new Map<string, PromptRender>();\n  private overrides = new Map<string, Map<string, PromptRender>>();\n  private appenders = new Map<string, PromptRender[]>();\n\n  /**\n   * Register the SDK-shipped default for a prompt id. Called at module\n   * init by the subsystem that owns the prompt (see `./defaults.ts`).\n   * Hosts typically don't call this — they use `override()` instead.\n   */\n  registerDefault<Ctx = unknown>(id: string, render: PromptRender<Ctx>): void {\n    this.defaults.set(id, render as PromptRender);\n  }\n\n  /**\n   * Replace the SDK default for one locale. Later calls with the same\n   * `(id, locale)` win — hosts can rebind at runtime (e.g. after the\n   * user changes site language).\n   *\n   * @example\n   *   dddk.prompts.override('inline-edit.system', 'ja', () => `あなたは…`);\n   */\n  override<Ctx = unknown>(id: string, locale: string, render: PromptRender<Ctx>): void {\n    let localeMap = this.overrides.get(id);\n    if (!localeMap) {\n      localeMap = new Map();\n      this.overrides.set(id, localeMap);\n    }\n    localeMap.set(locale, render as PromptRender);\n  }\n\n  /**\n   * Append extra content on the end of the resolved prompt. Runs for\n   * every locale — good for site-wide reminders (\"always cite sources\",\n   * \"never mention pricing\") that shouldn't require re-writing the\n   * whole prompt. Multiple `append()` calls stack in registration order.\n   */\n  append<Ctx = unknown>(id: string, extra: PromptRender<Ctx>): void {\n    let list = this.appenders.get(id);\n    if (!list) {\n      list = [];\n      this.appenders.set(id, list);\n    }\n    list.push(extra as PromptRender);\n  }\n\n  /**\n   * Resolve a prompt id to its final string. Order of preference:\n   *   1. `override(id, locale)` — exact locale match\n   *   2. `override(id, 'en')`   — English fallback\n   *   3. `registerDefault(id)`  — SDK default\n   * All matching `append()` extras are joined on with double-newlines.\n   */\n  render<Ctx = unknown>(id: string, ctx?: Ctx, locale: string = FALLBACK_LOCALE): string {\n    const localeMap = this.overrides.get(id);\n    const render =\n      localeMap?.get(locale)\n      ?? localeMap?.get(FALLBACK_LOCALE)\n      ?? this.defaults.get(id);\n    if (!render) {\n      throw new Error(\n        `[dddk] No prompt registered for id '${id}'. `\n        + `Registered ids: ${this.list().join(', ') || '(none)'}. `\n        + `Register via dddk.prompts.registerDefault(id, render) or dddk.prompts.override(id, locale, render).`,\n      );\n    }\n    const base = render(ctx as unknown, locale);\n    const extras = this.appenders.get(id) ?? [];\n    if (extras.length === 0) return base;\n    return extras.reduce(\n      (acc, fn) => `${acc}\\n\\n${fn(ctx as unknown, locale)}`,\n      base,\n    );\n  }\n\n  /** Is there any renderer (default or override) for this id? */\n  has(id: string): boolean {\n    return this.defaults.has(id) || this.overrides.has(id);\n  }\n\n  /** All registered ids, sorted for stable output. */\n  list(): string[] {\n    const ids = new Set<string>();\n    for (const id of this.defaults.keys()) ids.add(id);\n    for (const id of this.overrides.keys()) ids.add(id);\n    return Array.from(ids).sort();\n  }\n\n  /**\n   * Drop all overrides + appenders for one id. Does NOT touch the\n   * default — that stays as the SDK shipped it. Useful for test setup /\n   * \"reset to defaults\" UI in a host tuning tool.\n   */\n  reset(id: string): void {\n    this.overrides.delete(id);\n    this.appenders.delete(id);\n  }\n}\n\n/**\n * Process-wide singleton. Subsystems reach for this at module-init to\n * register their defaults so consumers can override without needing a\n * DotDotDuck instance in hand. The DotDotDuck constructor also exposes\n * this same singleton as `.prompts` for the more idiomatic path.\n */\nexport const promptRegistry = new PromptRegistry();\n","/**\n * Helpers for parsing LLM output.\n *\n * Models love to wrap structured replies in ```json ... ``` fences even when\n * the system prompt explicitly forbids it. Rather than scatter a slightly-\n * different regex through every module, we centralize here.\n */\n\n/**\n * Strip leading/trailing markdown code fences (with optional language tag) and\n * whitespace. Leaves the inner content untouched.\n *\n * Examples:\n *   \"```json\\n{\\\"a\\\":1}\\n```\"  -> '{\"a\":1}'\n *   \"```\\n{}\\n```\"               -> '{}'\n *   \"{\\\"a\\\":1}\"                  -> '{\"a\":1}'\n */\nexport function stripCodeFence(s: string): string {\n  return s\n    .replace(/^\\s*```(?:[a-zA-Z0-9_-]+)?\\s*\\n?/i, '')\n    .replace(/```\\s*$/i, '')\n    .trim();\n}\n\n/**\n * Parse JSON, returning `null` on failure instead of throwing. Optionally\n * strips code fences first — convenient when feeding raw LLM completions.\n */\nexport function safeJsonParse<T = unknown>(s: string, { stripFence = true } = {}): T | null {\n  try {\n    return JSON.parse(stripFence ? stripCodeFence(s) : s) as T;\n  } catch {\n    return null;\n  }\n}\n","/**\n * LLM-output parsing helpers for InlineAgent.\n * The system prompt is also here — keeping prompt + parser in one place makes\n * it easier to update them together when tuning the contract.\n */\n\nimport { stripCodeFence } from '../../utils/llm-parse';\n\n/**\n * System prompt — strict edit-file style. The model gets the FULL surrounding\n * text (so it understands the context) and the marked fragment, but its\n * job is only to write the replacement for the fragment. We apply via\n * splice at the known character offsets — no fuzzy matching, no leakage.\n */\nexport const SYSTEM_PROMPT = `You are an inline editing assistant. The user highlighted a fragment INSIDE a longer text and gave an instruction. You see the full text (for context) and the fragment (delimited by [[SEL]] / [[/SEL]] markers).\n\nYour ONLY job is to compute the new text that should replace the fragment between the markers. You DO NOT need to think out loud, plan, or analyse — the model is being used as a fast text-edit operator, not a reasoning agent.\n\nLanguage rule: detect the language of the surrounding text and write the replacement in the SAME language, unless the instruction explicitly requests another language (e.g. \"translate to Japanese\"). This applies to any human language — English, Traditional Chinese, Japanese, Spanish, Arabic, etc.\n\nOutput format — wrap the new fragment text inside a single <replacement>…</replacement> XML tag. Nothing outside the tag: no prose, no JSON, no code fences.\n\n<replacement>the new fragment text</replacement>\n\nThe text inside the tag replaces the original fragment between [[SEL]] and [[/SEL]]. Keep punctuation and whitespace clean. Stream-friendly: the runtime begins inserting your text into the user's input the moment the opening <replacement> tag closes, character by character; don't put leading newlines inside the tag unless they belong in the replacement.`;\n\nexport const REPLACEMENT_START = '<replacement>';\nexport const REPLACEMENT_END = '</replacement>';\n\n/**\n * End-marker variants the streaming parser accepts. The canonical form\n * is `</replacement>` — a plain XML close tag that every model handles\n * reliably because it matches HTML/XML training data. The extras below\n * are legacy from the previous `<<<END>>>` prompt: kept so proxies\n * with cached responses still parse, but new prompts drive the XML\n * form and won't emit them.\n */\nexport const REPLACEMENT_END_VARIANTS: readonly string[] = [\n  '</replacement>',\n  '<< /replacement >>',       // rare stylistic variant\n  // Legacy end markers from the old `<<<END>>>` prompt format. Kept\n  // for back-compat while cached responses cycle out.\n  '<<<END>>>',\n  '<<</REPLACEMENT>>>',\n  '[[/REPLACEMENT>>>',\n  '[[/REPLACEMENT/>>>',\n  '[[/REPLACEMENT]]',\n  '<<<REPLACEMENT/>>>',\n  '<<<END_REPLACEMENT>>>',\n  '<<</END>>>',\n  '[[/SEL]]',\n];\n\n/**\n * Catch-all pattern for any marker shape the enumerated list missed.\n * Handles both the canonical XML close (`</replacement>`) and any\n * legacy bracket-word-bracket hybrid a cached-response proxy might\n * still return. Any combination of `<`/`<<<`/`[[` opener + optional\n * slashes + `replacement`/`end`/`sel` word (case-insensitive) +\n * optional slashes + `>`/`>>>`/`]]` closer counts as an end marker.\n */\nconst END_MARKER_FALLBACK_RE = /(?:<{1,3}|\\[\\[)\\s*\\/?\\s*(?:replacement|end|sel)\\s*\\/?\\s*(?:>{1,3}|\\]\\])/i;\n\n/** Scan `text` for the earliest end-marker variant. Returns the match\n *  position and the matched marker's length, or null if none. */\nexport function findEndMarker(text: string): { idx: number; len: number } | null {\n  let best: { idx: number; len: number } | null = null;\n  for (const m of REPLACEMENT_END_VARIANTS) {\n    const idx = text.indexOf(m);\n    if (idx >= 0 && (best === null || idx < best.idx)) {\n      best = { idx, len: m.length };\n    }\n  }\n  // Regex fallback — only kicks in if none of the enumerated variants\n  // matched. Guarantees any bracket-word-bracket combo terminates the\n  // stream instead of leaking.\n  if (best === null) {\n    const m = END_MARKER_FALLBACK_RE.exec(text);\n    if (m) best = { idx: m.index, len: m[0].length };\n  }\n  return best;\n}\n\n/**\n * Extract the replacement payload from the model's marker-wrapped\n * response. Resilient to:\n *   - extra whitespace / newlines around the markers\n *   - markers missing entirely (model ignored format → use raw text)\n *   - legacy JSON format from earlier prompts (parse and extract)\n *   - code-fenced output from a chatty model\n */\nexport function extractReplacement(raw: string): string {\n  const trimmed = stripCodeFence(raw);\n  const startIdx = trimmed.indexOf(REPLACEMENT_START);\n  if (startIdx >= 0) {\n    const after = trimmed.slice(startIdx + REPLACEMENT_START.length);\n    const end = findEndMarker(after);\n    const body = end !== null ? after.slice(0, end.idx) : after;\n    return trimMarkerEdges(body);\n  }\n  // Legacy JSON fallback (in case any caller still sends old SYSTEM_PROMPT).\n  try {\n    const obj = JSON.parse(trimmed);\n    if (obj && typeof obj.replacement === 'string') return obj.replacement;\n  } catch { /* fall through */ }\n  const m = /\"replacement\"\\s*:\\s*\"((?:[^\"\\\\]|\\\\.)*)\"/.exec(trimmed);\n  if (m) {\n    try {\n      return JSON.parse(`\"${m[1]}\"`);\n    } catch { /* … */ }\n  }\n  const out = trimmed.replace(/^(here'?s|here is|sure[,!]?|certainly[,!]?)\\b[^\\n]*\\n+/i, '');\n  // Belt for the no-start-marker fallback path: if the model echoed any of\n  // the SEL input markers (or REPLACEMENT_END variant) without ever opening\n  // <<<REPLACEMENT>>>, strip them so they don't leak into the editable.\n  return stripStrayMarkers(out).trim();\n}\n\nfunction stripStrayMarkers(s: string): string {\n  let out = s.replace(/\\[\\[\\/?SEL\\]\\]/g, '');\n  for (const m of REPLACEMENT_END_VARIANTS) {\n    out = out.split(m).join('');\n  }\n  out = out.split(REPLACEMENT_START).join('');\n  // Regex fallback — sweeps any leftover bracket-word-bracket combos\n  // the enumerated list missed.\n  out = out.replace(new RegExp(END_MARKER_FALLBACK_RE.source, 'g'), '');\n  return out;\n}\n\n/** Strip the single leading + trailing newline the marker format\n *  encourages (each marker on its own line) without nuking meaningful\n *  whitespace inside the body. */\nfunction trimMarkerEdges(s: string): string {\n  let out = s;\n  if (out.startsWith('\\r\\n')) out = out.slice(2);\n  else if (out.startsWith('\\n')) out = out.slice(1);\n  if (out.endsWith('\\r\\n')) out = out.slice(0, -2);\n  else if (out.endsWith('\\n')) out = out.slice(0, -1);\n  return out;\n}\n\n/** Slice a \"context window\" around the selection — up to ~CONTEXT_CHARS\n *  before and after — so the LLM understands the surrounding meaning\n *  without us shipping multi-megabyte textareas. */\nconst CONTEXT_CHARS = 400;\n\nexport function buildContextPrompt(fullText: string, selStart: number, selEnd: number): string {\n  const ctxStart = Math.max(0, selStart - CONTEXT_CHARS);\n  const ctxEnd = Math.min(fullText.length, selEnd + CONTEXT_CHARS);\n  const head = fullText.slice(ctxStart, selStart);\n  const sel = fullText.slice(selStart, selEnd);\n  const tail = fullText.slice(selEnd, ctxEnd);\n  const truncatedBefore = ctxStart > 0 ? '…' : '';\n  const truncatedAfter = ctxEnd < fullText.length ? '…' : '';\n  return `${truncatedBefore}${head}[[SEL]]${sel}[[/SEL]]${tail}${truncatedAfter}`;\n}\n","/**\n * Markdown artifact — in-memory CRUD for `MarkdownDoc`s. Not used by the\n * webagent loop; exposed so hosts can build LLM-mediated authoring\n * surfaces (meeting notes, drafts, KB articles) on top of the same\n * Plan instance / storage adapter.\n *\n * Two edit paths:\n *   - `edit(id, content)` — direct overwrite (host-driven, no LLM)\n *   - `editWithInstruction(id, instruction)` — LLM-mediated rewrite; uses\n *     the Plan instance's LLM. Returns the new doc.\n *\n * `id` scheme matches `TodosArtifact` — short stable `m1`, `m2`, ...\n */\n\nimport type { LLMProvider } from '../llm/types';\nimport type { MarkdownDoc } from './types';\nimport { PROMPT_IDS, promptRegistry } from '../../prompts/registry';\nimport { registerBuiltinPrompts } from '../../prompts/defaults';\n\nregisterBuiltinPrompts();\n\n/**\n * Markdown-edit system prompt. Exported so the SDK-wide `promptRegistry`\n * (see `src/prompts/defaults.ts`) can register it as the default under\n * id `markdown-edit.system`. Hosts override per-locale via\n * `dddk.prompts.override('markdown-edit.system', locale, render)`.\n */\nexport const MARKDOWN_EDIT_SYSTEM_PROMPT = `You are a markdown editing assistant. The user provides the current document and an instruction. Rewrite the document to satisfy the instruction. Reply with ONLY the new markdown content — no surrounding prose, no code fences, no commentary. Preserve sections / formatting the instruction did not touch.`;\n\nexport interface MarkdownArtifactOptions {\n  /** LLM provider used for `editWithInstruction`. Optional — without it\n   *  the LLM-mediated edit method throws. Direct `edit()` always works. */\n  llm?: LLMProvider;\n  /** Optional change hook. Fires after every mutation with the new list. */\n  onChange?: (docs: MarkdownDoc[]) => void;\n  /** Seed docs — used when restoring from a storage adapter. */\n  initial?: MarkdownDoc[];\n  initialIdCounter?: number;\n}\n\nexport class MarkdownArtifact {\n  private docs: MarkdownDoc[] = [];\n  private idCounter: number;\n  private readonly llm?: LLMProvider;\n  private readonly onChange?: (docs: MarkdownDoc[]) => void;\n\n  constructor(opts: MarkdownArtifactOptions = {}) {\n    this.llm = opts.llm;\n    this.onChange = opts.onChange;\n    this.docs = [...(opts.initial ?? [])];\n    this.idCounter = opts.initialIdCounter ?? this.docs.length;\n  }\n\n  list(): MarkdownDoc[] {\n    return this.docs.map((d) => ({ ...d }));\n  }\n\n  read(id: string): MarkdownDoc | null {\n    const found = this.docs.find((d) => d.id === id);\n    return found ? { ...found } : null;\n  }\n\n  create(input: { title: string; content: string }): MarkdownDoc {\n    const id = `m${++this.idCounter}`;\n    const doc: MarkdownDoc = { id, title: input.title, content: input.content, updatedAt: Date.now() };\n    this.docs.push(doc);\n    this.notify();\n    return { ...doc };\n  }\n\n  /** Direct overwrite — host knows what content to write. */\n  edit(id: string, patch: Partial<{ title: string; content: string }>): MarkdownDoc | null {\n    const idx = this.docs.findIndex((d) => d.id === id);\n    if (idx < 0) return null;\n    const next: MarkdownDoc = { ...this.docs[idx]!, ...patch, updatedAt: Date.now() };\n    this.docs[idx] = next;\n    this.notify();\n    return { ...next };\n  }\n\n  /** LLM-mediated rewrite — pass an instruction, the model returns new\n   *  content. Throws if no LLM was configured. */\n  async editWithInstruction(id: string, instruction: string): Promise<MarkdownDoc | null> {\n    if (!this.llm) {\n      throw new Error('MarkdownArtifact: editWithInstruction requires an LLM provider at construct time');\n    }\n    const doc = this.docs.find((d) => d.id === id);\n    if (!doc) return null;\n    const result = await this.llm.complete({\n      messages: [\n        { role: 'system', content: promptRegistry.render(PROMPT_IDS.MARKDOWN_EDIT, undefined, 'en') },\n        { role: 'user', content: `# Current document\\n\\n${doc.content}\\n\\n# Instruction\\n\\n${instruction}` },\n      ],\n      thinking: 'off',\n      temperature: 0.2,\n    });\n    return this.edit(id, { content: result.content.trim() });\n  }\n\n  delete(id: string): boolean {\n    const before = this.docs.length;\n    this.docs = this.docs.filter((d) => d.id !== id);\n    const removed = this.docs.length < before;\n    if (removed) this.notify();\n    return removed;\n  }\n\n  serialize(): { docs: MarkdownDoc[]; idCounter: number } {\n    return {\n      docs: this.docs.map((d) => ({ ...d })),\n      idCounter: this.idCounter,\n    };\n  }\n\n  private notify(): void {\n    if (this.onChange) this.onChange(this.list());\n  }\n}\n","/**\n * Immersive-translate system prompt. Extracted into its own file so the\n * central prompt registry (`src/prompts/defaults.ts`) can import it\n * without pulling in the whole translate module.\n *\n * Override at runtime:\n *   dddk.prompts.override('translate.system', 'ja', () => `あなたは翻訳エンジンです…`);\n */\nexport const TRANSLATE_SYSTEM_PROMPT = `You are a translation engine. The user gives you a JSON array of strings (one source paragraph per element). Return an object \\`{\"translations\": [...]}\\` where \\`translations\\` is an array of EXACTLY THE SAME LENGTH as the input, and index N is the translation of input[N] into the requested target language.\n\nABSOLUTE RULES:\n- Output ONLY the JSON object \\`{\"translations\": [...]}\\`. No markdown code fences. No commentary.\n- Preserve inline tags like <a>, <strong>, <em>, <code>, <span> verbatim and around the same content.\n- Do NOT add bullets / numbering that weren't in the source.\n- Keep numbers, dates, URLs, and proper nouns (especially product/brand names) as-is unless they have an established translation.\n- If a paragraph contains only a code snippet, a URL, or pure symbols, return it unchanged.`;\n","/**\n * Voice STT cleanup prompt. Extracted into its own file so the central\n * prompt registry can import it without pulling in the voice runtime.\n *\n * The runtime concatenates an optional language hint on the end (see\n * `voice.ts:640-641`), so the registered default is the STATIC portion\n * only. Override the whole thing via:\n *   dddk.prompts.override('voice-cleanup.system', 'ja', () => `…`);\n * — or keep the default and use `dddk.prompts.append(...)` for site-\n * specific reminders.\n */\nexport const VOICE_CLEANUP_SYSTEM_PROMPT = `You are a speech-to-text post-processor.\n\nRules:\n- Detect the language(s) of the transcript and ALWAYS reply in the SAME language(s). If the speaker mixes multiple languages, preserve all of them — do not translate.\n- Add correct punctuation and capitalisation appropriate to the detected language.\n- Remove filler words (the equivalents of \"um\", \"uh\", \"you know\", \"like\", \"I mean\" in the speaker's language).\n- Fix obvious homophone errors.\n- Handle self-corrections: when the speaker corrects themselves mid-utterance (any phrasing equivalent to \"X — no wait, Y\" / \"X, I mean Y\" / \"make it X, actually Y\"), keep ONLY the final intended meaning and drop the misspoken part.\n- Preserve the speaker's original tone and register — do not rewrite into formal style.\n- Output the cleaned transcript ONLY. No preface, no explanation, no surrounding quotes, no markdown.`;\n","/**\n * Dwell classifier system prompt. Extracted into its own file so the\n * central prompt registry can import it without pulling in the Dwell\n * runtime.\n *\n * Override at runtime:\n *   dddk.prompts.override('dwell-classify.system', 'ja', () => `…`);\n */\nexport const DWELL_CLASSIFY_SYSTEM_PROMPT = `You are a Dwell assistant. The user long-pressed an HTML element.\nReturn a tight JSON description:\n\n{\n  \"label\": \"<3-7 word semantic label, eg. 'Refund button for order ORD-1002'>\",\n  \"actions\": [\"<action 1>\", \"<action 2>\", \"<action 3>\"]\n}\n\nActions are short imperatives the user might want to do with this element\n(eg. \"Refund\", \"Copy order ID\", \"Open customer profile\"). Max 3 actions.\nReply with JSON only, no prose, no markdown fences.`;\n","/**\n * Sitemap traversal + LLM-friendly serialization helpers.\n */\n\nimport type { SitemapNode, SitemapResolution } from './types';\n\n/**\n * Render the sitemap as an indented outline an LLM can read efficiently.\n * Marks auth-gated pages, lists actions, shows dynamic segments as \":param\".\n *\n * Example output:\n *   /                    Home — landing page\n *     /orders            Orders — list of orders\n *       actions: view, export, filter\n *       /:id             Order detail [auth]\n *         actions: refund, ship, cancel\n *       /new             New order [auth]\n *     /billing           Billing [auth]\n */\nexport function serializeSitemap(root: SitemapNode, options: { rootPath?: string } = {}): string {\n  const lines: string[] = [];\n  walk(root, options.rootPath ?? '/', 0, lines);\n  return lines.join('\\n');\n}\n\nfunction walk(node: SitemapNode, path: string, depth: number, out: string[]): void {\n  if (node.hidden) return;\n\n  const indent = '  '.repeat(depth);\n  const flags: string[] = [];\n  if (node.requiresAuth) flags.push('auth');\n  if (node.requiresAdmin) flags.push('admin');\n  const flagStr = flags.length ? ` [${flags.join(',')}]` : '';\n\n  out.push(`${indent}${path.padEnd(30 - depth * 2)} ${node.title}${flagStr}${node.description ? ` — ${node.description}` : ''}`);\n\n  if (node.actions && node.actions.length > 0) {\n    out.push(`${indent}  actions: ${node.actions.join(', ')}`);\n  }\n  if (node.notes) {\n    out.push(`${indent}  note: ${node.notes}`);\n  }\n  if (node.keywords && node.keywords.length > 0) {\n    out.push(`${indent}  keywords: ${node.keywords.join(', ')}`);\n  }\n\n  if (node.children) {\n    for (const [segment, child] of Object.entries(node.children)) {\n      const childPath = path === '/' ? `/${segment}` : `${path}/${segment}`;\n      walk(child, childPath, depth + 1, out);\n    }\n  }\n}\n\n/**\n * Resolve a concrete URL path against the sitemap.\n * Supports `:param` segments matching any value.\n */\nexport function resolvePath(root: SitemapNode, targetPath: string): SitemapResolution | null {\n  const segments = targetPath.replace(/^\\/+|\\/+$/g, '').split('/').filter(Boolean);\n  return resolveSegments(root, '/', segments, {});\n}\n\nfunction resolveSegments(\n  node: SitemapNode,\n  currentPath: string,\n  remaining: string[],\n  params: Record<string, string>\n): SitemapResolution | null {\n  if (remaining.length === 0) {\n    return { path: currentPath, node, params };\n  }\n  if (!node.children) return null;\n\n  const [head, ...tail] = remaining;\n  if (!head) return null;\n\n  // Try exact match first — but allow backtracking to param match if the\n  // exact-match subtree doesn't resolve the remainder.\n  const exact = node.children[head];\n  if (exact) {\n    const next = currentPath === '/' ? `/${head}` : `${currentPath}/${head}`;\n    const exactResult = resolveSegments(exact, next, tail, params);\n    if (exactResult) return exactResult;\n  }\n\n  // Try param matches — multiple param siblings are possible; try each.\n  for (const [segment, child] of Object.entries(node.children)) {\n    if (segment.startsWith(':')) {\n      const paramName = segment.slice(1);\n      const next = currentPath === '/' ? `/${head}` : `${currentPath}/${head}`;\n      const result = resolveSegments(child, next, tail, { ...params, [paramName]: head });\n      if (result) return result;\n    }\n  }\n\n  return null;\n}\n\n/**\n * Find nodes whose `title`, `description`, or `keywords` fuzzy-match a query.\n * Returns sorted by path depth (shallower first).\n */\nexport function searchSitemap(\n  root: SitemapNode,\n  query: string\n): SitemapResolution[] {\n  const lower = query.toLowerCase();\n  const matches: Array<SitemapResolution & { depth: number }> = [];\n\n  function visit(node: SitemapNode, path: string, depth: number, params: Record<string, string>) {\n    if (node.hidden) return;\n    const haystack = [\n      node.title,\n      node.description ?? '',\n      ...(node.keywords ?? []),\n    ].join(' ').toLowerCase();\n    if (haystack.includes(lower)) {\n      matches.push({ path, node, params, depth });\n    }\n    if (node.children) {\n      for (const [seg, child] of Object.entries(node.children)) {\n        const childPath = path === '/' ? `/${seg}` : `${path}/${seg}`;\n        visit(child, childPath, depth + 1, params);\n      }\n    }\n  }\n\n  visit(root, '/', 0, {});\n  matches.sort((a, b) => a.depth - b.depth);\n  return matches.map(({ depth, ...m }) => m);\n}\n\n/** List all auth-gated paths in the tree (so agent can warn/login first). */\nexport function listAuthGatedPaths(root: SitemapNode): string[] {\n  const out: string[] = [];\n  function visit(node: SitemapNode, path: string) {\n    if (node.requiresAuth || node.requiresAdmin) out.push(path);\n    if (node.children) {\n      for (const [seg, child] of Object.entries(node.children)) {\n        const next = path === '/' ? `/${seg}` : `${path}/${seg}`;\n        visit(child, next);\n      }\n    }\n  }\n  visit(root, '/');\n  return out;\n}\n\n/**\n * Template — a starter SaaS sitemap structure. Host copies + customizes.\n * Covers most common shape: marketing root, auth gate, dashboard, settings,\n * a resource list+detail+new pattern, billing.\n */\nexport const SAAS_SITEMAP_TEMPLATE: SitemapNode = {\n  title: 'Home',\n  description: 'Marketing / landing page',\n  children: {\n    'login': { title: 'Sign in', description: 'Login page' },\n    'signup': { title: 'Sign up', description: 'Create an account' },\n    'dashboard': {\n      title: 'Dashboard',\n      description: 'Main app entry after login',\n      requiresAuth: true,\n      actions: ['view'],\n    },\n    'orders': {\n      title: 'Orders',\n      description: 'List of orders',\n      requiresAuth: true,\n      actions: ['view', 'filter', 'export'],\n      children: {\n        'new': { title: 'New order', requiresAuth: true, actions: ['create'] },\n        ':id': {\n          title: 'Order detail',\n          requiresAuth: true,\n          actions: ['view', 'edit', 'cancel', 'refund', 'ship'],\n        },\n      },\n    },\n    'settings': {\n      title: 'Settings',\n      requiresAuth: true,\n      children: {\n        'profile': { title: 'Profile', requiresAuth: true, actions: ['edit'] },\n        'team': { title: 'Team', requiresAuth: true, requiresAdmin: true },\n        'billing': {\n          title: 'Billing',\n          requiresAuth: true,\n          requiresAdmin: true,\n          actions: ['view', 'upgrade', 'cancel'],\n        },\n        'api-keys': {\n          title: 'API keys',\n          requiresAuth: true,\n          requiresAdmin: true,\n          actions: ['view', 'create', 'revoke'],\n        },\n      },\n    },\n  },\n};\n","/**\r\n * System prompt assembly — narrator persona.\r\n *\r\n * Override layers (most → least common):\r\n *   1. `brand` — structured fields (productName / voice / constraints[])\r\n *   2. `appendSystemPrompt` — plain string appended to default\r\n *   3. `systemPrompt` as function — receives default + ctx\r\n *   4. `systemPrompt` as string — hard replace\r\n */\r\n\r\nimport type { AgentSession, SitemapConfig, SitemapEntry, SelectionContext, AgentTurn } from './types';\r\nimport { serializeSitemap } from '../sitemap/helpers';\r\nimport type { SitemapNode } from '../sitemap/types';\r\n\r\nexport interface BrandPrompt {\r\n  productName?: string;\r\n  voice?: string;\r\n  constraints?: string[];\r\n}\r\n\r\n/** Persona — tells the agent who it speaks AS. Without this the agent\r\n *  narrates in third-person observer voice. */\r\nexport interface PersonaConfig {\r\n  /** First-person identity statement. Required. */\r\n  identity: string;\r\n  /** Voice / tone notes. */\r\n  voice?: string;\r\n  /** Hard rules the persona must never break. */\r\n  constraints?: string[];\r\n}\r\n\r\nexport type PersonaInput = string | PersonaConfig;\r\n\r\n/** Summary of one palette command — orchestrator passes the list so the\r\n *  agent sees host-registered commands in its system prompt. */\r\nexport interface PaletteCommandSummary {\r\n  id: string;\r\n  name: string;\r\n  description?: string;\r\n  prefix?: string;\r\n  section?: string;\r\n  acceptsArg?: boolean;\r\n}\r\n\r\nexport interface PromptContext {\r\n  locale?: string;\r\n  agentName: string;\r\n  siteName?: string;\r\n  sitemap?: SitemapConfig;\r\n  session: AgentSession;\r\n  pageContext: string;\r\n  selection?: SelectionContext;\r\n  brand?: BrandPrompt;\r\n  persona?: PersonaInput;\r\n  appendSystemPrompt?: string;\r\n  previousUrl?: string;\r\n  /** When true, render the CoT-mode prompt (no procedural rules, schema\r\n   *  enforces structure). When false, render the classic narrator prompt. */\r\n  cotMode?: boolean;\r\n  /** Pre-rendered tool reference (name + description + JSON Schema) for\r\n   *  every action exposed this turn. Pushed into the `# Tools` section\r\n   *  of the system prompt so the model sees the tool catalogue in one\r\n   *  place rather than buried inside the agent_turn tool description. */\r\n  toolReference?: string;\r\n}\r\n\r\nexport type SystemPromptOverride =\r\n  | string\r\n  | ((ctx: PromptContext, defaultPrompt: string) => string);\r\n\r\nexport interface AssemblePromptInput extends PromptContext {\r\n  systemPrompt?: SystemPromptOverride;\r\n}\r\n\r\nexport function assembleSystemPrompt(input: AssemblePromptInput): string {\r\n  const { systemPrompt, ...ctx } = input;\r\n  const defaultPrompt = renderDefault(ctx);\r\n  if (typeof systemPrompt === 'function') return systemPrompt(ctx, defaultPrompt);\r\n  if (typeof systemPrompt === 'string' && systemPrompt.length > 0) return systemPrompt;\r\n  return defaultPrompt;\r\n}\r\n\r\n// ─── default system prompt — narrator persona ─────────────────────────\r\n\r\nfunction renderDefault(ctx: PromptContext): string {\r\n  if (ctx.cotMode) return renderCotDefault(ctx);\r\n  const sections: string[] = [];\r\n  sections.push(renderHeader(ctx));\r\n  // Persona goes right after header so identity framing wins over\r\n  // downstream rules.\r\n  const personaBlock = renderPersona(ctx.persona, ctx.siteName);\r\n  if (personaBlock) sections.push(personaBlock);\r\n  sections.push(renderNarrationRules());\r\n  sections.push(renderSafety());\r\n  if (ctx.brand) sections.push(renderBrand(ctx.brand));\r\n  sections.push(renderOutputLanguage(ctx.locale));\r\n  if (ctx.appendSystemPrompt) sections.push(ctx.appendSystemPrompt);\r\n  return sections.filter(Boolean).join('\\n\\n');\r\n}\r\n\r\n/** CoT-mode system prompt. Two blocks: SDK default (identity / tools /\r\n *  envelope / DOM format) + host appendSystemPrompt. */\r\nfunction renderCotDefault(ctx: PromptContext): string {\r\n  const siteClause = ctx.siteName ? ` on ${ctx.siteName}` : '';\r\n  const sdkBlock: string[] = [];\r\n\r\n  const now = new Date();\r\n  const yyyy = now.getFullYear();\r\n  const mm = String(now.getMonth() + 1).padStart(2, '0');\r\n  const dd = String(now.getDate()).padStart(2, '0');\r\n  sdkBlock.push(`You are ${ctx.agentName}${siteClause}, an in-page assistant. Today is ${yyyy}-${mm}-${dd}.`);\r\n\r\n  const personaBlock = renderPersona(ctx.persona, ctx.siteName);\r\n  if (personaBlock) sdkBlock.push(personaBlock);\r\n\r\n  if (ctx.toolReference) {\r\n    sdkBlock.push(`# Tools\r\n\r\n${ctx.toolReference}`);\r\n  }\r\n\r\n  sdkBlock.push(`# Envelope\r\n\r\nEach turn calls \\`agent_turn\\` with these fields, IN THIS ORDER:\r\n- **memory** — private 1-2 sentence recap of the previous turn. Items already covered stay covered.\r\n- **turn_planning** — \\`{evaluation_previous_goal, next_goal}\\` in planned mode.\r\n- **todo_adjust** — \\`{remove, replace}\\` mutations to the master plan (planned mode).\r\n- **actions** — ordered steps for this turn. Each step is one of:\r\n  - \\`{tool, args}\\` — perform an action.\r\n  - \\`{narrate, about}\\` — speak a declarative sentence. \\`about\\` is the \\`[id]\\` of the element runtime auto-borders. ALMOST ALWAYS REQUIRED.\r\n- **is_final** — Boolean. Write this LAST, AFTER actions[] is fully written. Closes the run when true.`);\r\n\r\n  sdkBlock.push(`# Narrate + about\r\n\r\nNarrate without \\`about\\` is rare. Whenever you're talking ABOUT a chunk on the page — a card, a section, a row, a heading, a paragraph — pass that element's \\`[id]\\` from the DOM dump as \\`about\\`. The runtime auto-borders it so the user sees the framing as you speak. Skipping \\`about\\` makes the agent feel like a chat box, not a tour.\r\n\r\nOmit \\`about\\` only when the narrate genuinely refers to nothing visible (a meta closing line, a status update unrelated to any element).`);\r\n\r\n  sdkBlock.push(`# Navigate semantics\r\n\r\n\\`navigate\\` is the act itself — the user perceives the page change as the announcement. Do NOT precede or follow navigate with a narrate that re-states \"we'll go to X\" or \"we're now on X\". On the destination page (the NEXT turn after navigate, when the new DOM dump arrives), narrate about the actual content with \\`about\\` pointing at a real element.\r\n\r\nIf the navigate confirm copy needs to read in the user's voice, pass it via the navigate tool's optional \\`note\\` arg — that wording becomes the confirm message instead of the SDK default.`);\r\n\r\n  sdkBlock.push(`# User answers — never re-ask\r\n\r\nWhen \\`ask_user\\` / \\`ask_user_choice\\` / \\`pause\\` returns, the tool result carries the full context: \\`{ question, options?, answer, source }\\`. The user has already answered that exact question — re-asking it is a bug.\r\n\r\nNext turn after an ask_*, the memory line MUST mention the answer (\"user picked Pro from {Hobby, Pro, Enterprise}\"). turn_planning.evaluation_previous_goal MUST restate the answer in your own words before next_goal proposes the action that uses it. The next action must consume the answer, not re-elicit it.\r\n\r\nIf \\`source: 'cancelled'\\`, the user dismissed without picking. Treat as \"user does not want to clarify this branch\" — pick a sensible default or close the task. Do NOT pop the same picker again.`);\r\n\r\n  sdkBlock.push(`# Finishing\r\n\r\nSet \\`is_final: true\\` ONLY after the actions in this same turn fully cover the user's original ask. Once given, the task is over — no follow-up narrate restating the same thing, no closing summary, no \"anything else?\" question.\r\nRe-narrating something already covered is a bug, not thoroughness.\r\nDo NOT set is_final when this turn ran \\`navigate\\`, \\`ask_user_choice\\`, or any tool whose result the next turn must read — the run is not actually done yet.`);\r\n\r\n  sdkBlock.push(`# Language\r\n\r\nReply in the language of the user's latest message. The user, not the page and not the browser, decides the conversation language. Only fall back to a default when the user's input carries no language signal at all.`);\r\n\r\n  sdkBlock.push(`# DOM\r\n\r\nThe last user message carries the indexed DOM. \\`[id]\\` markers are stable per-element hashes — pass them as \\`selector\\` args. \\`↑\\`/\\`↓\\` markers mean above/below viewport.`);\r\n\r\n  const blocks: string[] = [sdkBlock.join('\\n\\n')];\r\n  if (ctx.appendSystemPrompt) blocks.push(ctx.appendSystemPrompt);\r\n  return blocks.join('\\n\\n');\r\n}\r\n\r\nfunction renderHeader(ctx: PromptContext): string {\r\n  const siteClause = ctx.siteName ? `, embedded in ${ctx.siteName}` : '';\r\n  return `You are ${ctx.agentName}${siteClause}. You guide the user around the page like a real tour host — walking them somewhere, framing what you're about to talk about, then explaining it in plain words.\r\n\r\nThe tool list (with names, descriptions, JSON schemas) is attached to this turn. Read it there.`;\r\n}\r\n\r\nfunction renderNarrationRules(): string {\r\n  return `# Your role\r\n\r\nYou are a real-time tour guide for the user's website. The user is on the page WITH you. They want a guide who knows where to look, knows what's worth pointing out, and knows when to shut up.\r\n\r\n# What the user wants from a turn\r\n\r\nThey want:\r\n- to be pointed AT something on the page (a \\`border\\` / \\`highlight\\` on a meaningful chunk), AND\r\n- to hear 1–3 short sentences about THAT chunk, streaming into the subtitle bar as you write them, AND\r\n- a beat (a \\`pause\\`) to read, before you move on.\r\n\r\nA turn that frames something without speaking is wrong. A turn that speaks without framing what it's talking about is wrong. The two come together.\r\n\r\n# What to point at\r\n\r\nWhole logical chunks, not individual rows or words. A pricing table is one subject (border the \\`<table>\\`, summarise the spread in two sentences) — not six subjects, one per row. A feature card is one subject. A section is one subject. Drop down to a single row / cell / line only when that specific row is the user's actual question. Reading order, top to bottom.\r\n\r\n# When to stop\r\n\r\nPages are finite. Cover the substantive content — usually two to four chunks for a typical page — then emit a single short closing sentence and no tool call. The loop ends. Asking \"next?\" once there's nothing distinctly new left is worse than ending cleanly.\r\n\r\n# Honesty about location\r\n\r\nThe DOM dump's URL line tells you where you ARE. If the user asked to go somewhere else and you haven't actually run \\`navigate\\`, run it first — don't narrate the destination's content from the wrong page. Same-named home-page section / card / link is a teaser, not the destination. Never claim to have arrived if the URL hasn't changed.\r\n\r\n# DOM dump\r\n\r\nEach turn you see a fresh dump:\r\n\r\n\\`\\`\\`\r\nURL: https://...\r\nTITLE: ...\r\nVIEWPORT: 240px above · 900px visible · 1820px below\r\n\r\n[ea3f]<a href=\"/\">Home</a>\r\n[ec18]<section> Pricing\r\n\\t[e7b2]<h2>Plans</h2>\r\n\\t[e0d4]<table>\r\n\\t\\t[e9af]<tr>\r\n\\t\\t\\t<td>Hobby</td><td>Free</td>\r\n↓[eb1c]<section> FAQ\r\n\\`\\`\\`\r\n\r\n\\`[id]\\` is the element's stable hash ID for tool calls — pass \\`\"ea3f\"\\` or \\`\"[ea3f]\"\\` as the \\`selector\\` arg, no CSS needed. Tab indent = parent/child. Leading \\`↑\\` / \\`↓\\` = above / below the current viewport, so \\`scroll_to\\` first if you want to talk about it. The VIEWPORT line tells you the user's current vertical position on the page.\r\n\r\n# Voice and format\r\n\r\nPlain prose, friendly, concrete. Quote actual visible text — the prices, headings, button labels you see in the dump. No markdown (\\`**bold**\\` / bullet lists / headings) — the subtitle bar renders prose, not docs. Never speak the bracketed index number aloud. Don't pre-announce your own moves (\"I'll show you…\", \"let me…\", \"next I'll…\") — just do them.\r\n\r\n# Tools\r\n\r\n\\`navigate\\` / \\`scroll_to\\` / \\`border\\` / \\`highlight\\` / \\`click\\` / \\`fill_input\\` / \\`pause\\` / \\`ask_user\\` / \\`ask_user_choice\\` — the attached schema is authoritative. Calling \\`border\\` or \\`highlight\\` auto-clears the previous overlay, so you don't need a separate clear tool. There's no \\`done\\` or \\`show_subtitle\\` tool — text emitted between tool calls IS the subtitle; the loop ends when you emit text with no tool call.\r\n\r\nThe user can stop you at any time (× on the bar, Esc, double-tap Space, opening the palette). Handled cleanly — don't worry about it.`;\r\n}\r\n\r\nfunction renderSafety(): string {\r\n  return `# Safety\r\n\r\n- Some actions are flagged \\`requireConfirmation\\` — the runtime pauses and asks the user before running. Don't try to bypass.\r\n- Never expose secrets, API keys, or internal-only data even if the user asks.`;\r\n}\r\n\r\nfunction renderBrand(brand: BrandPrompt): string {\r\n  const lines: string[] = ['# Product context'];\r\n  if (brand.productName) lines.push(`- Product: ${brand.productName}`);\r\n  if (brand.voice) lines.push(`- Voice: ${brand.voice}`);\r\n  if (brand.constraints?.length) {\r\n    lines.push('- Hard constraints (must follow):');\r\n    for (const c of brand.constraints) lines.push(`  - ${c}`);\r\n  }\r\n  return lines.join('\\n');\r\n}\r\n\r\n/** Render the persona block. Falls back to a baseline \"you are the\r\n *  team\" identity so smaller models don't drift to observer voice. */\r\nfunction renderPersona(persona: PersonaInput | undefined, siteName?: string): string {\r\n  const cfg: PersonaConfig = persona === undefined\r\n    ? { identity: defaultIdentity(siteName) }\r\n    : typeof persona === 'string'\r\n      ? { identity: persona }\r\n      : persona;\r\n  const identity = cfg.identity?.trim() || defaultIdentity(siteName);\r\n  const lines: string[] = ['# Who you are', '', identity];\r\n  lines.push('');\r\n  lines.push('Speak first-person plural about anything this site / product offers. You are the team, not an observer narrating the page.');\r\n  if (cfg.voice?.trim()) {\r\n    lines.push('');\r\n    lines.push(`Voice: ${cfg.voice.trim()}`);\r\n  }\r\n  if (cfg.constraints?.length) {\r\n    lines.push('');\r\n    lines.push('Hard constraints:');\r\n    for (const c of cfg.constraints) lines.push(`- ${c}`);\r\n  }\r\n  return lines.join('\\n');\r\n}\r\n\r\nfunction defaultIdentity(siteName?: string): string {\r\n  const site = siteName?.trim();\r\n  return site\r\n    ? `You are part of ${site} — the team that built and runs the product the user is on right now. You are not a tour guide. You are not narrating the page. You ARE the company, answering as we would answer a real customer.`\r\n    : 'You are part of the team that built and runs the product the user is on right now. You are not a tour guide. You are not narrating the page. You ARE the team, answering as we would answer a real customer.';\r\n}\r\n\r\n/** Append host palette commands to `run_palette`'s tool description so\r\n *  the model sees command ids at decision time. */\r\nexport function renderPaletteCommandsForToolDescription(items: PaletteCommandSummary[] | undefined): string {\r\n  if (!items || items.length === 0) return '';\r\n  const lines: string[] = ['', 'Registered palette commands:'];\r\n  for (const it of items) {\r\n    const desc = it.description ? ` — ${it.description}` : '';\r\n    const arg = it.acceptsArg ? ' (takes arg)' : '';\r\n    const prefix = it.prefix ? ` [${it.prefix}]` : '';\r\n    lines.push(`- ${it.name}${prefix}${arg}${desc}`);\r\n  }\r\n  lines.push('');\r\n  lines.push('After open, items appear in DOM dump — `click` the one that matches.');\r\n  return lines.join('\\n');\r\n}\r\n\r\nfunction renderOutputLanguage(locale?: string): string {\r\n  const hint = locale\r\n    ? `Host locale hint: \\`${locale}\\` — only a tiebreaker when input is ambiguous.`\r\n    : `Detect reply language from the user's first clear sentence.`;\r\n  return `# Language\r\n\r\nReply language = user's input language. ${hint} Page DOM language doesn't decide it.\r\n\r\nIf the user asks to translate / rewrite into a target language, the payload goes in THAT language; only the wrapper (\"here it is\") follows reply language.\r\n\r\n# Style\r\n\r\nPlain prose, conversational, no markdown, no emoji. Each narrate: 1–3 short sentences.`;\r\n}\r\n\r\n// ─── helpers used by webagent.buildMessages for the per-turn user msg ─\r\n\r\nconst MAX_SITEMAP_ENTRIES = 40;\r\nconst MAX_SITEMAP_TREE_CHARS = 3000;\r\n\r\nexport function renderSitemap(sitemap: SitemapConfig): string {\r\n  const header = '# Site map (hint — also follow links present on the current page)';\r\n  if (Array.isArray(sitemap)) {\r\n    const all = sitemap as SitemapEntry[];\r\n    const overflow = all.length > MAX_SITEMAP_ENTRIES;\r\n    const used = overflow ? all.slice(0, MAX_SITEMAP_ENTRIES) : all;\r\n    const lines = used.map((entry) => {\r\n      const aliases = entry.aliases?.length ? ` (aliases: ${entry.aliases.join(', ')})` : '';\r\n      return `- ${entry.path} — ${entry.description}${aliases}`;\r\n    });\r\n    if (overflow) lines.push(`- … (${all.length - MAX_SITEMAP_ENTRIES} more routes — follow on-page links)`);\r\n    return [header, ...lines].join('\\n');\r\n  }\r\n  const serialized = serializeSitemap(sitemap as SitemapNode);\r\n  const trimmed = serialized.length > MAX_SITEMAP_TREE_CHARS\r\n    ? serialized.slice(0, MAX_SITEMAP_TREE_CHARS) + '\\n… (sitemap truncated)'\r\n    : serialized;\r\n  return `${header}\\n${trimmed}`;\r\n}\r\n\r\nexport function renderSelectionBlock(sel: SelectionContext): string {\r\n  const parts: string[] = ['# User selection at invocation'];\r\n  parts.push(\r\n    \"The user pointed at this BEFORE invoking you — read its CONTENT to understand what they're asking about. Don't reflex-frame it with `border` just because it's referenced.\"\r\n  );\r\n  if (sel.text) parts.push(`- Selected content:\\n\"\"\"\\n${sel.text}\\n\"\"\"`);\r\n  if (sel.elements?.length) {\r\n    parts.push(`- Internal selector (tool calls only — never mention to user): ${sel.elements.join(', ')}`);\r\n    parts.push(`- If you DO need to act on the selected element, pass these selectors verbatim.`);\r\n  }\r\n  if (sel.bbox) parts.push(`- Selection bbox: ${JSON.stringify(sel.bbox)}`);\r\n  if (sel.images?.length) parts.push(`- ${sel.images.length} image(s) attached as visual context.`);\r\n  return parts.join('\\n');\r\n}\r\n\r\nexport function renderPageStateBlock(opts: {\r\n  currentPage: string;\r\n  pageContext: string;\r\n  plan?: import('../plan/types').TaskPlan;\r\n}): string {\r\n  const parts: string[] = [\r\n    '# Current page',\r\n    `- URL: ${opts.currentPage}`,\r\n  ];\r\n  if (opts.plan) {\r\n    parts.push('', renderMasterPlan(opts.plan));\r\n  }\r\n  parts.push('', '# Page DOM', opts.pageContext);\r\n  return parts.join('\\n');\r\n}\r\n\r\n/** Render the live master plan. Model anchors `turn_planning.next_goal`\r\n *  to a real id and emits `todo_adjust.remove` on completion. */\r\nfunction renderMasterPlan(plan: import('../plan/types').TaskPlan): string {\r\n  const lines: string[] = ['# Master plan'];\r\n  lines.push(`Task: ${plan.task_summary}`);\r\n  lines.push('Todos remaining (head first):');\r\n  for (const t of plan.todos) {\r\n    const turnHint = typeof t.expected_turn === 'number' ? ` [expected turn ${t.expected_turn}]` : '';\r\n    lines.push(`- ${t.id} (${t.intent}): ${t.description}${turnHint}`);\r\n  }\r\n  if (plan.todos.length === 0) {\r\n    lines.push('- (empty — set `is_final: true` and end the run)');\r\n  }\r\n  return lines.join('\\n');\r\n}\r\n\r\n/**\r\n * Re-inject the user's latest query as a system-reminder at the end of\r\n * the messages. Without this, after a couple of tool turns the model\r\n * tends to think the task is finished after the first clause —\r\n * especially when the first clause involves navigation. Re-stating the\r\n * original request keeps every clause in view.\r\n */\r\nexport function renderUserReminder(opts: {\r\n  latestUserText: string;\r\n  stepsSoFar: AgentTurn[];\r\n  currentUrl?: string;\r\n  cotMode?: boolean;\r\n}): string {\r\n  if (opts.cotMode) return renderCotReminder(opts);\r\n  const stepLines: string[] = [];\r\n  let pauseCount = 0;\r\n  let lastWasPause = false;\r\n  let navigatedThisRun = false;\r\n  let lastNavigateIdx = -1;\r\n  let borderHighlightAfterNav = 0;\r\n  for (let i = 0; i < opts.stepsSoFar.length; i++) {\r\n    const t = opts.stepsSoFar[i]!;\r\n    if (t.kind !== 'agent_step') continue;\r\n    const ok = t.result.ok ? '✓' : '✗';\r\n    stepLines.push(`- ${ok} ${t.toolCall.name}(${JSON.stringify(t.toolCall.arguments).slice(0, 80)})`);\r\n    if (t.toolCall.name === 'pause') pauseCount++;\r\n    lastWasPause = t.toolCall.name === 'pause';\r\n    if (t.toolCall.name === 'navigate' && t.result.ok) {\r\n      navigatedThisRun = true;\r\n      lastNavigateIdx = i;\r\n      borderHighlightAfterNav = 0;\r\n    }\r\n    if (lastNavigateIdx >= 0 && i > lastNavigateIdx && (t.toolCall.name === 'border' || t.toolCall.name === 'highlight')) {\r\n      borderHighlightAfterNav++;\r\n    }\r\n  }\r\n  const stepBlock = stepLines.length === 0\r\n    ? '(no tools executed yet)'\r\n    : stepLines.join('\\n');\r\n\r\n  // Derive pacing hint from the actual trace — concrete observation about\r\n  // THIS run feels less like nagging than a generic always-on rule.\r\n  let pacingHint = '';\r\n  if (stepLines.length >= 2 && pauseCount === 0) {\r\n    pacingHint = '\\nWatch your pacing: you have taken actions but never called `pause`. Each subject should end with a pause so the user presses Space to continue.';\r\n  } else if (navigatedThisRun && borderHighlightAfterNav === 0) {\r\n    // Just arrived at the destination. The agent's biggest failure mode\r\n    // here is to dump a summary paragraph and pause-close. Force the\r\n    // first post-arrival turn to actually start the subject-by-subject\r\n    // walkthrough.\r\n    pacingHint = '\\nYou just arrived at the destination — this is the first post-navigate turn. Do NOT write a summary paragraph and pause-close. Pick the FIRST subject on this page (the first `[N]<section>` / `[N]<article>` / `[N]<tr>` in reading order), `border` it, narrate 1–3 sentences about THAT subject (not the whole page), then `pause`. The next turn picks the next subject; at least 2 subjects total.';\r\n  } else if (pauseCount >= 3 && lastWasPause) {\r\n    // Already paused 3+ times — the page is finite and the model is\r\n    // looping. Push hard toward termination so the agent doesn't keep\r\n    // asking \"next?\" forever and start framing random elements just to\r\n    // produce something new.\r\n    pacingHint = '\\nYou have already paused 3+ times this run. Most pages have 3–5 main subjects; if you have covered the substantive content, STOP NOW. Emit one short closing sentence (not a recap, not \"is there anything else\") and NO tool call — the loop ends. Do NOT call `pause` again. Do NOT `border` a new element just to extend the conversation. Asking \"next?\" when you have nothing new to show is worse than ending cleanly.';\r\n  } else if (lastWasPause) {\r\n    pacingHint = '\\nLast step was `pause` and the user just pressed Space — move to the NEXT subject in reading order that you have NOT already discussed. Frame it first, narrate it in 1–3 sentences quoting actual page content, then `pause`. If there is no new subject left, stop instead: one closing sentence and no tool call.';\r\n  }\r\n\r\n  const urlLine = opts.currentUrl ? `\\nCurrent URL: ${opts.currentUrl}` : '';\r\n\r\n  return `<reminder>\r\nUser said: \"${opts.latestUserText}\"${urlLine}\r\nDone so far:\r\n${stepBlock}${pacingHint}\r\n\r\nSTEP 1 — Destination check (do this first, every turn, before anything else):\r\nDid the user name a destination on the site? Look at the sitemap routes. Does any route's path or description match that destination? If yes AND that route's URL is NOT the current URL above → your FIRST tool call this turn MUST be \\`navigate\\` to that route's path. Do NOT emit any text, do NOT border anything, do NOT call \\`pause\\` — just navigate. You are at the WRONG URL right now; every word of narration you would write describes a page the user isn't looking at.\r\n\r\nThe home-page section / card / button that shares the destination's name is a TEASER, not the destination. Do not treat its content as if you had arrived.\r\n\r\nNEVER say \"I brought you to X\" / \"Here at X\" / equivalent without an actually-successful navigate to X earlier this run. That is hallucination — the worst failure mode of this agent.\r\n\r\nSTEP 2 — Tour mode:\r\nIf the user's verb means explain / walk through / introduce / show me around, the task is a TOUR. After arriving at the destination, walk through it subject-by-subject — at least 2 separate subjects, each with (border or highlight) → 1–3 sentences → \\`pause\\`. Don't dump a one-paragraph summary of the page and call it done.\r\n\r\nPer-turn rules:\r\n- ONE subject per turn. Don't introduce multiple subjects in one paragraph.\r\n- Don't narrate your own behaviour (no \"I will\", \"I just\", \"let me\", \"to recap\").\r\n- Quote concrete words from the DOM dump — visible labels, prices, headings, descriptions.\r\n- NEVER frame an element you have already framed earlier this run. Look at the trace above — if you already \\`border\\`-ed it, move on or stop. Pages are finite.\r\n- Pause notes hint at the next beat (\"ready for the next?\"), not at finality.\r\n\r\nLoop control — when to STOP:\r\nThe page is finite. Once you have covered the main subjects of the user's request, STOP. Concretely:\r\n- Every clause of the user's message is addressed by a successful step, AND\r\n- A tour has covered at least 2 subjects, AND\r\n- There are no further distinct subjects on the page that you have not already discussed,\r\nthen emit one short closing sentence (NOT a recap, NOT a list of what you did) and NO tool call. The loop ends.\r\n\r\nDo NOT keep paginating with \\`pause\\` forever. Do NOT \\`border\\` a fresh element just to have something new to say. If the trace shows you have already paused many times and there is nothing distinctly new left, the correct move is to stop.\r\n\r\nLoop control — when to continue:\r\nOtherwise (still subjects to cover, or clauses not yet addressed): pick the next DISTINCT subject in reading order — one you have not already framed — narrate it, then \\`pause\\`.\r\n</reminder>`;\r\n}\r\n\r\n/**\r\n * CoT-mode per-turn reminder — small, context-only. Does NOT carry the\r\n * procedural rules from the classic reminder (no STEP 1 / STEP 2, no\r\n * pause-counting, no tour-mode prescription). Just re-grounds the model\r\n * on the user's question and surfaces concrete observations from this\r\n * run that should change the next action — chiefly repeated failures\r\n * on the same selector, so the model picks a different strategy.\r\n */\r\nfunction renderCotReminder(opts: {\r\n  latestUserText: string;\r\n  stepsSoFar: AgentTurn[];\r\n  currentUrl?: string;\r\n}): string {\r\n  // Walk recent agent_turn steps; collect per-action results from their\r\n  // result.data.action_results array (set by executeCotLoop). Track which\r\n  // (tool, selector) pairs have failed and how often, in the last N steps.\r\n  const failures: Map<string, number> = new Map();\r\n  const recentSteps: string[] = [];\r\n  let stepsSeen = 0;\r\n  for (let i = opts.stepsSoFar.length - 1; i >= 0 && stepsSeen < 6; i--) {\r\n    const t = opts.stepsSoFar[i]!;\r\n    if (t.kind !== 'agent_step') continue;\r\n    stepsSeen++;\r\n    if (!t.result.ok) continue;\r\n    const data = t.result.data as { action_results?: Array<{ type: string; name?: string; ok?: boolean; reason?: string }> } | undefined;\r\n    const results = data?.action_results;\r\n    if (!Array.isArray(results)) continue;\r\n    for (const r of results) {\r\n      if (r.type === 'tool' && r.ok === false && r.name) {\r\n        const key = r.name;\r\n        failures.set(key, (failures.get(key) ?? 0) + 1);\r\n      }\r\n      recentSteps.push(\r\n        r.type === 'narrate'\r\n          ? `narrate`\r\n          : `${r.name}${r.ok === false ? ` ✗ (${r.reason ?? 'failed'})` : ' ✓'}`,\r\n      );\r\n    }\r\n  }\r\n\r\n  // Stuck hint — only fire when a tool has failed 2+ times recently. Gives\r\n  // the model a concrete observation (not a generic \"be careful\") so it\r\n  // shifts strategy.\r\n  const stuck: string[] = [];\r\n  for (const [tool, count] of failures) {\r\n    if (count >= 2) stuck.push(`\\`${tool}\\` has failed ${count}× in recent turns`);\r\n  }\r\n  const stuckHint = stuck.length > 0\r\n    ? `\\n\\nObservation: ${stuck.join(', ')}. Do NOT retry the same call shape. Pick a different selector (parent / sibling / alternative target visible in the DOM dump), a different action (e.g. scroll into view first, or focus + Enter instead of click), or ask the user with \\`ask_user_choice\\` for clarification.`\r\n    : '';\r\n\r\n  const recentBlock = recentSteps.length > 0\r\n    ? `\\nRecent actions: ${recentSteps.slice(-12).join(' → ')}`\r\n    : '';\r\n  const urlLine = opts.currentUrl ? `\\nCurrent URL: ${opts.currentUrl}` : '';\r\n\r\n  return `<reminder>\r\nUser said: \"${opts.latestUserText}\"${urlLine}${recentBlock}${stuckHint}\r\n</reminder>`;\r\n}\r\n","/**\n * Planning system prompt — built once per `Plan.makeTodos()` call.\n *\n * Conceptual split: this prompt is STRATEGIC (sitemap, brand, persona,\n * site mental model). The webagent per-turn prompt is TACTICAL (envelope\n * shape, tool reference, current DOM). The planner runs ONCE per agent\n * run, no DOM context, so we can afford to put rich strategic context\n * here without paying it on every turn.\n *\n * Host's `appendSystemPrompt` is concatenated at the bottom — that's\n * where sitemap mental model / tour playbook / route routing logic goes.\n */\n\nimport { renderSitemap } from '../webagent/prompt';\nimport type { BrandPrompt, PersonaInput } from '../webagent/prompt';\nimport type { SitemapConfig } from '../webagent/types';\n\nexport interface PlanPromptContext {\n  locale?: string;\n  agentName?: string;\n  sitemap?: SitemapConfig;\n  brand?: BrandPrompt;\n  persona?: PersonaInput;\n  appendSystemPrompt?: string;\n}\n\nexport function buildPlanSystemPrompt(ctx: PlanPromptContext): string {\n  const sections: string[] = [];\n  const agent = ctx.agentName ?? 'Agent';\n\n  // Single short core. The webagent loop already knows how to execute\n  // todos; the planner just needs to know its JOB, its OUTPUT SHAPE,\n  // and that the user message carries the live DOM. No section headers,\n  // no example routes, no keyword rules. Trust the model to reason\n  // from the host's route descriptions + the current DOM.\n  sections.push(\n    `You are ${agent}'s planner. Output JSON: { task_summary, todos }.\n\n- task_summary: one short sentence the user will see.\n- todos: ordered array. Each item: { intent, description, expected_turn }. intent ∈ navigate | narrate | click | fill | ask | finish. Last item's intent is \"finish\".\n- One todo = one turn. Don't combine navigate and narrate — the DOM only refreshes after navigate.\n\nintent semantics:\n- navigate / narrate / click / fill: agent actions on the page.\n- ask: pause the loop and wait for user input. Use ONLY when the next agent step literally cannot proceed without a user choice. Do not use as a friendly follow-up, a clarification you could answer yourself, or a \"what would you like next\".\n- finish: signals the run is over. Its description states what was just delivered, never a question. Asking the user something is not finishing.\n\nIf the user's task is informational (introduce / explain / tell / show / what is / where is / how do I), the plan is navigate-then-narrate-then-finish. Do not add an \\`ask\\` step to qualify needs the user did not bring up.\n\nThe user message carries the user's task, the current page DOM, and any selection. The current DOM is your first source — if it already contains what the user needs (a paragraph, a contact, a link, an answer), narrate from it, no navigate. Only navigate when the answer is NOT on the current page and a different route's description matches the topic better.\n\nReply in exactly the language the user wrote their task in. The page DOM and brand voice may be in other languages — they do not set the output language. Match the user's task language, not the page's language.`\n  );\n\n  // Persona + brand voice + constraints inline as prose, no headers.\n  const personaLines: string[] = [];\n  if (ctx.persona) {\n    const identity = typeof ctx.persona === 'string' ? ctx.persona : ctx.persona.identity;\n    if (identity?.trim()) personaLines.push(identity.trim());\n  }\n  if (ctx.brand?.voice) personaLines.push(`Voice: ${ctx.brand.voice}`);\n  if (ctx.brand?.constraints?.length) {\n    for (const c of ctx.brand.constraints) personaLines.push(c);\n  }\n  if (personaLines.length) sections.push(personaLines.join('\\n'));\n\n  // Sitemap is auto-rendered ONLY when the host hasn't provided their\n  // own route descriptions via appendSystemPrompt. Avoids duplicating\n  // \"what each route is for\" in two competing places — the host's\n  // prose descriptions are richer than the auto-rendered list.\n  if (ctx.sitemap && !ctx.appendSystemPrompt) {\n    sections.push(renderSitemap(ctx.sitemap));\n  }\n\n  if (ctx.appendSystemPrompt) {\n    sections.push(ctx.appendSystemPrompt);\n  }\n\n  return sections.filter(Boolean).join('\\n\\n');\n}\n","/**\n * SDK-shipped prompt defaults, registered on the process-wide singleton.\n *\n * This module is the \"one place\" where every prompt the SDK ships is\n * enumerated. Hosts wanting to survey what's overridable can `console.log\n * (dddk.prompts.list())` and see everything registered here.\n *\n * IMPORTANT — this is the ONLY module allowed to call `registerDefault`\n * for a shipping prompt id. Any subsystem that wants to register a\n * new prompt should add it to `PROMPT_IDS` in `./registry.ts` and\n * register the default here, so nothing hides in module-init side-\n * effects deep inside a feature module.\n *\n * Ordering. Simple string constants first, function renderers last —\n * makes it obvious at a glance which prompts are static text vs.\n * assembled per-turn from context.\n */\n\nimport { PROMPT_IDS, promptRegistry } from './registry';\nimport { SYSTEM_PROMPT as INLINE_EDIT_SYSTEM } from '../agent/inline/parse';\nimport { MARKDOWN_EDIT_SYSTEM_PROMPT } from '../agent/plan/markdown';\nimport { TRANSLATE_SYSTEM_PROMPT } from '../modules/immersive-translate/prompt';\nimport { VOICE_CLEANUP_SYSTEM_PROMPT } from '../modules/voice/prompt';\nimport { DWELL_CLASSIFY_SYSTEM_PROMPT } from '../triggers/dwell/prompt';\nimport { buildPlanSystemPrompt, type PlanPromptContext } from '../agent/plan/prompt';\nimport { assembleSystemPrompt, type AssemblePromptInput } from '../agent/webagent/prompt';\n\nlet registered = false;\n\n/**\n * Idempotent — safe to call from multiple entry points (the WebAgent\n * subsystem calls it lazily on first use so tree-shaking still works\n * for hosts that only touch the UI-primitive layer).\n */\nexport function registerBuiltinPrompts(): void {\n  if (registered) return;\n  registered = true;\n\n  // ── Simple string prompts ──────────────────────────────────────\n  promptRegistry.registerDefault(PROMPT_IDS.INLINE_EDIT, () => INLINE_EDIT_SYSTEM);\n  promptRegistry.registerDefault(PROMPT_IDS.MARKDOWN_EDIT, () => MARKDOWN_EDIT_SYSTEM_PROMPT);\n  promptRegistry.registerDefault(PROMPT_IDS.TRANSLATE, () => TRANSLATE_SYSTEM_PROMPT);\n  promptRegistry.registerDefault(PROMPT_IDS.VOICE_CLEANUP, () => VOICE_CLEANUP_SYSTEM_PROMPT);\n  promptRegistry.registerDefault(PROMPT_IDS.DWELL_CLASSIFY, () => DWELL_CLASSIFY_SYSTEM_PROMPT);\n\n  // ── Context-driven prompts ─────────────────────────────────────\n  // The Planner + WebAgent narrator receive rich per-run context\n  // (sitemap, brand, persona) so we register the assembler functions\n  // — hosts overriding these get the same context object.\n  promptRegistry.registerDefault<PlanPromptContext>(\n    PROMPT_IDS.PLANNER,\n    (ctx) => buildPlanSystemPrompt(ctx ?? {}),\n  );\n  promptRegistry.registerDefault<AssemblePromptInput>(\n    PROMPT_IDS.WEBAGENT_NARRATOR,\n    (ctx) => assembleSystemPrompt(ctx ?? ({} as AssemblePromptInput)),\n  );\n  // CoT variant reuses the same assembler — the `cotMode` field in\n  // ctx flips it internally. Registered as a separate id so hosts can\n  // override just the thinking-mode narrator without touching the\n  // regular one.\n  promptRegistry.registerDefault<AssemblePromptInput>(\n    PROMPT_IDS.WEBAGENT_COT,\n    (ctx) => assembleSystemPrompt({ ...(ctx ?? {}), cotMode: true } as AssemblePromptInput),\n  );\n}\n","/**\n * PanelRuntime — runtime support for `PanelSkill`.\n *\n * Renders a \"top input + bottom panel\" overlay separate from the regular\n * CommandPalette. Manages a navigation stack so Esc/Backspace pop frames\n * instead of closing entirely. Breadcrumbs at the top let users jump back\n * any level.\n *\n * This is a minimal DOM implementation — the goal is to make PanelSkill\n * executable end-to-end. Hosts wanting deep UI customization can replace it\n * by listening to `panel_enter` / `panel_input` / `panel_action` events.\n */\n\nimport type { PanelSkill, PanelSkillContext } from '../skills/types';\nimport { ensurePaletteStyles, UI_ATTR } from './command-palette/styles';\n\ntype StackFrame = {\n  skill: PanelSkill;\n  input: string;\n  currentSurface: unknown | null;\n};\n\nexport interface PanelRuntimeHost {\n  /** Called when user submits an action — usually a button click in the rendered surface. */\n  llm?: (prompt: string) => Promise<string>;\n  navigate: (path: string) => void;\n  /** Render a PieceSurface into a host-provided DOM container. */\n  renderPiece?: (container: HTMLElement, surface: unknown, onAction: (action: string, data: unknown) => void) => void;\n}\n\nexport interface PanelRuntimeOptions {\n  host: PanelRuntimeHost;\n  /** Debounce ms for onInput. Default 200ms. */\n  inputDebounceMs?: number;\n}\n\nexport class PanelRuntime {\n  private stack: StackFrame[] = [];\n  private overlay: HTMLDivElement | null = null;\n  private inputEl: HTMLInputElement | null = null;\n  private breadcrumbEl: HTMLElement | null = null;\n  private contentEl: HTMLDivElement | null = null;\n  private inputTimer: ReturnType<typeof setTimeout> | null = null;\n  private host: PanelRuntimeHost;\n  private debounceMs: number;\n\n  constructor(opts: PanelRuntimeOptions) {\n    this.host = opts.host;\n    this.debounceMs = opts.inputDebounceMs ?? 200;\n  }\n\n  /** Push a panel skill onto the stack and render. */\n  async enter(skill: PanelSkill): Promise<void> {\n    if (!this.overlay) this.mount();\n    const frame: StackFrame = { skill, input: '', currentSurface: null };\n    this.stack.push(frame);\n    this.renderShell();\n    if (skill.onEnter) {\n      const ctx = this.makeContext(frame);\n      await skill.onEnter(ctx);\n    }\n  }\n\n  /** Pop the top frame. Closes the overlay if stack empties. */\n  async back(): Promise<void> {\n    const popped = this.stack.pop();\n    if (popped?.skill.onLeave) await popped.skill.onLeave();\n    if (this.stack.length === 0) {\n      this.unmount();\n    } else {\n      this.renderShell();\n    }\n  }\n\n  /** Close everything. */\n  async close(): Promise<void> {\n    while (this.stack.length > 0) {\n      const popped = this.stack.pop()!;\n      if (popped.skill.onLeave) await popped.skill.onLeave();\n    }\n    this.unmount();\n  }\n\n  isOpen(): boolean {\n    return this.stack.length > 0;\n  }\n\n  stackDepth(): number {\n    return this.stack.length;\n  }\n\n  // ── DOM management ─────────────────────────────────────────────\n\n  private mount(): void {\n    ensurePaletteStyles();\n\n    // Visually identical to the CommandPalette — same overlay, card,\n    // input row, result area, close button. The user perceives the\n    // transition palette → panel skill as the same window changing\n    // content, not a separate modal popping over with a different\n    // shape. The single visual differentiator is the BACK button\n    // tucked inside the input row when the panel stack is deeper\n    // than one, which signals \"you're in a sub-view, esc returns\".\n    const overlay = document.createElement('div');\n    overlay.setAttribute(UI_ATTR, 'palette-backdrop');\n    overlay.setAttribute('data-dddk-panel', 'true');\n\n    const card = document.createElement('div');\n    card.setAttribute(UI_ATTR, 'palette');\n\n    // Input row — same as palette, with optional back arrow on the\n    // left side AND the standard × close button on the right.\n    const inputRow = document.createElement('div');\n    inputRow.setAttribute(UI_ATTR, 'palette-input-row');\n\n    const backBtn = document.createElement('button');\n    backBtn.type = 'button';\n    backBtn.setAttribute(UI_ATTR, 'panel-back');\n    backBtn.setAttribute('aria-label', 'Back');\n    backBtn.innerHTML = '←';\n    backBtn.addEventListener('click', () => { void this.back(); });\n    this.breadcrumbEl = backBtn; // reusing the field as the back-button ref\n\n    const input = document.createElement('input');\n    input.type = 'text';\n    input.setAttribute(UI_ATTR, 'palette-input');\n    input.addEventListener('input', this.handleInput);\n    input.addEventListener('keydown', this.handleKeyDown);\n    this.inputEl = input;\n\n    const closeBtn = document.createElement('button');\n    closeBtn.type = 'button';\n    closeBtn.setAttribute(UI_ATTR, 'panel-close');\n    closeBtn.setAttribute('aria-label', 'Close');\n    closeBtn.textContent = '×';\n    closeBtn.addEventListener('click', () => { void this.close(); });\n\n    inputRow.appendChild(backBtn);\n    inputRow.appendChild(input);\n    inputRow.appendChild(closeBtn);\n\n    // Content area — host's surface paints here. Uses `palette-result`\n    // so the panel-surface utility classes (.dddk-panel-*) compose\n    // naturally with zero extra padding wrappers.\n    const content = document.createElement('div');\n    content.setAttribute(UI_ATTR, 'palette-result');\n    this.contentEl = content;\n\n    card.appendChild(inputRow);\n    card.appendChild(content);\n    overlay.appendChild(card);\n\n    overlay.addEventListener('click', (e) => {\n      if (e.target === overlay) void this.close();\n    });\n\n    document.body.appendChild(overlay);\n    this.overlay = overlay;\n    setTimeout(() => input.focus(), 0);\n  }\n\n  private unmount(): void {\n    if (this.inputTimer) clearTimeout(this.inputTimer);\n    this.inputTimer = null;\n    this.overlay?.remove();\n    this.overlay = null;\n    this.inputEl = null;\n    this.breadcrumbEl = null;\n    this.contentEl = null;\n  }\n\n  private renderShell(): void {\n    if (!this.inputEl) return;\n    // Show the back arrow only when there's somewhere to go back to.\n    // For the top-level panel, hide it — the × button takes care of\n    // dismissal. This keeps the input row chrome quiet when there's\n    // no navigation history.\n    if (this.breadcrumbEl) {\n      (this.breadcrumbEl as HTMLElement).style.display = this.stack.length > 1 ? '' : 'none';\n    }\n    const top = this.stack[this.stack.length - 1];\n    this.inputEl.placeholder = top?.skill.inputPlaceholder ?? '';\n    this.inputEl.value = top?.input ?? '';\n    this.inputEl.focus();\n    if (top?.currentSurface) this.renderSurface(top.currentSurface);\n    else this.clearContent();\n  }\n\n  private renderSurface(surface: unknown): void {\n    if (!this.contentEl) return;\n    this.contentEl.innerHTML = '';\n    if (this.host.renderPiece) {\n      this.host.renderPiece(this.contentEl, surface, (action, data) =>\n        this.handleAction(action, data)\n      );\n      return;\n    }\n    // Fallback: render JSON-stringified preview if no host renderer.\n    this.contentEl.appendChild(this.fallbackRender(surface));\n  }\n\n  private clearContent(): void {\n    if (!this.contentEl) return;\n    this.contentEl.innerHTML = '';\n  }\n\n  private fallbackRender(node: unknown): HTMLElement {\n    const root = (node as { root?: unknown })?.root ?? node;\n    return this.renderNode(root);\n  }\n\n  private renderNode(node: unknown): HTMLElement {\n    const n = node as { kind?: string; text?: string; children?: unknown[]; action?: string; data?: unknown };\n    const el = document.createElement('div');\n    if (!n || typeof n !== 'object') {\n      el.textContent = String(node);\n      return el;\n    }\n    switch (n.kind) {\n      case 'Stack':\n        el.style.display = 'flex';\n        el.style.flexDirection = 'column';\n        el.style.gap = '8px';\n        break;\n      case 'Row':\n        el.style.display = 'flex';\n        el.style.flexDirection = 'row';\n        el.style.gap = '8px';\n        el.style.alignItems = 'center';\n        break;\n      case 'Card':\n        el.style.border = '1px solid var(--dddk-border, rgba(0,0,0,0.08))';\n        el.style.borderRadius = '8px';\n        el.style.padding = '10px 12px';\n        el.style.display = 'flex';\n        el.style.flexDirection = 'column';\n        el.style.gap = '6px';\n        break;\n      case 'Heading':\n        el.style.fontWeight = '600';\n        el.style.fontSize = '14px';\n        el.textContent = n.text ?? '';\n        break;\n      case 'Text':\n        el.textContent = n.text ?? '';\n        el.style.fontSize = '13px';\n        break;\n      case 'Markdown':\n        el.textContent = n.text ?? '';\n        el.style.whiteSpace = 'pre-wrap';\n        el.style.fontSize = '13px';\n        break;\n      case 'Tag':\n        el.textContent = n.text ?? '';\n        el.style.padding = '2px 8px';\n        el.style.borderRadius = '10px';\n        el.style.background = 'rgba(0,0,0,0.06)';\n        el.style.fontSize = '11px';\n        el.style.display = 'inline-block';\n        break;\n      case 'Button': {\n        const btn = document.createElement('button');\n        btn.textContent = n.text ?? '';\n        Object.assign(btn.style, {\n          padding: '4px 10px',\n          fontSize: '12px',\n          borderRadius: '6px',\n          border: '1px solid var(--dddk-border, rgba(0,0,0,0.12))',\n          background: 'transparent',\n          cursor: 'pointer',\n          color: 'inherit',\n        });\n        btn.addEventListener('click', () => {\n          if (n.action) this.handleAction(n.action, n.data);\n        });\n        return btn;\n      }\n    }\n    if (Array.isArray(n.children)) {\n      for (const c of n.children) el.appendChild(this.renderNode(c));\n    } else if (n.text) {\n      el.textContent = n.text;\n    }\n    return el;\n  }\n\n  // ── Event handlers ─────────────────────────────────────────────\n\n  private handleInput = (): void => {\n    const top = this.stack[this.stack.length - 1];\n    if (!top || !this.inputEl) return;\n    top.input = this.inputEl.value;\n    if (this.inputTimer) clearTimeout(this.inputTimer);\n    this.inputTimer = setTimeout(async () => {\n      const ctx = this.makeContext(top);\n      await top.skill.onInput(top.input, ctx);\n    }, this.debounceMs);\n  };\n\n  private handleKeyDown = async (e: KeyboardEvent): Promise<void> => {\n    const top = this.stack[this.stack.length - 1];\n    if (!top || !this.inputEl) return;\n\n    if (e.key === 'Escape') {\n      e.preventDefault();\n      await this.back();\n      return;\n    }\n    if (e.key === 'Backspace' && this.inputEl.value === '') {\n      e.preventDefault();\n      await this.back();\n      return;\n    }\n    if (e.key === 'Enter') {\n      e.preventDefault();\n      if (top.skill.onSubmit) {\n        const ctx = this.makeContext(top);\n        await top.skill.onSubmit(this.inputEl.value, ctx);\n      }\n    }\n  };\n\n  private async handleAction(action: string, data: unknown): Promise<void> {\n    const top = this.stack[this.stack.length - 1];\n    if (!top || !top.skill.onAction) return;\n    const ctx = this.makeContext(top);\n    await top.skill.onAction(action, data, ctx);\n  }\n\n  private makeContext(frame: StackFrame): PanelSkillContext {\n    return {\n      palette: { close: () => this.close(), replace: () => {} },\n      subtitle: { show: () => {}, hide: () => {} },\n      storage: { get: () => null, set: () => {} },\n      getPreferences: () => ({}) as never,\n      llm: this.host.llm,\n      navigate: (path: string) => this.host.navigate(path),\n      render: (surface: unknown) => {\n        frame.currentSurface = surface;\n        this.renderSurface(surface);\n      },\n      back: () => void this.back(),\n      setPlaceholder: (text: string) => {\n        if (this.inputEl) this.inputEl.placeholder = text;\n      },\n    };\n  }\n}\n","/**\n * Placement slots — the canonical screen positions every transient\n * dddk UI piece routes through.\n *\n * Slot names match `SurfacePlacement` from `skills/types` so callers\n * who already chose a placement (PanelSkill, SurfaceSkill, Proactive)\n * can pass it through unchanged.\n *\n * Apply with `applyPlacement(el, 'subtitle')` — the CSS selectors are\n * `[data-dddk-slot=...]`. The `Placements` class gives ergonomic\n * mount/unmount helpers.\n */\n\nimport { injectScopedStyle } from '../utils/dom';\n\nexport type PlacementSlot =\n  | 'subtitle'   // center-bottom horizontal bar (text + buttons)\n  | 'indicator'  // center-bottom small chip (sits above the subtitle bar)\n  | 'palette'   // upper-center modal-like input panel\n  | 'dock'      // persistent right-side panel\n  | 'modal'     // full-screen centered with backdrop\n  | 'banner'    // full-width top strip\n  | 'fab'       // bottom-right floating action button\n  | 'toast';    // top-center transient notification\n\nexport const PLACEMENT_ATTR = 'data-dddk-slot';\nconst STYLE_ID = 'dddk-placement-style';\n\nconst PLACEMENT_CSS = `\n  /* Z-index ladder, low → high:\n     fab(9200) < banner(9300) < dock(9400) < palette(9900) <\n     modal(9700) < subtitle(9950) < indicator(9960) < toast(9999)\n\n     Note: subtitle sits ABOVE palette / modal. The agent narrates\n     into the subtitle bar while the user interacts with palette / form\n     surfaces — both must stay visible. If subtitle were below the\n     palette backdrop the user would lose the narration the moment the\n     agent opens a palette / modal. */\n\n  [${PLACEMENT_ATTR}=\"subtitle\"] {\n    position: fixed;\n    left: 50%;\n    bottom: var(--dddk-bar-bottom, 24px);\n    transform: translateX(-50%);\n    max-width: var(--dddk-bar-max-width, 720px);\n    width: calc(100% - 48px);\n    z-index: var(--dddk-z-bar, 9950);\n    box-sizing: border-box;\n  }\n\n  [${PLACEMENT_ATTR}=\"indicator\"] {\n    position: fixed;\n    left: 50%;\n    bottom: var(--dddk-indicator-bottom, 88px);\n    transform: translateX(-50%);\n    z-index: calc(var(--dddk-z-bar, 9950) + 10);\n    box-sizing: border-box;\n  }\n\n  [${PLACEMENT_ATTR}=\"palette\"] {\n    position: fixed;\n    top: var(--dddk-palette-top, 12%);\n    left: 50%;\n    transform: translateX(-50%);\n    width: min(var(--dddk-palette-max-width, 640px), 92vw);\n    z-index: var(--dddk-z-palette, 9600);\n    box-sizing: border-box;\n  }\n\n  [${PLACEMENT_ATTR}=\"dock\"] {\n    position: fixed;\n    top: 0;\n    right: 0;\n    height: 100vh;\n    width: min(var(--dddk-dock-width, 380px), 92vw);\n    z-index: var(--dddk-z-dock, 9400);\n    box-sizing: border-box;\n  }\n\n  [${PLACEMENT_ATTR}=\"modal\"] {\n    position: fixed;\n    inset: 0;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    background: var(--dddk-modal-backdrop, rgba(0, 0, 0, 0.5));\n    z-index: var(--dddk-z-modal, 9700);\n  }\n\n  [${PLACEMENT_ATTR}=\"banner\"] {\n    position: fixed;\n    top: 0;\n    left: 0;\n    right: 0;\n    z-index: var(--dddk-z-banner, 9300);\n    box-sizing: border-box;\n  }\n\n  [${PLACEMENT_ATTR}=\"fab\"] {\n    position: fixed;\n    right: var(--dddk-fab-right, 18px);\n    bottom: var(--dddk-fab-bottom, 22px);\n    z-index: var(--dddk-z-fab, 9200);\n  }\n\n  [${PLACEMENT_ATTR}=\"toast\"] {\n    position: fixed;\n    top: var(--dddk-toast-top, 24px);\n    left: 50%;\n    transform: translateX(-50%);\n    z-index: var(--dddk-z-toast, 9800);\n    box-sizing: border-box;\n  }\n`;\n\nlet stylesEnsured = false;\nexport function ensurePlacementStyles(): void {\n  if (stylesEnsured) return;\n  stylesEnsured = true;\n  injectScopedStyle(STYLE_ID, PLACEMENT_CSS);\n}\n\n/**\n * Tag an element with the slot attribute so it inherits the slot's CSS.\n * The element must already be (or will be) in the DOM — placement does\n * not append it.\n */\nexport function applyPlacement(el: HTMLElement, slot: PlacementSlot): void {\n  ensurePlacementStyles();\n  el.setAttribute(PLACEMENT_ATTR, slot);\n}\n\n/** Strip any slot attribute. */\nexport function clearPlacement(el: HTMLElement): void {\n  el.removeAttribute(PLACEMENT_ATTR);\n}\n\n/**\n * Mount handle returned by `Placements.mount()` — unmount with `.unmount()`,\n * swap content with `.update(html)`.\n */\nexport interface PlacementHandle {\n  readonly el: HTMLElement;\n  readonly slot: PlacementSlot;\n  update(html: string): void;\n  unmount(): void;\n}\n\n/**\n * Convenience class for hosts that want to drop custom content into a\n * placement slot without writing the boilerplate. Owns one element per\n * mount; multiple mounts into the same slot stack as siblings (the CSS\n * does not enforce single-occupancy — callers decide).\n *\n *   const handle = dddk.placement.mount('subtitle', `<div>Hi</div>`);\n *   // ... later:\n *   handle.unmount();\n */\nexport class Placements {\n  mount(slot: PlacementSlot, content: string | HTMLElement): PlacementHandle {\n    ensurePlacementStyles();\n    const wrap = document.createElement('div');\n    wrap.setAttribute(PLACEMENT_ATTR, slot);\n    if (typeof content === 'string') {\n      wrap.innerHTML = content;\n    } else {\n      wrap.appendChild(content);\n    }\n    document.body.appendChild(wrap);\n    return {\n      el: wrap,\n      slot,\n      update: (html: string) => { wrap.innerHTML = html; },\n      unmount: () => { wrap.remove(); },\n    };\n  }\n}\n","/**\r\n * PinnedPanel — a corner-anchored frame whose body is a `PieceSurface`.\r\n *\r\n * The frame owns: placement (one of the four screen corners), the close\r\n * button, the optional title / subtitle / footer chrome, animation, and\r\n * dismiss lifecycle. Everything inside is rendered by `PieceDomRenderer`\r\n * — the same renderer that powers the palette detail pane — so layout\r\n * (`Card` / `Stack` / `Grid` / `Tabs`), inputs (`Checkbox` / `Button` /\r\n * `TextField` / `Switch` …), data (`Listing` / `Metric` / `ProgressBar`)\r\n * and `Slot` host-supplied content all work out of the box.\r\n *\r\n *   const handle = dddk.panel.create({\r\n *     id: 'getting-started',\r\n *     placement: 'bottom-right',\r\n *     title: 'The Basics',\r\n *     subtitle: 'Setup the basics to get your team started',\r\n *     surface: {\r\n *       root: {\r\n *         kind: 'Stack', gap: 10, children: [\r\n *           { kind: 'ProgressBar', bind: '/progress' },\r\n *           { kind: 'Checkbox', bind: '/tasks/create',  label: 'Create your first project' },\r\n *           { kind: 'Button',    text: 'Create',  variant: 'primary', action: 'create' },\r\n *           { kind: 'Checkbox', bind: '/tasks/invite',  label: 'Invite your team' },\r\n *         ],\r\n *       },\r\n *       data: { progress: 0, tasks: {} },\r\n *     },\r\n *     onAction: (name, payload, data) => { ... },\r\n *     onDataChange: (data) => { ... },\r\n *   });\r\n *\r\n *   handle.setData({ progress: 50, tasks: { create: true } });\r\n *   handle.unmount();\r\n */\r\n\r\nimport { injectScopedStyle } from '../utils/dom';\r\nimport { PieceDomRenderer } from '../ui/pieces/dom-renderer';\r\nimport type { PieceCatalog, PieceSurface } from '../ui/pieces/types';\r\n\r\nexport type PinnedPanelPlacement =\r\n  | 'bottom-right'\r\n  | 'bottom-left'\r\n  | 'top-right'\r\n  | 'top-left';\r\n\r\nexport interface PinnedPanelSpec {\r\n  /** Stable id — re-creating with the same id replaces the existing panel. */\r\n  id: string;\r\n  /** Title rendered in the panel header. Hide the header by setting both\r\n   *  `title` and `subtitle` to empty / undefined. */\r\n  title?: string;\r\n  subtitle?: string;\r\n  /** Default `bottom-right`. */\r\n  placement?: PinnedPanelPlacement;\r\n  /** Body — any Pieces tree. See `PieceDomRenderer` for the catalog. */\r\n  surface: PieceSurface;\r\n  /** Renders a small × button in the header. Default `true`. */\r\n  dismissible?: boolean;\r\n  /** Footer caption (e.g. \"Powered by Acme\"). */\r\n  footer?: string;\r\n  /** Host can swap the piece catalog (e.g. to register custom kinds). */\r\n  catalog?: PieceCatalog;\r\n  /** Fired by Button / IconButton / Link clicks inside the surface. */\r\n  onAction?: (name: string, payload: unknown, data: Record<string, unknown>) => void;\r\n  /** Fired on every input change inside the surface. */\r\n  onDataChange?: (data: Record<string, unknown>) => void;\r\n  /** Fired when the user dismisses via the × button. */\r\n  onDismiss?: (handle: PinnedPanelHandle) => void;\r\n}\r\n\r\nexport interface PinnedPanelHandle {\r\n  readonly id: string;\r\n  /** Mount / show the panel. Idempotent. */\r\n  show(): void;\r\n  /** Hide and detach from the DOM (panel can be re-shown). */\r\n  hide(): void;\r\n  /** Whether the panel is currently in the DOM. */\r\n  isVisible(): boolean;\r\n  /** Replace any subset of the spec — the panel re-renders in place. */\r\n  update(patch: Partial<Omit<PinnedPanelSpec, 'id'>>): void;\r\n  /** Read the current data model from the surface. */\r\n  getData(): Record<string, unknown>;\r\n  /** Replace the data model wholesale. */\r\n  setData(data: Record<string, unknown>): void;\r\n  /** Permanently remove and forget this panel. */\r\n  unmount(): void;\r\n}\r\n\r\nimport { UI_ATTR } from '../utils/dom';\r\nconst STYLE_ID = 'dddk-pinned-panel-style';\r\n\r\nconst PANEL_CSS = `\r\n  [${UI_ATTR}=\"pinned-panel\"] {\r\n    position: fixed;\r\n    width: min(360px, calc(100vw - 24px));\r\n    max-height: calc(100vh - 48px);\r\n    overflow: hidden;\r\n    background: var(--dddk-bg-elevated, #fff);\r\n    color: var(--dddk-text, #18181b);\r\n    border: 1px solid var(--dddk-border, rgba(0,0,0,0.08));\r\n    border-radius: var(--dddk-pinned-panel-radius, 12px);\r\n    box-shadow: var(--dddk-shadow-lg, 0 12px 32px rgba(0,0,0,0.16));\r\n    font-family: var(--dddk-font, system-ui, sans-serif);\r\n    z-index: var(--dddk-z-pinned, 9450);\r\n    display: flex; flex-direction: column;\r\n    animation: dddk-pinned-fade 180ms cubic-bezier(0.2,0,0,1);\r\n  }\r\n  [${UI_ATTR}=\"pinned-panel\"][data-placement=\"bottom-right\"] { right: 18px; bottom: 18px; }\r\n  [${UI_ATTR}=\"pinned-panel\"][data-placement=\"bottom-left\"]  { left:  18px; bottom: 18px; }\r\n  [${UI_ATTR}=\"pinned-panel\"][data-placement=\"top-right\"]    { right: 18px; top:    18px; }\r\n  [${UI_ATTR}=\"pinned-panel\"][data-placement=\"top-left\"]     { left:  18px; top:    18px; }\r\n\r\n  [${UI_ATTR}=\"pinned-panel-head\"] {\r\n    padding: 14px 16px 10px;\r\n    display: flex; align-items: flex-start; gap: 10px;\r\n  }\r\n  [${UI_ATTR}=\"pinned-panel-head-text\"] { flex: 1; min-width: 0; }\r\n  [${UI_ATTR}=\"pinned-panel-title\"] {\r\n    font-size: 14px; font-weight: 600;\r\n    color: var(--dddk-text, #18181b);\r\n    line-height: 1.35;\r\n  }\r\n  [${UI_ATTR}=\"pinned-panel-subtitle\"] {\r\n    margin-top: 2px;\r\n    font-size: 12px; color: var(--dddk-text-muted, #71717a);\r\n    line-height: 1.45;\r\n  }\r\n  [${UI_ATTR}=\"pinned-panel-close\"] {\r\n    appearance: none; border: 0; background: transparent;\r\n    color: var(--dddk-text-muted, #71717a);\r\n    cursor: pointer; padding: 2px 6px; font-size: 16px;\r\n    border-radius: 4px;\r\n  }\r\n  [${UI_ATTR}=\"pinned-panel-close\"]:hover {\r\n    background: var(--dddk-row-hover, rgba(0,0,0,0.05));\r\n    color: var(--dddk-text, #18181b);\r\n  }\r\n\r\n  [${UI_ATTR}=\"pinned-panel-body\"] {\r\n    flex: 1; overflow-y: auto;\r\n    padding: 4px 16px 14px;\r\n  }\r\n\r\n  [${UI_ATTR}=\"pinned-panel-footer\"] {\r\n    padding: 8px 14px;\r\n    border-top: 1px solid var(--dddk-border, rgba(0,0,0,0.05));\r\n    font-size: 11px;\r\n    text-align: right;\r\n    color: var(--dddk-text-muted, #71717a);\r\n  }\r\n\r\n  @keyframes dddk-pinned-fade {\r\n    from { transform: translateY(8px); opacity: 0; }\r\n    to   { transform: translateY(0);   opacity: 1; }\r\n  }\r\n\r\n  @media (max-width: 480px) {\r\n    [${UI_ATTR}=\"pinned-panel\"] {\r\n      left: 12px; right: 12px;\r\n      width: auto;\r\n    }\r\n    [${UI_ATTR}=\"pinned-panel\"][data-placement=\"bottom-right\"],\r\n    [${UI_ATTR}=\"pinned-panel\"][data-placement=\"bottom-left\"] {\r\n      bottom: 12px; top: auto;\r\n    }\r\n    [${UI_ATTR}=\"pinned-panel\"][data-placement=\"top-right\"],\r\n    [${UI_ATTR}=\"pinned-panel\"][data-placement=\"top-left\"] {\r\n      top: 12px; bottom: auto;\r\n    }\r\n  }\r\n`;\r\n\r\nlet stylesEnsured = false;\r\nfunction ensureStyles(): void {\r\n  if (stylesEnsured) return;\r\n  stylesEnsured = true;\r\n  injectScopedStyle(STYLE_ID, PANEL_CSS);\r\n}\r\n\r\n/**\r\n * Owns the active set of pinned panels keyed by id. Re-creating with the\r\n * same id replaces the existing panel so the registry stays clean.\r\n */\r\nexport class PinnedPanelRegistry {\r\n  private panels = new Map<string, InternalPanel>();\r\n\r\n  create(spec: PinnedPanelSpec, opts: { showImmediately?: boolean } = {}): PinnedPanelHandle {\r\n    const existing = this.panels.get(spec.id);\r\n    if (existing) existing.handle.unmount();\r\n    const panel = new InternalPanel(spec, () => this.panels.delete(spec.id));\r\n    this.panels.set(spec.id, panel);\r\n    if (opts.showImmediately !== false) panel.handle.show();\r\n    return panel.handle;\r\n  }\r\n\r\n  get(id: string): PinnedPanelHandle | undefined {\r\n    return this.panels.get(id)?.handle;\r\n  }\r\n\r\n  clear(): void {\r\n    for (const p of Array.from(this.panels.values())) p.handle.unmount();\r\n    this.panels.clear();\r\n  }\r\n}\r\n\r\nclass InternalPanel {\r\n  readonly handle: PinnedPanelHandle;\r\n  private spec: PinnedPanelSpec;\r\n  private rootEl: HTMLDivElement | null = null;\r\n  private bodyEl: HTMLDivElement | null = null;\r\n  private renderer: PieceDomRenderer | null = null;\r\n\r\n  constructor(spec: PinnedPanelSpec, onUnmount: () => void) {\r\n    this.spec = spec;\r\n\r\n    const self = this;\r\n    this.handle = {\r\n      get id() { return self.spec.id; },\r\n      show: () => self.mount(),\r\n      hide: () => self.detach(),\r\n      isVisible: () => self.rootEl !== null,\r\n      update: (patch) => self.applyPatch(patch),\r\n      getData: () => self.renderer?.getData() ?? {},\r\n      setData: (data) => self.renderer?.setData(data),\r\n      unmount: () => {\r\n        self.detach();\r\n        onUnmount();\r\n      },\r\n    };\r\n  }\r\n\r\n  private mount(): void {\r\n    if (this.rootEl) return;\r\n    ensureStyles();\r\n    const root = document.createElement('div');\r\n    root.setAttribute(UI_ATTR, 'pinned-panel');\r\n    root.setAttribute('data-id', this.spec.id);\r\n    root.setAttribute('data-placement', this.spec.placement ?? 'bottom-right');\r\n    this.rootEl = root;\r\n    document.body.appendChild(root);\r\n    this.renderChrome();\r\n  }\r\n\r\n  private detach(): void {\r\n    if (this.renderer) {\r\n      this.renderer.unmount();\r\n      this.renderer = null;\r\n    }\r\n    if (this.rootEl) {\r\n      this.rootEl.remove();\r\n      this.rootEl = null;\r\n    }\r\n    this.bodyEl = null;\r\n  }\r\n\r\n  private applyPatch(patch: Partial<Omit<PinnedPanelSpec, 'id'>>): void {\r\n    const surfaceChanged = patch.surface !== undefined && patch.surface !== this.spec.surface;\r\n    this.spec = { ...this.spec, ...patch };\r\n    if (!this.rootEl) return;\r\n    if (patch.placement) this.rootEl.setAttribute('data-placement', patch.placement);\r\n    if (\r\n      patch.title !== undefined ||\r\n      patch.subtitle !== undefined ||\r\n      patch.footer !== undefined ||\r\n      patch.dismissible !== undefined\r\n    ) {\r\n      this.renderChrome();\r\n      return;\r\n    }\r\n    if (surfaceChanged && this.renderer && this.spec.surface) {\r\n      this.renderer.update(this.spec.surface);\r\n    }\r\n  }\r\n\r\n  private renderChrome(): void {\r\n    const root = this.rootEl;\r\n    if (!root) return;\r\n    root.innerHTML = '';\r\n\r\n    const showHeader = this.spec.title || this.spec.subtitle || this.spec.dismissible !== false;\r\n    if (showHeader) {\r\n      const head = document.createElement('div');\r\n      head.setAttribute(UI_ATTR, 'pinned-panel-head');\r\n      const headText = document.createElement('div');\r\n      headText.setAttribute(UI_ATTR, 'pinned-panel-head-text');\r\n      if (this.spec.title) {\r\n        const title = document.createElement('div');\r\n        title.setAttribute(UI_ATTR, 'pinned-panel-title');\r\n        title.textContent = this.spec.title;\r\n        headText.appendChild(title);\r\n      }\r\n      if (this.spec.subtitle) {\r\n        const sub = document.createElement('div');\r\n        sub.setAttribute(UI_ATTR, 'pinned-panel-subtitle');\r\n        sub.textContent = this.spec.subtitle;\r\n        headText.appendChild(sub);\r\n      }\r\n      head.appendChild(headText);\r\n      if (this.spec.dismissible !== false) {\r\n        const close = document.createElement('button');\r\n        close.type = 'button';\r\n        close.setAttribute(UI_ATTR, 'pinned-panel-close');\r\n        close.textContent = '×';\r\n        close.title = 'Dismiss';\r\n        close.addEventListener('click', () => {\r\n          this.spec.onDismiss?.(this.handle);\r\n          this.handle.unmount();\r\n        });\r\n        head.appendChild(close);\r\n      }\r\n      root.appendChild(head);\r\n    }\r\n\r\n    const body = document.createElement('div');\r\n    body.setAttribute(UI_ATTR, 'pinned-panel-body');\r\n    root.appendChild(body);\r\n    this.bodyEl = body;\r\n\r\n    // Mount the renderer onto the body. Reuse the existing renderer's\r\n    // data when present so chrome-only updates don't reset user inputs.\r\n    const previousData = this.renderer?.getData();\r\n    if (this.renderer) this.renderer.unmount();\r\n    this.renderer = new PieceDomRenderer({\r\n      catalog: this.spec.catalog,\r\n      onAction: (name, payload, data) => this.spec.onAction?.(name, payload, data),\r\n      onDataChange: (data) => this.spec.onDataChange?.(data),\r\n    });\r\n    this.renderer.mount(body, this.spec.surface);\r\n    if (previousData) this.renderer.setData({ ...previousData });\r\n\r\n    if (this.spec.footer) {\r\n      const footer = document.createElement('div');\r\n      footer.setAttribute(UI_ATTR, 'pinned-panel-footer');\r\n      footer.textContent = this.spec.footer;\r\n      root.appendChild(footer);\r\n    }\r\n  }\r\n}\r\n","export type Doc<TMeta = Record<string, unknown>> = {\n  id: string;\n  fields: Record<string, string>;\n  meta?: TMeta;\n};\n\nexport interface Adapter<R, D = Doc> {\n  fromRow(row: R): D;\n  toRow?(doc: D, original?: R): R;\n}\n\nexport const identityAdapter: Adapter<Doc, Doc> = { fromRow: (d) => d };\n\nexport type DeltaOp<TRow = unknown> =\n  | { op: 'add'; row: TRow }\n  | { op: 'update'; row: TRow }\n  | { op: 'remove'; id: string };\n\nexport type DeltaPayload<TRow = unknown> = {\n  version: string | number;\n  changes: DeltaOp<TRow>[];\n};\n\nexport type BootstrapPayload<TRow = unknown> = {\n  version: string | number;\n  rows: TRow[];\n};\n\nexport type SyncConfig<TRow = unknown> = {\n  bootstrap?: () => Promise<BootstrapPayload<TRow>>;\n  fetchDelta?: (sinceVersion: string | number) => Promise<DeltaPayload<TRow>>;\n  pollIntervalMs?: number;\n  subscribe?: (onChange: (delta: DeltaPayload<TRow>) => void) => () => void;\n};\n\nexport interface Signal<TDoc = Doc, TCtx = unknown> {\n  id: string;\n  compute(doc: TDoc, ctx: TCtx): number;\n  meta?: { range?: [number, number]; description?: string };\n}\n\nexport type CombinerKind = 'product' | 'weighted_sum' | 'log_sum';\nexport type Combiner =\n  | CombinerKind\n  | ((scores: Record<string, number>, weights: Record<string, number>) => number);\n\nexport type ScoreExplanation = {\n  docId: string;\n  total: number;\n  contributions: Array<{ signalId: string; value: number; weight: number }>;\n};\n\nexport type IdentityProvider = () => Record<string, unknown> | undefined;\n\nexport function nfkc(s: string): string {\n  return s.normalize('NFKC');\n}\n\nexport function clamp(n: number, lo: number, hi: number): number {\n  return Math.max(lo, Math.min(hi, n));\n}\n\nexport function combine(\n  kind: Combiner,\n  scores: Record<string, number>,\n  weights: Record<string, number>\n): number {\n  if (typeof kind === 'function') return kind(scores, weights);\n  const ids = Object.keys(scores);\n  if (kind === 'product') {\n    let p = 1;\n    for (const id of ids) {\n      const w = weights[id] ?? 1;\n      p *= Math.pow(Math.max(0, scores[id] ?? 0), w);\n    }\n    return p;\n  }\n  if (kind === 'log_sum') {\n    let s = 0;\n    for (const id of ids) {\n      const w = weights[id] ?? 1;\n      s += w * Math.log(Math.max(1e-9, scores[id] ?? 0));\n    }\n    return Math.exp(s);\n  }\n  let s = 0;\n  for (const id of ids) {\n    const w = weights[id] ?? 1;\n    s += w * (scores[id] ?? 0);\n  }\n  return s;\n}\n","import type { StorageAdapter } from './types.js';\n\nexport function memoryAdapter(): StorageAdapter {\n  const store = new Map<string, unknown>();\n  return {\n    async open() {},\n    async get(key) {\n      return store.get(key) as never;\n    },\n    async set(key, value) {\n      store.set(key, value);\n    },\n    async delete(key) {\n      store.delete(key);\n    },\n    async *iterate(prefix) {\n      for (const [k, v] of store) if (k.startsWith(prefix)) yield [k, v];\n    },\n    async close() {\n      store.clear();\n    },\n  };\n}\n","import type { StorageAdapter } from './types.js';\n\nexport function localStorageAdapter(prefix = 'dddk:'): StorageAdapter {\n  const fullKey = (k: string) => prefix + k;\n  return {\n    async open() {\n      if (typeof localStorage === 'undefined') {\n        throw new Error('localStorageAdapter: localStorage is unavailable in this runtime');\n      }\n    },\n    async get(key) {\n      const raw = localStorage.getItem(fullKey(key));\n      if (raw === null) return undefined as never;\n      try {\n        return JSON.parse(raw) as never;\n      } catch {\n        return raw as never;\n      }\n    },\n    async set(key, value) {\n      localStorage.setItem(fullKey(key), JSON.stringify(value));\n    },\n    async delete(key) {\n      localStorage.removeItem(fullKey(key));\n    },\n    async *iterate(p) {\n      const full = prefix + p;\n      for (let i = 0; i < localStorage.length; i++) {\n        const k = localStorage.key(i);\n        if (!k || !k.startsWith(full)) continue;\n        const raw = localStorage.getItem(k);\n        if (raw === null) continue;\n        let val: unknown;\n        try {\n          val = JSON.parse(raw);\n        } catch {\n          val = raw;\n        }\n        yield [k.slice(prefix.length), val];\n      }\n    },\n    async close() {},\n  };\n}\n","import type { StorageAdapter } from './types.js';\n\nconst STORE = 'kv';\n\nfunction promisify<T>(req: IDBRequest<T>): Promise<T> {\n  return new Promise((resolve, reject) => {\n    req.onsuccess = () => resolve(req.result);\n    req.onerror = () => reject(req.error);\n  });\n}\n\nexport function indexedDBAdapter(dbName = 'dddk-toolbox'): StorageAdapter {\n  let db: IDBDatabase | undefined;\n  return {\n    async open() {\n      if (typeof indexedDB === 'undefined') {\n        throw new Error('indexedDBAdapter: IndexedDB unavailable; falling back recommended for SSR / Node');\n      }\n      db = await new Promise<IDBDatabase>((resolve, reject) => {\n        const req = indexedDB.open(dbName, 1);\n        req.onupgradeneeded = () => {\n          const d = req.result;\n          if (!d.objectStoreNames.contains(STORE)) d.createObjectStore(STORE);\n        };\n        req.onsuccess = () => resolve(req.result);\n        req.onerror = () => reject(req.error);\n      });\n    },\n    async get(key) {\n      if (!db) throw new Error('indexedDBAdapter: not opened');\n      const tx = db.transaction(STORE, 'readonly');\n      return (await promisify(tx.objectStore(STORE).get(key))) as never;\n    },\n    async set(key, value) {\n      if (!db) throw new Error('indexedDBAdapter: not opened');\n      const tx = db.transaction(STORE, 'readwrite');\n      await promisify(tx.objectStore(STORE).put(value, key));\n    },\n    async delete(key) {\n      if (!db) throw new Error('indexedDBAdapter: not opened');\n      const tx = db.transaction(STORE, 'readwrite');\n      await promisify(tx.objectStore(STORE).delete(key));\n    },\n    async *iterate(prefix) {\n      if (!db) throw new Error('indexedDBAdapter: not opened');\n      const tx = db.transaction(STORE, 'readonly');\n      const store = tx.objectStore(STORE);\n      const range = IDBKeyRange.bound(prefix, prefix + '￿');\n      const cursorReq = store.openCursor(range);\n      while (true) {\n        const cur = await new Promise<IDBCursorWithValue | null>((resolve, reject) => {\n          cursorReq.onsuccess = () => resolve(cursorReq.result);\n          cursorReq.onerror = () => reject(cursorReq.error);\n        });\n        if (!cur) break;\n        yield [String(cur.key), cur.value];\n        cur.continue();\n      }\n    },\n    async close() {\n      db?.close();\n      db = undefined;\n    },\n  };\n}\n","export type { StorageAdapter, StorageKind } from './types.js';\nexport { memoryAdapter } from './memory.js';\nexport { localStorageAdapter } from './local-storage.js';\nexport { indexedDBAdapter } from './indexeddb.js';\n\nimport type { StorageAdapter, StorageKind } from './types.js';\nimport { memoryAdapter } from './memory.js';\nimport { localStorageAdapter } from './local-storage.js';\nimport { indexedDBAdapter } from './indexeddb.js';\n\nexport function resolveStorage(kind: StorageKind | undefined): StorageAdapter {\n  if (!kind || kind === 'memory') return memoryAdapter();\n  if (kind === 'localstorage') return localStorageAdapter();\n  if (kind === 'indexeddb') {\n    if (typeof indexedDB === 'undefined') return memoryAdapter();\n    return indexedDBAdapter();\n  }\n  return kind;\n}\n","/**\n * Universal tokeniser — Unicode-aware, no language packs, no per-locale forks.\n *\n * Why universal-only:\n *   The package ships globally. Hardcoding `en` / `zh-TW` stopword lists or\n *   Porter-stemming locks the toolbox to two languages and silently breaks\n *   for everyone else. Instead we split on Unicode script class:\n *     - whitespace scripts (Latin, Cyrillic, Arabic, Hebrew, Indic, Greek, …)\n *       → split on whitespace + punctuation\n *     - no-space scripts (CJK, Thai, Lao, Khmer, Burmese, …)\n *       → emit each letter / number codepoint\n *   Then NFKC-normalise + lowercase + bigram for both paths.\n *\n *   Hosts that have a domain-specific tokeniser (e.g. medical term splitter)\n *   pass their own `tokenize(text)` function to the toolbox module — see\n *   `createSearch({ tokenize })`. The default fits 200+ languages reasonably.\n */\n\nconst CJK_RE = /[぀-ヿ㐀-䶿一-鿿가-힯]/;\nconst SE_ASIAN_RE = /[฀-๿຀-໿ក-៿က-႟]/; // Thai / Lao / Khmer / Burmese\nconst LETTER_NUM_RE = /[\\p{L}\\p{N}]/u;\n\nexport function nfkc(s: string): string {\n  return s.normalize('NFKC');\n}\n\nfunction isNoSpaceScript(text: string): boolean {\n  const sample = text.slice(0, 200);\n  return CJK_RE.test(sample) || SE_ASIAN_RE.test(sample);\n}\n\nfunction tokenizeNoSpace(text: string): string[] {\n  const out: string[] = [];\n  for (const c of nfkc(text)) {\n    if (LETTER_NUM_RE.test(c)) out.push(c.toLowerCase());\n  }\n  return out;\n}\n\nfunction tokenizeWhitespace(text: string): string[] {\n  return nfkc(text)\n    .toLowerCase()\n    .split(/[\\s\\p{P}\\p{S}]+/u)\n    .filter((t) => t.length > 0);\n}\n\n/** Plain token list. Default for QA / memory full-text matching. */\nexport function tokenize(text: string): string[] {\n  return isNoSpaceScript(text) ? tokenizeNoSpace(text) : tokenizeWhitespace(text);\n}\n\n/**\n * Token list + bigrams — slightly broader recall than `tokenize`. Default\n * feature set for search / recommend scoring. Whitespace-script bigrams join\n * with `_`; CJK bigrams join with empty string (faithful to written form).\n */\nexport function extractFeatures(text: string): string[] {\n  const noSpace = isNoSpaceScript(text);\n  const tokens = noSpace ? tokenizeNoSpace(text) : tokenizeWhitespace(text);\n  const bigrams: string[] = [];\n  const sep = noSpace ? '' : '_';\n  for (let i = 0; i + 1 < tokens.length; i++) {\n    bigrams.push(tokens[i] + sep + tokens[i + 1]);\n  }\n  return [...tokens, ...bigrams];\n}\n","/**\n * Okapi-BM25 with Lucene-style smoothed IDF.\n *   idf = log((N - df + 0.5) / (df + 0.5) + 1)      // always >= 0\n *\n * Used by `search` for full-text ranking and by `qa` for FAQ retrieval.\n */\n\nexport type BM25Opts = { k1?: number; b?: number };\n\nexport function bm25TermScore(\n  tf: number,\n  df: number,\n  totalDocs: number,\n  docLen: number,\n  avgDocLen: number,\n  opts: BM25Opts = {},\n): number {\n  const k1 = opts.k1 ?? 1.5;\n  const b = opts.b ?? 0.75;\n  if (tf <= 0 || df <= 0 || totalDocs <= 0) return 0;\n  const idf = Math.log((totalDocs - df + 0.5) / (df + 0.5) + 1);\n  const denom = tf + k1 * (1 - b + (b * docLen) / Math.max(1, avgDocLen));\n  return (idf * (tf * (k1 + 1))) / denom;\n}\n\n/** Saturated TF — caps marginal contribution after `cap` hits. Prevents\n *  keyword spam from dominating ranking. */\nexport function saturateTf(rawTf: number, cap: number): number {\n  if (cap <= 0) return rawTf;\n  return cap * (1 - Math.exp(-rawTf / cap));\n}\n","import type { Doc } from '../common/types.js';\r\n\r\nexport type Posting = { docId: string; fieldFreqs: Record<string, number> };\r\n\r\n/** Tokeniser signature — feeds the inverted index. */\r\nexport type Extract = (text: string) => string[];\r\n\r\nexport class SearchStore {\r\n  postings = new Map<string, Posting[]>();\r\n  docs = new Map<string, Doc>();\r\n  fieldStats = new Map<string, { totalLength: number; docCount: number }>();\r\n  totalDocs = 0;\r\n  features = new Map<string, string[]>();\r\n  private docFieldLengths = new Map<string, Record<string, number>>();\r\n\r\n  add(doc: Doc, extract: Extract): void {\r\n    if (this.docs.has(doc.id)) this.remove(doc.id);\r\n    this.docs.set(doc.id, doc);\r\n    this.totalDocs++;\r\n    const fieldFeats = new Map<string, string[]>();\r\n    const perFieldLen: Record<string, number> = {};\r\n    for (const [field, value] of Object.entries(doc.fields)) {\r\n      const str = String(value ?? '');\r\n      const feats = extract(str);\r\n      fieldFeats.set(field, feats);\r\n      perFieldLen[field] = feats.length;\r\n      const stat = this.fieldStats.get(field) ?? { totalLength: 0, docCount: 0 };\r\n      stat.totalLength += feats.length;\r\n      stat.docCount++;\r\n      this.fieldStats.set(field, stat);\r\n    }\r\n    this.docFieldLengths.set(doc.id, perFieldLen);\r\n    const featCounts = new Map<string, Record<string, number>>();\r\n    for (const [field, feats] of fieldFeats) {\r\n      for (const f of feats) {\r\n        let m = featCounts.get(f);\r\n        if (!m) {\r\n          m = {};\r\n          featCounts.set(f, m);\r\n        }\r\n        m[field] = (m[field] ?? 0) + 1;\r\n      }\r\n    }\r\n    const uniqueFeats: string[] = [];\r\n    for (const [f, fieldFreqs] of featCounts) {\r\n      uniqueFeats.push(f);\r\n      let list = this.postings.get(f);\r\n      if (!list) {\r\n        list = [];\r\n        this.postings.set(f, list);\r\n      }\r\n      list.push({ docId: doc.id, fieldFreqs });\r\n    }\r\n    this.features.set(doc.id, uniqueFeats);\r\n  }\r\n\r\n  remove(docId: string): void {\r\n    const doc = this.docs.get(docId);\r\n    if (!doc) return;\r\n    const feats = this.features.get(docId) ?? [];\r\n    for (const f of feats) {\r\n      const list = this.postings.get(f);\r\n      if (!list) continue;\r\n      const next = list.filter((p) => p.docId !== docId);\r\n      if (next.length === 0) this.postings.delete(f);\r\n      else this.postings.set(f, next);\r\n    }\r\n    const perFieldLen = this.docFieldLengths.get(docId) ?? {};\r\n    for (const field of Object.keys(doc.fields)) {\r\n      const stat = this.fieldStats.get(field);\r\n      if (!stat) continue;\r\n      const len = perFieldLen[field] ?? 0;\r\n      stat.totalLength = Math.max(0, stat.totalLength - len);\r\n      stat.docCount = Math.max(0, stat.docCount - 1);\r\n    }\r\n    this.docFieldLengths.delete(docId);\r\n    this.features.delete(docId);\r\n    this.docs.delete(docId);\r\n    this.totalDocs = Math.max(0, this.totalDocs - 1);\r\n  }\r\n\r\n  candidates(queryFeats: string[]): Set<string> {\r\n    const set = new Set<string>();\r\n    for (const f of queryFeats) {\r\n      const list = this.postings.get(f);\r\n      if (!list) continue;\r\n      for (const p of list) set.add(p.docId);\r\n    }\r\n    return set;\r\n  }\r\n\r\n  postingsFor(feature: string): Posting[] | undefined {\r\n    return this.postings.get(feature);\r\n  }\r\n\r\n  avgFieldLen(field: string): number {\r\n    const s = this.fieldStats.get(field);\r\n    if (!s || s.docCount === 0) return 1;\r\n    return s.totalLength / s.docCount;\r\n  }\r\n}\r\n","import type { Doc } from '../common/types.js';\nimport type { SearchContext, SearchScorer } from './types.js';\nimport { bm25TermScore, saturateTf } from '../../utils/text/bm25.js';\nimport type { SearchStore } from './store.js';\n\nexport type FieldWeightConfig = {\n  weight: number;\n  saturation?: number;\n};\n\nexport type BM25FieldOpts = {\n  weights: Record<string, FieldWeightConfig>;\n  k1?: number;\n  b?: number;\n};\n\n/**\n * Per-field BM25 with saturation. Reads the store from ctx._store (injected by Search).\n */\nexport function bm25Field(opts: BM25FieldOpts): SearchScorer {\n  return {\n    id: 'bm25_field',\n    compute(doc: Doc, ctx: SearchContext): number {\n      const s = ctx._store;\n      if (!s) return 0;\n      const uniqQ = new Set(ctx.queryFeatures);\n      let total = 0;\n      for (const f of uniqQ) {\n        const postings = s.postingsFor(f);\n        if (!postings) continue;\n        const hit = postings.find((p) => p.docId === doc.id);\n        if (!hit) continue;\n        const df = postings.length;\n        for (const [field, freq] of Object.entries(hit.fieldFreqs)) {\n          const fw = opts.weights[field];\n          if (!fw) continue;\n          const sat = saturateTf(freq, fw.saturation ?? 7);\n          const avgLen = s.avgFieldLen(field);\n          const docLen = avgLen;\n          const score = bm25TermScore(sat, df, s.totalDocs, docLen, avgLen, opts);\n          total += score * fw.weight;\n        }\n      }\n      return total;\n    },\n  };\n}\n\nexport type RecencyOpts = { field: string; halfLifeDays?: number };\nexport function recencyDecay(opts: RecencyOpts): SearchScorer {\n  const half = (opts.halfLifeDays ?? 90) * 86_400_000;\n  return {\n    id: 'recency_decay',\n    compute(doc: Doc, ctx: SearchContext): number {\n      const ts = Number(doc.meta?.[opts.field] ?? 0);\n      if (!ts) return 1;\n      const age = Math.max(0, ctx.now - ts);\n      return Math.pow(0.5, age / half);\n    },\n  };\n}\n\nexport type NewProductBoostOpts = { field: string; withinDays?: number; multiplier?: number };\nexport function newProductBoost(opts: NewProductBoostOpts): SearchScorer {\n  const window = (opts.withinDays ?? 30) * 86_400_000;\n  const m = opts.multiplier ?? 1.4;\n  return {\n    id: 'new_product_boost',\n    compute(doc: Doc, ctx: SearchContext): number {\n      const ts = Number(doc.meta?.[opts.field] ?? 0);\n      if (!ts) return 1;\n      return ctx.now - ts < window ? m : 1;\n    },\n  };\n}\n\nexport type BestsellerBoostOpts = {\n  field: string;\n  method?: 'log_normalize' | 'rank_inverse';\n  maxBoost?: number;\n};\nexport function bestsellerBoost(opts: BestsellerBoostOpts): SearchScorer {\n  const max = opts.maxBoost ?? 1.3;\n  return {\n    id: 'bestseller_boost',\n    compute(doc: Doc): number {\n      const v = Number(doc.meta?.[opts.field] ?? 0);\n      if (v <= 0) return 1;\n      if (opts.method === 'rank_inverse') {\n        return 1 + (max - 1) / Math.max(1, v);\n      }\n      // default: log_normalize, with diminishing returns\n      const norm = Math.log1p(v) / Math.log1p(10_000);\n      return 1 + (max - 1) * Math.min(1, norm);\n    },\n  };\n}\n\nexport function promoBoost(opts: { field?: string } = {}): SearchScorer {\n  const field = opts.field ?? 'promo_boost';\n  return {\n    id: 'promo_boost',\n    compute(doc: Doc): number {\n      const v = Number(doc.meta?.[field] ?? 1);\n      return v > 0 ? v : 1;\n    },\n  };\n}\n\nexport function inventoryFilter(opts: { field?: string; min?: number } = {}): SearchScorer {\n  const field = opts.field ?? 'stock_qty';\n  const min = opts.min ?? 1;\n  return {\n    id: 'inventory_filter',\n    compute: () => 1,\n    gate(doc: Doc): boolean {\n      const v = Number(doc.meta?.[field] ?? Infinity);\n      return v >= min;\n    },\n  };\n}\n\nexport function activeFilter(opts: { field?: string } = {}): SearchScorer {\n  const field = opts.field ?? 'active';\n  return {\n    id: 'active_filter',\n    compute: () => 1,\n    gate(doc: Doc): boolean {\n      const v = doc.meta?.[field];\n      return v === undefined || Boolean(v);\n    },\n  };\n}\n\nexport const builtin = {\n  bm25Field,\n  recencyDecay,\n  newProductBoost,\n  bestsellerBoost,\n  promoBoost,\n  inventoryFilter,\n  activeFilter,\n};\n","import { combine, type Adapter, type Doc, identityAdapter } from '../common/types.js';\r\nimport { resolveStorage } from '../../utils/storage/index.js';\r\nimport type { StorageAdapter } from '../../utils/storage/types.js';\r\nimport { extractFeatures as defaultExtract } from '../../utils/text/index.js';\r\nimport { SearchStore } from './store.js';\r\nimport * as builtinAll from './builtin.js';\r\nimport type {\r\n  QueryOpts,\r\n  SearchContext,\r\n  SearchOpts,\r\n  SearchResult,\r\n  SearchScorer,\r\n} from './types.js';\r\n\r\nexport type { SearchOpts, SearchResult, SearchScorer, SearchContext, QueryOpts } from './types.js';\r\nexport const builtin = builtinAll.builtin;\r\n\r\nconst SNAPSHOT_KEY = (id: string) => `search:${id}:snapshot`;\r\nconst VERSION_KEY = (id: string) => `search:${id}:version`;\r\n\r\nexport class Search<TRow = unknown> {\r\n  private id: string;\r\n  private store = new SearchStore();\r\n  private adapter: Adapter<TRow, Doc>;\r\n  private storage: StorageAdapter;\r\n  private scorers: SearchScorer[];\r\n  private weights: Record<string, number>;\r\n  private extract: (text: string) => string[];\r\n  private combiner: SearchOpts<TRow>['combiner'];\r\n  private topK: number;\r\n  private scoreThreshold: number;\r\n  private opts: SearchOpts<TRow>;\r\n  private opened = false;\r\n  private lowConfHook?: (q: string, c: SearchResult[]) => Promise<SearchResult[]>;\r\n  private pollTimer?: ReturnType<typeof setInterval>;\r\n  private unsubscribe?: () => void;\r\n\r\n  constructor(opts: SearchOpts<TRow>) {\r\n    this.id = opts.id ?? 'default';\r\n    this.adapter = (opts.adapter ?? (identityAdapter as unknown as Adapter<TRow, Doc>));\r\n    this.storage = resolveStorage(opts.storage);\r\n    this.scorers = opts.scorers ?? [];\r\n    this.weights = opts.weights ?? {};\r\n    this.extract = opts.extractFeatures ?? defaultExtract;\r\n    this.combiner = opts.combiner ?? 'product';\r\n    this.topK = opts.topK ?? 20;\r\n    this.scoreThreshold = opts.scoreThreshold ?? 0;\r\n    this.opts = opts;\r\n  }\r\n\r\n  async init(): Promise<void> {\r\n    await this.storage.open(`dddk-search-${this.id}`);\r\n    this.opened = true;\r\n    const snapshot = (await this.storage.get(SNAPSHOT_KEY(this.id))) as { docs: Doc[] } | undefined;\r\n    if (snapshot?.docs) {\r\n      for (const d of snapshot.docs) this.store.add(d, this.extract);\r\n    }\r\n    if (this.opts.sync) await this.startSync();\r\n  }\r\n\r\n  async addDoc(row: TRow): Promise<void> {\r\n    const doc = this.adapter.fromRow(row);\r\n    this.store.add(doc, this.extract);\r\n    await this.persist();\r\n  }\r\n\r\n  async addDocs(rows: TRow[]): Promise<void> {\r\n    for (const row of rows) {\r\n      const doc = this.adapter.fromRow(row);\r\n      this.store.add(doc, this.extract);\r\n    }\r\n    await this.persist();\r\n  }\r\n\r\n  async removeDoc(id: string): Promise<void> {\r\n    this.store.remove(id);\r\n    await this.persist();\r\n  }\r\n\r\n  async updateDoc(row: TRow): Promise<void> {\r\n    return this.addDoc(row);\r\n  }\r\n\r\n  async query(text: string, opts: QueryOpts = {}): Promise<SearchResult[]> {\r\n    const queryFeatures = this.extract(text);\r\n    const ctx: SearchContext = {\r\n      query: text,\r\n      queryFeatures,\r\n      now: Date.now(),\r\n      customMeta: opts.customMeta,\r\n      _store: this.store,\r\n    };\r\n    const candIds = this.store.candidates(queryFeatures);\r\n    const results: SearchResult[] = [];\r\n    for (const id of candIds) {\r\n      const doc = this.store.docs.get(id);\r\n      if (!doc) continue;\r\n      let passed = true;\r\n      const partial: Record<string, number> = {};\r\n      for (const s of this.scorers) {\r\n        if (s.gate && !s.gate(doc, ctx)) {\r\n          passed = false;\r\n          break;\r\n        }\r\n        partial[s.id] = s.compute(doc, ctx);\r\n      }\r\n      if (!passed) continue;\r\n      const score = combine(this.combiner ?? 'product', partial, this.weights);\r\n      if (score < (opts.scoreThreshold ?? this.scoreThreshold)) continue;\r\n      const result: SearchResult = { doc, score };\r\n      if (opts.explain) {\r\n        result.explanation = {\r\n          docId: id,\r\n          total: score,\r\n          contributions: Object.entries(partial).map(([signalId, value]) => ({\r\n            signalId,\r\n            value,\r\n            weight: this.weights[signalId] ?? 1,\r\n          })),\r\n        };\r\n      }\r\n      results.push(result);\r\n    }\r\n    results.sort((a, b) => b.score - a.score);\r\n    const top = results.slice(0, opts.topK ?? this.topK);\r\n    const threshold = opts.scoreThreshold ?? this.scoreThreshold;\r\n    if (this.lowConfHook && top.length > 0 && threshold > 0 && (top[0]?.score ?? 0) < threshold * 2) {\r\n      return await this.lowConfHook(text, top);\r\n    }\r\n    return top;\r\n  }\r\n\r\n  explain(text: string, docId: string) {\r\n    const queryFeatures = this.extract(text);\r\n    const doc = this.store.docs.get(docId);\r\n    if (!doc) return undefined;\r\n    const ctx: SearchContext = { query: text, queryFeatures, now: Date.now(), _store: this.store };\r\n    const partial: Record<string, number> = {};\r\n    for (const s of this.scorers) {\r\n      if (s.gate && !s.gate(doc, ctx)) return { docId, total: 0, gated: true, contributions: [] };\r\n      partial[s.id] = s.compute(doc, ctx);\r\n    }\r\n    const total = combine(this.combiner ?? 'product', partial, this.weights);\r\n    return {\r\n      docId,\r\n      total,\r\n      contributions: Object.entries(partial).map(([signalId, value]) => ({\r\n        signalId,\r\n        value,\r\n        weight: this.weights[signalId] ?? 1,\r\n      })),\r\n    };\r\n  }\r\n\r\n  onLowConfidence(fn: (q: string, c: SearchResult[]) => Promise<SearchResult[]>): void {\r\n    this.lowConfHook = fn;\r\n  }\r\n\r\n  async snapshot() {\r\n    return { docs: [...this.store.docs.values()] };\r\n  }\r\n  async restore(snap: { docs: Doc[] }): Promise<void> {\r\n    this.store = new SearchStore();\r\n    for (const d of snap.docs) this.store.add(d, this.extract);\r\n    await this.persist();\r\n  }\r\n\r\n  async dispose(): Promise<void> {\r\n    if (this.pollTimer) clearInterval(this.pollTimer);\r\n    if (this.unsubscribe) this.unsubscribe();\r\n    if (this.opened) await this.storage.close();\r\n    this.opened = false;\r\n  }\r\n\r\n  getDoc(id: string): Doc | undefined {\r\n    return this.store.docs.get(id);\r\n  }\r\n  allDocs(): Iterable<Doc> {\r\n    return this.store.docs.values();\r\n  }\r\n  getFeatures(id: string): string[] | undefined {\r\n    return this.store.features.get(id);\r\n  }\r\n  // Internal access used by adjacent modules (e.g. recommend.contentSimilarity)\r\n  _store(): SearchStore {\r\n    return this.store;\r\n  }\r\n\r\n  private async persist(): Promise<void> {\r\n    if (!this.opened) return;\r\n    await this.storage.set(SNAPSHOT_KEY(this.id), { docs: [...this.store.docs.values()] });\r\n  }\r\n\r\n  private async startSync(): Promise<void> {\r\n    const sync = this.opts.sync;\r\n    if (!sync) return;\r\n    const currentVersion = (await this.storage.get(VERSION_KEY(this.id))) as string | number | undefined;\r\n\r\n    if (currentVersion === undefined && sync.bootstrap) {\r\n      const payload = await sync.bootstrap();\r\n      for (const row of payload.rows) {\r\n        const doc = this.adapter.fromRow(row);\r\n        this.store.add(doc, this.extract);\r\n      }\r\n      await this.persist();\r\n      await this.storage.set(VERSION_KEY(this.id), payload.version);\r\n    }\r\n\r\n    if (sync.subscribe) {\r\n      this.unsubscribe = sync.subscribe(async (delta) => this.applyDeltaPayload(delta));\r\n    } else if (sync.fetchDelta && sync.pollIntervalMs) {\r\n      this.pollTimer = setInterval(async () => {\r\n        const v = (await this.storage.get(VERSION_KEY(this.id))) as string | number | undefined;\r\n        if (v === undefined) return;\r\n        try {\r\n          const payload = await sync.fetchDelta!(v);\r\n          await this.applyDeltaPayload(payload);\r\n        } catch {\r\n          /* swallow */\r\n        }\r\n      }, sync.pollIntervalMs);\r\n    }\r\n  }\r\n\r\n  private async applyDeltaPayload(payload: {\r\n    version: string | number;\r\n    changes: Array<{ op: 'add' | 'update' | 'remove'; row?: TRow; id?: string }>;\r\n  }): Promise<void> {\r\n    for (const ch of payload.changes) {\r\n      if (ch.op === 'remove' && ch.id) this.store.remove(ch.id);\r\n      else if (ch.row) {\r\n        const d = this.adapter.fromRow(ch.row);\r\n        this.store.add(d, this.extract);\r\n      }\r\n    }\r\n    await this.persist();\r\n    await this.storage.set(VERSION_KEY(this.id), payload.version);\r\n  }\r\n}\r\n\r\nexport function createSearch<TRow = unknown>(opts: SearchOpts<TRow>): Search<TRow> {\r\n  return new Search<TRow>(opts);\r\n}\r\n","import type { Doc, Signal, Combiner } from '../common/types.js';\r\nimport { combine } from '../common/types.js';\r\nimport { resolveStorage } from '../../utils/storage/index.js';\r\nimport type { StorageAdapter, StorageKind } from '../../utils/storage/types.js';\r\n\r\n/**\r\n * Structural interface a catalog implementation must satisfy to feed\r\n * `Recommend`. The shipped `Search` class implements this naturally, so\r\n * the most common wiring is still\r\n *\r\n *   const cat = createSearch({...});\r\n *   const rec = createRecommend({ catalog: cat, ... });\r\n *\r\n * but the interface lets hosts plug their own catalog backend in —\r\n * e.g. a remote-paged vector store, a graph-based retriever, or a\r\n * raw in-memory list with no BM25 layer at all. Whatever holds your\r\n * docs and can yield their features for similarity matching works.\r\n */\r\nexport interface RecommendCatalog {\r\n  /** Look up a single doc by id. */\r\n  getDoc(id: string): Doc | undefined;\r\n  /** Yield every doc the catalog knows about. Order doesn't matter —\r\n   *  `Recommend` scores then re-sorts. */\r\n  allDocs(): Iterable<Doc>;\r\n  /** Return the feature-vector / token list for the doc with this id,\r\n   *  or `undefined` if absent. Used by `contentSimilarity` and the\r\n   *  preference-match scorer to compute Jaccard-style overlap. */\r\n  getFeatures(id: string): string[] | undefined;\r\n}\r\n\r\nexport type Preference = {\r\n  productId: string;\r\n  response: 'yes' | 'no' | 'dismiss';\r\n  ts: number;\r\n  context?: Record<string, unknown>;\r\n};\r\n\r\nexport type RecommendContext = {\r\n  userId?: string;\r\n  source?: 'similarTo' | 'forCustomer' | 'goesWith';\r\n  sourceProductId?: string | string[];\r\n  now: number;\r\n  prefs?: Preference[];\r\n  customMeta?: Record<string, unknown>;\r\n};\r\n\r\nexport type RecommendScorer = Signal<Doc, RecommendContext> & {\r\n  gate?(doc: Doc, ctx: RecommendContext): boolean;\r\n};\r\n\r\nexport type DiversityOpts = {\r\n  /** meta field to diversify on (e.g. 'category'). */\r\n  field: string;\r\n  /** 0..1 — higher = more diversity. Pure MMR lambda is (1 - this). */\r\n  weight?: number;\r\n  /** how many candidates to consider in MMR pool before slicing topK. */\r\n  poolSize?: number;\r\n};\r\n\r\nexport type RecommendOpts = {\r\n  id?: string;\r\n  /**\r\n   * Doc source. Any object with `getDoc` / `allDocs` / `getFeatures` works\r\n   * — the shipped `Search` class satisfies this out of the box, but hosts\r\n   * can pass a custom backend (vector store, graph retriever, etc.).\r\n   */\r\n  catalog: RecommendCatalog;\r\n  customerId?: string;\r\n  storage?: StorageKind;\r\n  signals: RecommendScorer[];\r\n  weights?: Record<string, number>;\r\n  combiner?: Combiner;\r\n  topK?: number;\r\n  diversity?: DiversityOpts;\r\n  prefsSync?: {\r\n    bootstrap?: () => Promise<Preference[]>;\r\n    pushChange?: (p: Preference) => Promise<void>;\r\n  };\r\n};\r\n\r\nexport class Recommend {\r\n  private id: string;\r\n  private catalog: RecommendCatalog;\r\n  private customerId?: string;\r\n  private storage: StorageAdapter;\r\n  private signals: RecommendScorer[];\r\n  private weights: Record<string, number>;\r\n  private combiner: Combiner;\r\n  private topK: number;\r\n  private prefs: Preference[] = [];\r\n  private opened = false;\r\n  private opts: RecommendOpts;\r\n\r\n  constructor(opts: RecommendOpts) {\r\n    this.id = opts.id ?? 'default';\r\n    this.catalog = opts.catalog;\r\n    this.customerId = opts.customerId;\r\n    this.storage = resolveStorage(opts.storage ?? 'indexeddb');\r\n    this.signals = opts.signals;\r\n    this.weights = opts.weights ?? {};\r\n    this.combiner = opts.combiner ?? 'product';\r\n    this.topK = opts.topK ?? 10;\r\n    this.opts = opts;\r\n  }\r\n\r\n  async init(): Promise<void> {\r\n    await this.storage.open(`dddk-recommend-${this.id}`);\r\n    this.opened = true;\r\n    const snap = (await this.storage.get('recommend:prefs')) as Preference[] | undefined;\r\n    if (snap != null && snap.length > 0) {\r\n      this.prefs = snap;\r\n    } else if (this.opts.prefsSync?.bootstrap) {\r\n      this.prefs = await this.opts.prefsSync.bootstrap();\r\n      await this.storage.set('recommend:prefs', this.prefs);\r\n    } else if (snap != null) {\r\n      this.prefs = snap;\r\n    }\r\n  }\r\n\r\n  async recordPreference(p: Omit<Preference, 'ts'> & { ts?: number }): Promise<void> {\r\n    const pref: Preference = { ...p, ts: p.ts ?? Date.now() };\r\n    this.prefs.push(pref);\r\n    if (this.opened) await this.storage.set('recommend:prefs', this.prefs);\r\n    if (this.opts.prefsSync?.pushChange) {\r\n      try {\r\n        await this.opts.prefsSync.pushChange(pref);\r\n      } catch {\r\n        /* swallow */\r\n      }\r\n    }\r\n  }\r\n\r\n  async similarTo(productId: string, opts: { topK?: number } = {}): Promise<Array<{ doc: Doc; score: number }>> {\r\n    const ctx: RecommendContext = {\r\n      userId: this.customerId,\r\n      source: 'similarTo',\r\n      sourceProductId: productId,\r\n      now: Date.now(),\r\n      prefs: this.prefs,\r\n    };\r\n    return this.rank(ctx, (d) => d.id !== productId, opts.topK ?? this.topK);\r\n  }\r\n\r\n  async forCustomer(opts: { topK?: number } = {}): Promise<Array<{ doc: Doc; score: number }>> {\r\n    const ctx: RecommendContext = {\r\n      userId: this.customerId,\r\n      source: 'forCustomer',\r\n      now: Date.now(),\r\n      prefs: this.prefs,\r\n    };\r\n    return this.rank(ctx, () => true, opts.topK ?? this.topK);\r\n  }\r\n\r\n  async goesWith(productIds: string[], opts: { topK?: number } = {}): Promise<Array<{ doc: Doc; score: number }>> {\r\n    const ctx: RecommendContext = {\r\n      userId: this.customerId,\r\n      source: 'goesWith',\r\n      sourceProductId: productIds,\r\n      now: Date.now(),\r\n      prefs: this.prefs,\r\n    };\r\n    const set = new Set(productIds);\r\n    return this.rank(ctx, (d) => !set.has(d.id), opts.topK ?? this.topK);\r\n  }\r\n\r\n  explain(productId: string, ctx?: Partial<RecommendContext>) {\r\n    const doc = this.catalog.getDoc(productId);\r\n    if (!doc) return undefined;\r\n    const full: RecommendContext = {\r\n      userId: this.customerId,\r\n      source: 'forCustomer',\r\n      now: Date.now(),\r\n      prefs: this.prefs,\r\n      ...ctx,\r\n    };\r\n    const partial: Record<string, number> = {};\r\n    for (const s of this.signals) {\r\n      if (s.gate && !s.gate(doc, full)) return { docId: productId, total: 0, gated: true, contributions: [] };\r\n      partial[s.id] = s.compute(doc, full);\r\n    }\r\n    const total = combine(this.combiner, partial, this.weights);\r\n    return {\r\n      docId: productId,\r\n      total,\r\n      contributions: Object.entries(partial).map(([signalId, value]) => ({\r\n        signalId,\r\n        value,\r\n        weight: this.weights[signalId] ?? 1,\r\n      })),\r\n    };\r\n  }\r\n\r\n  private rank(ctx: RecommendContext, filter: (d: Doc) => boolean, topK: number) {\r\n    const results: Array<{ doc: Doc; score: number }> = [];\r\n    for (const doc of this.catalog.allDocs()) {\r\n      if (!filter(doc)) continue;\r\n      let passed = true;\r\n      const partial: Record<string, number> = {};\r\n      for (const s of this.signals) {\r\n        if (s.gate && !s.gate(doc, ctx)) {\r\n          passed = false;\r\n          break;\r\n        }\r\n        partial[s.id] = s.compute(doc, ctx);\r\n      }\r\n      if (!passed) continue;\r\n      const score = combine(this.combiner, partial, this.weights);\r\n      results.push({ doc, score });\r\n    }\r\n    results.sort((a, b) => b.score - a.score);\r\n\r\n    // Optional diversity re-rank (MMR-style: greedy max relevance penalized by similarity to already-picked)\r\n    const div = this.opts.diversity;\r\n    if (div) {\r\n      const pool = results.slice(0, div.poolSize ?? topK * 5);\r\n      const picked: Array<{ doc: Doc; score: number }> = [];\r\n      const lambda = 1 - (div.weight ?? 0.3);\r\n      while (picked.length < topK && pool.length > 0) {\r\n        let bestIdx = 0;\r\n        let bestMmr = -Infinity;\r\n        for (let i = 0; i < pool.length; i++) {\r\n          const cand = pool[i]!;\r\n          const candValue = String(cand.doc.meta?.[div.field] ?? '');\r\n          let maxSim = 0;\r\n          for (const p of picked) {\r\n            const pv = String(p.doc.meta?.[div.field] ?? '');\r\n            if (pv && candValue && pv === candValue) {\r\n              maxSim = 1;\r\n              break;\r\n            }\r\n          }\r\n          const mmr = lambda * cand.score - (1 - lambda) * maxSim * (results[0]?.score ?? 1);\r\n          if (mmr > bestMmr) {\r\n            bestMmr = mmr;\r\n            bestIdx = i;\r\n          }\r\n        }\r\n        picked.push(pool.splice(bestIdx, 1)[0]!);\r\n      }\r\n      return picked;\r\n    }\r\n\r\n    return results.slice(0, topK);\r\n  }\r\n\r\n  async dispose(): Promise<void> {\r\n    if (this.opened) await this.storage.close();\r\n    this.opened = false;\r\n  }\r\n}\r\n\r\n// ── Built-in signals ──\r\n\r\nfunction contentSimilarity(opts: { source: RecommendCatalog }): RecommendScorer {\r\n  return {\r\n    id: 'content_similarity',\r\n    compute(doc, ctx) {\r\n      const sourceId = Array.isArray(ctx.sourceProductId) ? ctx.sourceProductId[0] : ctx.sourceProductId;\r\n      if (!sourceId) return 0;\r\n      const sFeats = opts.source.getFeatures(sourceId);\r\n      const tFeats = opts.source.getFeatures(doc.id);\r\n      if (!sFeats || !tFeats) return 0;\r\n      const sSet = new Set(sFeats);\r\n      let overlap = 0;\r\n      for (const f of tFeats) if (sSet.has(f)) overlap++;\r\n      const denom = Math.sqrt(sFeats.length * tFeats.length) || 1;\r\n      return overlap / denom;\r\n    },\r\n  };\r\n}\r\n\r\nfunction recencyDecay(opts: { field?: string; halfLifeDays?: number } = {}): RecommendScorer {\r\n  const field = opts.field ?? 'listed_at';\r\n  const half = (opts.halfLifeDays ?? 90) * 86_400_000;\r\n  return {\r\n    id: 'recency_decay',\r\n    compute(doc, ctx) {\r\n      const ts = Number(doc.meta?.[field] ?? 0);\r\n      if (!ts) return 1;\r\n      const age = Math.max(0, ctx.now - ts);\r\n      return Math.pow(0.5, age / half);\r\n    },\r\n  };\r\n}\r\n\r\nfunction coldStartBayesian(opts: { priorWeight?: number; priorRate?: number; yesField?: string; eventsField?: string } = {}): RecommendScorer {\r\n  const k = opts.priorWeight ?? 50;\r\n  const prior = opts.priorRate ?? 0.5;\r\n  const yes = opts.yesField ?? 'lifetime_yes_count';\r\n  const events = opts.eventsField ?? 'lifetime_event_count';\r\n  return {\r\n    id: 'cold_start_bayesian',\r\n    compute(doc) {\r\n      const y = Number(doc.meta?.[yes] ?? 0);\r\n      const e = Number(doc.meta?.[events] ?? 0);\r\n      return (y + prior * k) / (e + k);\r\n    },\r\n  };\r\n}\r\n\r\nfunction saturation(opts: { field: string; cap?: number }): RecommendScorer {\r\n  const cap = opts.cap ?? 200;\r\n  return {\r\n    id: 'saturation_' + opts.field,\r\n    compute(doc) {\r\n      const v = Number(doc.meta?.[opts.field] ?? 0);\r\n      return cap * (1 - Math.exp(-v / cap));\r\n    },\r\n  };\r\n}\r\n\r\nfunction promoBoost(opts: { field?: string } = {}): RecommendScorer {\r\n  const field = opts.field ?? 'promo_boost';\r\n  return {\r\n    id: 'promo_boost',\r\n    compute(doc) {\r\n      const v = Number(doc.meta?.[field] ?? 1);\r\n      return v > 0 ? v : 1;\r\n    },\r\n  };\r\n}\r\n\r\nfunction preferenceMatch(opts: { catalog: RecommendCatalog; yesBoost?: number; noBoost?: number } = {} as never): RecommendScorer {\r\n  const yesBoost = opts.yesBoost ?? 2.0;\r\n  const noBoost = opts.noBoost ?? 0.3;\r\n  return {\r\n    id: 'preference_match',\r\n    compute(doc, ctx) {\r\n      const prefs = ctx.prefs ?? [];\r\n      if (prefs.length === 0) return 1;\r\n      const targetFeats = new Set(opts.catalog.getFeatures(doc.id) ?? []);\r\n      let yesOverlap = 0;\r\n      let noOverlap = 0;\r\n      for (const p of prefs) {\r\n        const f = opts.catalog.getFeatures(p.productId);\r\n        if (!f) continue;\r\n        let overlap = 0;\r\n        for (const x of f) if (targetFeats.has(x)) overlap++;\r\n        if (p.response === 'yes') yesOverlap += overlap;\r\n        else if (p.response === 'no') noOverlap += overlap;\r\n      }\r\n      const yesFactor = 1 + (yesBoost - 1) * Math.tanh(yesOverlap / 10);\r\n      const noFactor = noBoost + (1 - noBoost) * Math.exp(-noOverlap / 10);\r\n      return yesFactor * noFactor;\r\n    },\r\n  };\r\n}\r\n\r\nfunction diversityPenalty(opts: { field: string; topNPenalty?: number }): RecommendScorer {\r\n  // Note: true diversity needs post-ranking; this stub just deprioritizes overrepresented categories\r\n  void opts;\r\n  return {\r\n    id: 'diversity_penalty',\r\n    compute: () => 1,\r\n  };\r\n}\r\n\r\nexport const builtin = {\r\n  contentSimilarity,\r\n  recencyDecay,\r\n  coldStartBayesian,\r\n  saturation,\r\n  promoBoost,\r\n  preferenceMatch,\r\n  diversityPenalty,\r\n};\r\n\r\nexport function createRecommend(opts: RecommendOpts): Recommend {\r\n  return new Recommend(opts);\r\n}\r\n","/**\n * Tool registry — host-friendly API for exposing arbitrary capabilities\n * (QA, search, recommend, custom domain ops) to the webagent.\n *\n * What this gives you:\n *   - `dddk.tools.register({...})` — register any ActionDefinition; the\n *     webagent picks it up on next build, and if the agent is already\n *     running, the new tool is added live via `agent.registerAction(...)`.\n *   - `dddk.tools.registerQA({items, description?})` — convenience\n *     wrapper that takes a list of FAQ items, spins up a `dddk/toolbox/qa`\n *     instance internally, and exposes it as a `<id>_lookup` tool the\n *     LLM can call (e.g. agent decides on its own \"I should look this\n *     up in the company FAQ first\").\n *   - `dddk.tools.unregister(id)` — remove a tool.\n *   - `dddk.tools.list()` — read the current set (for debugging).\n *\n * Design notes:\n *   - QA / search / recommend are NOT palette panel demos. They are\n *     tools the agent uses automatically when it reasons. Putting them\n *     in the palette as standalone surfaces forces the user to pick\n *     which tool to use; registering them as agent tools lets the LLM\n *     decide.\n *   - The host can also provide per-turn context via the WebAgent\n *     config's `brand` + `appendSystemPrompt` fields — that's\n *     orthogonal to tools.\n */\n\nimport type {\n  ActionDefinition,\n  ActionResult,\n} from './agent';\nimport type { WebAgent } from './agent';\nimport { createSearch } from './toolbox/search/index.js';\nimport { builtin as searchBuiltin } from './toolbox/search/builtin.js';\nimport { createRecommend, builtin as recBuiltin } from './toolbox/recommend/index.js';\n\nexport interface ToolSpec extends ActionDefinition {\n  /** Optional human label shown in `tools.list()` output. */\n  label?: string;\n}\n\nexport interface QAToolItem {\n  id: string;\n  question: string;\n  answer: string;\n  category?: string;\n  lang?: string;\n}\n\nexport interface RegisterQAOpts {\n  /** Tool id. Default `'qa_lookup'`. Becomes the agent-visible action\n   *  name (must be alphanumeric + underscore, no slashes/dots). */\n  id?: string;\n  /** FAQ entries. Host can pass mixed-language items; the QA module\n   *  auto-detects per-item. */\n  items: QAToolItem[];\n  /** Override description the LLM sees. Default tells the agent this\n   *  is the canonical \"look something up in the company knowledge\n   *  base\" tool. */\n  description?: string;\n  /** topK returned to the LLM. Default 3. */\n  topK?: number;\n}\n\n/** Search-tool registration — wires `dddk/toolbox/search` as a tool. */\nexport interface RegisterSearchOpts<TRow> {\n  /** Tool id. Default `'search_catalog'`. */\n  id?: string;\n  /** Default description: \"search the product catalog by free text\". */\n  description?: string;\n  /** Items the search index holds (products, articles, …). */\n  items: TRow[];\n  /** Map each row to `{ id, fields, meta? }`. The `fields` keys become\n   *  searchable text per-row; `fields` values can be strings or string\n   *  arrays. */\n  toDoc: (row: TRow) => { id: string; fields: Record<string, string | string[]>; meta?: Record<string, unknown> };\n  /** Per-field weight + tf-saturation. Default: weight 1.0, sat 7. */\n  fieldWeights?: Record<string, number>;\n  /** topK returned. Default 5. */\n  topK?: number;\n}\n\n/** Recommender-tool registration — wires `dddk/toolbox/recommend`. */\nexport interface RegisterRecommendOpts<TRow> {\n  /** Tool id prefix. Default `'recommend'` → produces actions\n   *  `recommend_for_customer`, `recommend_similar`. */\n  id?: string;\n  /** Description for the `for_customer` variant. */\n  forCustomerDescription?: string;\n  /** Description for the `similar` variant. */\n  similarDescription?: string;\n  /** Catalog items. */\n  items: TRow[];\n  toDoc: (row: TRow) => { id: string; fields: Record<string, string | string[]>; meta?: Record<string, unknown> };\n  /** Customer ID for preference scoping. Default `'anon'`. */\n  customerId?: string;\n  /** topK returned. Default 5. */\n  topK?: number;\n}\n\n/**\n * Internal — the orchestrator instantiates this and exposes a subset\n * as `dddk.tools`. Holds the buffer of registered tools so the\n * WebAgent picks them up at build-time AND can be added at runtime.\n */\nexport class ToolsRegistry {\n  private tools = new Map<string, ToolSpec>();\n  /** Set by the orchestrator after WebAgent is built so runtime\n   *  registrations land in the live agent immediately. */\n  private liveAgent: WebAgent | null = null;\n\n  attachAgent(agent: WebAgent): void {\n    this.liveAgent = agent;\n    // Replay all already-registered tools into the live agent so order\n    // of (host registers tool) → (host opens dddk for first time) doesn't\n    // matter.\n    for (const spec of this.tools.values()) {\n      try { agent.registerAction(spec); } catch { /* swallow */ }\n    }\n  }\n\n  detachAgent(): void {\n    this.liveAgent = null;\n  }\n\n  /** All currently-registered tools — passed to WebAgent at build time. */\n  snapshot(): ActionDefinition[] {\n    return [...this.tools.values()];\n  }\n\n  register(spec: ToolSpec): void {\n    if (!/^[a-z][a-z0-9_]*$/i.test(spec.name)) {\n      throw new Error(`tool name \"${spec.name}\" must be alphanumeric + underscore`);\n    }\n    this.tools.set(spec.name, spec);\n    if (this.liveAgent) {\n      try { this.liveAgent.registerAction(spec); } catch { /* swallow */ }\n    }\n  }\n\n  unregister(id: string): boolean {\n    const removed = this.tools.delete(id);\n    // v0.2.0: WebAgent now supports runtime un-register\n    // via `unregisterAction`. Mirror the delete into the live agent\n    // so the next step actually loses the tool.\n    if (removed && this.liveAgent) {\n      try { this.liveAgent.unregisterAction(id); } catch { /* swallow */ }\n    }\n    return removed;\n  }\n\n  list(): ToolSpec[] {\n    return [...this.tools.values()];\n  }\n\n  /**\n   *\n   * Wait for any in-flight agent turn to complete, so the very next\n   * turn observes whatever tools have just been registered. Without\n   * this, mid-flight `register(...)` calls only apply to subsequent\n   * turns — the in-flight turn finishes with the snapshot it started\n   * with, which is correct but surprises hosts.\n   *\n   * If no agent is attached or no run is in flight, resolves\n   * immediately. Otherwise resolves when the current run reaches idle.\n   *\n   * Implementation note: WebAgent doesn't expose a public event\n   * emitter, so this poll-until-idle approach is the lowest-coupling\n   * way to wire the same semantics. Poll interval is 100ms — agent\n   * turn boundaries are typically 1-3s on `gpt-5.4-nano`, so the\n   * loop tops out at ~30 polls per turn.\n   */\n  async flush(): Promise<void> {\n    const agent = this.liveAgent;\n    if (!agent) return;\n    // Peek at WebAgent's status via the public `isRunning` semantics.\n    // We can't import WebAgent's status directly without a type\n    // dependency, so probe via the session: a non-null session whose\n    // status is 'thinking' / 'executing' / 'waiting' means there's\n    // a turn in progress.\n    type StatusProbe = { isRunning?: () => boolean };\n    const probe = agent as unknown as StatusProbe;\n    if (typeof probe.isRunning !== 'function') return;\n    if (!probe.isRunning()) return;\n    return new Promise<void>((resolve) => {\n      const t = setInterval(() => {\n        if (typeof probe.isRunning !== 'function' || !probe.isRunning()) {\n          clearInterval(t);\n          resolve();\n        }\n      }, 100);\n    });\n  }\n\n  // ─── QA convenience ────────────────────────────────────────────\n\n  /**\n   * Wire a FAQ dataset as a webagent tool. The LLM sees one action\n   * (`qa_lookup` by default) that takes a `question: string` and gets\n   * back the top matched entries. Lets the agent decide on its own\n   * \"the user is asking about refunds, let me check the FAQ\" without\n   * the host having to wire each FAQ entry as a separate tool.\n   */\n  registerQA(opts: RegisterQAOpts): void {\n    const id = opts.id ?? 'qa_lookup';\n    const topK = opts.topK ?? 3;\n    const description = opts.description ??\n      'Look up an answer in the company knowledge base (FAQ — refund, shipping, payment, account, privacy, etc.). Call this whenever the user asks something that likely has a canonical answer. Returns the top 3 matching FAQ entries with their answers and confidence.';\n\n    // Index FAQ entries with a BM25 search over the question field.\n    // Each Doc is `{ id, fields: { question, answer }, meta: { category } }`;\n    // recall the entry by ranking on the `question` field only — the\n    // answer text would otherwise pollute the score for off-topic queries\n    // that share vocabulary with the body.\n    type QASearchRow = { id: string; question: string; answer: string; category?: string };\n    let searchInstance: ReturnType<typeof createSearch<QASearchRow>> | null = null;\n    let initPromise: Promise<void> | null = null;\n    const getSearch = () => {\n      if (searchInstance) return searchInstance;\n      searchInstance = createSearch<QASearchRow>({\n        adapter: {\n          fromRow: (row) => ({\n            id: row.id,\n            fields: { question: row.question, answer: row.answer },\n            meta: { category: row.category, answer: row.answer },\n          }),\n        },\n        scorers: [\n          {\n            id: 'bm25_question',\n            compute: (doc, ctx) => {\n              // Hand-rolled BM25 against the `question` field only.\n              const store = ctx._store;\n              if (!store) return 0;\n              const uniqQ = new Set(ctx.queryFeatures);\n              let total = 0;\n              for (const f of uniqQ) {\n                const postings = store.postingsFor(f);\n                if (!postings) continue;\n                const hit = postings.find((p) => p.docId === doc.id);\n                if (!hit) continue;\n                const tf = hit.fieldFreqs['question'] ?? 0;\n                if (tf === 0) continue;\n                const N = store.totalDocs;\n                const df = postings.length;\n                const avgLen = store.avgFieldLen('question');\n                // Reuse the same BM25 the search module ships with.\n                const idf = Math.log((N - df + 0.5) / (df + 0.5) + 1);\n                const k1 = 1.5;\n                const b = 0.75;\n                const denom = tf + k1 * (1 - b + (b * avgLen) / Math.max(1, avgLen));\n                total += (idf * (tf * (k1 + 1))) / denom;\n              }\n              return total;\n            },\n          },\n        ],\n        combiner: 'weighted_sum',\n        weights: { bm25_question: 1.0 },\n        topK,\n      });\n      const inst = searchInstance;\n      initPromise = (async () => {\n        await inst.init();\n        await inst.addDocs(opts.items.map((it) => ({\n          id: it.id,\n          question: it.question,\n          answer: it.answer,\n          category: it.category,\n        })));\n      })();\n      return inst;\n    };\n\n    this.register({\n      name: id,\n      description,\n      parameters: {\n        type: 'object',\n        properties: {\n          question: {\n            type: 'string',\n            description: 'The user question to look up, in the user\\'s own words.',\n          },\n        },\n        required: ['question'],\n      },\n      handler: async (params: unknown): Promise<ActionResult<unknown>> => {\n        const question = (params as { question?: string })?.question ?? '';\n        try {\n          const search = getSearch();\n          if (initPromise) { await initPromise; initPromise = null; }\n          const results = await search.query(question, { topK });\n          // Map results back to {q, a, score, category} shape the LLM sees.\n          const max = results[0]?.score ?? 0;\n          const matches = results.map((r) => {\n            const ratio = max > 0 ? r.score / max : 0;\n            const confidence: 'high' | 'medium' | 'low' =\n              ratio > 0.8 ? 'high' : ratio > 0.5 ? 'medium' : 'low';\n            return {\n              q: r.doc.fields.question,\n              a: typeof r.doc.meta?.answer === 'string' ? r.doc.meta.answer : '',\n              confidence,\n              score: r.score,\n              category: typeof r.doc.meta?.category === 'string' ? r.doc.meta.category : undefined,\n            };\n          });\n          return { ok: true, data: { matches } };\n        } catch (err) {\n          return { ok: false, reason: 'unknown', message: (err as Error).message };\n        }\n      },\n    });\n  }\n\n  // ─── Search convenience ────────────────────────────────────────\n\n  /**\n   * Wire a catalog as a search tool. The LLM sees `search_catalog(query)`\n   * and can call it to find products / articles / records by free text.\n   * Backed by `dddk/toolbox/search` with per-field BM25.\n   */\n  registerSearch<TRow>(opts: RegisterSearchOpts<TRow>): void {\n    const id = opts.id ?? 'search_catalog';\n    const topK = opts.topK ?? 5;\n    const description = opts.description ??\n      'Full-text search the product catalog. Call this when the user wants to find a specific item by name, description, or keyword. Returns the top matching catalog rows with relevance scores.';\n    const fieldWeights = opts.fieldWeights ?? { title: 3.0, body: 1.0 };\n\n    // Async setup runs once on first call.\n    let searchInstance: ReturnType<typeof createSearch<TRow>> | null = null;\n    let initPromise: Promise<void> | null = null;\n    const getSearch = () => {\n      if (searchInstance) return searchInstance;\n      const fieldWeightsConfig: Record<string, { weight: number; saturation?: number }> = {};\n      for (const [field, weight] of Object.entries(fieldWeights)) {\n        fieldWeightsConfig[field] = { weight };\n      }\n      searchInstance = createSearch<TRow>({\n        adapter: {\n          fromRow: (row) => {\n            const d = opts.toDoc(row);\n            // Doc.fields is string-only; collapse arrays to space-joined.\n            const flat: Record<string, string> = {};\n            for (const [k, v] of Object.entries(d.fields)) {\n              flat[k] = Array.isArray(v) ? v.join(' ') : v;\n            }\n            return { id: d.id, fields: flat, ...(d.meta ? { meta: d.meta } : {}) };\n          },\n        },\n        scorers: [searchBuiltin.bm25Field({ weights: fieldWeightsConfig })],\n        weights: { bm25_field: 1.0 },\n        combiner: 'weighted_sum',\n        topK,\n      });\n      const inst = searchInstance;\n      initPromise = (async () => {\n        await inst.init();\n        await inst.addDocs(opts.items);\n      })();\n      return inst;\n    };\n\n    this.register({\n      name: id,\n      description,\n      parameters: {\n        type: 'object',\n        properties: {\n          query: { type: 'string', description: 'Free-text search query.' },\n        },\n        required: ['query'],\n      },\n      handler: async (params: unknown): Promise<ActionResult<unknown>> => {\n        const query = (params as { query?: string })?.query ?? '';\n        const s = getSearch();\n        try {\n          if (initPromise) { await initPromise; initPromise = null; }\n          const results = await s.query(query, { topK });\n          const hits = results.map((r) => ({\n            id: r.doc.id,\n            fields: r.doc.fields,\n            meta: r.doc.meta,\n            score: r.score,\n          }));\n          return { ok: true, data: { hits } };\n        } catch (err) {\n          return { ok: false, reason: 'unknown', message: (err as Error).message };\n        }\n      },\n    });\n  }\n\n  // ─── Recommender convenience ───────────────────────────────────\n\n  /**\n   * Wire a recommender as TWO tools — `recommend_for_customer` (no\n   * input, returns personalised top-K) and `recommend_similar` (given\n   * a product id, returns similar items). The recommender uses the\n   * same catalog as the search builder and learns from\n   * `recordPreference(productId, response)` calls — the LLM can hand\n   * the user's ♥/✕ choices back to the recommender by calling\n   * `record_preference` (third tool registered here).\n   */\n  registerRecommend<TRow>(opts: RegisterRecommendOpts<TRow>): void {\n    const idPrefix = opts.id ?? 'recommend';\n    const topK = opts.topK ?? 5;\n\n    // Recommend needs a Search-backed catalog. Build a dedicated Search\n    // instance per recommender (NOT shared with the search tool, so the\n    // host can use both independently with different field weights).\n    let recInstance: ReturnType<typeof createRecommend> | null = null;\n    let initPromise: Promise<void> | null = null;\n    const getRec = () => {\n      if (recInstance) return recInstance;\n      const catalog = createSearch<TRow>({\n        adapter: {\n          fromRow: (row) => {\n            const d = opts.toDoc(row);\n            // Doc.fields is string-only; collapse arrays to space-joined.\n            const flat: Record<string, string> = {};\n            for (const [k, v] of Object.entries(d.fields)) {\n              flat[k] = Array.isArray(v) ? v.join(' ') : v;\n            }\n            return { id: d.id, fields: flat, ...(d.meta ? { meta: d.meta } : {}) };\n          },\n        },\n        scorers: [searchBuiltin.bm25Field({ weights: { title: { weight: 2 } } })],\n      });\n      recInstance = createRecommend({\n        catalog,\n        customerId: opts.customerId ?? 'anon',\n        signals: [recBuiltin.preferenceMatch({ catalog })],\n        weights: { preference_match: 1.0 },\n        combiner: 'weighted_sum',\n        topK,\n      });\n      const cat = catalog;\n      const rec = recInstance;\n      initPromise = (async () => {\n        await cat.init();\n        await cat.addDocs(opts.items);\n        await rec.init();\n      })();\n      return rec;\n    };\n\n    this.register({\n      name: `${idPrefix}_for_customer`,\n      description: opts.forCustomerDescription ??\n        'Get personalised recommendations for the current customer based on their accumulated likes / dislikes. Returns top items with scores.',\n      parameters: { type: 'object', properties: {} },\n      handler: async (): Promise<ActionResult<unknown>> => {\n        try {\n          const rec = getRec();\n          if (initPromise) { await initPromise; initPromise = null; }\n          const results = await rec.forCustomer({ topK });\n          return { ok: true, data: { recommendations: results.map((r) => ({ id: r.doc.id, fields: r.doc.fields, score: r.score })) } };\n        } catch (err) {\n          return { ok: false, reason: 'unknown', message: (err as Error).message };\n        }\n      },\n    });\n\n    this.register({\n      name: `${idPrefix}_similar`,\n      description: opts.similarDescription ??\n        'Find items similar to a given product. Useful when the user is browsing one item and wants suggestions like it.',\n      parameters: {\n        type: 'object',\n        properties: { productId: { type: 'string', description: 'Catalog id of the seed item.' } },\n        required: ['productId'],\n      },\n      handler: async (params: unknown): Promise<ActionResult<unknown>> => {\n        const productId = (params as { productId?: string })?.productId ?? '';\n        try {\n          const rec = getRec();\n          if (initPromise) { await initPromise; initPromise = null; }\n          const results = await rec.similarTo(productId, { topK });\n          return { ok: true, data: { recommendations: results.map((r) => ({ id: r.doc.id, fields: r.doc.fields, score: r.score })) } };\n        } catch (err) {\n          return { ok: false, reason: 'unknown', message: (err as Error).message };\n        }\n      },\n    });\n\n    this.register({\n      name: 'record_preference',\n      description:\n        'Record that the user likes (response=\"yes\"), dislikes (\"no\"), or dismissed (\"dismiss\") a product. Affects future recommendations.',\n      parameters: {\n        type: 'object',\n        properties: {\n          productId: { type: 'string' },\n          response: { type: 'string', enum: ['yes', 'no', 'dismiss'] },\n        },\n        required: ['productId', 'response'],\n      },\n      handler: async (params: unknown): Promise<ActionResult<unknown>> => {\n        const { productId, response } = (params as { productId?: string; response?: 'yes' | 'no' | 'dismiss' });\n        if (!productId || !response) {\n          return { ok: false, reason: 'unknown', message: 'productId and response required' };\n        }\n        try {\n          const rec = getRec();\n          if (initPromise) { await initPromise; initPromise = null; }\n          await rec.recordPreference({ productId, response });\n          return { ok: true, data: { recorded: true } };\n        } catch (err) {\n          return { ok: false, reason: 'unknown', message: (err as Error).message };\n        }\n      },\n    });\n  }\n}\n","/**\r\n * Skill preferences — declarative per-skill settings.\r\n *\r\n * When a skill declares preferences, dddk:\r\n *   1. Refuses to run the skill until all `required: true` prefs are filled.\r\n *   2. Auto-renders a setup form (as a Surface) the first time.\r\n *   3. Stores values keyed by skill id via the dddk StorageAdapter.\r\n *   4. Provides `ctx.getPreferences<T>()` inside the skill handler.\r\n */\r\n\r\nimport type { StorageAdapter } from '../types';\r\nimport { sdkString } from '../utils/sdk-i18n';\r\n\r\nexport type PreferenceKind = 'text' | 'password' | 'number' | 'checkbox' | 'select';\r\n\r\nexport interface PreferenceField {\r\n  name: string;\r\n  title: string;\r\n  kind: PreferenceKind;\r\n  description?: string;\r\n  required?: boolean;\r\n  default?: unknown;\r\n  placeholder?: string;\r\n  /** For 'select' kind. */\r\n  options?: Array<{ value: string; label: string }>;\r\n}\r\n\r\nexport interface PreferenceSchema {\r\n  skillId: string;\r\n  fields: PreferenceField[];\r\n}\r\n\r\nexport interface PreferenceContext {\r\n  get<T = Record<string, unknown>>(): T;\r\n  set(values: Record<string, unknown>): void;\r\n  isComplete(): boolean;\r\n  missingRequired(): PreferenceField[];\r\n}\r\n\r\nexport class PreferenceStore {\r\n  constructor(private storage: StorageAdapter, private locale?: string) {}\r\n\r\n  private keyOf(skillId: string): string {\r\n    return `prefs.${skillId}`;\r\n  }\r\n\r\n  read(skillId: string): Record<string, unknown> {\r\n    const raw = this.storage.get(this.keyOf(skillId));\r\n    if (raw == null) return {};\r\n    const value = raw as string;\r\n    try {\r\n      return JSON.parse(value) as Record<string, unknown>;\r\n    } catch {\r\n      return {};\r\n    }\r\n  }\r\n\r\n  write(skillId: string, values: Record<string, unknown>): void {\r\n    this.storage.set(this.keyOf(skillId), JSON.stringify(values));\r\n  }\r\n\r\n  remove(skillId: string): void {\r\n    this.storage.remove(this.keyOf(skillId));\r\n  }\r\n\r\n  contextFor(schema: PreferenceSchema): PreferenceContext {\r\n    const self = this;\r\n    return {\r\n      get<T>() {\r\n        return self.read(schema.skillId) as T;\r\n      },\r\n      set(values: Record<string, unknown>) {\r\n        const merged = { ...self.read(schema.skillId), ...values };\r\n        self.write(schema.skillId, merged);\r\n      },\r\n      isComplete() {\r\n        const cur = self.read(schema.skillId);\r\n        return schema.fields\r\n          .filter((f) => f.required)\r\n          .every((f) => cur[f.name] !== undefined && cur[f.name] !== '');\r\n      },\r\n      missingRequired() {\r\n        const cur = self.read(schema.skillId);\r\n        return schema.fields.filter(\r\n          (f) => f.required && (cur[f.name] === undefined || cur[f.name] === '')\r\n        );\r\n      },\r\n    };\r\n  }\r\n\r\n  /** Build a Surface (flat envelope shape) representing the setup form. */\r\n  buildSetupSurface(schema: PreferenceSchema): {\r\n    version: 'v0.10';\r\n    updateComponents: {\r\n      surfaceId: string;\r\n      catalogId: string;\r\n      components: Array<Record<string, unknown>>;\r\n    };\r\n    updateDataModel: { data: Record<string, unknown> };\r\n  } {\r\n    const components: Array<Record<string, unknown>> = [\r\n      { id: 'root', component: 'Card', children: ['title', 'form'] },\r\n      { id: 'title', component: 'Heading', text: sdkString(this.locale, 'prefs.title', { skill: schema.skillId }) },\r\n      {\r\n        id: 'form',\r\n        component: 'Stack',\r\n        children: [...schema.fields.map((f) => f.name), 'submit'],\r\n      },\r\n    ];\r\n\r\n    for (const field of schema.fields) {\r\n      components.push(buildFieldComponent(field));\r\n    }\r\n    components.push({ id: 'submit', component: 'Button', text: sdkString(this.locale, 'form.submit'), action: 'submit' });\r\n\r\n    const data: Record<string, unknown> = {};\r\n    const existing = this.read(schema.skillId);\r\n    for (const f of schema.fields) {\r\n      data[f.name] = existing[f.name] ?? f.default ?? '';\r\n    }\r\n\r\n    return {\r\n      version: 'v0.10',\r\n      updateComponents: { surfaceId: `prefs:${schema.skillId}`, catalogId: 'basic', components },\r\n      updateDataModel: { data },\r\n    };\r\n  }\r\n}\r\n\r\nfunction buildFieldComponent(f: PreferenceField): Record<string, unknown> {\r\n  switch (f.kind) {\r\n    case 'text':\r\n    case 'password':\r\n      return {\r\n        id: f.name,\r\n        component: 'TextField',\r\n        label: f.title,\r\n        placeholder: f.placeholder,\r\n        bind: `/${f.name}`,\r\n      };\r\n    case 'number':\r\n      return { id: f.name, component: 'TextField', label: f.title, bind: `/${f.name}` };\r\n    case 'checkbox':\r\n      return { id: f.name, component: 'Checkbox', label: f.title, bind: `/${f.name}` };\r\n    case 'select':\r\n      return {\r\n        id: f.name,\r\n        component: 'Picker',\r\n        label: f.title,\r\n        bind: `/${f.name}`,\r\n        options: (f.options ?? []).map((o) => o.value),\r\n      };\r\n  }\r\n}\r\n","/**\n * Subtitle bar stylesheet — injected on first paint via `ensureStyles`.\n * Positioning lives in ../placement.ts; this file only owns chrome,\n * typography, scroll behaviour, indicator + choice + streaming visuals.\n */\n\nimport { injectScopedStyle, UI_ATTR } from '../../utils/dom';\n\nexport const STYLE_ID = 'dddk-subtitle-style';\n\nexport function ensureStyles(): void {\n  injectScopedStyle(STYLE_ID, `\n    /* Theming prefers host-bridged tokens (--dddk-bg-elevated / --dddk-text\n     * / --dddk-border) so a host that defines a dark theme via those\n     * tokens gets a properly-themed bar without overriding --dddk-bar-bg. */\n    [${UI_ATTR}=\"bar\"] {\n      position: relative;\n      background: var(--dddk-bar-bg, var(--dddk-bg-elevated, rgba(255, 255, 255, 0.985)));\n      color: var(--dddk-bar-text, var(--dddk-text, #1a1a1a));\n      border: 1px solid var(--dddk-bar-border, var(--dddk-border, rgba(0, 0, 0, 0.08)));\n      border-radius: var(--dddk-bar-radius, 16px);\n      box-shadow: var(--dddk-bar-shadow, 0 18px 48px -12px rgba(0, 0, 0, 0.32), 0 4px 14px rgba(0, 0, 0, 0.08));\n      padding: 0;\n      font-family: var(--dddk-bar-font, var(--dddk-font, system-ui, -apple-system, \"Segoe UI\", \"PingFang TC\", \"Microsoft JhengHei\", sans-serif));\n      font-size: var(--dddk-bar-font-size, 15.5px);\n      line-height: 1.65;\n      letter-spacing: 0.005em;\n      backdrop-filter: blur(var(--dddk-blur, 18px));\n      -webkit-backdrop-filter: blur(var(--dddk-blur, 18px));\n      /* No transform animation on the bar itself — placement.ts\n         positions the bar with translateX(-50%) for centring, and\n         animating transform overrode that (bar visibly landed off-\n         centre to the right, then jumped back). Use a pseudo layer\n         for entrance visuals if we want richer choreo. */\n    }\n    /* Content fade-in on the scroll container (safe — doesn't fight\n       the outer transform). */\n    [${UI_ATTR}=\"bar-scroll\"] {\n      animation: dddk-bar-scroll-fade 280ms ease-out;\n    }\n    @keyframes dddk-bar-scroll-fade {\n      from { opacity: 0; transform: translateY(4px); }\n      to   { opacity: 1; transform: translateY(0); }\n    }\n    @media (prefers-reduced-motion: reduce) {\n      [${UI_ATTR}=\"bar-scroll\"] { animation: none; }\n    }\n    [${UI_ATTR}=\"bar-scroll\"] {\n      max-height: var(--dddk-bar-max-height, min(52vh, 460px));\n      overflow-y: auto;\n      overscroll-behavior: contain;\n      padding: 18px 56px 18px 22px;\n      display: flex; flex-direction: column; gap: 10px;\n      scrollbar-width: thin;\n      scrollbar-color: var(--dddk-border, rgba(0,0,0,0.18)) transparent;\n    }\n    /* Mascot avatar — a duck face pinned at the LEFT edge of the bar\n       (mirroring the × close on the right). When present, bar-scroll\n       gets extra left padding so the text doesn't slide under it.\n       Entrance: swims IN from the direction of the FAB (bottom-right)\n       — reads as \"the duck flew over from its perch to deliver this\n       message\". Then idle-bob loops so the avatar stays alive. */\n    [${UI_ATTR}=\"bar-avatar\"] {\n      position: absolute;\n      top: 50%; left: 14px;\n      width: 36px; height: 36px;\n      pointer-events: none;\n      user-select: none;\n      z-index: 2;\n      /* First: swim-in from bottom-right; then: idle bob loop. Comma-\n         separated animations run in parallel but bounded ones (swim-in)\n         land on their final state via the \"both\" fill mode. */\n      animation:\n        dddk-bar-avatar-swim var(--dddk-avatar-swim-duration, 620ms) var(--dddk-avatar-swim-easing, cubic-bezier(0.34, 1.4, 0.64, 1)) both,\n        dddk-bar-avatar-bob var(--dddk-avatar-bob-duration, 2.6s) ease-in-out infinite var(--dddk-avatar-swim-duration, 620ms);\n      transform: translateY(-50%);\n    }\n    @keyframes dddk-bar-avatar-swim {\n      0%   { transform: translate(80px, calc(-50% + 40px)) rotate(-20deg) scale(0.6); opacity: 0; }\n      70%  { opacity: 1; }\n      100% { transform: translate(0, -50%) rotate(0deg) scale(1); opacity: 1; }\n    }\n    @keyframes dddk-bar-avatar-bob {\n      0%, 100% { transform: translateY(-50%); }\n      50%      { transform: translateY(calc(-50% - 3px)); }\n    }\n    /* When the avatar is rendered, push subtitle content right so the\n       face doesn't overlap the text. Uses :has() — supported on all\n       modern engines that dddk targets. */\n    [${UI_ATTR}=\"bar\"]:has([${UI_ATTR}=\"bar-avatar\"]) [${UI_ATTR}=\"bar-scroll\"] {\n      padding-left: 62px;\n    }\n    @media (prefers-reduced-motion: reduce) {\n      [${UI_ATTR}=\"bar-avatar\"] { animation: none; }\n    }\n    [${UI_ATTR}=\"bar-scroll\"]::-webkit-scrollbar { width: 8px; }\n    [${UI_ATTR}=\"bar-scroll\"]::-webkit-scrollbar-track { background: transparent; }\n    [${UI_ATTR}=\"bar-scroll\"]::-webkit-scrollbar-thumb {\n      background: var(--dddk-border, rgba(0,0,0,0.18));\n      border-radius: 4px;\n    }\n    [${UI_ATTR}=\"bar-close\"] {\n      position: absolute;\n      top: 10px; right: 10px;\n      width: 32px; height: 32px;\n      display: inline-flex; align-items: center; justify-content: center;\n      background: var(--dddk-close-bg, rgba(0,0,0,0.05));\n      color: var(--dddk-close-fg, var(--dddk-text, #1a1a1a));\n      border: 1px solid var(--dddk-close-border, rgba(0,0,0,0.08));\n      border-radius: 10px;\n      font-size: 18px; line-height: 1;\n      font-weight: 500;\n      cursor: pointer;\n      padding: 0;\n      transition: background 0.12s, color 0.12s, border-color 0.12s, transform 0.08s;\n      z-index: 2;\n      -webkit-tap-highlight-color: transparent;\n    }\n    [${UI_ATTR}=\"bar-close\"]:hover {\n      background: var(--dddk-close-bg-hover, rgba(0,0,0,0.1));\n      border-color: var(--dddk-close-border-hover, rgba(0,0,0,0.16));\n    }\n    [${UI_ATTR}=\"bar-close\"]:focus-visible {\n      outline: 2px solid var(--dddk-accent, #6366f1);\n      outline-offset: 2px;\n    }\n    [${UI_ATTR}=\"bar-close\"]:active { transform: scale(0.92); }\n    [${UI_ATTR}=\"bar-hints\"] {\n      color: var(--dddk-bar-hints, var(--dddk-text-muted, #6b7280));\n      font-size: var(--dddk-font-size-sm, 12.5px);\n      margin-top: 2px;\n    }\n    [${UI_ATTR}=\"bar-text\"] { line-height: 1.65; font-size: inherit; }\n    /* Streaming mode: a blinking block cursor sits at the tail of the\n       live Text node so users know more text is on the way. */\n    [${UI_ATTR}=\"bar\"][data-dddk-bar-mode=\"streaming\"] [${UI_ATTR}=\"bar-text\"] {\n      white-space: pre-wrap;\n      word-break: break-word;\n    }\n    [${UI_ATTR}=\"streaming-cursor\"] {\n      display: inline-block;\n      margin-left: 2px;\n      color: var(--dddk-accent, #6366f1);\n      animation: dddk-cursor-blink 1s steps(2) infinite;\n      font-weight: 400;\n      transform: translateY(-1px);\n    }\n    [${UI_ATTR}=\"bar\"][data-dddk-bar-mode=\"streaming-done\"] [${UI_ATTR}=\"bar-text\"] {\n      white-space: pre-wrap;\n      word-break: break-word;\n    }\n    @keyframes dddk-cursor-blink {\n      0%, 49% { opacity: 1; }\n      50%, 100% { opacity: 0; }\n    }\n    /* Pause hint attaches BELOW the streamed text without replacing the\n       bar, so the user can finish reading before deciding. */\n    [${UI_ATTR}=\"streaming-pause\"] {\n      margin-top: 12px;\n      padding-top: 12px;\n      border-top: 1px dashed var(--dddk-border, rgba(0, 0, 0, 0.12));\n      display: flex; flex-direction: column; gap: 4px;\n    }\n    [${UI_ATTR}=\"streaming-pause-text\"] {\n      font-size: var(--dddk-font-size-md, 14.5px);\n      color: var(--dddk-text, #1a1a1a);\n    }\n    [${UI_ATTR}=\"streaming-pause-hints\"] {\n      font-size: var(--dddk-font-size-sm, 12.5px);\n      color: var(--dddk-text-muted, #6b7280);\n    }\n    [${UI_ATTR}=\"bar-text\"] strong { font-weight: 700; }\n    [${UI_ATTR}=\"bar-text\"] em { font-style: italic; }\n    [${UI_ATTR}=\"bar-text\"] code {\n      font-family: var(--dddk-mono, ui-monospace, \"SF Mono\", Menlo, monospace);\n      font-size: 0.92em;\n      padding: 1px 5px;\n      background: var(--dddk-row-hover, rgba(0,0,0,0.06));\n      border-radius: 4px;\n    }\n    [${UI_ATTR}=\"bar-text\"] ul,\n    [${UI_ATTR}=\"bar-text\"] ol {\n      margin: 6px 0 6px 0;\n      padding-left: 20px;\n    }\n    [${UI_ATTR}=\"bar-text\"] li { margin: 2px 0; }\n    [${UI_ATTR}=\"bar-text\"] a {\n      color: var(--dddk-accent, #6366f1);\n      text-decoration: underline;\n    }\n    [${UI_ATTR}=\"bar-hints\"] {\n      font-size: var(--dddk-font-size-sm, 12px);\n    }\n    [${UI_ATTR}=\"bar-buttons\"] {\n      display: flex; gap: 8px; justify-content: flex-end;\n      margin-top: 4px;\n    }\n    /* Put hint text and action buttons on the SAME row so a proactive\n       bar's \"space 好 ｜ 雙擊 space 暫時不用 ｜ Esc 略過\" hint sits\n       next to the ✓/✕ buttons instead of taking its own row below.\n       Uses grid: text stays on its own row above, hints+buttons share\n       the row beneath. */\n    [${UI_ATTR}=\"bar-scroll\"]:has([${UI_ATTR}=\"bar-hints\"]):has([${UI_ATTR}=\"bar-buttons\"]) {\n      display: grid;\n      grid-template-columns: 1fr auto;\n      gap: 8px 16px;\n      align-items: center;\n    }\n    [${UI_ATTR}=\"bar-scroll\"]:has([${UI_ATTR}=\"bar-hints\"]):has([${UI_ATTR}=\"bar-buttons\"]) [${UI_ATTR}=\"bar-text\"] {\n      grid-column: 1 / -1;\n    }\n    [${UI_ATTR}=\"bar-scroll\"]:has([${UI_ATTR}=\"bar-hints\"]):has([${UI_ATTR}=\"bar-buttons\"]) [${UI_ATTR}=\"bar-hints\"] {\n      grid-column: 1;\n      margin: 0;\n    }\n    [${UI_ATTR}=\"bar-scroll\"]:has([${UI_ATTR}=\"bar-hints\"]):has([${UI_ATTR}=\"bar-buttons\"]) [${UI_ATTR}=\"bar-buttons\"] {\n      grid-column: 2;\n      margin: 0;\n    }\n    [${UI_ATTR}=\"bar-buttons\"] button {\n      border: 0;\n      /* 44x44 minimum tap target per WCAG. */\n      min-width: 44px; min-height: 36px;\n      padding: 6px 16px;\n      border-radius: var(--dddk-radius-sm, 6px);\n      background: var(--dddk-accent, #ec4899);\n      color: var(--dddk-text-on-accent, #fff);\n      cursor: pointer;\n      font-size: var(--dddk-font-size-md, 14px);\n      font-weight: 600;\n      display: inline-flex; align-items: center; justify-content: center; gap: 4px;\n      -webkit-tap-highlight-color: transparent;\n      transition: background 0.1s, transform 0.08s;\n    }\n    [${UI_ATTR}=\"bar-buttons\"] button:hover {\n      background: var(--dddk-accent-hover, #db2777);\n    }\n    [${UI_ATTR}=\"bar-buttons\"] button:active {\n      transform: scale(0.96);\n    }\n    /* Reject reads as secondary so accept stays the primary action. */\n    [${UI_ATTR}=\"bar-buttons\"] button[data-dddk-action=\"reject\"] {\n      background: transparent;\n      color: var(--dddk-text-muted, #6b6b6b);\n      border: 1px solid var(--dddk-border, rgba(0,0,0,0.15));\n    }\n    [${UI_ATTR}=\"bar-buttons\"] button[data-dddk-action=\"reject\"]:hover {\n      background: var(--dddk-row-hover, rgba(0,0,0,0.04));\n      color: var(--dddk-text, #1a1a1a);\n    }\n    /* Multi-choice mode — question + N numbered rows + optional\n       free-text input + hint line. */\n    [${UI_ATTR}=\"choice-list\"] {\n      display: flex; flex-direction: column; gap: 4px;\n      margin: 4px 0 2px;\n    }\n    [${UI_ATTR}=\"choice-row\"] {\n      display: flex; align-items: center; gap: 10px;\n      width: 100%;\n      padding: 7px 10px;\n      border: 1px solid transparent;\n      border-radius: var(--dddk-radius-sm, 6px);\n      background: var(--dddk-row-bg, transparent);\n      color: inherit;\n      font: inherit;\n      cursor: pointer;\n      text-align: left;\n    }\n    [${UI_ATTR}=\"choice-row\"]:hover,\n    [${UI_ATTR}=\"choice-row\"]:focus-visible {\n      background: var(--dddk-row-hover, rgba(255,220,80,0.14));\n      border-color: var(--dddk-border-subtle, rgba(0,0,0,0.08));\n      outline: none;\n      transform: translateX(2px);\n      transition: transform 0.15s ease-out, background 0.15s ease-out;\n    }\n    /* Duck-key: the numeric picker kbd becomes a small yellow disc so\n       the choice list feels like it belongs to the mascot. Circle,\n       warm-yellow fill, dark-navy digit — same palette as the FAB\n       face. Hosts can override via --dddk-choice-key-* variables. */\n    [${UI_ATTR}=\"choice-key\"] {\n      display: inline-flex; align-items: center; justify-content: center;\n      min-width: 22px; height: 22px;\n      padding: 0 7px;\n      border-radius: 50%;\n      background: var(--dddk-choice-key-bg, #ffd93d);\n      color: var(--dddk-choice-key-fg, #1a2a4a);\n      border: 1px solid var(--dddk-choice-key-border, rgba(20,30,60,0.15));\n      font-size: 11px;\n      font-family: var(--dddk-mono, ui-monospace, monospace);\n      font-weight: 700;\n      box-shadow: 0 1px 2px rgba(0,0,0,0.06);\n    }\n    [${UI_ATTR}=\"choice-row\"]:hover [${UI_ATTR}=\"choice-key\"] {\n      background: var(--dddk-choice-key-bg-hover, #ffcf1a);\n    }\n    [${UI_ATTR}=\"choice-label\"] { font-size: var(--dddk-font-size-md, 14px); }\n    [${UI_ATTR}=\"choice-freetext\"] { margin-top: 4px; }\n    [${UI_ATTR}=\"choice-input\"] {\n      width: 100%;\n      padding: 7px 10px;\n      border: 1px solid var(--dddk-border, rgba(0,0,0,0.12));\n      border-radius: var(--dddk-radius-sm, 6px);\n      background: var(--dddk-input-bg, transparent);\n      color: inherit;\n      font: inherit;\n    }\n    [${UI_ATTR}=\"choice-input\"]:focus {\n      outline: none;\n      border-color: var(--dddk-accent, #ec4899);\n    }\n    /* Indicator background uses ACCENT (not bg-elevated) so it stays\n       visible on dark themes; \"listening\" gets a pulsing ring so the\n       hot mic state is obvious. */\n    [${UI_ATTR}=\"indicator\"] {\n      background: var(--dddk-accent, #6366f1);\n      color: var(--dddk-text-on-accent, #fff);\n      border-radius: var(--dddk-radius-pill, 999px);\n      padding: 10px 20px;\n      box-shadow: var(--dddk-shadow-md, 0 6px 20px rgba(0,0,0,0.25));\n      display: flex; align-items: center; gap: 10px;\n      font-size: var(--dddk-font-size-md, 14px);\n      font-weight: 600;\n      border: 1px solid rgba(255,255,255,0.15);\n    }\n    @media (max-width: 480px) {\n      [${UI_ATTR}=\"indicator\"] {\n        padding: 6px 14px;\n        gap: 8px;\n        font-size: var(--dddk-font-size-sm, 13px);\n      }\n      [${UI_ATTR}=\"indicator-dots\"] span {\n        width: 6px; height: 6px;\n      }\n      [${UI_ATTR}=\"indicator-check\"] {\n        font-size: 14px;\n      }\n    }\n    [${UI_ATTR}=\"indicator\"][data-state=\"listening\"] {\n      animation: dddk-indicator-pulse 1.4s ease-in-out infinite;\n    }\n    [${UI_ATTR}=\"indicator\"][data-state=\"done\"] {\n      background: var(--dddk-success, #16a34a);\n    }\n    [${UI_ATTR}=\"indicator-check\"] {\n      font-size: 16px; line-height: 1;\n    }\n    [${UI_ATTR}=\"indicator-dots\"] {\n      display: inline-flex; gap: 5px;\n      align-items: center;\n    }\n    /* Default dot appearance — solid pill. When the host sets\n       --dddk-indicator-duck-url, the spans switch to duck-face pips:\n       larger, transparent bg, image inside. Enables the \"three little\n       ducks bouncing\" thinking indicator without JS changes. */\n    [${UI_ATTR}=\"indicator-dots\"] span {\n      width: 7px; height: 7px; border-radius: 50%;\n      background: var(--dddk-text-on-accent, #fff);\n      animation: dddk-dot-bounce 1.2s infinite ease-in-out;\n      background-image: var(--dddk-indicator-duck-url, none);\n      background-size: contain;\n      background-repeat: no-repeat;\n      background-position: center;\n    }\n    /* When the duck URL is set, size up the pips so faces are readable. */\n    [${UI_ATTR}=\"indicator\"]:where([style*=\"--dddk-indicator-duck-url\"], :root) [${UI_ATTR}=\"indicator-dots\"] span {\n      /* This selector is intentionally lax — the actual size upgrade\n         relies on the variable being defined at :root, which we then\n         confirm via a chained rule below. */\n    }\n    /* Root-driven duck sizing: only applies when --dddk-indicator-duck-url\n       is defined (any non-none value). Uses --dddk-indicator-duck-size\n       so hosts can tune. */\n    [${UI_ATTR}=\"indicator-dots\"][data-duck] span {\n      width: var(--dddk-indicator-duck-size, 16px);\n      height: var(--dddk-indicator-duck-size, 16px);\n      background-color: transparent;\n    }\n    [${UI_ATTR}=\"indicator-dots\"] span:nth-child(2) { animation-delay: 0.15s; }\n    [${UI_ATTR}=\"indicator-dots\"] span:nth-child(3) { animation-delay: 0.3s; }\n    /* ── Thinking indicator: swim relay ─────────────────────────────\n       Three side-view rubber-duck sprites bounce in relay-swim\n       sequence + one larger \"hero\" sprite pulses. Reads as \"the duck\n       is paddling hard to think\" — not 3 face-heads bouncing (that\n       read as weird). Sprites default to the side-view swim pose\n       (--dddk-swim-url), so the swim spritesheet is reused. */\n    [${UI_ATTR}=\"indicator-swim\"] {\n      display: inline-flex;\n      align-items: flex-end;\n      gap: 4px;\n      padding: 2px 0;\n    }\n    [${UI_ATTR}=\"indicator-swim-hero\"] {\n      width: 28px;\n      height: 22px;\n      background-image: var(--dddk-indicator-swim-url, none);\n      background-size: contain;\n      background-repeat: no-repeat;\n      background-position: center;\n      animation: dddk-indicator-swim-hero var(--dddk-indicator-swim-duration, 1.5s) ease-in-out infinite;\n    }\n    [${UI_ATTR}=\"indicator-swim-pip\"] {\n      width: 14px;\n      height: 12px;\n      background-image: var(--dddk-indicator-swim-url, none);\n      background-size: contain;\n      background-repeat: no-repeat;\n      background-position: center;\n      animation: dddk-indicator-swim-pip var(--dddk-indicator-swim-pip-duration, 1s) ease-in-out infinite;\n    }\n    [${UI_ATTR}=\"indicator-swim-pip\"]:nth-of-type(2) { animation-delay: 0.15s; }\n    [${UI_ATTR}=\"indicator-swim-pip\"]:nth-of-type(3) { animation-delay: 0.3s; }\n    [${UI_ATTR}=\"indicator-swim-pip\"]:nth-of-type(4) { animation-delay: 0.45s; }\n    @keyframes dddk-indicator-swim-hero {\n      0%, 100% { transform: translateY(0)   scale(1); }\n      50%      { transform: translateY(-4px) scale(1.08); }\n    }\n    @keyframes dddk-indicator-swim-pip {\n      0%, 60%, 100% { transform: translateY(0);    opacity: 0.55; }\n      30%           { transform: translateY(-6px); opacity: 1; }\n    }\n\n    /* ── Listening indicator: waveform bars ─────────────────────────\n       Five vertical bars pulse independently, mimicking an audio\n       waveform / mic level meter. No duck heads on this one (voice\n       is a distinct interaction — three duck heads bouncing read as\n       weird for \"I'm listening\"). Yellow brand colour matches the\n       FAB's listening sonar rings. */\n    [${UI_ATTR}=\"indicator-waves\"] {\n      display: inline-flex;\n      align-items: center;\n      gap: 3px;\n      height: 22px;\n    }\n    [${UI_ATTR}=\"indicator-waves\"] span {\n      display: inline-block;\n      width: 3px;\n      height: 8px;\n      background: var(--dddk-indicator-wave-color, #ffd93d);\n      border-radius: 3px;\n      transform-origin: center;\n      animation: dddk-indicator-wave var(--dddk-indicator-wave-duration, 0.9s) ease-in-out infinite;\n    }\n    [${UI_ATTR}=\"indicator-waves\"] span:nth-child(1) { animation-delay: 0s;    }\n    [${UI_ATTR}=\"indicator-waves\"] span:nth-child(2) { animation-delay: 0.1s;  }\n    [${UI_ATTR}=\"indicator-waves\"] span:nth-child(3) { animation-delay: 0.2s;  }\n    [${UI_ATTR}=\"indicator-waves\"] span:nth-child(4) { animation-delay: 0.15s; }\n    [${UI_ATTR}=\"indicator-waves\"] span:nth-child(5) { animation-delay: 0.05s; }\n    @keyframes dddk-indicator-wave {\n      0%, 100% { transform: scaleY(0.35); }\n      50%      { transform: scaleY(1.6); }\n    }\n\n    [${UI_ATTR}=\"indicator-label\"] {\n      letter-spacing: 0.02em;\n      position: relative;\n    }\n    /* Shimmer sweep — a soft light bar travels left-to-right under\n       the indicator label, giving a \"cooking, don't worry\" feel.\n       Purely decorative; kept subtle so it doesn't upstage the label. */\n    [${UI_ATTR}=\"indicator\"][data-state=\"processing\"] [${UI_ATTR}=\"indicator-label\"]::after {\n      content: '';\n      position: absolute;\n      left: 0; right: 0; bottom: -3px;\n      height: 2px;\n      background: linear-gradient(\n        90deg,\n        transparent 0%,\n        rgba(255,220,80,0.9) 35%,\n        rgba(255,220,80,0.9) 55%,\n        transparent 100%\n      );\n      background-size: 220% 100%;\n      border-radius: 2px;\n      animation: dddk-indicator-shimmer 1.6s linear infinite;\n      opacity: 0.75;\n    }\n    @keyframes dddk-indicator-shimmer {\n      from { background-position: 100% 0; }\n      to   { background-position: -120% 0; }\n    }\n    @keyframes dddk-dot-bounce {\n      0%, 80%, 100% { transform: scale(0.7); opacity: 0.55; }\n      40% { transform: scale(1); opacity: 1; }\n    }\n    @keyframes dddk-indicator-pulse {\n      0%, 100% {\n        box-shadow:\n          var(--dddk-shadow-md, 0 6px 20px rgba(0,0,0,0.25)),\n          0 0 0 0 rgba(99, 102, 241, 0.55);\n      }\n      50% {\n        box-shadow:\n          var(--dddk-shadow-md, 0 6px 20px rgba(0,0,0,0.25)),\n          0 0 0 12px rgba(99, 102, 241, 0);\n      }\n    }\n  `);\n}\n","/** Subtitle markdown — `**bold**` / `*italic*` / `` `code` `` /\n *  `- list` / `1. list` / bare URL autolink / `\\n` line breaks.\n *  Headings / blockquotes / tables / images pass through as text.\n *  No marked.js dep — subtitle module stays under 30KB. */\n\nimport { escapeHtml } from '../../utils/dom';\n\n// Escape FIRST, then run pattern subs on the escaped string —\n// otherwise `<script>` could sneak in via a markdown pattern.\nexport function renderInlineMarkdown(raw: string): string {\n  let html = escapeHtml(raw);\n\n  // Lists run before inline subs because markers anchor at line start.\n  html = html.replace(\n    /(?:^|\\n)((?:[-*]\\s.+\\n?)+)/g,\n    (_match, group: string) => {\n      const items = group\n        .trim()\n        .split('\\n')\n        .map((line) => line.replace(/^[-*]\\s+/, ''))\n        .map((item) => `<li>${item.trim()}</li>`)\n        .join('');\n      return `\\n<ul>${items}</ul>`;\n    },\n  );\n  html = html.replace(\n    /(?:^|\\n)((?:\\d+\\.\\s.+\\n?)+)/g,\n    (_match, group: string) => {\n      const items = group\n        .trim()\n        .split('\\n')\n        .map((line) => line.replace(/^\\d+\\.\\s+/, ''))\n        .map((item) => `<li>${item.trim()}</li>`)\n        .join('');\n      return `\\n<ol>${items}</ol>`;\n    },\n  );\n\n  // Inline code first — its content shouldn't be re-processed for bold/italic.\n  // Stash via placeholder, restore after the bold/italic/link passes.\n  const codeSpans: string[] = [];\n  html = html.replace(/`([^`\\n]+)`/g, (_m, code: string) => {\n    codeSpans.push(code);\n    return `\\x00CODE${codeSpans.length - 1}\\x00`;\n  });\n\n  // **bold** / __bold__ before *italic* / _italic_ so doubled markers\n  // don't get half-matched.\n  html = html.replace(/\\*\\*([^*\\n]+)\\*\\*/g, '<strong>$1</strong>');\n  html = html.replace(/__([^_\\n]+)__/g, '<strong>$1</strong>');\n  html = html.replace(/(?<!\\w)\\*([^*\\n]+)\\*(?!\\w)/g, '<em>$1</em>');\n  html = html.replace(/(?<!\\w)_([^_\\n]+)_(?!\\w)/g, '<em>$1</em>');\n\n  // Bare URL autolink. Strict tail to avoid eating trailing punctuation.\n  html = html.replace(\n    /(https?:\\/\\/[^\\s<]+[^\\s<.,!?])/g,\n    '<a href=\"$1\" target=\"_blank\" rel=\"noopener noreferrer\">$1</a>',\n  );\n\n  html = html.replace(/\\x00CODE(\\d+)\\x00/g, (_m, idx: string) => {\n    return `<code>${codeSpans[Number(idx)] ?? ''}</code>`;\n  });\n\n  // Line breaks last — after lists, so list \\n's are already consumed.\n  html = html.replace(/\\n/g, '<br>');\n\n  return html;\n}\n","/** Touch-only helpers: tap-gesture binding (no Space key on phones)\n *  and the locale × bar-type hint table rendered below the text. */\n\nimport type { SubtitleShowOptions } from '../../types';\nimport { UI_ATTR } from '../../utils/dom';\nimport { sdkString } from '../../utils/sdk-i18n';\nimport type { Subtitle } from './index';\n\n/** Requires BOTH touch capability AND coarse pointer, so a 2-in-1\n *  laptop in laptop mode still gets the keyboard hint. */\nexport function isTouchOnlyDevice(): boolean {\n  if (typeof window === 'undefined' || typeof navigator === 'undefined') return false;\n  const hasTouch = 'ontouchstart' in window || (navigator.maxTouchPoints ?? 0) > 0;\n  if (!hasTouch) return false;\n  try {\n    return window.matchMedia('(pointer: coarse)').matches;\n  } catch {\n    return hasTouch;\n  }\n}\n\n/** Single click/tap → accept (= space), double click/tap → reject\n *  (= double space). v0.2.0: extended from touch-only to also handle\n *  mouse — users asked \"clicking the subtitle should equal space\".\n *  Interactive children (button / input / textarea / a / role=\"button\"\n *  / close-×) still handle their own pointer events; the gesture only\n *  fires on the bare subtitle surface. */\nexport function bindTouchTapGestures(el: HTMLElement): void {\n  let lastTapAt = 0;\n  let singleTapTimer: ReturnType<typeof setTimeout> | null = null;\n  const doubleTapMs = 320;\n  el.addEventListener('pointerup', (e) => {\n    if (e.pointerType !== 'touch' && e.pointerType !== 'mouse' && e.pointerType !== 'pen') return;\n    // Interactive children handle themselves. The close × button is\n    // matched via its data-dddk-ui=\"bar-close\" attribute so the\n    // selector doesn't have to know its tag.\n    const target = e.target as HTMLElement | null;\n    if (target?.closest('button, input, textarea, a, [role=\"button\"], [data-dddk-ui=\"bar-close\"]')) return;\n    const now = Date.now();\n    if (now - lastTapAt < doubleTapMs) {\n      if (singleTapTimer !== null) { clearTimeout(singleTapTimer); singleTapTimer = null; }\n      lastTapAt = 0;\n      document.dispatchEvent(new CustomEvent('dddk:bar-tap-reject'));\n      return;\n    }\n    lastTapAt = now;\n    singleTapTimer = setTimeout(() => {\n      singleTapTimer = null;\n      document.dispatchEvent(new CustomEvent('dddk:bar-tap-accept'));\n    }, doubleTapMs);\n  });\n}\n\n/** Hint line beneath the bar text. Explicit `opts.hints` wins, then a\n *  \"press space to close\" for decisionless info subtitles, then the\n *  locale × bar-type defaults table. Touch swaps keyboard hints for\n *  tap copy. Bundled `en` + `zh-TW`; other locales fall back to en. */\nexport function renderHints(host: Subtitle, opts: SubtitleShowOptions): string {\n  if (opts.hints) return `<div ${UI_ATTR}=\"bar-hints\">${opts.hints}</div>`;\n\n  const isDecisionless = !opts.onAccept && !opts.onReject;\n  if (isDecisionless && opts.type !== 'agent') {\n    const text = sdkString(\n      host._locale,\n      isTouchOnlyDevice() ? 'agent.tap_to_dismiss' : 'agent.press_space_close',\n    );\n    return `<div ${UI_ATTR}=\"bar-hints\">${text}</div>`;\n  }\n\n  const touch = isTouchOnlyDevice();\n  const defaults: Record<string, Record<SubtitleShowOptions['type'], string>> = touch ? {\n    'zh-TW': {\n      voice: '點一下繼續 ｜ 雙擊結束',\n      selection: '點一下接受 ｜ 雙擊拒絕',\n      agent: '點一下繼續 ｜ 雙擊結束',\n      post: '點一下接受 ｜ 雙擊拒絕',\n      info: '點一下關閉',\n    },\n    en: {\n      voice: 'tap to continue · double-tap to exit',\n      selection: 'tap to accept · double-tap to reject',\n      agent: 'tap to continue · double-tap to exit',\n      post: 'tap to accept · double-tap to reject',\n      info: 'tap to dismiss',\n    },\n  } : {\n    'zh-TW': {\n      voice: 'Tab 一行 ｜ space 同意 ｜ 兩下 space 拒絕',\n      selection: 'space 接受 ｜ 兩下 space 拒絕',\n      agent: 'space 下一步 ｜ 兩下 space 直接結束',\n      post: 'space 接受 ｜ 兩下 space 拒絕',\n      info: '按 space 關閉',\n    },\n    en: {\n      voice: 'Tab line · space to accept · double space to reject',\n      selection: 'space to accept · double space to reject',\n      agent: 'space → next · double space → exit',\n      post: 'space to accept · double space to reject',\n      info: 'press space to close',\n    },\n  };\n  const dict = defaults[host._locale] ?? defaults.en!;\n  const text = dict[opts.type];\n  return text ? `<div ${UI_ATTR}=\"bar-hints\">${text}</div>` : '';\n}\n","/** Split long text into space-advanced pages, format the N/M hint,\n *  render the current page into the bar. */\n\nimport type { SubtitleShowOptions } from '../../types';\nimport { escapeHtml, UI_ATTR } from '../../utils/dom';\nimport type { Subtitle } from './index';\nimport { renderInlineMarkdown } from './markdown';\nimport { renderHints } from './touch';\n\n/** Chunks ≤ maxChars, broken on sentence boundaries\n *  (`. ! ? 。 ！ ？`) or paragraph breaks. Falls back to hard cut at\n *  maxChars when no boundary exists in the window. */\nexport function splitIntoPages(text: string, maxChars: number): string[] {\n  const out: string[] = [];\n  let remaining = text.trim();\n  while (remaining.length > maxChars) {\n    const window = remaining.slice(0, maxChars);\n    // Paragraph break preferred — best read-aloud rhythm.\n    let cut = window.lastIndexOf('\\n\\n');\n    if (cut < maxChars * 0.3) {\n      const marks = ['. ', '! ', '? ', '。', '！', '？', '\\n'];\n      for (const m of marks) {\n        const idx = window.lastIndexOf(m);\n        if (idx > cut) cut = idx + m.length;\n      }\n    } else {\n      cut += 2;\n    }\n    if (cut < maxChars * 0.3) cut = maxChars;\n    out.push(remaining.slice(0, cut).trim());\n    remaining = remaining.slice(cut).trim();\n  }\n  if (remaining) out.push(remaining);\n  return out.length > 0 ? out : [text];\n}\n\n/** Returns HTML directly — caller's startsWith check inlines it\n *  without escaping. Both intermediate and last pages carry the exit\n *  hint so double-space-to-exit is always visible mid-tour. */\nexport function formatPageHint(\n  host: Subtitle,\n  idx: number,\n  total: number,\n  isLast: boolean,\n): string {\n  const zh = host._locale === 'zh-TW';\n  const counter = `${idx}/${total}`;\n  const action = isLast\n    ? (zh ? 'space 下一步 ｜ 兩下 space 直接結束' : 'space → next · double space → exit')\n    : (zh ? 'space → 下一段 ｜ 兩下 space 直接結束' : 'space → next page · double space → exit');\n  return (\n    `<div ${UI_ATTR}=\"bar-hints\" style=\"display:flex;justify-content:space-between;gap:16px;\">`\n    + `<span>${counter}</span>`\n    + `<span>${escapeHtml(action)}</span>`\n    + `</div>`\n  );\n}\n\n/** Intermediate pages strip onAccept/onReject so wireButtons doesn't\n *  expose actions mid-tour; the final page restores them. */\nexport function renderCurrentPage(host: Subtitle): void {\n  if (!host._el || !host._currentOpts) return;\n  const opts = host._currentOpts;\n  const isPaged = host._pages !== null;\n  const isLastPage = !isPaged || host._pageIdx === host._pages!.length - 1;\n  const pageText = isPaged ? host._pages![host._pageIdx]! : opts.text;\n\n  const effectiveOpts: SubtitleShowOptions = isLastPage\n    ? opts\n    : { ...opts, onAccept: undefined, onReject: undefined, onCopy: undefined };\n\n  const pageHint = isPaged\n    ? formatPageHint(host, host._pageIdx + 1, host._pages!.length, isLastPage)\n    : '';\n  const hints = pageHint\n    || (isLastPage ? renderHints(host, effectiveOpts) : '');\n\n  host._el.setAttribute('data-dddk-bar-type', opts.type);\n  host._el.innerHTML = host._wrapBarShell(`\n    <div ${UI_ATTR}=\"bar-text\">${renderInlineMarkdown(pageText)}</div>\n    ${hints.startsWith(`<div ${UI_ATTR}=\"bar-hints\"`) ? hints : (hints ? `<div ${UI_ATTR}=\"bar-hints\">${escapeHtml(hints)}</div>` : '')}\n    ${host._renderButtons(effectiveOpts)}\n  `);\n  host._wireButtons(effectiveOpts);\n  host._wireClose();\n}\n","/** Click-anywhere / any-key dismiss for info subtitles. Action bars\n *  (have onAccept/onReject), streaming bars, persistent bars opt out\n *  — those need explicit accept/reject/× gestures. */\n\nimport type { SubtitleShowOptions } from '../../types';\nimport type { Subtitle } from './index';\n\n/** IME guard. `keyCode === 229` is the spec value browsers fire for\n *  every keystroke during CJK candidate composition; combined with\n *  `isComposing` it stops space/esc/digit from being misrouted as\n *  bar dismissal. */\nexport function isImeComposing(e: KeyboardEvent): boolean {\n  return e.isComposing || (e as KeyboardEvent & { keyCode?: number }).keyCode === 229;\n}\n\nexport function isModifierKey(e: KeyboardEvent): boolean {\n  return ['Control', 'Shift', 'Alt', 'Meta', 'Tab'].includes(e.key);\n}\n\nexport function clearAutoHide(host: Subtitle): void {\n  if (host._autoHideTimer) {\n    clearTimeout(host._autoHideTimer);\n    host._autoHideTimer = null;\n  }\n}\n\n/** Click-outside / any-key dismiss. Action + streaming bars stay open\n *  on outside click so incidental clicks while the agent runs don't\n *  feel fragile. Space/Esc skip here — GestureManager owns them.\n *  120ms attach delay so the click that OPENED the bar doesn't\n *  immediately dismiss it. */\nexport function installInteractionDismiss(host: Subtitle, opts: SubtitleShowOptions): void {\n  if (host._dismissTeardown) { host._dismissTeardown(); host._dismissTeardown = null; }\n  // Persistent bars opt out of every passive dismiss — host has\n  // declared the user MUST answer via accept/reject before closing.\n  if (opts.persistent) return;\n  const ac = new AbortController();\n  setTimeout(() => {\n    if (ac.signal.aborted) return;\n    const onClick = (e: Event): void => {\n      const target = e.target as Element | null;\n      if (target && host._el && host._el.contains(target)) return;\n      const hasAction = !!(host._currentOpts?.onAccept || host._currentOpts?.onReject);\n      const isStreaming = host._el?.getAttribute('data-dddk-bar-mode') === 'streaming';\n      if (hasAction || isStreaming) return;\n      host._handleCloseClick();\n    };\n    const onKey = (e: KeyboardEvent): void => {\n      if (isModifierKey(e)) return;\n      if (e.key === ' ' || e.key === 'Spacebar' || e.key === 'Escape') return;\n      // Paged + action subtitles must NOT dismiss on arbitrary keys —\n      // would close a multi-page translation mid-read.\n      const isPaged = host._pages !== null && host._pages.length > 1;\n      const hasAction = !!(host._currentOpts?.onAccept || host._currentOpts?.onReject);\n      if (isPaged || hasAction) return;\n      host.hide();\n    };\n    document.addEventListener('click', onClick, true);\n    document.addEventListener('keydown', onKey, true);\n    host._dismissTeardown = () => {\n      document.removeEventListener('click', onClick, true);\n      document.removeEventListener('keydown', onKey, true);\n    };\n  }, 120);\n  // hide() before listeners attach → abort the setTimeout so we don't leak.\n  host._dismissTeardown = () => { ac.abort(); };\n}\n","/**\n * Streaming bar — LLM tokens stream between tool calls into a live Text\n * node so the bar \"types itself\". Sentence-boundary TTS is auto-buffered\n * + flushed.\n */\n\nimport type { SubtitleShowOptions } from '../../types';\nimport { escapeHtml, UI_ATTR } from '../../utils/dom';\nimport { applyPlacement } from '../placement';\nimport { sdkString } from '../../utils/sdk-i18n';\nimport type { Subtitle } from './index';\nimport { ensureStyles } from './styles';\nimport { renderInlineMarkdown } from './markdown';\nimport { bindTouchTapGestures, isTouchOnlyDevice } from './touch';\nimport { installInteractionDismiss, clearAutoHide } from './dismiss';\n\nexport function appendStreamed(host: Subtitle, delta: string): void {\n  if (typeof document === 'undefined' || !delta) return;\n  ensureStreamingBar(host);\n  // Strip `**bold**` markers — system prompt asks the LLM to skip\n  // markdown, but smaller models still slip them in.\n  const cleaned = delta.replace(/\\*\\*/g, '');\n  if (host._streamingTextNode) {\n    host._streamingTextNode.appendData(cleaned);\n    host._streamingFullText += cleaned;\n    autoScrollStream(host);\n  }\n  host._streamingTtsBuffer += cleaned;\n  flushStreamingTts(host, false);\n}\n\nexport function replaceStreamed(host: Subtitle, text: string): void {\n  if (typeof document === 'undefined') return;\n  flushStreamingTts(host, true);\n  ensureStreamingBar(host);\n  if (host._streamingTextNode) {\n    host._streamingTextNode.data = text;\n    host._streamingFullText = text;\n  }\n  host._streamingTtsBuffer = text;\n  flushStreamingTts(host, false);\n}\n\nexport function finalizeStreamed(host: Subtitle, opts?: { autoHide?: number }): void {\n  flushStreamingTts(host, true);\n  // Loop is done — drop queued indicator so a stale \"Agent 執行中\"\n  // pip doesn't appear after the agent has ended.\n  host._pendingIndicator = null;\n  if (!host._el) return;\n  // Empty stream → \"press space to close\" hint on an empty bar is noise.\n  if (!host._streamingFullText.trim()) {\n    host.hide();\n    return;\n  }\n  host._el.setAttribute('data-dddk-bar-mode', 'streaming-done');\n  if (host._streamingCursor) {\n    host._streamingCursor.remove();\n    host._streamingCursor = null;\n  }\n  // Run renderInlineMarkdown now (during streaming we used a raw Text\n  // node — cheap, no parse per token) so lists / bold / inline code /\n  // bare URLs all render properly on the finished message.\n  const barText = host._el.querySelector<HTMLDivElement>(`[${UI_ATTR}=\"bar-text\"]`);\n  if (barText && host._streamingFullText) {\n    barText.innerHTML = renderInlineMarkdown(host._streamingFullText);\n  }\n  const scroll = host._el.querySelector<HTMLDivElement>(`[${UI_ATTR}=\"bar-scroll\"]`);\n  if (scroll && !scroll.querySelector(`[${UI_ATTR}=\"bar-hints\"]`)) {\n    const hintEl = document.createElement('div');\n    hintEl.setAttribute(UI_ATTR, 'bar-hints');\n    hintEl.textContent = sdkString(host._locale, 'agent.press_space_close');\n    scroll.appendChild(hintEl);\n  }\n  const dismissOpts: SubtitleShowOptions = { text: host._streamingFullText, type: 'agent' };\n  host._currentOpts = dismissOpts;\n  installInteractionDismiss(host, dismissOpts);\n  const autoHideMs = opts?.autoHide;\n  if (typeof autoHideMs === 'number' && autoHideMs > 0) {\n    clearAutoHide(host);\n    host._autoHideTimer = setTimeout(() => host.hide(), autoHideMs);\n  }\n}\n\nexport function clearStreamed(host: Subtitle): void {\n  flushStreamingTts(host, true);\n  host._streamingTextNode = null;\n  host._streamingCursor = null;\n  host._streamingFullText = '';\n  host._streamingTtsBuffer = '';\n  host.hide();\n}\n\nexport function applyStreamingPauseHint(\n  host: Subtitle,\n  opts: { hint: string; rejectHint?: string; onAccept: () => void; onReject: () => void },\n): void {\n  if (!host._el) return;\n  host.clearStreamingPauseHint();\n  // Halt the cursor — agent paused, not \"still typing\".\n  if (host._streamingCursor) {\n    host._streamingCursor.style.opacity = '0.35';\n    host._streamingCursor.style.animation = 'none';\n  }\n  const scroll = host._el.querySelector<HTMLDivElement>(`[${UI_ATTR}=\"bar-scroll\"]`);\n  if (!scroll) return;\n  const hintEl = document.createElement('div');\n  hintEl.setAttribute(UI_ATTR, 'streaming-pause');\n  // Dedupe: many callers pass the gesture-hint string as `opts.hint`\n  // (because that's what the agent's pauseHandler propagates), then\n  // the rejectHint fallback resolves to the same i18n key — same\n  // string rendered TWICE stacked. Skip the upper \"text\" div when it\n  // matches the lower \"hints\" string.\n  const rejectHint = opts.rejectHint ?? defaultPauseRejectHint(host);\n  const showText = opts.hint && opts.hint.trim() !== rejectHint.trim();\n  hintEl.innerHTML = `\n    ${showText ? `<div ${UI_ATTR}=\"streaming-pause-text\">${escapeHtml(opts.hint)}</div>` : ''}\n    <div ${UI_ATTR}=\"streaming-pause-hints\">${escapeHtml(rejectHint)}</div>\n  `;\n  scroll.appendChild(hintEl);\n  autoScrollStream(host);\n  host._streamingPauseAccept = opts.onAccept;\n  host._streamingPauseReject = opts.onReject;\n}\n\nexport function clearStreamingPauseHint(host: Subtitle): void {\n  if (!host._el) return;\n  const hintEl = host._el.querySelector(`[${UI_ATTR}=\"streaming-pause\"]`);\n  if (hintEl) hintEl.remove();\n  host._streamingPauseAccept = null;\n  host._streamingPauseReject = null;\n  if (host._streamingCursor) {\n    host._streamingCursor.style.opacity = '';\n    host._streamingCursor.style.animation = '';\n  }\n}\n\nfunction defaultPauseRejectHint(host: Subtitle): string {\n  return sdkString(\n    host._locale,\n    isTouchOnlyDevice() ? 'agent.tap_to_continue' : 'agent.space_continue_reject',\n  );\n}\n\n/** Pin scroll to bottom as text streams in — unless the user has\n *  scrolled up to re-read; leave them where they are then. */\nexport function autoScrollStream(host: Subtitle): void {\n  if (!host._el) return;\n  const scroll = host._el.querySelector<HTMLDivElement>(`[${UI_ATTR}=\"bar-scroll\"]`);\n  if (!scroll) return;\n  const distFromBottom = scroll.scrollHeight - scroll.scrollTop - scroll.clientHeight;\n  if (distFromBottom < 80) scroll.scrollTop = scroll.scrollHeight;\n}\n\nexport function ensureStreamingBar(host: Subtitle): void {\n  if (host._streamingTextNode && host._el?.getAttribute('data-dddk-bar-mode') === 'streaming') return;\n\n  ensureStyles();\n\n  if (host._indicator) {\n    host._indicator.remove();\n    host._indicator = null;\n    host._pendingIndicator = null;\n  }\n  if (host._dismissTeardown) { host._dismissTeardown(); host._dismissTeardown = null; }\n  clearAutoHide(host);\n\n  const wasVisible = host._el !== null;\n  if (!host._el) {\n    host._el = document.createElement('div');\n    host._el.setAttribute(UI_ATTR, 'bar');\n    applyPlacement(host._el, 'subtitle');\n    document.body.appendChild(host._el);\n    bindTouchTapGestures(host._el);\n  }\n  host._el.setAttribute('data-dddk-bar-type', 'agent');\n  host._el.setAttribute('data-dddk-bar-mode', 'streaming');\n\n  host._el.innerHTML = host._wrapBarShell(`<div ${UI_ATTR}=\"bar-text\"></div>`);\n  host._wireClose();\n\n  const textWrap = host._el.querySelector<HTMLDivElement>(`[${UI_ATTR}=\"bar-text\"]`);\n  if (!textWrap) return;\n  const textNode = document.createTextNode('');\n  const cursor = document.createElement('span');\n  cursor.setAttribute(UI_ATTR, 'streaming-cursor');\n  cursor.textContent = '▍';\n  textWrap.appendChild(textNode);\n  textWrap.appendChild(cursor);\n\n  host._streamingTextNode = textNode;\n  host._streamingCursor = cursor;\n  host._streamingFullText = '';\n  host._streamingTtsBuffer = '';\n  host._currentOpts = null;\n  document.body.dataset.dddkActive = 'true';\n  if (!wasVisible) host._onVisibilityChange?.(true);\n}\n\n/** Flush buffered text through TTS at sentence boundaries\n *  (`。 . ！ ! ？ ? \\n`). `force = true` flushes whatever's left\n *  regardless. Non-forced mode requires buffer length ≥ 80 to avoid\n *  choppy mid-clause reads. */\nexport function flushStreamingTts(host: Subtitle, force: boolean): void {\n  if (!host._ttsProvider) {\n    host._streamingTtsBuffer = '';\n    return;\n  }\n  const buf = host._streamingTtsBuffer;\n  if (!buf) return;\n\n  if (force) {\n    try { host._ttsProvider(buf, { locale: host._locale, type: 'agent' }); } catch { /* swallow */ }\n    host._streamingTtsBuffer = '';\n    return;\n  }\n\n  const SENTENCE_END = /[。．.！!？?\\n]/g;\n  let lastIdx = -1;\n  let m: RegExpExecArray | null;\n  while ((m = SENTENCE_END.exec(buf)) !== null) lastIdx = m.index;\n  if (lastIdx < 0) {\n    if (buf.length < 80) return;\n    // No punctuation but buffer is long — cut at closest whitespace\n    // (less likely to break a word) or flush whole.\n    const ws = buf.lastIndexOf(' ');\n    const cut = ws > 30 ? ws + 1 : buf.length;\n    const head = buf.slice(0, cut);\n    host._streamingTtsBuffer = buf.slice(cut);\n    try { host._ttsProvider(head, { locale: host._locale, type: 'agent' }); } catch { /* swallow */ }\n    return;\n  }\n  const head = buf.slice(0, lastIdx + 1);\n  host._streamingTtsBuffer = buf.slice(lastIdx + 1);\n  try { host._ttsProvider(head, { locale: host._locale, type: 'agent' }); } catch { /* swallow */ }\n}\n","/**\n * Multi-choice subtitle bar — question + numbered options + optional\n * free-text input. Mirrors Claude Code's AskUserQuestion envelope into\n * the subtitle slot.\n */\n\nimport type { SubtitleChoiceOptions } from '../../types';\nimport { escapeHtml, UI_ATTR } from '../../utils/dom';\nimport { applyPlacement } from '../placement';\nimport type { Subtitle } from './index';\nimport { ensureStyles } from './styles';\nimport { renderInlineMarkdown } from './markdown';\nimport { bindTouchTapGestures } from './touch';\nimport { clearAutoHide, isImeComposing, isModifierKey } from './dismiss';\n\nexport function showChoice(host: Subtitle, opts: SubtitleChoiceOptions): void {\n  if (typeof document === 'undefined') return;\n  ensureStyles();\n  clearAutoHide(host);\n\n  const allowFreeText = opts.allowFreeText !== false;\n  const freeTextLabel =\n    opts.freeTextLabel ??\n    (host._locale === 'zh-TW' ? '其他 (按 Enter 送出)' : 'Other (press Enter)');\n\n  const wasVisible = host._el !== null;\n  if (!host._el) {\n    host._el = document.createElement('div');\n    host._el.setAttribute(UI_ATTR, 'bar');\n    applyPlacement(host._el, 'subtitle');\n    document.body.appendChild(host._el);\n    bindTouchTapGestures(host._el);\n  }\n  if (!wasVisible) host._onVisibilityChange?.(true);\n\n  // Route every negative gesture (Esc, double-tap, single-tap Space)\n  // to onCancel — a choice bar with nothing focused-by-default must\n  // not auto-pick option 1 on bare Space tap.\n  const cancelPath = (): void => {\n    const cb = opts.onCancel;\n    host.hide();\n    cb?.();\n  };\n  host._currentOpts = {\n    text: opts.question,\n    type: 'agent',\n    onCancel: cancelPath,\n    onReject: cancelPath,\n  };\n  host._el.setAttribute('data-dddk-bar-type', 'agent');\n  host._el.setAttribute('data-dddk-bar-mode', 'choice');\n\n  const optionsHtml = opts.options\n    .map((label, i) => {\n      const safe = escapeHtml(label);\n      return `<button ${UI_ATTR}=\"choice-row\" data-dddk-action=\"choose\" data-choice-index=\"${i}\">\n        <kbd ${UI_ATTR}=\"choice-key\">${i + 1}</kbd>\n        <span ${UI_ATTR}=\"choice-label\">${safe}</span>\n      </button>`;\n    })\n    .join('');\n\n  const freeTextHtml = allowFreeText\n    ? `<div ${UI_ATTR}=\"choice-freetext\">\n        <input type=\"text\" ${UI_ATTR}=\"choice-input\" placeholder=\"${escapeHtml(freeTextLabel)}\" />\n      </div>`\n    : '';\n\n  const hintText = host._locale === 'zh-TW'\n    ? `按數字鍵選 ｜ 點擊也可以 ｜ esc 取消${allowFreeText ? ' ｜ Other 區可以直接打字' : ''}`\n    : `digit to pick · click works too · esc cancels${allowFreeText ? ' · type into Other to free-text' : ''}`;\n\n  host._el.innerHTML = host._wrapBarShell(`\n    <div ${UI_ATTR}=\"bar-text\">${renderInlineMarkdown(opts.question)}</div>\n    <div ${UI_ATTR}=\"choice-list\">${optionsHtml}</div>\n    ${freeTextHtml}\n    <div ${UI_ATTR}=\"bar-hints\">${hintText}</div>\n  `);\n\n  wireChoice(host, opts, allowFreeText);\n  host._wireClose();\n  document.body.dataset.dddkActive = 'true';\n\n  if (host._ttsProvider) {\n    try { host._ttsProvider(opts.question, { locale: host._locale, type: 'agent' }); }\n    catch { /* swallow */ }\n  }\n\n  const DEFAULT_AUTO_HIDE = 0;\n  const autoHideMs = opts.autoHide ?? DEFAULT_AUTO_HIDE;\n  if (autoHideMs > 0) {\n    host._autoHideTimer = setTimeout(() => host.hide(), autoHideMs);\n  }\n\n  installChoiceDismiss(host, opts);\n}\n\n/** Choice-specific dismiss — Esc fires onCancel here (GestureManager's\n *  Esc handler doesn't know about the picker's onCancel); free-text\n *  input keys never dismiss. */\nexport function installChoiceDismiss(host: Subtitle, opts: SubtitleChoiceOptions): void {\n  if (host._dismissTeardown) { host._dismissTeardown(); host._dismissTeardown = null; }\n  const ac = new AbortController();\n  setTimeout(() => {\n    if (ac.signal.aborted) return;\n    const cancelAndHide = (): void => {\n      const cb = opts.onCancel;\n      host.hide();\n      cb?.();\n      // Treat outside-dismiss as cancel — also stop the agent loop +\n      // clear the thinking indicator. Same path as the × button.\n      host._closeHandler?.();\n    };\n    const onClick = (e: Event): void => {\n      const target = e.target as Element | null;\n      if (target && host._el && host._el.contains(target)) return;\n      cancelAndHide();\n    };\n    const onKey = (e: KeyboardEvent): void => {\n      if (isImeComposing(e)) return;\n      const target = e.target as Element | null;\n      if (target && host._el && host._el.contains(target)) return;\n      // Only Escape dismisses via keyboard. Previously ANY key that\n      // wasn't Space/1-9/Modifier cancelled — Enter/Arrow/Tab typed\n      // by the user or auto-focused UI would eat the choice bar\n      // before they got to pick.\n      if (e.key === 'Escape') { e.preventDefault(); cancelAndHide(); return; }\n    };\n    document.addEventListener('click', onClick, true);\n    document.addEventListener('keydown', onKey, true);\n    host._dismissTeardown = () => {\n      document.removeEventListener('click', onClick, true);\n      document.removeEventListener('keydown', onKey, true);\n    };\n  }, 120);\n  host._dismissTeardown = () => { ac.abort(); };\n}\n\n/** Wire 1-N digit keys + click rows + Enter-in-free-text. Document-\n *  level capture-phase keydown catches digits even when focus is\n *  elsewhere; removed via _choiceTeardown on hide(). */\nexport function wireChoice(\n  host: Subtitle,\n  opts: SubtitleChoiceOptions,\n  allowFreeText: boolean,\n): void {\n  if (!host._el) return;\n  if (host._delegatedHandler) {\n    host._el.removeEventListener('click', host._delegatedHandler);\n    host._delegatedHandler = null;\n  }\n  if (host._choiceTeardown) { host._choiceTeardown(); host._choiceTeardown = null; }\n\n  const input = allowFreeText\n    ? host._el.querySelector<HTMLInputElement>(`[${UI_ATTR}=\"choice-input\"]`)\n    : null;\n\n  let resolved = false;\n  const resolve = (value: string, index: number): void => {\n    if (resolved) return;\n    resolved = true;\n    // hide() before delivering the answer — lets a consumer reopen a\n    // new choice bar inside onChoose without racing our listeners.\n    host.hide();\n    opts.onChoose(value, index);\n  };\n\n  const onClick = (e: Event): void => {\n    const btn = (e.target as HTMLElement | null)?.closest<HTMLButtonElement>(\n      'button[data-dddk-action=\"choose\"]'\n    );\n    if (!btn) return;\n    const idx = Number(btn.dataset.choiceIndex);\n    if (Number.isNaN(idx)) return;\n    resolve(opts.options[idx] ?? '', idx);\n  };\n\n  const onKey = (e: KeyboardEvent): void => {\n    if (isImeComposing(e)) return;\n    if (e.target === input) {\n      if (e.key === 'Enter' && input) {\n        e.preventDefault();\n        const v = input.value.trim();\n        if (v) resolve(v, -1);\n      }\n      return;\n    }\n    // Focus on another interactive surface (palette, textarea,\n    // contenteditable) — don't hijack the digit, or opening the\n    // palette while the choice bar is up would steal \"1\" / \"2\".\n    const active = document.activeElement;\n    if (active && active !== document.body) {\n      const tag = active.tagName.toLowerCase();\n      if (tag === 'input' || tag === 'textarea' || tag === 'select') return;\n      if ((active as HTMLElement).isContentEditable) return;\n    }\n    if (/^[1-9]$/.test(e.key)) {\n      const idx = Number(e.key) - 1;\n      if (idx < opts.options.length) {\n        e.preventDefault();\n        resolve(opts.options[idx] ?? '', idx);\n      }\n    }\n  };\n\n  host._el.addEventListener('click', onClick);\n  document.addEventListener('keydown', onKey, true);\n  host._delegatedHandler = onClick;\n  host._choiceTeardown = () => {\n    document.removeEventListener('keydown', onKey, true);\n  };\n}\n","/** Listening / processing / done status pip. Subtitle takes priority:\n *  if the bar is up, `showIndicator` queues into `_pendingIndicator`\n *  and `hide()` materialises it when the bar goes away. */\n\nimport { escapeHtml, UI_ATTR } from '../../utils/dom';\nimport { applyPlacement } from '../placement';\nimport type { Subtitle } from './index';\nimport { ensureStyles } from './styles';\n\nexport function showIndicator(\n  host: Subtitle,\n  state: 'listening' | 'processing' | 'done',\n  label?: string,\n): void {\n  // Subtitle takes priority — stacking a \"thinking…\" pip on top of an\n  // actionable bar was confusing (indicator drawn over reply text).\n  // Queue and let `hide()` surface it later.\n  if (host._el) {\n    host._pendingIndicator = { state, label };\n    return;\n  }\n  ensureStyles();\n  if (!host._indicator) {\n    host._indicator = document.createElement('div');\n    host._indicator.setAttribute(UI_ATTR, 'indicator');\n    applyPlacement(host._indicator, 'indicator');\n    document.body.appendChild(host._indicator);\n  }\n  host._indicator.setAttribute('data-state', state);\n  // Per-state visual: each state gets its own animation vocabulary.\n  //   done       — static check mark (finished, not waiting)\n  //   processing — three side-view swim-duck sprites bouncing in\n  //                relay-swim sequence + one larger \"hero\" sprite\n  //                that pulses. Reads as \"the duck is paddling hard\n  //                to think\" (user's ask: 游泳中的鴨子，努力再游)\n  //   listening  — waveform bars pulsing under the label. No duck\n  //                heads (three heads read as weird for voice input).\n  //                Clean text + audio-visualizer vibe.\n  let visual: string;\n  if (state === 'done') {\n    visual = `<div ${UI_ATTR}=\"indicator-check\">✓</div>`;\n  } else if (state === 'listening') {\n    visual = `<div ${UI_ATTR}=\"indicator-waves\"><span></span><span></span><span></span><span></span><span></span></div>`;\n  } else {\n    // processing / thinking\n    const swimUrl = getRootVar('--dddk-swim-url');\n    const swimStyle = swimUrl ? ` style=\"--dddk-indicator-swim-url: ${swimUrl}\"` : '';\n    visual = `<div ${UI_ATTR}=\"indicator-swim\"${swimStyle}>\n      <span ${UI_ATTR}=\"indicator-swim-hero\"></span>\n      <span ${UI_ATTR}=\"indicator-swim-pip\"></span>\n      <span ${UI_ATTR}=\"indicator-swim-pip\"></span>\n      <span ${UI_ATTR}=\"indicator-swim-pip\"></span>\n    </div>`;\n  }\n  host._indicator.innerHTML = `\n    ${visual}\n    ${label ? `<div ${UI_ATTR}=\"indicator-label\">${escapeHtml(label)}</div>` : ''}\n  `;\n}\n\n/** Read a CSS custom property from `:root`. Empty string if unset. */\nfunction getRootVar(name: string): string {\n  if (typeof document === 'undefined') return '';\n  const v = getComputedStyle(document.documentElement).getPropertyValue(name).trim();\n  return v || '';\n}\n\nexport function hideIndicator(host: Subtitle): void {\n  host._indicator?.remove();\n  host._indicator = null;\n  // Explicit hide means \"STOP showing it\", not \"tuck it away\" — drop\n  // the pending buffer so the next subtitle hide doesn't re-summon a\n  // stale indicator.\n  host._pendingIndicator = null;\n}\n\nexport function resolveRunningLabel(host: Subtitle): string | undefined {\n  if (host._runningLabel) return host._runningLabel;\n  // Locale-aware default; bundled `en` / `zh-TW`; anything else falls\n  // back to English so the indicator never breaks on unknown locales.\n  if (host._locale === 'zh-TW') return 'Agent 執行中…';\n  return 'Agent running…';\n}\n","/**\n * Subtitle bar — DOM-rendered, CSS-variable themed. Shell file: public\n * class surface + state. Implementation in sibling modules (streaming /\n * choice / indicator / paging / markdown / styles / dismiss / touch).\n * See ../../../docs/07-subtitle-ui.md for the full design.\n */\n\nimport type { SubtitleChoiceOptions, SubtitleShowOptions, SubtitleType } from '../../types';\nimport { escapeHtml, UI_ATTR } from '../../utils/dom';\nimport { applyPlacement } from '../placement';\nimport { ensureStyles } from './styles';\nimport { renderInlineMarkdown } from './markdown';\nimport { renderCurrentPage as renderCurrentPageImpl, splitIntoPages } from './paging';\nimport { bindTouchTapGestures, isTouchOnlyDevice } from './touch';\nimport {\n  appendStreamed as appendStreamedImpl,\n  replaceStreamed as replaceStreamedImpl,\n  finalizeStreamed as finalizeStreamedImpl,\n  clearStreamed as clearStreamedImpl,\n  applyStreamingPauseHint as applyStreamingPauseHintImpl,\n  clearStreamingPauseHint as clearStreamingPauseHintImpl,\n} from './streaming';\nimport { showChoice as showChoiceImpl } from './choice';\nimport {\n  showIndicator as showIndicatorImpl,\n  hideIndicator as hideIndicatorImpl,\n  resolveRunningLabel,\n} from './indicator';\nimport { installInteractionDismiss, clearAutoHide } from './dismiss';\n\nexport class Subtitle {\n  /** @internal */ _el: HTMLDivElement | null = null;\n  /** @internal */ _indicator: HTMLDivElement | null = null;\n  /** @internal */ _autoHideTimer: ReturnType<typeof setTimeout> | null = null;\n  /** @internal */ _currentOpts: SubtitleShowOptions | null = null;\n  /** @internal */ _delegatedHandler: ((e: Event) => void) | null = null;\n  /** @internal Document keydown teardown for multi-choice mode. */\n  _choiceTeardown: (() => void) | null = null;\n  /** @internal Click-anywhere / any-key dismiss teardown. */\n  _dismissTeardown: (() => void) | null = null;\n  /** @internal */ _locale: string;\n  /** @internal Indicator request queued while a subtitle is visible;\n   *  materialises on hide(). Subtitle + indicator are mutually exclusive. */\n  _pendingIndicator: { state: 'listening' | 'processing' | 'done'; label?: string } | null = null;\n  /** @internal Multi-page state for a single `show()` call. */\n  _pages: string[] | null = null;\n  /** @internal */ _pageIdx = 0;\n  /** @internal Host hook for \"user explicitly closed the bar\". */\n  _closeHandler: (() => void) | null = null;\n  /** @internal Live Text node the streaming bar appends into. */\n  _streamingTextNode: Text | null = null;\n  /** @internal */ _streamingCursor: HTMLSpanElement | null = null;\n  /** @internal Untranscribed tail held for sentence-boundary TTS flush. */\n  _streamingTtsBuffer = '';\n  /** @internal Raw accumulated streaming text (for replaceStreamed). */\n  _streamingFullText = '';\n  /** @internal Pause-hint callbacks — invokeAccept = advance, invokeReject = stop. */\n  _streamingPauseAccept: (() => void) | null = null;\n  /** @internal */ _streamingPauseReject: (() => void) | null = null;\n  /** @internal Override for the \"running\" indicator label after accept/reject. */\n  _runningLabel: string | null = null;\n  /** @internal Orchestrator hook — flips GestureManager.hasSuggestion so\n   *  space-tap on a proactive prompt isn't a no-op. */\n  _onVisibilityChange?: (visible: boolean) => void;\n  /** @internal Fire-and-forget TTS hook — failures swallowed (no audio\n   *  is strictly better than blocking the visual subtitle). */\n  _ttsProvider?: (text: string, opts: { locale: string; type: SubtitleType }) => void;\n  /** @internal Duck-face avatar URL — when set, `_wrapBarShell` prepends\n   *  an <img> at the left edge of the bar so the subtitle reads as\n   *  coming from the mascot. Off by default (host opt-in). */\n  _avatarUrl: string | null = null;\n\n  constructor(opts: { locale?: string } = {}) {\n    this._locale = opts.locale ?? 'en';\n  }\n\n  setLocale(locale: string): void { this._locale = locale; }\n  setVisibilityListener(fn: (visible: boolean) => void): void { this._onVisibilityChange = fn; }\n  setTTSProvider(fn: typeof this._ttsProvider | null): void { this._ttsProvider = fn ?? undefined; }\n\n  /** Set the mascot-avatar URL that renders at the left edge of the\n   *  subtitle bar. Passes `null` to hide. Hosts that don't want the\n   *  avatar can skip this call entirely — default is off. */\n  setAvatarUrl(url: string | null): void { this._avatarUrl = url; }\n  /** Hook for × button + outside dismiss — orchestrator typically\n   *  stops the agent loop here. */\n  setCloseHandler(fn: (() => void) | null): void { this._closeHandler = fn; }\n\n  show(opts: SubtitleShowOptions): void {\n    if (typeof document === 'undefined') return;\n    ensureStyles();\n\n    // Subtitle + indicator are mutually exclusive — tuck the indicator\n    // into _pendingIndicator and let hide() restore it.\n    if (this._indicator) {\n      const state = (this._indicator.getAttribute('data-state') as 'listening' | 'processing' | 'done') ?? 'processing';\n      const labelEl = this._indicator.querySelector<HTMLElement>(`[${UI_ATTR}=\"indicator-label\"]`);\n      this._pendingIndicator = { state, label: labelEl?.textContent ?? undefined };\n      this._indicator.remove();\n      this._indicator = null;\n    }\n\n    clearAutoHide(this);\n\n    // Wipe streaming state so a confirm Space-accept replacing a\n    // streaming bar isn't misrouted as \"stop the agent\".\n    this._streamingTextNode = null;\n    this._streamingCursor = null;\n    this._streamingFullText = '';\n    this._streamingTtsBuffer = '';\n\n    const wasVisible = this._el !== null;\n    if (!this._el) {\n      this._el = document.createElement('div');\n      this._el.setAttribute(UI_ATTR, 'bar');\n      applyPlacement(this._el, 'subtitle');\n      document.body.appendChild(this._el);\n      bindTouchTapGestures(this._el);\n    } else {\n      // Reusing the el for a different mode — clear bar-mode so\n      // streaming / streaming-done CSS selectors stop applying.\n      this._el.removeAttribute('data-dddk-bar-mode');\n    }\n    if (!wasVisible) this._onVisibilityChange?.(true);\n\n    // Paginate long content on sentence boundaries — keeps the bar's\n    // three-line layout intact, lets Space advance pages instead of\n    // forcing a scroll that loses Space-tap context.\n    const maxPerPage = opts.maxCharsPerPage ?? 220;\n    if (maxPerPage > 0 && opts.text.length > maxPerPage) {\n      this._pages = splitIntoPages(opts.text, maxPerPage);\n      this._pageIdx = 0;\n    } else {\n      this._pages = null;\n      this._pageIdx = 0;\n    }\n\n    this._currentOpts = opts;\n    renderCurrentPageImpl(this);\n    document.body.dataset.dddkActive = 'true';\n\n    if (this._ttsProvider) {\n      try { this._ttsProvider(opts.text, { locale: this._locale, type: opts.type }); }\n      catch { /* swallow */ }\n    }\n\n    // Default OFF — caller opts in via `autoHide: <ms>`. Bars stick\n    // until: click outside, any non-modifier key, double-tap Space, or hide().\n    const DEFAULT_AUTO_HIDE = 0;\n    const autoHideMs = opts.autoHide ?? DEFAULT_AUTO_HIDE;\n    if (autoHideMs > 0) {\n      this._autoHideTimer = setTimeout(() => this.hide(), autoHideMs);\n    }\n    installInteractionDismiss(this, opts);\n  }\n\n  update(text: string): void {\n    if (!this._el) return;\n    const textEl = this._el.querySelector(`[${UI_ATTR}=\"bar-text\"]`);\n    if (textEl) textEl.innerHTML = renderInlineMarkdown(text);\n    if (this._currentOpts) this._currentOpts.text = text;\n  }\n\n  // ── streaming ───────────────────────────────────────────────────\n\n  appendStreamed(delta: string): void { appendStreamedImpl(this, delta); }\n  replaceStreamed(text: string): void { replaceStreamedImpl(this, text); }\n  finalizeStreamed(opts?: { autoHide?: number }): void { finalizeStreamedImpl(this, opts); }\n  clearStreamed(): void { clearStreamedImpl(this); }\n\n  isStreaming(): boolean {\n    return this._streamingTextNode !== null && this._el?.getAttribute('data-dddk-bar-mode') === 'streaming';\n  }\n\n  applyStreamingPauseHint(opts: {\n    hint: string;\n    rejectHint?: string;\n    onAccept: () => void;\n    onReject: () => void;\n  }): void {\n    applyStreamingPauseHintImpl(this, opts);\n  }\n\n  clearStreamingPauseHint(): void { clearStreamingPauseHintImpl(this); }\n\n  // ── choice ──────────────────────────────────────────────────────\n\n  showChoice(opts: SubtitleChoiceOptions): void { showChoiceImpl(this, opts); }\n\n  // ── hide / visibility ───────────────────────────────────────────\n\n  hide(): void {\n    const wasVisible = this._el !== null;\n    if (this._el && this._delegatedHandler) {\n      this._el.removeEventListener('click', this._delegatedHandler);\n      this._delegatedHandler = null;\n    }\n    if (this._choiceTeardown) { this._choiceTeardown(); this._choiceTeardown = null; }\n    if (this._dismissTeardown) { this._dismissTeardown(); this._dismissTeardown = null; }\n    if (this._el) { this._el.remove(); this._el = null; }\n    this._currentOpts = null;\n    // Streaming state lives on the bar el; reset when it goes.\n    this._streamingTextNode = null;\n    this._streamingCursor = null;\n    this._streamingFullText = '';\n    this._streamingTtsBuffer = '';\n    delete document.body.dataset.dddkActive;\n    clearAutoHide(this);\n    if (wasVisible) this._onVisibilityChange?.(false);\n    // Materialise queued indicator now that the bar is gone.\n    if (this._pendingIndicator) {\n      const p = this._pendingIndicator;\n      this._pendingIndicator = null;\n      this.showIndicator(p.state, p.label);\n    }\n  }\n\n  isVisible(): boolean {\n    return this._el !== null;\n  }\n\n  // ── gesture entry points ────────────────────────────────────────\n\n  /** Gesture entry points — single space → invokeAccept, double tap →\n   *  invokeReject, Esc → invokeCancel. Without these the bar would\n   *  only respond to clicks. */\n  invokeAccept(): boolean {\n    // Paged: Space advances to the next page until we run out.\n    if (this._pages && this._pageIdx < this._pages.length - 1) {\n      this._pageIdx += 1;\n      renderCurrentPageImpl(this);\n      return true;\n    }\n    // Streaming + pause hint — Space ADVANCES past the pause (does\n    // NOT stop the agent); hint clears, streamed text stays.\n    if (this._streamingPauseAccept) {\n      const cb = this._streamingPauseAccept;\n      this.clearStreamingPauseHint();\n      cb();\n      return true;\n    }\n    // Streaming IN PROGRESS (cursor blinking, no pause): Space stops\n    // the agent via the host close handler so the orchestrator can\n    // run its stop-feedback path.\n    if (this.isStreaming()) {\n      this._handleCloseClick();\n      return true;\n    }\n    // Streaming-done / info bars (no accept callback): Space closes.\n    if (this._el && !this._currentOpts?.onAccept) {\n      this.hide();\n      return true;\n    }\n    const cb = this._currentOpts?.onAccept;\n    if (!cb) {\n      if (this._pages) { this.hide(); return true; }\n      return false;\n    }\n    // Acknowledge the tap immediately — hide the gated bar + show a\n    // \"running\" indicator. Without this the previous step's bar\n    // lingers for 3-5s of LLM latency and users assume Space was eaten.\n    this.hide();\n    this.showIndicator('processing', resolveRunningLabel(this));\n    cb();\n    return true;\n  }\n\n  invokeReject(): boolean {\n    // Pause-hint reject takes priority — fires reject (host stops the\n    // agent) and clears the hint without going through hide(); the\n    // streaming bar winds down via host stop-feedback instead.\n    if (this._streamingPauseReject) {\n      const cb = this._streamingPauseReject;\n      this.clearStreamingPauseHint();\n      cb();\n      return true;\n    }\n    const cb = this._currentOpts?.onReject;\n    if (!cb) return false;\n    this.hide();\n    this.showIndicator('processing', resolveRunningLabel(this));\n    cb();\n    return true;\n  }\n\n  invokeCancel(): boolean {\n    // Persistent bars refuse Esc / outside-cancel — host has declared\n    // the user must explicitly pick accept or reject.\n    if (this._currentOpts?.persistent) return false;\n    const cb = this._currentOpts?.onCancel;\n    if (!cb) return false;\n    this.hide();\n    cb();\n    return true;\n  }\n\n  /** Override the \"running\" indicator label; `null` falls back to the\n   *  locale-aware default (\"處理中…\" / \"Working…\"). */\n  setRunningLabel(label: string | null): void {\n    this._runningLabel = label;\n  }\n\n  // ── indicator ───────────────────────────────────────────────────\n\n  showIndicator(state: 'listening' | 'processing' | 'done', label?: string): void {\n    showIndicatorImpl(this, state, label);\n  }\n\n  hideIndicator(): void { hideIndicatorImpl(this); }\n\n  // ── internal renderers (used by paging.ts / streaming.ts) ───────\n\n  /** @internal Wrap inner HTML in the shell — pinned × button + a\n   *  `bar-scroll` container that can max-height-cap + scroll without\n   *  losing the close button. Persistent opts skip the ×. */\n  _wrapBarShell(innerHtml: string): string {\n    const persistent = this._currentOpts?.persistent === true;\n    const closeBtn = persistent\n      ? ''\n      : `<button ${UI_ATTR}=\"bar-close\" data-dddk-action=\"close\" aria-label=\"${escapeHtml(this._closeLabel())}\" title=\"${escapeHtml(this._closeLabel())}\">×</button>`;\n    const avatar = this._avatarUrl\n      ? `<img ${UI_ATTR}=\"bar-avatar\" src=\"${escapeHtml(this._avatarUrl)}\" alt=\"\" aria-hidden=\"true\" />`\n      : '';\n    return `\n      ${closeBtn}\n      ${avatar}\n      <div ${UI_ATTR}=\"bar-scroll\">${innerHtml}</div>\n    `;\n  }\n\n  /** @internal */\n  _closeLabel(): string {\n    return this._locale === 'zh-TW' ? '關閉' : 'Close';\n  }\n\n  /** @internal Idempotent — safe to call after any wrapBarShell render. */\n  _wireClose(): void {\n    if (!this._el) return;\n    const btn = this._el.querySelector<HTMLButtonElement>(`button[${UI_ATTR}=\"bar-close\"]`);\n    if (!btn) return;\n    btn.addEventListener('click', (e) => {\n      e.stopPropagation();\n      this._handleCloseClick();\n    });\n  }\n\n  /** @internal */\n  _handleCloseClick(): void {\n    // × is \"user explicitly dismissed\". Drop pending indicator BEFORE\n    // hide() to avoid a 1-frame flicker of the pip we're about to clear.\n    const cancel = this._currentOpts?.onCancel;\n    this._pendingIndicator = null;\n    this.hide();\n    this.hideIndicator();\n    cancel?.();\n    // Notify the host so cross-cutting cleanup (stop the agent loop\n    // even when there was no per-subtitle onCancel — case for\n    // streaming bars) can run.\n    this._closeHandler?.();\n  }\n\n  /** @internal Touch devices use the bar's tap-gesture instead of the\n   *  ✓/✕ buttons (redundant + heavy on small screens). Copy stays —\n   *  no gesture equivalent. Monochrome glyphs only — no emoji. */\n  _renderButtons(opts: SubtitleShowOptions): string {\n    if (opts.type === 'info') return '';\n    const showCopy = opts.onCopy !== undefined;\n    const touch = isTouchOnlyDevice();\n    return `\n      <div ${UI_ATTR}=\"bar-buttons\">\n        ${showCopy ? `<button data-dddk-action=\"copy\" aria-label=\"Copy\">⎘</button>` : ''}\n        ${!touch && opts.onAccept ? `<button data-dddk-action=\"accept\" aria-label=\"Accept\">✓</button>` : ''}\n        ${!touch && opts.onReject ? `<button data-dddk-action=\"reject\" aria-label=\"Reject\">✕</button>` : ''}\n      </div>\n    `;\n  }\n\n  /** @internal Single delegated click listener (vs per-button) so no\n   *  dangling listeners accumulate when innerHTML is replaced mid-life. */\n  _wireButtons(opts: SubtitleShowOptions): void {\n    if (!this._el) return;\n    if (this._delegatedHandler) {\n      this._el.removeEventListener('click', this._delegatedHandler);\n      this._delegatedHandler = null;\n    }\n    const handler = (e: Event) => {\n      const btn = (e.target as HTMLElement | null)?.closest<HTMLButtonElement>(\n        'button[data-dddk-action]'\n      );\n      if (!btn) return;\n      const action = btn.dataset.dddkAction;\n      if (action === 'accept') opts.onAccept?.();\n      else if (action === 'reject') opts.onReject?.();\n      else if (action === 'copy') opts.onCopy?.();\n    };\n    this._el.addEventListener('click', handler);\n    this._delegatedHandler = handler;\n  }\n}\n","import type { DddkEventName, DddkEventMap, DddkEventHandler } from './types';\n\nexport class TypedEmitter {\n  private handlers: Map<DddkEventName, Set<DddkEventHandler<DddkEventName>>> = new Map();\n\n  on<E extends DddkEventName>(event: E, handler: DddkEventHandler<E>): void {\n    if (!this.handlers.has(event)) this.handlers.set(event, new Set());\n    this.handlers.get(event)!.add(handler as DddkEventHandler<DddkEventName>);\n  }\n\n  off<E extends DddkEventName>(event: E, handler: DddkEventHandler<E>): void {\n    this.handlers.get(event)?.delete(handler as DddkEventHandler<DddkEventName>);\n  }\n\n  emit<E extends DddkEventName>(event: E, payload: DddkEventMap[E]): void {\n    const set = this.handlers.get(event);\n    if (!set) return;\n    for (const h of set) {\n      try {\n        (h as DddkEventHandler<E>)(payload);\n      } catch (err) {\n        console.error('[dddk] event handler error:', err);\n      }\n    }\n  }\n\n  clear(): void {\n    this.handlers.clear();\n  }\n}\n","/**\n * Session persistence — sessionStorage backed, BroadcastChannel mirror for\n * cross-tab sync. The session is an append-only `turns[]` log; each\n * `agent.runStream()` call either creates a fresh one or appends a new\n * user turn to an existing one within the continuity window.\n */\n\nimport type { AgentSession, AgentTurn, UserTurn, AgentStepTurn, AgentFinalTurn } from './types';\n\nexport const DEFAULT_SESSION_KEY = 'webagent.session';\n\nexport function createSession(currentPage: string): AgentSession {\n  const now = Date.now();\n  return {\n    id: `s_${now}_${Math.random().toString(36).slice(2, 8)}`,\n    turns: [],\n    status: 'idle',\n    currentPage,\n    startedAt: now,\n    updatedAt: now,\n  };\n}\n\nexport function pushUserTurn(session: AgentSession, turn: Omit<UserTurn, 'kind' | 'ts'>): UserTurn {\n  const full: UserTurn = { kind: 'user', ts: Date.now(), ...turn };\n  session.turns.push(full);\n  session.updatedAt = full.ts;\n  return full;\n}\n\nexport function pushAgentStep(session: AgentSession, turn: Omit<AgentStepTurn, 'kind' | 'ts'>): AgentStepTurn {\n  const full: AgentStepTurn = { kind: 'agent_step', ts: Date.now(), ...turn };\n  session.turns.push(full);\n  session.updatedAt = full.ts;\n  return full;\n}\n\nexport function pushAgentFinal(session: AgentSession, text: string): AgentFinalTurn {\n  const full: AgentFinalTurn = { kind: 'agent_final', ts: Date.now(), text };\n  session.turns.push(full);\n  session.updatedAt = full.ts;\n  return full;\n}\n\nexport function lastUserTurn(session: AgentSession): UserTurn | null {\n  for (let i = session.turns.length - 1; i >= 0; i--) {\n    const t = session.turns[i];\n    if (t && t.kind === 'user') return t;\n  }\n  return null;\n}\n\nexport function loadSession(key: string = DEFAULT_SESSION_KEY): AgentSession | null {\n  if (typeof sessionStorage === 'undefined') return null;\n  try {\n    const raw = sessionStorage.getItem(key);\n    if (!raw) return null;\n    const parsed = JSON.parse(raw) as AgentSession;\n    if (!parsed || !Array.isArray(parsed.turns)) return null;\n    return parsed;\n  } catch {\n    return null;\n  }\n}\n\nexport function saveSession(session: AgentSession, key: string = DEFAULT_SESSION_KEY): void {\n  if (typeof sessionStorage === 'undefined') return;\n  try {\n    session.updatedAt = Date.now();\n    sessionStorage.setItem(key, JSON.stringify(session));\n  } catch {\n    /* quota / disabled */\n  }\n}\n\nexport function clearSession(key: string = DEFAULT_SESSION_KEY): void {\n  if (typeof sessionStorage === 'undefined') return;\n  try {\n    sessionStorage.removeItem(key);\n  } catch {\n    /* ignore */\n  }\n}\n\n/**\n * Decide whether a saved session is still \"live\" enough to pick up as\n * a follow-up. Returns true when:\n *   - status is not terminal (done / failed)\n *   - status === running ('thinking'/'executing'/'navigating'/'waiting')\n *     OR last update is within continuityMs\n */\nexport function isSessionLive(session: AgentSession, continuityMs: number): boolean {\n  // Explicit reload (F5 / Ctrl+R / Ctrl+Shift+R) means the user\n  // wants a clean slate. Stored sessions surviving a reload feel\n  // haunted — the agent claims to \"remember\" attempts from a tab\n  // the user manually reset. Treat reload as the boundary that ends\n  // session continuity, full stop. Cross-PAGE-navigation continuity\n  // (SPA route change) still works because that's not a reload.\n  if (isReloadNavigation()) return false;\n  if (session.status === 'thinking' || session.status === 'executing' || session.status === 'navigating' || session.status === 'waiting') {\n    return true;\n  }\n  if (session.status === 'idle' && continuityMs > 0) {\n    return Date.now() - session.updatedAt <= continuityMs;\n  }\n  return false;\n}\n\n/**\n * Was the current page entered via reload? Cached on first call —\n * `performance.getEntriesByType('navigation')` returns the same\n * record for the lifetime of the document. Returns false for SSR /\n * environments without performance API.\n */\nlet _isReloadCache: boolean | null = null;\nfunction isReloadNavigation(): boolean {\n  if (_isReloadCache !== null) return _isReloadCache;\n  if (typeof performance === 'undefined' || !performance.getEntriesByType) {\n    _isReloadCache = false;\n    return false;\n  }\n  try {\n    const nav = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming | undefined;\n    _isReloadCache = nav?.type === 'reload';\n  } catch {\n    _isReloadCache = false;\n  }\n  return _isReloadCache;\n}\n\n/**\n * Detect whether the agent should auto-resume — true when status was\n * `executing` / `navigating` (interrupted by a SPA route change) and\n * the current URL differs from the session's recorded `currentPage`.\n */\nexport function shouldAutoResume(session: AgentSession, currentPath: string): boolean {\n  if (session.status !== 'navigating' && session.status !== 'executing' && session.status !== 'thinking') {\n    return false;\n  }\n  return session.currentPage !== currentPath;\n}\n\nexport type { AgentTurn };\n","/**\r\n * Visual overlays — highlight / border / spotlight / inject text on the page.\r\n * All overlay elements are tagged with data-webagent-overlay for easy cleanup.\r\n *\r\n * Repositioning: overlays auto-track their target element via a shared\r\n * MutationObserver + ResizeObserver + scroll listener. When the target's\r\n * bounding box changes (sticky-header reflow, scroll, virtualised list,\r\n * animation), the overlay repositions in-place rather than going stale.\r\n *\r\n * Auto-clear: overlays are wiped on `popstate` (history navigation) and\r\n * `beforeunload` (full page reload). dddk's orchestrator also clears them\r\n * on agent `done` / `error` for belt-and-braces cleanup.\r\n */\r\n\r\nimport type { OverlayItem, OverlayType } from './types';\r\nimport { injectScopedStyle } from '../../utils/dom';\r\nimport { genId } from '../../utils/id';\r\n\r\nconst OVERLAY_ATTR = 'data-webagent-overlay';\r\nconst STYLE_ID = 'webagent-overlay-style';\r\nconst SELECTOR_DS_KEY = 'overlaySelector';\r\n\r\nconst STYLE_CSS = `\r\n  /* Overlays paint on top of page content but MUST sit below dddk's\r\n     UI chrome — subtitle bar (z-index 9500), indicator (9510), palette\r\n     (9600), modal (9700), toast (9800). The border / highlight frames\r\n     are visual context for whatever the subtitle is talking about;\r\n     they must never obscure the subtitle's text. */\r\n  [${OVERLAY_ATTR}] { position: absolute; pointer-events: none; z-index: var(--webagent-z-overlay, 9100); }\r\n  [${OVERLAY_ATTR}=\"highlight\"] { background: var(--webagent-highlight, rgba(255, 235, 59, 0.4)); border-radius: var(--webagent-radius-xs, 4px); }\r\n  /* Border: container has no visible chrome — the SVG <rect> inside\r\n     paints the outline using stroke-dashoffset for the draw-in\r\n     animation. Set --webagent-overlay-border-anim-ms to 0 to skip the\r\n     animation (instant border). */\r\n  [${OVERLAY_ATTR}=\"border\"]    { border-radius: var(--webagent-radius-sm, 6px); }\r\n  [${OVERLAY_ATTR}=\"border\"] > svg.webagent-border-svg {\r\n    position: absolute; inset: 0;\r\n    width: 100%; height: 100%;\r\n    overflow: visible;\r\n    pointer-events: none;\r\n  }\r\n  [${OVERLAY_ATTR}=\"border\"] > svg.webagent-border-svg > rect {\r\n    fill: none;\r\n    stroke: var(--webagent-overlay-border, #ff9800);\r\n    stroke-width: 2;\r\n    rx: var(--webagent-radius-sm, 6);\r\n    ry: var(--webagent-radius-sm, 6);\r\n    stroke-dasharray: var(--webagent-border-perimeter, 800);\r\n    stroke-dashoffset: var(--webagent-border-perimeter, 800);\r\n    animation: webagent-border-draw var(--webagent-overlay-border-anim-ms, 480ms) cubic-bezier(0.4, 0, 0.2, 1) forwards;\r\n  }\r\n  @keyframes webagent-border-draw {\r\n    to { stroke-dashoffset: 0; }\r\n  }\r\n  @media (prefers-reduced-motion: reduce) {\r\n    [${OVERLAY_ATTR}=\"border\"] > svg.webagent-border-svg > rect {\r\n      animation: none;\r\n      stroke-dashoffset: 0;\r\n    }\r\n  }\r\n  [${OVERLAY_ATTR}=\"spotlight\"] { box-shadow: 0 0 0 9999px var(--webagent-spotlight, rgba(0,0,0,0.55)); border-radius: 8px; }\r\n  [${OVERLAY_ATTR}=\"label\"]     {\r\n    padding: 4px 8px; background: var(--webagent-label-bg, #1a1a1a); color: var(--webagent-text-on-accent, #fff);\r\n    font-size: var(--webagent-font-size-sm, 12px); border-radius: var(--webagent-radius-xs, 4px); pointer-events: none;\r\n    font-family: var(--webagent-font, system-ui, sans-serif);\r\n  }\r\n  [${OVERLAY_ATTR}=\"inject\"]    {\r\n    padding: 6px 10px; background: var(--webagent-inject-bg, rgba(255,235,59,0.6));\r\n    border-left: 3px solid var(--webagent-accent, #ff9800);\r\n    font-family: var(--webagent-font, system-ui, sans-serif); font-size: 13px;\r\n  }\r\n`;\r\n\r\nfunction ensureStyles(): void {\r\n  injectScopedStyle(STYLE_ID, STYLE_CSS);\r\n  ensureRepositioner();\r\n}\r\n\r\n// ─── Repositioner — keeps overlays glued to their targets ──────────\r\n\r\nlet repositionerInstalled = false;\r\nlet rafScheduled = false;\r\n\r\nfunction scheduleRereposition(): void {\r\n  if (rafScheduled) return;\r\n  rafScheduled = true;\r\n  requestAnimationFrame(() => {\r\n    rafScheduled = false;\r\n    repositionAll();\r\n  });\r\n}\r\n\r\nfunction repositionAll(): void {\r\n  if (typeof document === 'undefined') return;\r\n  document.querySelectorAll<HTMLElement>(`[${OVERLAY_ATTR}]`).forEach((ov) => {\r\n    const selector = ov.dataset[SELECTOR_DS_KEY];\r\n    if (!selector) return;\r\n    const target = document.querySelector(selector);\r\n    if (!target) {\r\n      // Target gone (route nav / DOM swap) — drop the overlay.\r\n      ov.remove();\r\n      return;\r\n    }\r\n    // Labels are positioned relative to the target's top — handled below.\r\n    const type = ov.getAttribute(OVERLAY_ATTR);\r\n    if (type === 'label') {\r\n      const rect = target.getBoundingClientRect();\r\n      ov.style.left = `${rect.left + window.scrollX}px`;\r\n      ov.style.top = `${rect.top + window.scrollY - 28}px`;\r\n    } else if (type === 'inject') {\r\n      // Inject is positioned INLINE (insertBefore) at attach time —\r\n      // nothing to reposition geometrically. Skip.\r\n    } else {\r\n      position(ov, target);\r\n    }\r\n  });\r\n}\r\n\r\nfunction ensureRepositioner(): void {\r\n  if (repositionerInstalled) return;\r\n  if (typeof document === 'undefined' || typeof window === 'undefined') return;\r\n  repositionerInstalled = true;\r\n\r\n  // Scroll + resize + DOM-mutation triggers. We coalesce via rAF so a\r\n  // burst (scroll → layout → repaint) only repositions once per frame.\r\n  window.addEventListener('scroll', scheduleRereposition, true);\r\n  window.addEventListener('resize', scheduleRereposition);\r\n  const mo = new MutationObserver(scheduleRereposition);\r\n  mo.observe(document.body, {\r\n    childList: true,\r\n    subtree: true,\r\n    attributes: true,\r\n    attributeFilter: ['style', 'class'],\r\n  });\r\n\r\n  // Auto-clear on history nav + full page reload. dddk's orchestrator\r\n  // ALSO clears on agent done/error — these are belt-and-braces in case\r\n  // the host bypasses dddk (uses webagent standalone).\r\n  window.addEventListener('popstate', clearOverlays);\r\n  window.addEventListener('beforeunload', clearOverlays);\r\n}\r\n\r\nfunction makeId(): string {\r\n  return genId('ov');\r\n}\r\n\r\nfunction position(overlay: HTMLElement, target: Element): void {\r\n  const rect = target.getBoundingClientRect();\r\n  overlay.style.left = `${rect.left + window.scrollX}px`;\r\n  overlay.style.top = `${rect.top + window.scrollY}px`;\r\n  overlay.style.width = `${rect.width}px`;\r\n  overlay.style.height = `${rect.height}px`;\r\n\r\n  // Border overlays animate the SVG <rect>'s stroke-dashoffset; the\r\n  // dash array must match the actual perimeter for a clean \"draw in\"\r\n  // visual. Cap at 4000 so a giant target doesn't slow the keyframe.\r\n  if (overlay.getAttribute(OVERLAY_ATTR) === 'border') {\r\n    const perimeter = Math.min(4000, Math.ceil((rect.width + rect.height) * 2 + 16));\r\n    overlay.style.setProperty('--webagent-border-perimeter', String(perimeter));\r\n    const svgRect = overlay.querySelector('svg.webagent-border-svg > rect') as SVGRectElement | null;\r\n    if (svgRect) {\r\n      svgRect.setAttribute('width', String(Math.max(0, rect.width - 2)));\r\n      svgRect.setAttribute('height', String(Math.max(0, rect.height - 2)));\r\n    }\r\n  }\r\n}\r\n\r\n/**\r\n * Tag the target element with a unique attribute so the repositioner can\r\n * re-find it across DOM mutations even when the caller passed an `Element`\r\n * (numeric index path — no CSS selector available). Returns the stable\r\n * attribute selector for the repositioner to store.\r\n */\r\nconst TARGET_ATTR = 'data-webagent-overlay-target';\r\nfunction tagTarget(target: Element): string {\r\n  const html = target as HTMLElement;\r\n  let tag = html.getAttribute(TARGET_ATTR);\r\n  if (!tag) {\r\n    tag = genId('ot');\r\n    html.setAttribute(TARGET_ATTR, tag);\r\n  }\r\n  return `[${TARGET_ATTR}=\"${tag}\"]`;\r\n}\r\n\r\nfunction resolveOrTag(input: Element | string): { target: Element; selector: string } | null {\r\n  if (typeof input === 'string') {\r\n    const target = document.querySelector(input);\r\n    if (!target) return null;\r\n    return { target, selector: input };\r\n  }\r\n  return { target: input, selector: tagTarget(input) };\r\n}\r\n\r\nexport function highlight(target: Element | string, color?: string, label?: string): string {\r\n  ensureStyles();\r\n  const r = resolveOrTag(target);\r\n  if (!r) return '';\r\n  const id = makeId();\r\n  const ov = document.createElement('div');\r\n  ov.setAttribute(OVERLAY_ATTR, 'highlight');\r\n  ov.dataset.overlayId = id;\r\n  ov.dataset[SELECTOR_DS_KEY] = r.selector;\r\n  if (color) ov.style.background = color;\r\n  if (label) ov.dataset.overlayLabel = label;\r\n  position(ov, r.target);\r\n  document.body.appendChild(ov);\r\n  if (label) attachLabel(r.target, label, id, r.selector);\r\n  return id;\r\n}\r\n\r\nexport function border(target: Element | string, color?: string, label?: string): string {\r\n  ensureStyles();\r\n  const r = resolveOrTag(target);\r\n  if (!r) return '';\r\n  const id = makeId();\r\n  const ov = document.createElement('div');\r\n  ov.setAttribute(OVERLAY_ATTR, 'border');\r\n  ov.dataset.overlayId = id;\r\n  ov.dataset[SELECTOR_DS_KEY] = r.selector;\r\n  // Custom colour applies to both the legacy border + the new SVG stroke\r\n  // (set as a CSS variable so the rule's `stroke: var(--webagent-overlay-border)`\r\n  // picks it up without overriding the rule).\r\n  if (color) {\r\n    ov.style.setProperty('--webagent-overlay-border', color);\r\n  }\r\n  if (label) ov.dataset.overlayLabel = label;\r\n\r\n  // SVG rect that draws the border with stroke-dashoffset animation.\r\n  // Container `position()` sets the outer size; we update the rect's\r\n  // width/height + the --webagent-border-perimeter custom prop there.\r\n  const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\r\n  svg.setAttribute('class', 'webagent-border-svg');\r\n  svg.setAttribute('preserveAspectRatio', 'none');\r\n  const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');\r\n  rect.setAttribute('x', '1');\r\n  rect.setAttribute('y', '1');\r\n  rect.setAttribute('width', '0');\r\n  rect.setAttribute('height', '0');\r\n  svg.appendChild(rect);\r\n  ov.appendChild(svg);\r\n\r\n  position(ov, r.target);\r\n  document.body.appendChild(ov);\r\n  if (label) attachLabel(r.target, label, id, r.selector);\r\n  return id;\r\n}\r\n\r\nexport function spotlight(target: Element | string): string {\r\n  ensureStyles();\r\n  const r = resolveOrTag(target);\r\n  if (!r) return '';\r\n  const id = makeId();\r\n  const ov = document.createElement('div');\r\n  ov.setAttribute(OVERLAY_ATTR, 'spotlight');\r\n  ov.dataset.overlayId = id;\r\n  ov.dataset[SELECTOR_DS_KEY] = r.selector;\r\n  position(ov, r.target);\r\n  document.body.appendChild(ov);\r\n  return id;\r\n}\r\n\r\nexport function inject(\r\n  selector: string,\r\n  text: string,\r\n  position: 'before' | 'after' = 'after'\r\n): string {\r\n  ensureStyles();\r\n  const target = document.querySelector(selector);\r\n  if (!target) return '';\r\n  const id = makeId();\r\n  const node = document.createElement('div');\r\n  node.setAttribute(OVERLAY_ATTR, 'inject');\r\n  node.dataset.overlayId = id;\r\n  node.dataset[SELECTOR_DS_KEY] = selector;\r\n  node.dataset.overlayText = text;\r\n  node.dataset.overlayPosition = position;\r\n  node.textContent = text;\r\n  if (position === 'before') {\r\n    target.parentElement?.insertBefore(node, target);\r\n  } else {\r\n    target.parentElement?.insertBefore(node, target.nextSibling);\r\n  }\r\n  return id;\r\n}\r\n\r\nfunction attachLabel(target: Element, text: string, id: string, selector: string): void {\r\n  const rect = target.getBoundingClientRect();\r\n  const label = document.createElement('div');\r\n  label.setAttribute(OVERLAY_ATTR, 'label');\r\n  label.dataset.overlayId = `${id}_label`;\r\n  label.dataset[SELECTOR_DS_KEY] = selector;\r\n  label.textContent = text;\r\n  label.style.left = `${rect.left + window.scrollX}px`;\r\n  label.style.top = `${rect.top + window.scrollY - 28}px`;\r\n  label.style.position = 'absolute';\r\n  document.body.appendChild(label);\r\n}\r\n\r\nexport function removeOverlay(id: string): void {\r\n  document\r\n    .querySelectorAll(`[${OVERLAY_ATTR}][data-overlay-id^=\"${id}\"]`)\r\n    .forEach((el) => el.remove());\r\n}\r\n\r\nexport function clearOverlays(): void {\r\n  document.querySelectorAll(`[${OVERLAY_ATTR}]`).forEach((el) => el.remove());\r\n}\r\n\r\nexport function listOverlays(): OverlayItem[] {\r\n  const items: OverlayItem[] = [];\r\n  document.querySelectorAll(`[${OVERLAY_ATTR}]`).forEach((el) => {\r\n    const html = el as HTMLElement;\r\n    const id = html.dataset.overlayId;\r\n    const type = el.getAttribute(OVERLAY_ATTR) as OverlayType | null;\r\n    if (!id || !type) return;\r\n    // Labels are tagged but are sub-items of their parent overlay; surface them\r\n    // only if they carry their own primary selector (they do).\r\n    const selector = html.dataset[SELECTOR_DS_KEY] ?? '';\r\n    const item: OverlayItem = { id, type, selector };\r\n    const label = html.dataset.overlayLabel;\r\n    if (label) item.label = label;\r\n    const text = html.dataset.overlayText;\r\n    if (text) item.text = text;\r\n    const pos = html.dataset.overlayPosition;\r\n    if (pos === 'before' || pos === 'after') item.position = pos;\r\n    items.push(item);\r\n  });\r\n  return items;\r\n}\r\n","/**\n * Built-in actions — the narrator's hands. Visual overlays are first-class\n * here (border / highlight / spotlight) because the agent's job is to point\n * at things and then talk about them.\n *\n * The `show_subtitle` action was removed deliberately — between tool calls\n * the model emits free-form text which streams into the subtitle bar. There\n * is no `done` tool either; the loop ends when the model emits a turn with\n * no tool call (finish_reason=stop).\n */\n\nimport type { ActionDefinition, ActionResult } from './types';\nimport * as overlay from './overlay';\nimport { moveCursorAndTap, moveCursorTo, setCursorMode } from './cursor';\n\nconst objSchema = (props: Record<string, unknown>, required: string[] = []) => ({\n  type: 'object',\n  properties: props,\n  required,\n});\n\nfunction resolve(ctx: { resolveTarget: (t: string | number) => Element | null }, target: string | number):\n  { ok: true; el: HTMLElement } | { ok: false; result: ActionResult } {\n  if (typeof document === 'undefined') {\n    return { ok: false, result: { ok: false, reason: 'unknown', message: 'no DOM' } };\n  }\n  const el = ctx.resolveTarget(target);\n  if (!el) return { ok: false, result: { ok: false, reason: 'not_found' } };\n  const html = el as HTMLElement;\n  // For visibility we still use offsetParent — the index map was built\n  // from visible elements, but elements can become hidden between read\n  // and dispatch (e.g. async re-render).\n  if (html.offsetParent === null && html.tagName !== 'BODY') {\n    return { ok: false, result: { ok: false, reason: 'not_visible' } };\n  }\n  return { ok: true, el: html };\n}\n\nfunction isInteractive(el: HTMLElement): boolean {\n  if ((el as HTMLButtonElement).disabled) return false;\n  if (el.getAttribute('aria-disabled') === 'true') return false;\n  return true;\n}\n\n// ─── navigation ─────────────────────────────────────────────────────\n\nconst navigate: ActionDefinition<{ path: string; note?: string }> = {\n  name: 'navigate',\n  description: 'Take the user to a SPA-friendly path. Cross-page transition; runtime gates with a confirm by default. Optional `note` overrides the confirm message — write it in the user\\'s language and the persona\\'s voice.',\n  parameters: objSchema({\n    path: { type: 'string' },\n    note: { type: 'string', description: 'Optional natural-language sentence shown to the user as the confirm copy instead of the SDK default.' },\n  }, ['path']),\n  requireConfirmation: true,\n  confirmationMessage: ({ note }) => (note?.trim() ? note.trim() : undefined),\n  handler: async ({ path }) => {\n    if (typeof window === 'undefined') return { ok: false, reason: 'unknown', message: 'no window' };\n    return { ok: true, data: path };\n  },\n};\n\nconst pause: ActionDefinition<{ note?: string }> = {\n  name: 'pause',\n  description: 'Wait for the user to press Space before continuing. Use only for explicit-consent moments (about to submit, place an order, send a message).',\n  parameters: objSchema({\n    note: { type: 'string', description: 'Optional short hint shown in the subtitle bar.' },\n  }),\n  handler: async () => {\n    // Intercepted in execute-action.ts; this stub only registers the schema.\n    return { ok: true };\n  },\n};\n\nconst scrollTo: ActionDefinition<{ selector: string }> = {\n  name: 'scroll_to',\n  description: 'Smoothly scroll an element into view. `selector` accepts a stable hash ID from the DOM dump or a CSS selector.',\n  parameters: objSchema({ selector: { type: 'string' } }, ['selector']),\n  handler: async ({ selector }, ctx) => {\n    const found = resolve(ctx, selector);\n    if (!found.ok) return found.result;\n    // Cursor switches to scroll-mode glyph while we travel; the\n    // scrollIntoView promise doesn't exist, so wait a beat for the\n    // smooth scroll to settle before gliding the cursor to its\n    // destination. Restore pointer mode after.\n    if (ctx.uiHints?.cursorTrail) {\n      try { setCursorMode('scroll'); } catch { /* nicety */ }\n    }\n    found.el.scrollIntoView({ behavior: 'smooth', block: 'center' });\n    if (ctx.uiHints?.cursorTrail) {\n      // ~360ms covers a typical smooth scroll on modern browsers.\n      await new Promise((r) => setTimeout(r, 360));\n      try {\n        await moveCursorTo(found.el);\n      } catch { /* nicety */ }\n      try { setCursorMode('pointer'); } catch { /* nicety */ }\n    }\n    return { ok: true };\n  },\n};\n\nconst wait: ActionDefinition<{ ms?: number; selector?: string; timeout?: number }> = {\n  name: 'wait',\n  description: 'Wait for time or for a CSS selector to appear, capped at 5s. Pass `ms` to sleep, or `selector` (+ optional `timeout`) to poll.',\n  parameters: objSchema(\n    {\n      ms: { type: 'number', maximum: 5000 },\n      selector: { type: 'string' },\n      timeout: { type: 'number', maximum: 5000, default: 5000 },\n    }\n  ),\n  handler: async ({ ms, selector, timeout = 5000 }, ctx) => {\n    if (selector) {\n      const start = Date.now();\n      const cap = Math.min(timeout, 5000);\n      while (Date.now() - start < cap) {\n        if (ctx.signal.aborted) return { ok: false, reason: 'cancelled' };\n        if (typeof document !== 'undefined' && document.querySelector(selector)) return { ok: true };\n        await new Promise((r) => setTimeout(r, 100));\n      }\n      return { ok: false, reason: 'timeout' };\n    }\n    const duration = Math.min(ms ?? 0, 5000);\n    await new Promise<void>((resolveTimer, reject) => {\n      let timer: ReturnType<typeof setTimeout> | null = null;\n      const onAbort = (): void => {\n        if (timer !== null) clearTimeout(timer);\n        ctx.signal.removeEventListener('abort', onAbort);\n        reject(new Error('aborted'));\n      };\n      timer = setTimeout(() => {\n        ctx.signal.removeEventListener('abort', onAbort);\n        resolveTimer();\n      }, duration);\n      ctx.signal.addEventListener('abort', onAbort);\n    });\n    return { ok: true };\n  },\n};\n\n// ─── DOM interaction ────────────────────────────────────────────────\n\nconst click: ActionDefinition<{ selector: string }> = {\n  name: 'click',\n  description: 'Click an element — fires its onClick handler, follows links, opens menus, picks options, submits buttons. `selector` MUST be a stable `[id]` hash taken VERBATIM from the current DOM dump (e.g. `[a1b2]` or `a1b2`). NEVER invent CSS selectors like `#thing` / `.row` based on guessed names — the page does not necessarily use those IDs. If the element you want is not in the current DOM dump, scroll / wait / re-read instead of guessing.',\n  parameters: objSchema({ selector: { type: 'string' } }, ['selector']),\n  handler: async ({ selector }, ctx) => {\n    const found = resolve(ctx, selector);\n    if (!found.ok) return found.result;\n    if (!isInteractive(found.el)) return { ok: false, reason: 'not_interactive' };\n    // Synthetic cursor pre-flight — opt-in via WebAgentConfig.cursorTrail.\n    // Pure visual; el.click() still fires the real DOM event afterward.\n    if (ctx.uiHints?.cursorTrail) {\n      try { await moveCursorAndTap(found.el); } catch { /* visual nicety; never block */ }\n    }\n    found.el.click();\n    // Settle so framework handlers re-render before the next agent turn\n    // reads DOM.\n    await new Promise<void>((resolve) => {\n      let settled = false;\n      const finish = (): void => {\n        if (settled) return;\n        settled = true;\n        window.removeEventListener('popstate', finish);\n        resolve();\n      };\n      window.addEventListener('popstate', finish, { once: true });\n      setTimeout(finish, 250);\n    });\n    await new Promise<void>((r) => requestAnimationFrame(() => r()));\n    return { ok: true };\n  },\n};\n\nfunction setNativeInputValue(el: HTMLInputElement | HTMLTextAreaElement, value: string): void {\n  const proto = el instanceof HTMLTextAreaElement\n    ? HTMLTextAreaElement.prototype\n    : HTMLInputElement.prototype;\n  const setter = Object.getOwnPropertyDescriptor(proto, 'value')?.set;\n  if (setter) {\n    setter.call(el, value);\n  } else {\n    el.value = value;\n  }\n}\n\nconst fillInput: ActionDefinition<{ selector: string; value: string }> = {\n  name: 'fill_input',\n  description: 'Fill a text input or textarea with a value. Works with framework-controlled inputs (dispatches input + change events).',\n  parameters: objSchema(\n    { selector: { type: 'string' }, value: { type: 'string' } },\n    ['selector', 'value']\n  ),\n  handler: async ({ selector, value }, ctx) => {\n    const found = resolve(ctx, selector);\n    if (!found.ok) return found.result;\n    const el = found.el as HTMLInputElement | HTMLTextAreaElement;\n    if (!isInteractive(el)) return { ok: false, reason: 'not_interactive' };\n    // Glide cursor to the field before focusing — same UX beat as\n    // `click`: the user sees \"the agent is going to type HERE next\".\n    if (ctx.uiHints?.cursorTrail) {\n      try { await moveCursorTo(el); } catch { /* nicety */ }\n    }\n    el.focus();\n    setNativeInputValue(el, value);\n    el.dispatchEvent(new Event('input', { bubbles: true }));\n    el.dispatchEvent(new Event('change', { bubbles: true }));\n    return { ok: true };\n  },\n};\n\nconst selectOption: ActionDefinition<{ selector: string; value: string }> = {\n  name: 'select_option',\n  description: 'Select an <option> by value.',\n  parameters: objSchema(\n    { selector: { type: 'string' }, value: { type: 'string' } },\n    ['selector', 'value']\n  ),\n  handler: async ({ selector, value }, ctx) => {\n    const found = resolve(ctx, selector);\n    if (!found.ok) return found.result;\n    const el = found.el as HTMLSelectElement;\n    el.value = value;\n    el.dispatchEvent(new Event('change', { bubbles: true }));\n    return { ok: true };\n  },\n};\n\n/**\n * Maps a few common key names to their `event.code` value so frameworks\n * checking `code` (not just `key`) still match. Sparse on purpose — most\n * single-character keys map 1:1 and don't need an entry.\n */\nconst KEY_CODE_MAP: Record<string, string> = {\n  Enter: 'Enter',\n  Escape: 'Escape',\n  Tab: 'Tab',\n  Backspace: 'Backspace',\n  Delete: 'Delete',\n  ArrowUp: 'ArrowUp',\n  ArrowDown: 'ArrowDown',\n  ArrowLeft: 'ArrowLeft',\n  ArrowRight: 'ArrowRight',\n  ' ': 'Space',\n  Space: 'Space',\n};\n\ntype ModifierKey = 'ctrl' | 'shift' | 'alt' | 'meta';\nconst ALL_MODIFIERS: readonly ModifierKey[] = ['ctrl', 'shift', 'alt', 'meta'];\n\nfunction buildKeyEventInit(key: string, modifiers?: string[]): KeyboardEventInit {\n  const code = KEY_CODE_MAP[key] ?? (key.length === 1 ? `Key${key.toUpperCase()}` : key);\n  const mods = new Set((modifiers ?? []).map((m) => m.toLowerCase()));\n  return {\n    key,\n    code,\n    bubbles: true,\n    cancelable: true,\n    ctrlKey: mods.has('ctrl'),\n    shiftKey: mods.has('shift'),\n    altKey: mods.has('alt'),\n    metaKey: mods.has('meta'),\n  };\n}\n\nconst pressKey: ActionDefinition<{ key: string; selector?: string; modifiers?: string[] }> = {\n  name: 'press_key',\n  description: 'Dispatch a keyboard event (keydown + keyup) on an element, optionally with modifier keys. Use for Enter (commit forms / palette selections), Escape, Tab, ArrowUp/Down, or chords like Ctrl+S / Cmd+K / Shift+Tab. `key` is the W3C key name (\"Enter\", \"Escape\", \"ArrowDown\", \"a\", \" \"). `modifiers` is an array of \"ctrl\" | \"shift\" | \"alt\" | \"meta\" — empty / omitted = no modifiers. `selector` is optional — omitted = the currently focused element (`document.activeElement`).',\n  parameters: objSchema(\n    {\n      key: { type: 'string' },\n      selector: { type: 'string' },\n      modifiers: { type: 'array', items: { type: 'string', enum: ALL_MODIFIERS as unknown as string[] } },\n    },\n    ['key'],\n  ),\n  handler: async ({ key, selector, modifiers }, ctx) => {\n    if (typeof document === 'undefined') return { ok: false, reason: 'unknown', message: 'no DOM' };\n    let target: HTMLElement | null;\n    if (selector) {\n      const found = resolve(ctx, selector);\n      if (!found.ok) return found.result;\n      target = found.el;\n    } else {\n      target = (document.activeElement as HTMLElement | null) ?? document.body;\n    }\n    if (!target) return { ok: false, reason: 'not_found' };\n    const init = buildKeyEventInit(key, modifiers);\n    target.dispatchEvent(new KeyboardEvent('keydown', init));\n    target.dispatchEvent(new KeyboardEvent('keyup', init));\n    return { ok: true };\n  },\n};\n\nconst holdKey: ActionDefinition<{ key: string; ms: number; selector?: string; modifiers?: string[] }> = {\n  name: 'hold_key',\n  description: 'Hold a key down for `ms` milliseconds (keydown → wait → keyup). Use for hold-to-zoom, hold-Ctrl-to-multi-select, push-to-talk gestures. Caps at 5000ms. Same `key` / `selector` / `modifiers` semantics as press_key.',\n  parameters: objSchema(\n    {\n      key: { type: 'string' },\n      ms: { type: 'number', maximum: 5000 },\n      selector: { type: 'string' },\n      modifiers: { type: 'array', items: { type: 'string', enum: ALL_MODIFIERS as unknown as string[] } },\n    },\n    ['key', 'ms'],\n  ),\n  handler: async ({ key, ms, selector, modifiers }, ctx) => {\n    if (typeof document === 'undefined') return { ok: false, reason: 'unknown', message: 'no DOM' };\n    let target: HTMLElement | null;\n    if (selector) {\n      const found = resolve(ctx, selector);\n      if (!found.ok) return found.result;\n      target = found.el;\n    } else {\n      target = (document.activeElement as HTMLElement | null) ?? document.body;\n    }\n    if (!target) return { ok: false, reason: 'not_found' };\n    const init = buildKeyEventInit(key, modifiers);\n    target.dispatchEvent(new KeyboardEvent('keydown', { ...init, repeat: false }));\n    const duration = Math.min(Math.max(ms, 0), 5000);\n    await new Promise<void>((r) => setTimeout(r, duration));\n    target.dispatchEvent(new KeyboardEvent('keyup', init));\n    return { ok: true };\n  },\n};\n\nconst doubleClick: ActionDefinition<{ selector: string }> = {\n  name: 'double_click',\n  description: 'Double-click an element. Fires `dblclick` (NOT two `click` events) so handlers bound to `ondblclick` actually run — e.g. open detail, expand row, enter rename mode. Cursor glide pre-flight happens if cursorTrail is on.',\n  parameters: objSchema({ selector: { type: 'string' } }, ['selector']),\n  handler: async ({ selector }, ctx) => {\n    const found = resolve(ctx, selector);\n    if (!found.ok) return found.result;\n    if (!isInteractive(found.el)) return { ok: false, reason: 'not_interactive' };\n    if (ctx.uiHints?.cursorTrail) {\n      try { await moveCursorAndTap(found.el); } catch { /* nicety */ }\n    }\n    const rect = found.el.getBoundingClientRect();\n    const x = rect.left + rect.width / 2;\n    const y = rect.top + rect.height / 2;\n    const opts: MouseEventInit = { bubbles: true, cancelable: true, view: window, clientX: x, clientY: y, button: 0, detail: 2 };\n    found.el.dispatchEvent(new MouseEvent('mousedown', opts));\n    found.el.dispatchEvent(new MouseEvent('mouseup', opts));\n    found.el.dispatchEvent(new MouseEvent('click', opts));\n    found.el.dispatchEvent(new MouseEvent('mousedown', opts));\n    found.el.dispatchEvent(new MouseEvent('mouseup', opts));\n    found.el.dispatchEvent(new MouseEvent('click', opts));\n    found.el.dispatchEvent(new MouseEvent('dblclick', opts));\n    return { ok: true };\n  },\n};\n\nconst longPress: ActionDefinition<{ selector: string; ms?: number }> = {\n  name: 'long_press',\n  description: 'Press and HOLD an element for `ms` milliseconds (default 600). Fires `mousedown` + `touchstart` → wait → `mouseup` + `touchend`. Use for context menus, draggable handles, mobile long-press menus. Caps at 5000ms.',\n  parameters: objSchema(\n    { selector: { type: 'string' }, ms: { type: 'number', maximum: 5000 } },\n    ['selector'],\n  ),\n  handler: async ({ selector, ms = 600 }, ctx) => {\n    const found = resolve(ctx, selector);\n    if (!found.ok) return found.result;\n    if (ctx.uiHints?.cursorTrail) {\n      try { await moveCursorAndTap(found.el); } catch { /* nicety */ }\n    }\n    const rect = found.el.getBoundingClientRect();\n    const x = rect.left + rect.width / 2;\n    const y = rect.top + rect.height / 2;\n    const opts: MouseEventInit = { bubbles: true, cancelable: true, view: window, clientX: x, clientY: y, button: 0 };\n    const touchInit = { bubbles: true, cancelable: true };\n    found.el.dispatchEvent(new MouseEvent('mousedown', opts));\n    try { found.el.dispatchEvent(new Event('touchstart', touchInit)); } catch { /* touch unsupported */ }\n    const duration = Math.min(Math.max(ms, 0), 5000);\n    await new Promise<void>((r) => setTimeout(r, duration));\n    found.el.dispatchEvent(new MouseEvent('mouseup', opts));\n    try { found.el.dispatchEvent(new Event('touchend', touchInit)); } catch { /* touch unsupported */ }\n    return { ok: true };\n  },\n};\n\nconst drag: ActionDefinition<{ from: string; to: string; steps?: number }> = {\n  name: 'drag',\n  description: 'Drag from one element to another. mousedown on `from` → `steps` interpolated mousemove events along the path (default 10) → mouseup on `to`. Also fires `dragstart` / `dragover` / `drop` / `dragend` for HTML5 drag-and-drop. Use for sortable lists, kanban cards, slider handles.',\n  parameters: objSchema(\n    { from: { type: 'string' }, to: { type: 'string' }, steps: { type: 'number', minimum: 2, maximum: 50 } },\n    ['from', 'to'],\n  ),\n  handler: async ({ from, to, steps = 10 }, ctx) => {\n    const fromFound = resolve(ctx, from);\n    if (!fromFound.ok) return fromFound.result;\n    const toFound = resolve(ctx, to);\n    if (!toFound.ok) return toFound.result;\n    if (ctx.uiHints?.cursorTrail) {\n      try { await moveCursorAndTap(fromFound.el); } catch { /* nicety */ }\n    }\n    const r1 = fromFound.el.getBoundingClientRect();\n    const r2 = toFound.el.getBoundingClientRect();\n    const sx = r1.left + r1.width / 2, sy = r1.top + r1.height / 2;\n    const ex = r2.left + r2.width / 2, ey = r2.top + r2.height / 2;\n    const mk = (x: number, y: number, target: Element): MouseEventInit & { dataTransfer?: DataTransfer } => ({\n      bubbles: true, cancelable: true, view: window,\n      clientX: x, clientY: y, screenX: x, screenY: y, button: 0,\n    });\n    fromFound.el.dispatchEvent(new MouseEvent('mousedown', mk(sx, sy, fromFound.el)));\n    try { fromFound.el.dispatchEvent(new DragEvent('dragstart', mk(sx, sy, fromFound.el))); } catch { /* old browsers */ }\n    const n = Math.min(Math.max(steps, 2), 50);\n    for (let i = 1; i <= n; i++) {\n      const t = i / n;\n      const x = sx + (ex - sx) * t;\n      const y = sy + (ey - sy) * t;\n      const el = document.elementFromPoint(x, y) ?? fromFound.el;\n      el.dispatchEvent(new MouseEvent('mousemove', mk(x, y, el)));\n      try { el.dispatchEvent(new DragEvent('dragover', mk(x, y, el))); } catch { /* old browsers */ }\n      await new Promise<void>((r) => setTimeout(r, 16));\n    }\n    try { toFound.el.dispatchEvent(new DragEvent('drop', mk(ex, ey, toFound.el))); } catch { /* old browsers */ }\n    toFound.el.dispatchEvent(new MouseEvent('mouseup', mk(ex, ey, toFound.el)));\n    try { fromFound.el.dispatchEvent(new DragEvent('dragend', mk(ex, ey, fromFound.el))); } catch { /* old browsers */ }\n    return { ok: true };\n  },\n};\n\nconst clearInput: ActionDefinition<{ selector: string }> = {\n  name: 'clear_input',\n  description: 'Clear an input or textarea value.',\n  parameters: objSchema({ selector: { type: 'string' } }, ['selector']),\n  handler: async ({ selector }, ctx) => {\n    const found = resolve(ctx, selector);\n    if (!found.ok) return found.result;\n    const el = found.el as HTMLInputElement | HTMLTextAreaElement;\n    setNativeInputValue(el, '');\n    el.dispatchEvent(new Event('input', { bubbles: true }));\n    el.dispatchEvent(new Event('change', { bubbles: true }));\n    return { ok: true };\n  },\n};\n\n// ─── visual overlay actions — first-class for the narrator ─────────\n\nconst borderAction: ActionDefinition<\n  { selector: string; color?: string; label?: string },\n  string\n> = {\n  name: 'border',\n  description: 'Draw a border around an element to point at it. Previous border / highlight is auto-cleared.',\n  parameters: objSchema(\n    {\n      selector: { type: 'string' },\n      color: { type: 'string' },\n      label: { type: 'string' },\n    },\n    ['selector']\n  ),\n  handler: async ({ selector, color, label }, ctx) => {\n    const el = ctx.resolveTarget(selector);\n    if (!el) return { ok: false, reason: 'not_found' };\n    overlay.clearOverlays();\n    // Glide the synthetic cursor onto the target before drawing the\n    // frame — keeps the \"agent points at the thing\" beat consistent\n    // with how `click` already telegraphs intent.\n    if (ctx.uiHints?.cursorTrail) {\n      try { await moveCursorTo(el); } catch { /* nicety */ }\n    }\n    const id = overlay.border(el, color, label);\n    return id ? { ok: true, data: id } : { ok: false, reason: 'not_found' };\n  },\n};\n\nconst highlightAction: ActionDefinition<\n  { selector: string; color?: string; label?: string },\n  string\n> = {\n  name: 'highlight',\n  description: 'Translucent paint overlay on an element or text span. Previous border / highlight is auto-cleared.',\n  parameters: objSchema(\n    {\n      selector: { type: 'string' },\n      color: { type: 'string' },\n      label: { type: 'string' },\n    },\n    ['selector']\n  ),\n  handler: async ({ selector, color, label }, ctx) => {\n    const el = ctx.resolveTarget(selector);\n    if (!el) return { ok: false, reason: 'not_found' };\n    overlay.clearOverlays();\n    if (ctx.uiHints?.cursorTrail) {\n      try { await moveCursorTo(el); } catch { /* nicety */ }\n    }\n    const id = overlay.highlight(el, color, label);\n    return id ? { ok: true, data: id } : { ok: false, reason: 'not_found' };\n  },\n};\n\n// ─── ask the user (kept — for genuine pauses needing input) ────────\n\nconst askUser: ActionDefinition<{ question: string }, string> = {\n  name: 'ask_user',\n  description: 'Pause and ask the user a free-text question. Use only when you need information not derivable from the page or conversation.',\n  parameters: objSchema({ question: { type: 'string' } }, ['question']),\n  handler: async () => {\n    // Intercepted in execute-action.ts.\n    return { ok: true };\n  },\n};\n\nconst askUserChoice: ActionDefinition<\n  { question: string; options: string[]; allowFreeText?: boolean },\n  string\n> = {\n  name: 'ask_user_choice',\n  description: 'Pause and ask the user to pick one of 2-6 options. Prefer this over ask_user when the answer space is finite. Returns the chosen value.',\n  parameters: objSchema(\n    {\n      question: { type: 'string' },\n      options: { type: 'array', items: { type: 'string' }, minItems: 2, maxItems: 6 },\n      allowFreeText: { type: 'boolean' },\n    },\n    ['question', 'options'],\n  ),\n  handler: async () => {\n    // Intercepted in execute-action.ts.\n    return { ok: true };\n  },\n};\n\n// ─── present_surface — rich UI handoff (opt-in) ────────────────────\n// Not in the builtin set; the runtime adds it ONLY when the host opts\n// in via `WebAgentConfig.allowPresent`. Lives here so the schema is\n// next to the other actions for consistency.\n\nexport const presentSurface: ActionDefinition<{\n  surface: unknown;\n  placement?: 'subtitle' | 'modal' | 'dock' | 'inline';\n}> = {\n  name: 'present_surface',\n  description: 'Render a visual picker (OptionGroup of 2-6 options, each with value / title / optional description / optional image) and wait for the user to pick or cancel. Returns `{ value, cancelled }`. Use when the choice has visual weight (product cards, plan tiers); use ask_user_choice for plain 2-6 text options.',\n  parameters: objSchema(\n    {\n      surface: {\n        type: 'object',\n        additionalProperties: true,\n        description: 'PieceSurface tree. Shape: { root: { kind: \"OptionGroup\", bind: string, layout: \"row\" | \"column\", options: Array<{ value: string, title: string, description?: string, image?: { src: string, alt?: string } }> } }.',\n      },\n      placement: { type: 'string', enum: ['subtitle', 'modal', 'dock', 'inline'], description: 'Where the picker renders. Default `subtitle`.' },\n    },\n    ['surface'],\n  ),\n  handler: async () => {\n    // Intercepted in execute-action.ts; this stub only registers the schema.\n    return { ok: true };\n  },\n};\n\n// ─── v0.2.0 generic action additions (ROADMAP 3.1 + 4.7) ──────────\n\n/** ROADMAP 4.7: escalate to a human operator. Host wires the actual\n *  handoff (live chat, ticket, email) in their `escalate_to_human`\n *  action override; the bundled definition is a typed stub that emits\n *  the `agent_escalated` intent for analytics.\n *  Opt-in: NOT in `builtinActions`. Host registers via `customActions`. */\nexport const escalateToHuman: ActionDefinition<{ reason: string; context?: string }> = {\n  name: 'escalate_to_human',\n  description: 'Hand off the conversation to a human operator. Use when the user is frustrated, the request requires a human policy decision, or the agent has tried + failed N times. Provide `reason` describing why escalating. Optional `context` packages what to send the operator.',\n  parameters: objSchema(\n    {\n      reason: { type: 'string', description: 'Short reason for the handoff. Shown to the operator.' },\n      context: { type: 'string', description: 'Optional longer summary the operator needs.' },\n    },\n    ['reason'],\n  ),\n  handler: async ({ reason, context }) => {\n    return { ok: true, data: { reason, context: context ?? '' } };\n  },\n};\n\n/** ROADMAP 3.1: typed intent emission from agent. Lets the agent flag\n *  notable moments in a run for the host's analytics (\"user explicitly\n *  asked about pricing\", \"agent recommended product X\").\n *  Opt-in: NOT in `builtinActions`. Host registers via `customActions`. */\nexport const trackIntent: ActionDefinition<{ kind: string; payload?: Record<string, unknown> }> = {\n  name: 'track_intent',\n  description: 'Emit a typed intent event to the host\\'s analytics stream. Use to flag notable moments mid-run — the user explicitly committed to a plan, the agent recommended a specific product, the conversation drifted into a new topic. Does NOT change the conversation flow; agent should still narrate / act as appropriate after calling this.',\n  parameters: objSchema(\n    {\n      kind: { type: 'string', description: 'Intent kind. Use snake_case + describe what happened, not what to do (e.g. \"user_committed_to_pro_plan\").' },\n      payload: { type: 'object', additionalProperties: true, description: 'Optional structured payload — the entities involved, the outcome, etc.' },\n    },\n    ['kind'],\n  ),\n  handler: async ({ kind, payload }) => {\n    return { ok: true, data: { kind, payload: payload ?? {} } };\n  },\n};\n\n// `summarize_page` was prototyped as a schema-only stub then removed —\n// the runtime hand-off never landed and shipping the schema without a\n// real handler made the LLM call a no-op. Will return once the\n// streaming-envelope loop wiring is in place. Host can register their\n// own `summarize_page` action today via `customActions`.\n\n// `open_popup` / `enter_iframe` (frame actions, ROADMAP 2.1/2.2) were\n// prototyped then removed — the use cases (OAuth windows, embedded\n// checkout) overlap with `navigate`+`auth_required` and add little\n// for the agent's typical product-driving flows. Re-introduce when a\n// real host needs popup-driven OAuth round-tripping.\n\n// ─── narrate primitive ─────────────────────────────────────────────\n//\n// `narrate` is the most-used agent action in CoT mode — it's how the\n// agent \"speaks\" between page operations. Pre-v0.2 it lived ONLY\n// inside the CoT envelope (a {narrate, about?} object the runtime\n// intercepts before any tool handler is dispatched), so it never\n// appeared in the action registry. That confused hosts inspecting\n// `agent.actionsRef.keys()`: where's narrate?\n//\n// This stub registers `narrate` AS a tool so:\n//   - It shows up in the registry / prompt catalog under both\n//     protocols (CoT + plain).\n//   - Plain-protocol callers (e.g. a future WebAgent-without-CoT,\n//     or a TaskAgent borrowing the catalog) can call it and have\n//     the text routed to the subtitle bar like the runtime does.\n//\n// The CoT runtime continues to intercept the envelope's `narrate`\n// field BEFORE handler dispatch, so this handler is only reached on\n// plain-protocol direct calls. In CoT mode the runtime's interception\n// path is the source of truth — descriptions stay aligned in both.\nconst narrateAction: ActionDefinition<{ text: string; about?: string }> = {\n  name: 'narrate',\n  description: 'Speak to the user in the subtitle bar — describe what you see, what you found, what you\\'re about to do. ALWAYS use the user\\'s language. If `about` is set, ALSO point at that element on the page (synthesizes a `border` call). The page narration loop revolves around this action: most steps look like `narrate({text: \"Here\\'s the install snippet\", about: \"<id of the pre block>\"})`.',\n  parameters: objSchema(\n    { text: { type: 'string' }, about: { type: 'string' } },\n    ['text'],\n  ),\n  handler: async ({ text, about }, ctx) => {\n    // Plain-protocol fallback path. CoT runtime intercepts the\n    // envelope's `narrate` field before any handler runs.\n    if (typeof document !== 'undefined') {\n      // Best-effort subtitle routing. We don't import the Subtitle\n      // module directly (would force a dep on the orchestrator); the\n      // SDK's dddk handle dispatches subtitle via the lifecycle's\n      // `agent_text` event, which the orchestrator already wires.\n    }\n    if (about) {\n      const el = ctx.resolveTarget(about);\n      if (el) {\n        overlay.clearOverlays();\n        if (ctx.uiHints?.cursorTrail) {\n          try { await moveCursorTo(el); } catch { /* nicety */ }\n        }\n        overlay.border(el);\n      }\n    }\n    return { ok: true, data: text };\n  },\n};\n\n// ─── exports — bundled by purpose (v0.2.0 opt-in pivot) ─────────────\n//\n// Pre-v0.2 model: `builtinActions` (12 actions) was installed by default;\n// hosts trimmed via `excludeTools`. Empirically dddk-frontend disabled 6\n// of 12 — the \"default everything + remove\" pattern bloated the prompt\n// catalog for narrow use cases. v0.2 flips to opt-in:\n//\n//   - Default install = `coreActions` only (4 actions).\n//   - Hosts opt in to form / flow / extra bundles via `customActions`.\n//   - `builtinActions` kept as union for back-compat — passing it as\n//     `customActions` restores v0.1 behaviour.\n//\n// Rule of thumb when picking bundles:\n//   - Always-on agent that just points + navigates → `coreActions`\n//   - Form-filling agent (signup flows, checkout)  → `+ formActions`\n//   - Conversational agent (Q&A, pauses, choices) → `+ flowActions`\n\n/**\n * The five actions every webagent host needs. Installed by default.\n *  - `narrate`: speak to the user (CoT envelope native; plain-protocol fallback)\n *  - `navigate`: route changes\n *  - `click`: interactive elements\n *  - `border`: visual pointing (also auto-synthesized by narrate's `about`)\n *  - `scroll_to`: paginated content\n *\n * `border` is bundled with narrate intentionally — narrate-with-about\n * synthesizes a border call, so the primitive must exist in the\n * registry for that synthesis to resolve. Hosts who never want to\n * point at things can still `excludeTools: ['border']`.\n */\nexport const coreActions: ActionDefinition[] = [\n  narrateAction,\n  navigate,\n  click,\n  borderAction,\n  scrollTo,\n] as ActionDefinition[];\n\n/**\n * Form / input + richer pointer interactions. Opt in when the agent\n * needs to type, pick from selects, double-click, long-press, drag,\n * or hold keys. Off by default to keep the prompt slim on read-only\n * marketing / docs surfaces.\n *\n *  - `fill_input` / `select_option` / `clear_input`: text fields + selects\n *  - `press_key`: single keypress (Enter / Escape / Tab / Cmd+S chord)\n *  - `hold_key`: key down for N ms (hold-to-zoom, hold-Ctrl-to-multi-select)\n *  - `double_click`: open / expand / rename — anything bound to `dblclick`\n *  - `long_press`: context menus, drag handles, mobile long-press\n *  - `drag`: from element A to element B (sortable lists, kanban, sliders)\n */\nexport const formActions: ActionDefinition[] = [\n  fillInput,\n  selectOption,\n  clearInput,\n  pressKey,\n  holdKey,\n  doubleClick,\n  longPress,\n  drag,\n] as ActionDefinition[];\n\n/**\n * Control-flow actions — waiting, pausing, asking the user. Opt in\n * for conversational agents. Auto-pause-after-narrate is independent\n * (controlled by `disableAutoPauseAfterNarrate`).\n */\nexport const flowActions: ActionDefinition[] = [\n  wait,\n  pause,\n  askUser,\n  askUserChoice,\n] as ActionDefinition[];\n\n/**\n * Less-common visual / escalation actions. `highlight` is a paint\n * overlay (vs `border`'s frame) — was historically dropped from\n * default because the LLM couldn't reliably pick one. `track_intent`\n * is for hosts wiring custom analytics tunnels. `escalate_to_human`\n * is for support flows. `present_surface` is registered separately\n * via `allowPresent` + `setSurfaceMounter`.\n */\nexport const extraActions: ActionDefinition[] = [\n  highlightAction,\n  trackIntent,\n  escalateToHuman,\n] as ActionDefinition[];\n\n/**\n * Union of all bundles EXCEPT `present_surface` (which needs explicit\n * `allowPresent` + a mounter). Pass to `customActions` to restore\n * pre-v0.2 \"install everything\" behaviour.\n */\nexport const builtinActions: ActionDefinition[] = [\n  ...coreActions,\n  ...formActions,\n  ...flowActions,\n] as ActionDefinition[];\n\n// Opt-in: workflow actions are NOT auto-registered.\n// Host opts in with `new WebAgent({ ..., customActions: workflowActions })`\n// — keeps the default prompt catalog focused on the actions the host\n// actually uses.\nexport { workflowActions } from './actions-workflow';\nexport { validateForm, waitUntil } from './actions-workflow';\n\n// Exported so hosts that want both visual styles can opt in:\n//   new WebAgent({ ..., customActions: [highlightAction] })\nexport { highlightAction };\n","/**\n * workflow actions.\n *\n * The agent needs hooks for the common patterns that show up when it\n * operates real product UIs:\n *\n *   - 2.5  `validate_form`        — after fill_input, read back the\n *                                   browser's constraint validation or\n *                                   the page's own `aria-invalid` /\n *                                   `.error` markers to know if the\n *                                   submission will be accepted.\n *   - 2.7  `wait_until`           — poll a CSS selector (or its visible\n *                                   state) up to a timeout. Used for\n *                                   modal close / async result render /\n *                                   spinner disappearance.\n *   - 2.8  `detect_login_wall`    — after navigation, check whether the\n *                                   destination looks like a sign-in\n *                                   wall (URL pattern, form fields,\n *                                   visible OAuth buttons). Emits the\n *                                   `auth_required` failure reason so\n *                                   the agent surfaces a sign-in request\n *                                   instead of clicking on Google's\n *                                   button on the user's behalf.\n *\n * These are deliberately small — composable primitives the LLM picks\n * one-at-a-time, not a multi-step transaction macro. The \"multi-step\n * skill pattern\" (2.6) lives at the Skill SDK layer, not as a single\n * tool call.\n */\n\nimport type { ActionDefinition } from './types';\n\n// Tiny shared JSON-schema builder — same pattern as actions.ts.\nfunction objSchema<S extends Record<string, unknown>>(\n  properties: S,\n  required: Array<keyof S> = [],\n): { type: 'object'; properties: S; required?: string[]; additionalProperties: false } {\n  return {\n    type: 'object',\n    properties,\n    ...(required.length ? { required: required as string[] } : {}),\n    additionalProperties: false,\n  };\n}\n\n// ─── 2.5 · validate_form ────────────────────────────────────────────\n\ninterface ValidateFormParams {\n  selector: string;\n}\n\ninterface FieldValidation {\n  selector: string;\n  name: string | null;\n  valid: boolean;\n  message: string | null;\n}\n\ninterface ValidateFormResult {\n  valid: boolean;\n  fields: FieldValidation[];\n}\n\nexport const validateForm: ActionDefinition<ValidateFormParams> = {\n  name: 'validate_form',\n  description:\n    'Read back the validation state of every input inside a form. Returns each field\\'s validity, error message, and `aria-invalid` if the page sets it. Run this after fill_input to confirm the form will accept submission before clicking submit.',\n  parameters: objSchema(\n    {\n      selector: {\n        type: 'string',\n        description: 'CSS selector for the <form> (or any container holding the inputs).',\n      },\n    },\n    ['selector'],\n  ),\n  handler: async ({ selector }) => {\n    if (typeof document === 'undefined') {\n      return { ok: false, reason: 'unknown', message: 'no DOM available' };\n    }\n    const root = document.querySelector(selector);\n    if (!root) return { ok: false, reason: 'not_found', message: `selector not found: ${selector}` };\n\n    const fields: FieldValidation[] = [];\n    const inputs = root.querySelectorAll<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>(\n      'input, textarea, select',\n    );\n    for (const el of Array.from(inputs)) {\n      // Skip non-data inputs.\n      if (el instanceof HTMLInputElement && (el.type === 'submit' || el.type === 'button' || el.type === 'hidden')) {\n        continue;\n      }\n      const ariaInvalid = el.getAttribute('aria-invalid');\n      // ValidityState only exists on form-associated inputs.\n      const validity = (el as HTMLInputElement).validity;\n      const browserValid = validity ? validity.valid : true;\n      const ariaValid = ariaInvalid == null ? true : ariaInvalid === 'false';\n      const valid = browserValid && ariaValid;\n\n      // Hunt for an error message: prefer aria-describedby, fall back to\n      // a sibling .error / .invalid-feedback, then validationMessage.\n      let message: string | null = null;\n      const describedBy = el.getAttribute('aria-describedby');\n      if (describedBy) {\n        const desc = document.getElementById(describedBy);\n        if (desc) message = desc.textContent?.trim() || null;\n      }\n      if (!message) {\n        const sibling = el.parentElement?.querySelector('.error, .invalid-feedback, [data-error]');\n        if (sibling) message = sibling.textContent?.trim() || null;\n      }\n      if (!message && validity && !validity.valid) message = (el as HTMLInputElement).validationMessage;\n\n      fields.push({\n        selector: buildSelector(el),\n        name: el.getAttribute('name') ?? el.getAttribute('id') ?? null,\n        valid,\n        message,\n      });\n    }\n    const allValid = fields.every((f) => f.valid);\n    const result: ValidateFormResult = { valid: allValid, fields };\n    return { ok: true, data: result };\n  },\n};\n\nfunction buildSelector(el: Element): string {\n  if (el.id) return `#${el.id}`;\n  const name = el.getAttribute('name');\n  if (name) return `${el.tagName.toLowerCase()}[name=\"${name}\"]`;\n  return el.tagName.toLowerCase();\n}\n\n// ─── 2.7 · wait_until ───────────────────────────────────────────────\n\ninterface WaitUntilParams {\n  selector: string;\n  /** `present` (default) / `visible` / `absent` */\n  state?: 'present' | 'visible' | 'absent';\n  /** Poll cap in ms. Hard ceiling 30s — long-running waits should be\n   *  modelled as multi-turn (yield + come back) not single-action poll. */\n  timeout?: number;\n}\n\nexport const waitUntil: ActionDefinition<WaitUntilParams> = {\n  name: 'wait_until',\n  description:\n    'Poll for a CSS selector to reach a state. `state` is one of `present` (default — exists in DOM), `visible` (offsetParent != null), or `absent` (gone from DOM). Use this when the page does async work — modal close, spinner disappear, async result render. Capped at 30s; for longer waits, finish the turn and let the user re-trigger.',\n  parameters: objSchema(\n    {\n      selector: { type: 'string' },\n      state: { type: 'string', enum: ['present', 'visible', 'absent'], default: 'present' },\n      timeout: { type: 'number', maximum: 30_000, default: 10_000 },\n    },\n    ['selector'],\n  ),\n  handler: async ({ selector, state = 'present', timeout = 10_000 }, ctx) => {\n    if (typeof document === 'undefined') {\n      return { ok: false, reason: 'unknown', message: 'no DOM available' };\n    }\n    const cap = Math.min(timeout, 30_000);\n    const start = Date.now();\n    const check = (): boolean => {\n      const el = document.querySelector(selector) as HTMLElement | null;\n      if (state === 'absent') return el == null;\n      if (!el) return false;\n      if (state === 'visible') return el.offsetParent != null;\n      return true; // present\n    };\n    while (Date.now() - start < cap) {\n      if (ctx.signal.aborted) return { ok: false, reason: 'cancelled' };\n      if (check()) return { ok: true, data: { waitedMs: Date.now() - start } };\n      await new Promise((r) => setTimeout(r, 200));\n    }\n    return { ok: false, reason: 'timeout', message: `selector \"${selector}\" did not become ${state} in ${cap}ms` };\n  },\n};\n\n// `detect_login_wall` (2.8) was prototyped then removed — login flows\n// are not something the agent should second-guess heuristically. If a\n// host wants this behaviour they can register a custom action; the\n// generic builtin caused more confusion than it saved.\n\n/**\n * Opt-in workflow actions. NOT pushed into the default `builtinActions`\n * list — host registers explicitly so the agent's prompt catalog stays\n * focused on actions the host actually uses.\n *\n *   import { workflowActions } from '@perhapxin/dddk/agent';\n *   new WebAgent({ ..., customActions: workflowActions });\n *\n * Or cherry-pick:\n *\n *   import { validateForm, waitUntil } from '@perhapxin/dddk/agent';\n *   new WebAgent({ ..., customActions: [validateForm] });\n */\nexport const workflowActions: ActionDefinition[] = [\n  validateForm as ActionDefinition,\n  waitUntil as ActionDefinition,\n];\n","/**\n * Cross-tab session sync helpers.\n *\n * The agent uses a BroadcastChannel keyed on `${sessionStorageKey}.crosstab`\n * to notify peer tabs (same origin) when its session updates, plus a\n * `localStorage` mirror so a tab opening fresh after a navigation can pick up\n * the latest session.\n *\n * Cross-origin / cross-subdomain is NOT possible from the browser sandbox —\n * see docs/12-session-continuity.md.\n */\n\nimport type { AgentSession } from './types';\n\nexport interface CrossTabBindings {\n  /** Storage key for the BroadcastChannel + localStorage mirror. */\n  crossTabKey: string;\n  /** Latest known session ID (for echo suppression). */\n  getCurrentSessionId(): string | undefined;\n  /** True while a local agent loop is running — never overwrite mid-run. */\n  isLocalRunActive(): boolean;\n  /** Last `updatedAt` we've seen locally — used for monotonic ordering. */\n  getLocalUpdatedAt(): number | undefined;\n  /** Adopt a session received from another tab. */\n  adoptSession(session: AgentSession): void;\n}\n\n/**\n * Open a BroadcastChannel + seed from localStorage. Returns the channel so\n * callers can `.close()` it on destroy. Returns null when BroadcastChannel\n * isn't available (jsdom without polyfill, very old browsers).\n */\nexport function setupCrossTabSync(bindings: CrossTabBindings): BroadcastChannel | null {\n  if (typeof BroadcastChannel === 'undefined') return null;\n\n  let channel: BroadcastChannel;\n  try {\n    channel = new BroadcastChannel(bindings.crossTabKey);\n  } catch {\n    return null;\n  }\n\n  channel.onmessage = (e: MessageEvent<AgentSession>) => {\n    if (!e.data || e.data.id === bindings.getCurrentSessionId()) return;\n    const localUpdated = bindings.getLocalUpdatedAt();\n    // Adopt the newer session — never overwrite an in-flight local run.\n    if (!bindings.isLocalRunActive() && (localUpdated === undefined || e.data.updatedAt > localUpdated)) {\n      bindings.adoptSession(e.data);\n    }\n  };\n\n  // Also seed from localStorage in case this tab opens fresh.\n  if (typeof localStorage !== 'undefined') {\n    const raw = localStorage.getItem(bindings.crossTabKey);\n    if (raw) {\n      try {\n        const remote = JSON.parse(raw) as AgentSession;\n        const localUpdated = bindings.getLocalUpdatedAt();\n        if (remote && (localUpdated === undefined || remote.updatedAt > localUpdated)) {\n          bindings.adoptSession(remote);\n        }\n      } catch {\n        /* ignore corrupt entry */\n      }\n    }\n  }\n\n  return channel;\n}\n\n/** Broadcast the session to peer tabs and mirror it to localStorage. */\nexport function publishCrossTab(\n  session: AgentSession,\n  crossTabKey: string,\n  channel: BroadcastChannel | null,\n): void {\n  channel?.postMessage(session);\n  if (typeof localStorage !== 'undefined') {\n    try {\n      localStorage.setItem(crossTabKey, JSON.stringify(session));\n    } catch {\n      /* quota or disabled — best effort */\n    }\n  }\n}\n","/**\n * Default destructive-action pattern list.\n *\n * Any tool whose name matches one of these regexes is auto-gated on a\n * `confirm` event before its handler runs. Hosts can override via\n * `WebAgentConfig.destructivePatterns`; per-action\n * `requireConfirmation: false` opts a single action out of the pattern\n * match even when its name would match.\n *\n * The list captures the verbs that show up across CRUD apps, billing\n * surfaces, comms, and account lifecycle — actions whose effect a user\n * cannot trivially undo by clicking around.\n */\n\nexport const DEFAULT_DESTRUCTIVE_PATTERNS: RegExp[] = [\n  // Data destruction / mutation that's hard to reverse.\n  /^(delete|remove|destroy|drop|purge|erase|wipe|clear|reset)(_|$)/i,\n  // Outbound communication / publishing.\n  /^(send|email|sms|notify|post|publish|share|broadcast|tweet)(_|$)/i,\n  // Money movement.\n  /^(pay|charge|transfer|refund|withdraw|invoice|subscribe|cancel_subscription)(_|$)/i,\n  // Account / session lifecycle.\n  /^(logout|signout|sign_out|deactivate|disable|suspend|ban)(_|$)/i,\n  // Confirmation-shaped verbs commonly indicating an irreversible step.\n  /^(confirm_purchase|place_order|submit_order|finalize_)/i,\n];\n\nexport function isDestructiveByPattern(actionName: string, patterns: RegExp[]): boolean {\n  for (const p of patterns) if (p.test(actionName)) return true;\n  return false;\n}\n","/**\n * Structured CoT turn — per-turn schema that wraps the model's response\n * in a single `agent_turn` tool call with strict JSON schema.\n *\n * Schema property order matters for streaming: `actions` is always emitted\n * BEFORE `is_final` so the model fully commits to the work plan before\n * declaring the task complete.\n */\n\nimport type { ToolDefinition } from '../llm/types';\n\nexport interface CotToolRef {\n  name: string;\n  description: string;\n  parameters: Record<string, unknown>;\n}\n\n/** One step inside a CoT turn — narration or a tool call. Finish is now a\n *  turn-level `is_final` boolean (see TurnResponse). The legacy\n *  `{ task_finish: true }` action is parsed for back-compat and folded\n *  into `is_final` on the parsed TurnResponse. */\nexport type TurnAction =\n  | { narrate: string; about?: string }\n  | { tool: string; args?: Record<string, unknown> };\n\n/** Per-turn planning fields — present only in planned mode. browser-use's\n *  minimal validated set: previous-eval + next-goal. The top-level `memory`\n *  field on TurnResponse carries the progress recap. */\nexport interface TurnPlanning {\n  evaluation_previous_goal: string;\n  next_goal: string;\n}\n\n/** Mutations applied to `session.plan.todos` after this turn's actions\n *  run. NO insert — the master plan is locked at run start; mid-loop the\n *  model can only mark items done (`remove`) or rewrite stale ones\n *  (`replace`). */\nexport interface TodoAdjust {\n  remove?: string[];\n  replace?: Array<{ id: string; new_description: string; new_intent?: string }>;\n}\n\n/** Full parsed turn response. */\nexport interface TurnResponse {\n  memory: string;\n  todos_remaining?: string[];\n  turn_planning?: TurnPlanning;\n  todo_adjust?: TodoAdjust;\n  actions: TurnAction[];\n  /** True iff the user's original task has been fully satisfied by this\n   *  turn's actions[]. Set ONLY after actions[] is complete. Ending a turn\n   *  with `is_final: true` terminates the run; `false` (or omitted) keeps\n   *  the loop going. */\n  is_final?: boolean;\n}\n\nexport const AGENT_TURN_TOOL = 'agent_turn';\n\nexport function renderToolReference(availableTools: readonly CotToolRef[]): string {\n  return availableTools.map((t) => {\n    const params = JSON.stringify(t.parameters);\n    return `### \\`${t.name}\\`\\n${t.description}\\nargs schema (JSON Schema): ${params}`;\n  }).join('\\n\\n');\n}\n\nexport interface AgentTurnSchemaOptions {\n  planned?: boolean;\n}\n\nexport function buildAgentTurnTool(\n  availableTools: readonly CotToolRef[],\n  options: AgentTurnSchemaOptions = {},\n): ToolDefinition {\n  const toolNames = availableTools.map((t) => t.name);\n  const planned = options.planned === true;\n  const properties: Record<string, unknown> = {};\n\n  properties.memory = {\n    type: 'string',\n    description: planned\n      ? 'Private 1-2 sentence recap of what the previous turn tried and whether it worked. Read action_results from the previous tool message before writing. When previous turn ran ask_user / ask_user_choice / pause, recap MUST name the user\\'s answer (e.g. \"user picked Pro from {Hobby, Pro, Enterprise}\"). A tool failure means this turn retries with a corrected arg, not moves on.'\n      : 'Private 1-2 sentence progress recap. Describe forward motion only. Items already covered in previous turns are DONE — never go back to re-explain. When previous turn ran ask_user / ask_user_choice / pause, recap MUST name the user\\'s answer; do NOT re-ask. Do not invent new todos because the DOM dump shows more than the user asked about. When a tool fails, retry with a corrected arg, not by restarting from the user.',\n  };\n\n  if (planned) {\n    properties.turn_planning = {\n      type: 'object',\n      additionalProperties: false,\n      required: ['evaluation_previous_goal', 'next_goal'],\n      properties: {\n        evaluation_previous_goal: {\n          type: 'string',\n          description: 'One short clause: what the previous turn tried and whether it succeeded or failed. When the previous turn ran ask_user / ask_user_choice / pause, restate the user\\'s answer here in your own words BEFORE next_goal proposes what to do with it. For turn 1, say so explicitly.',\n        },\n        next_goal: {\n          type: 'string',\n          description: 'Anchor to a specific master-plan todo id and describe what this turn\\'s actions[] will accomplish.',\n        },\n      },\n      description: 'Per-turn planning fields.',\n    };\n    properties.todo_adjust = {\n      type: 'object',\n      additionalProperties: false,\n      properties: {\n        remove: {\n          type: 'array',\n          items: { type: 'string' },\n          description: 'Master-plan todo ids the PREVIOUS turn completed.',\n        },\n        replace: {\n          type: 'array',\n          items: {\n            type: 'object',\n            additionalProperties: false,\n            required: ['id', 'new_description'],\n            properties: {\n              id: { type: 'string' },\n              new_description: { type: 'string' },\n              new_intent: { type: 'string' },\n            },\n          },\n          description: 'Master todos whose description / intent no longer matches reality — rewrite in place (id preserved). No insert.',\n        },\n      },\n      description: 'Mutations to the master plan. Both fields optional.',\n    };\n  } else {\n    properties.todos_remaining = {\n      type: 'array',\n      items: { type: 'string' },\n      description: 'Concrete items still owed to the user\\'s original request. Each turn: remove completed items. No verification items, no \"ask the user if they want more\" items. Empty array ends the run.',\n    };\n  }\n\n  properties.actions = {\n    type: 'array',\n    description: planned\n      ? 'This turn\\'s steps, in order. MUST be non-empty when the run is ongoing. Narrate / tool entries do the work; the loop continues until is_final is true.'\n      : 'This turn\\'s steps, in order. Empty / omitted ends the loop (legacy path).',\n    items: {\n      type: 'object',\n      additionalProperties: false,\n      properties: {\n        narrate: {\n          type: 'string',\n          description: 'A short declarative statement streamed into the subtitle bar — the content the user should read. Not a preview of your next move. Not a meta status. Not a question (use the `ask_user_choice` tool). For multi-item content split items with `\\\\n` newlines.',\n        },\n        about: {\n          type: 'string',\n          description: 'Selector ([id] from DOM dump, or CSS) of the element this narrate describes. When set, the runtime auto-borders that element before streaming. Required whenever the narrate refers to anything visible on the page.',\n        },\n        tool: {\n          type: 'string',\n          enum: toolNames,\n          description: 'Built-in tool name to dispatch. See the tool reference in the system prompt for each tool\\'s required args.',\n        },\n        args: {\n          type: 'object',\n          additionalProperties: true,\n          description: 'Arguments for the tool. Required keys depend on the tool.',\n        },\n      },\n    },\n  };\n\n  properties.is_final = {\n    type: 'boolean',\n    description: 'Write this field LAST, AFTER actions[] is fully written. Set true ONLY when the original user request is now fully satisfied by the actions just emitted, and there is nothing more to do. False (or omitted) means the loop continues. Do not set true in the same turn as a tool whose result the next turn must observe (navigate / click / fill_input / ask_user_choice).',\n  };\n\n  // Schema requires actions and is_final in planned mode so the run has a\n  // clear terminator. In legacy mode actions can be omitted to end the\n  // loop (no is_final required).\n  const required = planned\n    ? ['memory', 'turn_planning', 'actions', 'is_final']\n    : ['memory', 'todos_remaining'];\n\n  return {\n    name: AGENT_TURN_TOOL,\n    description: `Your full response for this turn. Call exactly once; don't call any other tool directly. Property order: write memory, turn_planning, todo_adjust, actions FIRST, then is_final LAST.`,\n    parameters: {\n      type: 'object',\n      additionalProperties: false,\n      required,\n      properties,\n    },\n  };\n}\n\n/** Parse the JSON args from an `agent_turn` tool call. Tolerant of partial\n *  / malformed input — returns `null` if unparseable. Back-compat: the\n *  legacy `{ task_finish: true }` action and `will_finish_this_turn`\n *  planning flag both fold into the parsed `is_final`. */\nexport function parseTurnResponse(rawArgs: string | Record<string, unknown>): TurnResponse | null {\n  let obj: unknown;\n  if (typeof rawArgs === 'string') {\n    try {\n      obj = JSON.parse(rawArgs);\n    } catch {\n      return null;\n    }\n  } else {\n    obj = rawArgs;\n  }\n  if (!obj || typeof obj !== 'object') return null;\n  const r = obj as Partial<TurnResponse> & Record<string, unknown>;\n\n  if (typeof r.memory !== 'string') return null;\n\n  const todos_remaining: string[] | undefined = Array.isArray(r.todos_remaining)\n    ? r.todos_remaining.filter((t): t is string => typeof t === 'string')\n    : undefined;\n\n  let legacyFinishFromPlanning = false;\n  const turn_planning: TurnPlanning | undefined = (() => {\n    const tp = r.turn_planning;\n    if (!tp || typeof tp !== 'object') return undefined;\n    const o = tp as unknown as Record<string, unknown>;\n    if (o.will_finish_this_turn === true) legacyFinishFromPlanning = true;\n    const epg = typeof o.evaluation_previous_goal === 'string'\n      ? o.evaluation_previous_goal\n      : typeof o.last_turn_outcome === 'string' ? o.last_turn_outcome : null;\n    const ng = typeof o.next_goal === 'string'\n      ? o.next_goal\n      : typeof o.this_turn_does === 'string' ? o.this_turn_does : null;\n    if (epg === null || ng === null) return undefined;\n    return { evaluation_previous_goal: epg, next_goal: ng };\n  })();\n\n  const todo_adjust: TodoAdjust | undefined = (() => {\n    const ta = r.todo_adjust;\n    if (!ta || typeof ta !== 'object') return undefined;\n    const o = ta as Record<string, unknown>;\n    const remove = Array.isArray(o.remove)\n      ? o.remove.filter((s): s is string => typeof s === 'string')\n      : undefined;\n    const replace = Array.isArray(o.replace)\n      ? (o.replace as unknown[]).flatMap((entry) => {\n          if (!entry || typeof entry !== 'object') return [];\n          const e = entry as Record<string, unknown>;\n          if (typeof e.id !== 'string' || typeof e.new_description !== 'string') return [];\n          const out: { id: string; new_description: string; new_intent?: string } = {\n            id: e.id,\n            new_description: e.new_description,\n          };\n          if (typeof e.new_intent === 'string') out.new_intent = e.new_intent;\n          return [out];\n        })\n      : undefined;\n    if (!remove?.length && !replace?.length) return undefined;\n    return { remove, replace };\n  })();\n\n  const actions: TurnAction[] = [];\n  let legacyFinishFromAction = false;\n  if (Array.isArray(r.actions)) {\n    for (const a of r.actions) {\n      if (!a || typeof a !== 'object') continue;\n      const obj = a as Record<string, unknown>;\n      if (typeof obj.narrate === 'string') {\n        const about = typeof obj.about === 'string' && obj.about.trim().length > 0 ? obj.about.trim() : undefined;\n        actions.push(about ? { narrate: obj.narrate, about } : { narrate: obj.narrate });\n      } else if (typeof obj.tool === 'string') {\n        const args = (obj.args && typeof obj.args === 'object') ? obj.args as Record<string, unknown> : {};\n        const tool = obj.tool.replace(/^functions\\./, '');\n        actions.push({ tool, args });\n      } else if (obj.task_finish === true) {\n        legacyFinishFromAction = true;\n      }\n    }\n  }\n\n  const isFinal = r.is_final === true || legacyFinishFromAction || legacyFinishFromPlanning;\n\n  const out: TurnResponse = { memory: r.memory, actions };\n  if (todos_remaining !== undefined) out.todos_remaining = todos_remaining;\n  if (turn_planning) out.turn_planning = turn_planning;\n  if (todo_adjust) out.todo_adjust = todo_adjust;\n  if (isFinal) out.is_final = true;\n  return out;\n}\n\nexport function isNarrateAction(a: TurnAction): a is { narrate: string; about?: string } {\n  return 'narrate' in a;\n}\nexport function isToolAction(a: TurnAction): a is { tool: string; args?: Record<string, unknown> } {\n  return 'tool' in a;\n}\n","/**\n * Action execution — runs an action handler with the right side effects.\n *\n * Two built-ins handled here intercept the registry to yield user\n * interaction back to the host:\n *   - `ask_user`        — free-text question\n *   - `ask_user_choice` — picker\n *\n * `navigate` is also special-cased: the action handler itself only\n * returns metadata (the path); the agent runtime emits a `navigated`\n * event and the host's router moves the page. This file is the right\n * place to wire that bridge.\n */\n\nimport type {\n  ActionDefinition,\n  ActionResult,\n  ActionContext,\n  AgentSession,\n} from './types';\n\nexport interface AskUserPayload {\n  question: string;\n  resolve: (answer: string) => void;\n}\n\nexport interface AskUserChoicePayload {\n  question: string;\n  options: string[];\n  allowFreeText: boolean;\n  resolve: (answer: string) => void;\n}\n\n/**\n * `pause` is its own envelope (NOT an ask_user) so hosts can render it\n * differently — typically by attaching a \"press space to continue\"\n * hint to the running streaming subtitle bar, rather than replacing\n * the bar with a confirmation dialog. The text the agent just streamed\n * must stay visible while the user reads.\n */\nexport interface PausePayload {\n  hint: string;\n  resolve: (answer: string) => void;\n}\n\n/**\n * Surface presentation — agent emits a PieceSurface (image+text card,\n * option group, etc.) and waits for the user to pick or cancel. The\n * host renders into a PlacementSlot and resolves with the chosen\n * option's value (or null on cancel).\n *\n * Only fires when the host has opted in via `WebAgentConfig.allowPresent`\n * AND has wired the surface mounter via `setSurfaceMounter`.\n */\nexport interface PresentSurfacePayload {\n  /** Piece tree the host renders. The agent built it; the host trusts\n   *  its catalog won't include unsafe pieces (Slot's `render` fn etc.). */\n  surface: unknown;\n  /** Where on screen to render. Subset of PlacementSlot — agent isn't\n   *  given access to fab / banner / toast since those have semantics\n   *  the agent shouldn't be allowed to choose. */\n  placement: 'subtitle' | 'modal' | 'dock' | 'inline';\n  /** Resolves with the chosen option's value, or null on cancel. */\n  resolve: (pick: { value: string | null; cancelled: boolean }) => void;\n}\n\nexport interface ExecuteActionBindings {\n  actions: Map<string, ActionDefinition>;\n  /** Register a host-interaction resolver and return its id. */\n  registerPendingResolver(resolver: (raw: string) => void): string;\n  /** Surface a free-text question to the host. */\n  emitAskUser(payload: AskUserPayload): void;\n  /** Surface a multi-choice picker to the host. */\n  emitAskUserChoice(payload: AskUserChoicePayload): void;\n  /** Surface a narrator-controlled mid-stream pause. The host typically\n   *  attaches a \"press space to continue\" hint INSIDE the streaming\n   *  subtitle bar rather than spawning a separate prompt — so the\n   *  text the agent just streamed stays visible while the user reads. */\n  emitPause(payload: PausePayload): void;\n  /** Surface a structured PieceSurface to the host. Returns the user's\n   *  pick (or cancellation). `undefined` here means the host hasn't\n   *  wired the mounter — `present_surface` then fails fast with a\n   *  clear `reason: 'unknown'` so the model knows to fall back to\n   *  manual narration. */\n  emitPresentSurface?: (payload: PresentSurfacePayload) => void;\n  /** Stable-ID → element map from the latest readDOM. Action handlers\n   *  resolve `[id]` style selectors via this map so the LLM doesn't have\n   *  to invent CSS selectors. IDs are short alphanumeric hashes (e.g.\n   *  `e4f3a`) — they stay stable across turns for the same element. */\n  indexMap: Map<string, Element>;\n  session: AgentSession;\n  /** Subtitle-bar fallback shown when the `pause` tool is called with\n   *  no `note`. Hosts pass their own string here for a localised UX;\n   *  the LLM can still override per-call via the tool's `note` arg. */\n  defaultPauseNote?: string;\n  /** UI hints forwarded into every ActionContext (see types.ts).\n   *  Wired by the WebAgent runtime from WebAgentConfig. */\n  uiHints?: {\n    cursorTrail?: boolean;\n    preferClickLinkOverNavigate?: boolean;\n  };\n}\n\nexport async function executeAction(\n  bindings: ExecuteActionBindings,\n  name: string,\n  params: Record<string, unknown>,\n  signal: AbortSignal,\n): Promise<ActionResult> {\n  const action = bindings.actions.get(name);\n  if (!action) {\n    return { ok: false, reason: 'unknown', message: `Unknown action: ${name}` };\n  }\n\n  const ctx: ActionContext = {\n    session: bindings.session,\n    signal,\n    uiHints: bindings.uiHints,\n    resolveTarget: (target: string | number): Element | null => {\n      if (typeof target === 'number') {\n        // Legacy numeric path — keep working for old sessions persisted\n        // before the hash-ID change; new sessions never call with number.\n        return bindings.indexMap.get(String(target)) ?? null;\n      }\n      if (typeof target === 'string') {\n        const trimmed = target.trim();\n        // Stable-ID path — `[e4f3a]`, `e4f3a`, or with a viewport marker\n        // (`↓[e4f3a]`). Also accepts legacy numeric refs (`\"5\"`) for\n        // session-replay compatibility, though the new DOM dump never\n        // emits those.\n        const m = /^[↑↓]?\\s*\\[?([A-Za-z0-9_-]+)\\]?$/.exec(trimmed);\n        if (m) {\n          const id = m[1]!;\n          const el = bindings.indexMap.get(id);\n          if (el) return el;\n          // Fall through — id didn't match, try as CSS selector.\n        }\n        if (typeof document !== 'undefined') {\n          try {\n            return document.querySelector(trimmed);\n          } catch {\n            return null;\n          }\n        }\n      }\n      return null;\n    },\n  };\n\n  if (name === 'ask_user') {\n    const question = String(params.question ?? '');\n    const answer = await new Promise<string>((resolve) => {\n      bindings.registerPendingResolver(resolve);\n      bindings.emitAskUser({ question, resolve });\n    });\n    return { ok: true, data: { question, answer } };\n  }\n\n  if (name === 'pause') {\n    // Narrator's mid-narrative beat. Own envelope (not ask_user) so the\n    // host can render it as a \"space to continue\" hint on the streaming\n    // bar instead of replacing the bar with a prompt.\n    const llmNote = typeof params.note === 'string' && params.note ? params.note : null;\n    const hint = llmNote ?? bindings.defaultPauseNote ?? SDK_DEFAULT_PAUSE_NOTE;\n    const answer = await new Promise<string>((resolve) => {\n      bindings.registerPendingResolver(resolve);\n      bindings.emitPause({ hint, resolve });\n    });\n    return { ok: true, data: { hint, answer } };\n  }\n\n  if (name === 'ask_user_choice') {\n    const rawOptions = Array.isArray(params.options) ? params.options : [];\n    const options = rawOptions.map((o) => String(o));\n    const question = String(params.question ?? '');\n    const allowFreeText = params.allowFreeText !== false;\n    const answer = await new Promise<string>((resolve) => {\n      bindings.registerPendingResolver(resolve);\n      bindings.emitAskUserChoice({ question, options, allowFreeText, resolve });\n    });\n    const source: 'option' | 'free_text' | 'cancelled' =\n      answer === '' ? 'cancelled'\n        : options.includes(answer) ? 'option'\n        : 'free_text';\n    return { ok: true, data: { question, options, answer, source } };\n  }\n\n  if (name === 'present_surface') {\n    // Intercepted here so the action runtime can route a PieceSurface to\n    // the host's mounter and await the user's pick. The host wires the\n    // mounter via `WebAgent.setSurfaceMounter`; without that wire, we\n    // fail fast so the model falls back to manual narration / ask_user.\n    if (!bindings.emitPresentSurface) {\n      return {\n        ok: false,\n        reason: 'unknown',\n        message: 'present_surface requires the host to wire a surface mounter (WebAgent.setSurfaceMounter). Falling back: narrate the options manually or use ask_user_choice.',\n      };\n    }\n    const surface = params.surface;\n    if (!surface || typeof surface !== 'object') {\n      return { ok: false, reason: 'unknown', message: 'present_surface requires a `surface` object (a PieceSurface tree).' };\n    }\n    const placement = (typeof params.placement === 'string'\n      ? params.placement\n      : 'subtitle') as 'subtitle' | 'modal' | 'dock' | 'inline';\n    const surfaceObj = surface as Record<string, unknown>;\n    const surfaceId = typeof surfaceObj.id === 'string' ? surfaceObj.id\n      : typeof surfaceObj.kind === 'string' ? surfaceObj.kind\n      : 'surface';\n    const result = await new Promise<{ value: string | null; cancelled: boolean }>((resolve) => {\n      bindings.registerPendingResolver((raw) => {\n        try { resolve(JSON.parse(raw)); } catch { resolve({ value: null, cancelled: true }); }\n      });\n      bindings.emitPresentSurface!({\n        surface,\n        placement,\n        resolve: (pick) => resolve(pick),\n      });\n    });\n    return {\n      ok: true,\n      data: {\n        surface_id: surfaceId,\n        placement,\n        answer: result.value,\n        cancelled: result.cancelled,\n      },\n    };\n  }\n\n  try {\n    return await action.handler(params, ctx);\n  } catch (err) {\n    return { ok: false, reason: 'unknown', message: (err as Error).message };\n  }\n}\n\n/** SDK-default fallback used when neither the LLM nor the host provided\n *  pause-bar copy. English-only by design — hosts override via\n *  `WebAgentConfig.defaultPauseNote` for a localised UX. */\nconst SDK_DEFAULT_PAUSE_NOTE = 'Press space to continue';\n","/**\n * Module-level pure helpers shared across the WebAgent runtime.\n * No reference to the WebAgent instance — anything that needs `this`\n * lives in loops.ts / messages.ts.\n */\n\nimport type { LLMMessage } from '../../llm/types';\nimport type { AgentEvent, AgentTurn } from '../types';\nimport { sdkString } from '../../../utils/sdk-i18n';\n\n/** Coarse chars-per-token approximation across mixed CJK + English.\n *  Used only to decide which turn to drop in the budget walk. */\nexport const CHARS_PER_TOKEN = 3.5;\n\nexport function sleep(ms: number): Promise<void> {\n  return new Promise((r) => setTimeout(r, ms));\n}\n\nexport async function* emptyStream(): AsyncIterable<AgentEvent> {\n  return;\n}\n\nexport function extractTargetSelector(params: Record<string, unknown>): string | undefined {\n  for (const key of ['selector', 'target', 'element']) {\n    const v = params[key];\n    if (typeof v === 'string' && v.length > 0) return v;\n  }\n  return undefined;\n}\n\nexport function composeSignals(a: AbortSignal, b: AbortSignal): AbortSignal {\n  const ctrl = new AbortController();\n  const onA = (): void => ctrl.abort(a.reason);\n  const onB = (): void => ctrl.abort(b.reason);\n  if (a.aborted) ctrl.abort(a.reason);\n  else a.addEventListener('abort', onA, { once: true });\n  if (b.aborted) ctrl.abort(b.reason);\n  else b.addEventListener('abort', onB, { once: true });\n  return ctrl.signal;\n}\n\n/** Scan the message array for any image content part — used to route to\n *  the `vision` provider. */\nexport function messageContentHasImage(messages: LLMMessage[]): boolean {\n  for (const m of messages) {\n    if (typeof m.content === 'string') continue;\n    for (const part of m.content) {\n      if (part.type === 'image') return true;\n    }\n  }\n  return false;\n}\n\n/** Cost estimate for one session turn, used by the token-budget\n *  truncation in buildMessages. Image content parts get a flat\n *  ~3500 char (≈1000 token) charge as a safe upper bound. */\nexport function estimateTurnChars(t: AgentTurn): number {\n  if (t.kind === 'user') {\n    let n = t.text.length;\n    if (t.selection?.text) n += t.selection.text.length;\n    if (t.selection?.elements) n += t.selection.elements.join(' ').length;\n    if (t.selection?.images) n += t.selection.images.length * 3500;\n    return n + 50;\n  }\n  if (t.kind === 'agent_step') {\n    return (t.preText?.length ?? 0)\n      + JSON.stringify(t.toolCall.arguments).length\n      + JSON.stringify(t.result).length\n      + 200;\n  }\n  if (t.kind === 'agent_final') return t.text.length + 20;\n  return 0;\n}\n\n/** `true` when the user currently has focus on an editable surface inside\n *  the open command palette. CoT auto-pause skips the Space gate here\n *  because the space-gesture handler treats Space inside palette inputs\n *  as literal typing — the pause watcher would never resolve. Scope is\n *  palette-only; page-level form fields still gate normally. */\nexport function isUserEditingInPalette(): boolean {\n  if (typeof document === 'undefined') return false;\n  const el = document.activeElement as (HTMLElement & { isContentEditable?: boolean }) | null;\n  if (!el || el === document.body) return false;\n  const tag = el.tagName;\n  const isEditable = tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || !!el.isContentEditable;\n  if (!isEditable) return false;\n  return !!el.closest('[data-dddk-ui=\"palette\"]');\n}\n\n/**\n * Wait for an SPA navigation to \"settle\" — both the URL has changed AND\n * the DOM has stopped mutating for a short idle window. Required because\n * `readDOM` on the next turn often reads the OLD page or a half-rendered\n * new page (just the route shell) — surfaces as \"I only see the title,\n * no content\".\n */\nexport async function awaitNavSettle(maxMs: number): Promise<void> {\n  if (typeof window === 'undefined') return;\n  if (typeof document === 'undefined' || typeof MutationObserver === 'undefined') {\n    await new Promise<void>((r) => setTimeout(r, Math.min(maxMs, 1200)));\n    return;\n  }\n  const idleMs = 250;\n  await new Promise<void>((resolve) => {\n    let settled = false;\n    let idleTimer: ReturnType<typeof setTimeout> | null = null;\n    const finish = (): void => {\n      if (settled) return;\n      settled = true;\n      observer.disconnect();\n      if (idleTimer !== null) clearTimeout(idleTimer);\n      clearTimeout(hardCap);\n      resolve();\n    };\n    const resetIdle = (): void => {\n      if (idleTimer !== null) clearTimeout(idleTimer);\n      idleTimer = setTimeout(finish, idleMs);\n    };\n    const observer = new MutationObserver(resetIdle);\n    observer.observe(document.body, { childList: true, subtree: true, characterData: true });\n    const hardCap = setTimeout(finish, maxMs);\n    resetIdle();\n  });\n  await new Promise<void>((r) => {\n    if (typeof requestAnimationFrame === 'undefined') return r();\n    requestAnimationFrame(() => r());\n  });\n}\n\n/**\n * SDK-default confirmation copy for built-in actions. Bundled in\n * en + zh-TW; other locales fall back to en. Hosts override at the\n * config level via `buildConfirmMessage` or per-action via\n * `ActionDefinition.confirmationMessage`.\n */\nexport function narrateAction(\n  actionName: string,\n  params: Record<string, unknown>,\n  locale: string,\n): string {\n  const str = (k: string): string => (typeof params[k] === 'string' ? (params[k] as string) : '');\n  const trim = (s: string, n = 40): string => (s.length > n ? s.slice(0, n - 1) + '…' : s);\n  const path = trim(str('path'), 50);\n  const target = trim(str('selector') || str('target') || str('element'), 50);\n  const suffix = ` ${sdkString(locale, 'agent.confirm.suffix')}`;\n  switch (actionName) {\n    case 'navigate':\n      return (path\n        ? sdkString(locale, 'agent.confirm.navigate.with_path', { path })\n        : sdkString(locale, 'agent.confirm.navigate.no_path')) + suffix;\n    case 'click':\n      return (target\n        ? sdkString(locale, 'agent.confirm.click.with_target', { target })\n        : sdkString(locale, 'agent.confirm.click.no_target')) + suffix;\n    case 'fill_input':\n      return (target\n        ? sdkString(locale, 'agent.confirm.fill_input.with_target', { target })\n        : sdkString(locale, 'agent.confirm.fill_input.no_target')) + suffix;\n    case 'delete':\n      return (target\n        ? sdkString(locale, 'agent.confirm.delete.with_target', { target })\n        : sdkString(locale, 'agent.confirm.delete.no_target')) + suffix;\n    default:\n      return (target\n        ? sdkString(locale, 'agent.confirm.generic.with_target', { action: actionName, target })\n        : sdkString(locale, 'agent.confirm.generic.no_target', { action: actionName })) + suffix;\n  }\n}\n","/**\n * `window.__dddkDebug` writes — single source of truth so test environments\n * (jsdom / SSR) can stub it once and there's no scattered `typeof window`\n * gates throughout loops.ts / messages.ts.\n */\n\nimport type { LLMMessage } from '../../llm/types';\n\ninterface DddkDebugWindow {\n  __dddkDebug?: {\n    lastParseFailure?: unknown;\n    lastParseFailureAt?: string;\n    turnLog?: unknown[];\n    lastTurnResponse?: unknown;\n    lastTurnAt?: string;\n    lastLlmMessages?: unknown;\n    lastLlmAt?: string;\n  };\n}\n\nfunction getStore(): DddkDebugWindow['__dddkDebug'] | undefined {\n  if (typeof window === 'undefined') return undefined;\n  const w = window as unknown as DddkDebugWindow;\n  w.__dddkDebug = w.__dddkDebug ?? {};\n  return w.__dddkDebug;\n}\n\nexport function recordParseFail(rawArguments: unknown): void {\n  const store = getStore();\n  if (!store) return;\n  store.lastParseFailure = rawArguments;\n  store.lastParseFailureAt = new Date().toISOString();\n}\n\nexport function recordTurn(summary: Record<string, unknown>, turn: unknown): void {\n  const store = getStore();\n  if (!store) return;\n  store.turnLog = store.turnLog ?? [];\n  store.turnLog.push(summary);\n  // Cap log at 50 entries so long sessions don't bloat memory.\n  if (store.turnLog.length > 50) {\n    store.turnLog = store.turnLog.slice(-50);\n  }\n  store.lastTurnResponse = turn;\n  store.lastTurnAt = new Date().toISOString();\n}\n\nexport function recordMessages(messages: LLMMessage[]): void {\n  const store = getStore();\n  if (!store) return;\n  store.lastLlmMessages = messages;\n  store.lastLlmAt = new Date().toISOString();\n}\n","/**\n * LLMRouter — pick a provider per role.\n *\n * 4 roles:\n *   - `webagent` — main agent loop (text-only)\n *   - `vision`   — webagent with images / screenshot context. Falls back to webagent.\n *   - `utility`  — short single-shot calls (inline AI / voice cleanup / etc). Falls back to webagent.\n *   - `plan`     — pre-loop planner. Falls back to webagent.\n *\n * Legacy field names (`webagentWithSelection`, `inline`, `voiceCleanup`)\n * are still accepted as fallback sources so existing host configs keep\n * working; prefer the new names for new code.\n */\n\nimport type { LLMProvider } from './types';\n\nexport type LLMRole =\n  | 'webagent'\n  | 'vision'\n  | 'utility'\n  | 'plan'\n  /** v0.2.0. Conversational + tool-calling agent\n   *  (TaskAgent). Defaults to `webagent` when not explicitly set on\n   *  the router. */\n  | 'task'\n  /** @deprecated — alias for `vision`. */\n  | 'webagentWithSelection'\n  /** @deprecated — alias for `utility`. */\n  | 'inline'\n  /** @deprecated — alias for `utility`. */\n  | 'voiceCleanup';\n\nexport interface LLMRouter {\n  /** Required. Default LLM for the webagent loop. All other roles fall back here. */\n  webagent: LLMProvider;\n  /** Used when the agent has images / screenshots to reason about. */\n  vision?: LLMProvider;\n  /** Short single-shot calls — inline AI, voice cleanup, immersive translate. */\n  utility?: LLMProvider;\n  /** Pre-loop planner. */\n  plan?: LLMProvider;\n  /** v0.2.0. TaskAgent — conversational + tool calling. */\n  task?: LLMProvider;\n  /** @deprecated — use `vision`. */\n  webagentWithSelection?: LLMProvider;\n  /** @deprecated — use `utility`. */\n  inline?: LLMProvider;\n  /** @deprecated — use `utility`. */\n  voiceCleanup?: LLMProvider;\n}\n\nexport type LLMSource = LLMProvider | LLMRouter;\n\nexport function isLLMRouter(v: LLMSource): v is LLMRouter {\n  if (!v || typeof v !== 'object') return false;\n  if (!('webagent' in v)) return false;\n  const inner = (v as LLMRouter).webagent;\n  return !!inner && typeof inner.complete === 'function';\n}\n\nexport function resolveLLM(source: LLMSource, role: LLMRole): LLMProvider {\n  if (!isLLMRouter(source)) return source;\n  switch (role) {\n    case 'webagent':\n      return source.webagent;\n    case 'vision':\n    case 'webagentWithSelection':\n      return source.vision ?? source.webagentWithSelection ?? source.webagent;\n    case 'utility':\n    case 'inline':\n    case 'voiceCleanup':\n      return source.utility ?? source.inline ?? source.voiceCleanup ?? source.webagent;\n    case 'plan':\n      return source.plan ?? source.webagent;\n    case 'task':\n      // TaskAgent prefers an explicit `task` provider, else the\n      // utility tier (short single-shot LLM is similar billing\n      // shape), else falls back to the main webagent model.\n      return source.task ?? source.utility ?? source.inline ?? source.webagent;\n  }\n}\n","/**\n * Message assembly + LLM streaming.\n *\n * `buildMessages` is the pure function that turns the live session into\n * `LLMMessage[]` — system prompt + capped history walk + env block + DOM\n * dump + optional screenshots.\n *\n * `callLlmStream` wraps the provider's streamComplete (or falls back to\n * complete()) into a unified iterable yielding text-delta / tool-call\n * events, applies the per-call timeout, and emits an `LlmCallInfo` to\n * the orchestrator's listener for analytics.\n */\n\nimport type { WebAgent } from '../webagent';\nimport type {\n  CompleteResult,\n  LLMMessage,\n  ToolCall,\n} from '../../llm/types';\nimport type { StreamingProvider, StreamChunk } from '../../llm/stream';\nimport type { AgentTurn } from '../types';\nimport type { ScreenshotConfig } from '../screenshot';\nimport { resolveLLM } from '../../llm/router';\nimport { lastUserTurn } from '../session';\nimport { PROMPT_IDS, promptRegistry } from '../../../prompts/registry';\nimport { registerBuiltinPrompts } from '../../../prompts/defaults';\nregisterBuiltinPrompts();\nimport {\n  renderSitemap,\n  renderSelectionBlock,\n  renderPageStateBlock,\n  renderUserReminder,\n} from '../prompt';\nimport { readDOM } from '../dom-reader';\nimport { captureScreenshots } from '../screenshot';\nimport { AGENT_TURN_TOOL, renderToolReference } from '../cot';\nimport {\n  CHARS_PER_TOKEN,\n  composeSignals,\n  estimateTurnChars,\n  messageContentHasImage,\n} from './helpers';\nimport { recordMessages } from './debug';\n\nexport async function buildMessages(agent: WebAgent): Promise<LLMMessage[]> {\n  const session = agent.sessionRef;\n  if (!session) return [];\n\n  const domResult = readDOM({\n    filter: agent.configRef.domFilter,\n    maxLength: agent.configRef.domMaxLength,\n  });\n  // Consult the registered DOM provider for the prompt\n  // text portion. The runtime KEEPS using readDOM for the indexMap\n  // (selector resolution at action-dispatch needs that map); only\n  // the LLM-visible string is swappable. Hosts who registered a\n  // custom `dom` provider get their text in the prompt; default\n  // installs `defaultDomProvider` which just re-wraps readDOM, so\n  // un-overridden behaviour is byte-identical to v0.1.\n  const domProvider = agent.contextProviders.get('dom');\n  const ctxReq = { signal: agent.abortSignalRef ?? new AbortController().signal };\n  let domText = domResult.text;\n  if (domProvider) {\n    try {\n      const override = await domProvider(ctxReq);\n      if (typeof override === 'string') domText = override;\n    } catch { /* fall back to readDOM text */ }\n  }\n  // Append optional slots from the provider registry. Each is\n  // additive — when the provider returns a non-empty string we\n  // tack it on after the DOM text. Default providers return null\n  // when their source isn't available (no selection, no history,\n  // SSR contexts) so absent data doesn't pollute the prompt.\n  const extraSlots: string[] = [];\n  for (const role of ['url', 'page_summary', 'history', 'selection'] as const) {\n    const fn = agent.contextProviders.get(role);\n    if (!fn) continue;\n    try {\n      const out = await fn(ctxReq);\n      if (typeof out === 'string' && out.length > 0) extraSlots.push(out);\n    } catch { /* skip slot */ }\n  }\n  const pageContext = extraSlots.length > 0\n    ? domText + '\\n\\n' + extraSlots.join('\\n\\n')\n    : domText;\n  agent.currentIndexMap = domResult.indexMap;\n\n  // Screenshot slot — runs through the provider registry too.\n  // Default `defaultScreenshotProvider` calls `captureScreenshots`,\n  // matching the existing behaviour. Hosts overriding the slot get\n  // their custom rasterizer; the legacy `agent.configRef.screenshot`\n  // config gates whether we ask the provider at all (so hosts who\n  // opted out keep paying zero cost).\n  let screenshotImages: string[] = [];\n  if (agent.configRef.screenshot) {\n    const ssProvider = agent.contextProviders.get('screenshot');\n    if (ssProvider) {\n      try {\n        const dataUrl = await ssProvider(ctxReq);\n        if (typeof dataUrl === 'string' && dataUrl.length > 0) {\n          screenshotImages = [dataUrl];\n        }\n      } catch { screenshotImages = []; }\n    } else {\n      // Defensive — constructor installs the default, but if a host\n      // explicitly unregistered the slot we fall back to the raw\n      // captureScreenshots path so the prompt still gets an image.\n      const sCfg: ScreenshotConfig = agent.configRef.screenshot === true\n        ? { mode: 'viewport' }\n        : agent.configRef.screenshot;\n      try {\n        screenshotImages = await captureScreenshots(sCfg);\n      } catch {\n        screenshotImages = [];\n      }\n    }\n  }\n\n  const toolReference = agent.configRef.cotMode\n    ? renderToolReference(agent.buildCotToolRefs())\n    : undefined;\n\n  // Route the narrator prompt through the SDK-wide registry so hosts\n  // override per-locale via `dddk.prompts.override('webagent-narrator.system', locale, render)`.\n  // `configRef.systemPrompt` (full replace) is still honoured inside\n  // `assembleSystemPrompt` — the id maps to the CoT variant when the\n  // agent is in thinking mode so hosts can override just that.\n  const narratorInput = {\n    locale: agent.configRef.locale,\n    agentName: agent.configRef.agentName,\n    siteName: agent.configRef.siteName,\n    systemPrompt: agent.configRef.systemPrompt,\n    brand: agent.configRef.brand,\n    persona: agent.configRef.persona,\n    appendSystemPrompt: agent.configRef.appendSystemPrompt,\n    sitemap: agent.configRef.sitemap,\n    session,\n    pageContext,\n    selection: agent.currentSelectionRef ?? undefined,\n    previousUrl: undefined,\n    cotMode: agent.configRef.cotMode,\n    toolReference,\n  };\n  const narratorId = agent.configRef.cotMode\n    ? PROMPT_IDS.WEBAGENT_COT\n    : PROMPT_IDS.WEBAGENT_NARRATOR;\n  const systemPrompt = promptRegistry.render(narratorId, narratorInput, agent.configRef.locale ?? 'en');\n\n  const messages: LLMMessage[] = [{ role: 'system', content: systemPrompt }];\n\n  // History capping. Two orthogonal limits:\n  //   - `maxTurnsInPrompt`: count-based slice (cheap, predictable)\n  //   - `maxPromptTokens` : token-budget walk from newest backward\n  // Both default to off. Count-cap runs first then token-cap.\n  // Leading non-user turns are stripped — LLM APIs reject conversations\n  // that start with an orphan assistant/tool right after the system prompt.\n  let turnsToSerialize: AgentTurn[] = session.turns;\n  const turnLimit = agent.configRef.maxTurnsInPrompt;\n  if (turnLimit && turnLimit > 0 && turnsToSerialize.length > turnLimit) {\n    turnsToSerialize = turnsToSerialize.slice(-turnLimit);\n  }\n  const tokenLimit = agent.configRef.maxPromptTokens;\n  if (tokenLimit && tokenLimit > 0 && turnsToSerialize.length > 0) {\n    const baseReserve = 3000;\n    let budgetChars = (tokenLimit - baseReserve) * CHARS_PER_TOKEN;\n    const kept: AgentTurn[] = [];\n    for (let i = turnsToSerialize.length - 1; i >= 0; i--) {\n      const t = turnsToSerialize[i]!;\n      const c = estimateTurnChars(t);\n      if (budgetChars - c < 0 && kept.length > 0) break;\n      kept.unshift(t);\n      budgetChars -= c;\n    }\n    turnsToSerialize = kept;\n  }\n  const firstUserIdx = turnsToSerialize.findIndex((t) => t.kind === 'user');\n  if (firstUserIdx > 0) {\n    turnsToSerialize = turnsToSerialize.slice(firstUserIdx);\n  }\n\n  for (const turn of turnsToSerialize) {\n    if (turn.kind === 'user') {\n      const parts: string[] = [turn.text];\n      if (turn.selection) parts.push(renderSelectionBlock(turn.selection));\n      const images = turn.selection?.images ?? [];\n      if (images.length > 0) {\n        messages.push({\n          role: 'user',\n          content: [\n            { type: 'text', text: parts.join('\\n\\n') },\n            ...images.map((img: string) => ({ type: 'image' as const, image: img })),\n          ],\n        });\n      } else {\n        messages.push({ role: 'user', content: parts.join('\\n\\n') });\n      }\n    } else if (turn.kind === 'agent_step') {\n      messages.push({\n        role: 'assistant',\n        content: turn.preText ?? '',\n        toolCalls: [{\n          id: turn.toolCallId,\n          name: turn.toolCall.name,\n          arguments: turn.toolCall.arguments,\n        }],\n      });\n      messages.push({\n        role: 'tool',\n        toolCallId: turn.toolCallId,\n        name: turn.toolCall.name,\n        content: JSON.stringify(turn.result),\n      });\n    } else if (turn.kind === 'agent_final') {\n      messages.push({ role: 'assistant', content: turn.text });\n    }\n  }\n\n  // Env block: current page state + fresh DOM dump. In classic mode the\n  // legacy reminder + sitemap also ride along; in CoT mode both live on\n  // the system prompt and env stays minimal.\n  const envParts: string[] = [];\n  if (!agent.configRef.cotMode) {\n    if (agent.configRef.sitemap) envParts.push(renderSitemap(agent.configRef.sitemap));\n    const latestUser = lastUserTurn(session);\n    envParts.push(renderUserReminder({\n      latestUserText: latestUser?.text ?? '',\n      stepsSoFar: session.turns,\n      currentUrl: session.currentPage,\n      cotMode: false,\n    }));\n  }\n  envParts.push(renderPageStateBlock({\n    currentPage: session.currentPage,\n    pageContext,\n    plan: session.plan,\n  }));\n  const envText = envParts.join('\\n\\n');\n  if (screenshotImages.length > 0) {\n    messages.push({\n      role: 'user',\n      content: [\n        { type: 'text', text: envText },\n        ...screenshotImages.map((img) => ({ type: 'image' as const, image: img })),\n      ],\n    });\n  } else {\n    messages.push({ role: 'user', content: envText });\n  }\n\n  recordMessages(messages);\n  return messages;\n}\n\nexport async function* callLlmStream(\n  agent: WebAgent,\n  signal: AbortSignal,\n): AsyncIterable<\n  | { kind: 'text-delta'; delta: string }\n  | { kind: 'tool-call'; call: ToolCall }\n  /**\n   * v0.2.0 streaming-envelope: forwards each fragment of a tool call's\n   * arguments AS the provider streams them. cotLoop consumes these to\n   * feed `StreamingEnvelopeParser`, so narrate text appears in the\n   * subtitle bar as the LLM types it instead of after parse completes.\n   * Only OpenAI-compatible providers emit this today.\n   */\n  | { kind: 'tool-args-delta'; id: string; name: string; deltaText: string; accumulatedText: string }\n> {\n  if (!agent.sessionRef) return;\n\n  const messages = await buildMessages(agent);\n  // Vision routing: any image content part → 'vision' role. Router\n  // fallback inside resolveLLM handles vision → webagent if vision is\n  // unconfigured.\n  const hasImages = agent.configRef.screenshot != null && agent.configRef.screenshot !== false\n    ? true\n    : messageContentHasImage(messages);\n  const role = hasImages ? 'vision' as const : 'webagent' as const;\n  const llm = resolveLLM(agent.configRef.llm, role);\n  const tools = agent.buildToolDefinitions();\n  const completeOpts = {\n    messages,\n    tools,\n    signal,\n    thinking: agent.configRef.thinking ?? 'off' as const,\n    // CoT mode forces the model to call the single wrapping tool every\n    // turn — without this, smaller models occasionally emit a free-text\n    // turn with no actions to dispatch.\n    toolChoice: agent.configRef.cotMode\n      ? ({ name: AGENT_TURN_TOOL } as const)\n      : undefined,\n  };\n\n  const streamProvider = llm as unknown as StreamingProvider;\n  const hasStreaming = typeof streamProvider.streamComplete === 'function';\n\n  const timeoutCtrl = new AbortController();\n  const timer = setTimeout(() => timeoutCtrl.abort('llm timeout'), agent.configRef.llmTimeoutMs);\n  const composedSignal = composeSignals(signal, timeoutCtrl.signal);\n\n  // Per-call perf instrumentation. Consumer-side measurement so it\n  // reflects what the agent actually saw.\n  const startedAt = Date.now();\n  let firstDeltaAt: number | undefined;\n  let usage: { promptTokens: number; completionTokens: number } | undefined;\n  const modelId = (llm as { name?: string; model?: string }).model\n    ?? (llm as { name?: string }).name;\n\n  try {\n    if (hasStreaming) {\n      const handle = streamProvider.streamComplete!({ ...completeOpts, signal: composedSignal });\n      let lastText = '';\n      const yieldedToolIds = new Set<string>();\n      for await (const chunk of handle as AsyncIterable<StreamChunk>) {\n        if (chunk.text.length > lastText.length) {\n          const newDelta = chunk.text.slice(lastText.length);\n          lastText = chunk.text;\n          if (newDelta) {\n            if (firstDeltaAt === undefined) firstDeltaAt = Date.now();\n            yield { kind: 'text-delta', delta: newDelta };\n          }\n        }\n        // v0.2.0 — forward per-fragment tool-args deltas so the cot\n        // loop can feed StreamingEnvelopeParser. We count this toward\n        // TTFT too: the user perceives \"agent started\" the moment narrate\n        // text begins streaming, even though no plain text-delta arrived.\n        if (chunk.toolArgsDelta) {\n          if (firstDeltaAt === undefined) firstDeltaAt = Date.now();\n          yield {\n            kind: 'tool-args-delta',\n            id: chunk.toolArgsDelta.id,\n            name: chunk.toolArgsDelta.name,\n            deltaText: chunk.toolArgsDelta.deltaText,\n            accumulatedText: chunk.toolArgsDelta.accumulatedText,\n          };\n        }\n        if (chunk.toolCalls) {\n          for (const tc of chunk.toolCalls) {\n            if (yieldedToolIds.has(tc.id)) continue;\n            if (!tc.name) continue;\n            yieldedToolIds.add(tc.id);\n            yield { kind: 'tool-call', call: tc };\n          }\n        }\n        if (chunk.error) throw chunk.error;\n      }\n      try {\n        const final = await (handle as unknown as Promise<CompleteResult>);\n        usage = final.usage;\n      } catch { /* error already surfaced via chunk.error */ }\n    } else {\n      const result = await llm.complete({ ...completeOpts, signal: composedSignal });\n      if (result.content) {\n        if (firstDeltaAt === undefined) firstDeltaAt = Date.now();\n        yield { kind: 'text-delta', delta: result.content };\n      }\n      if (result.toolCalls) {\n        for (const tc of result.toolCalls) yield { kind: 'tool-call', call: tc };\n      }\n      usage = result.usage;\n    }\n  } finally {\n    clearTimeout(timer);\n    const endedAt = Date.now();\n    if (agent.llmCallListenerRef && firstDeltaAt !== undefined) {\n      const ttftMs = firstDeltaAt - startedAt;\n      const durationMs = endedAt - startedAt;\n      try {\n        agent.llmCallListenerRef({\n          role,\n          ttftMs,\n          durationMs,\n          outputTokens: usage?.completionTokens,\n          inputTokens: usage?.promptTokens,\n          model: modelId,\n        });\n      } catch { /* listener errors must never break the agent loop */ }\n    }\n  }\n}\n","/**\n * Screenshot capture for WebAgent — feeds the LLM a visual snapshot of\n * the page alongside the indexed DOM dump. Disabled by default; opt in\n * via `WebAgentConfig.screenshot`.\n *\n * Two modes:\n *   - `viewport`   — only what the user can see right now (1 image).\n *   - `full-page`  — the entire scroll height, split into N segments\n *                    when taller than `maxSegmentHeight`. Each segment\n *                    becomes its own image, capped by `maxImages`.\n *\n * Implementation: dynamic-imports `html2canvas` so users who don't\n * enable screenshots pay zero bundle cost. When a host turns the\n * feature on without installing the peer, capture silently no-ops and\n * the agent continues with text-only input.\n */\n\nexport type ScreenshotMode = 'viewport' | 'full-page';\n\nexport interface ScreenshotConfig {\n  /** Default capture mode. Default `'viewport'`. */\n  mode?: ScreenshotMode;\n  /** Max pixel height per image segment. Full-page captures taller than\n   *  this split into multiple images. Default 4000. */\n  maxSegmentHeight?: number;\n  /** Hard cap on the number of images sent per turn (after splitting).\n   *  Default 3 — keeps token cost predictable. */\n  maxImages?: number;\n  /** JPEG quality 0–1. Default 0.75 (sweet spot for legibility vs. size). */\n  quality?: number;\n  /** Downscale factor — 1 = full resolution, 0.5 = half. Lower = cheaper\n   *  tokens but blurrier text. Default 0.75. */\n  scale?: number;\n  /**\n   * Override the capture function entirely. Host returns one image\n   * (viewport mode) or many (full-page mode), each as a data URL or\n   * remote URL the LLM can fetch. When provided, html2canvas is not\n   * loaded.\n   */\n  capture?: (mode: ScreenshotMode) => Promise<string[]>;\n}\n\ninterface H2COptions {\n  width?: number;\n  height?: number;\n  x?: number;\n  y?: number;\n  windowWidth?: number;\n  windowHeight?: number;\n  scale?: number;\n  useCORS?: boolean;\n  backgroundColor?: string | null;\n  logging?: boolean;\n}\ntype H2CFn = (el: Element, opts?: H2COptions) => Promise<HTMLCanvasElement>;\n\nlet html2canvasCache: H2CFn | null | undefined;\n\nasync function loadHtml2Canvas(): Promise<H2CFn | null> {\n  if (html2canvasCache !== undefined) return html2canvasCache;\n  try {\n    // Dynamic import via indirection so TypeScript doesn't try to resolve\n    // the optional peer dependency at compile time, and so bundlers leave\n    // html2canvas out of the default chunk. Users opt in to screenshots\n    // by adding `pnpm add html2canvas`.\n    const spec = 'html2canvas';\n    const dynImport = new Function('s', 'return import(s)') as (s: string) => Promise<unknown>;\n    const mod = await dynImport(spec);\n    const m = mod as { default?: H2CFn };\n    const fn = m.default ?? (mod as unknown as H2CFn);\n    html2canvasCache = fn;\n    return fn;\n  } catch {\n    html2canvasCache = null;\n    return null;\n  }\n}\n\n/**\n * Capture screenshot(s) of the current page according to `cfg`. Returns\n * an empty array when the host didn't install html2canvas (and didn't\n * provide a custom `capture`) — the agent loop continues without images.\n */\nexport async function captureScreenshots(cfg: ScreenshotConfig): Promise<string[]> {\n  if (typeof window === 'undefined' || typeof document === 'undefined') return [];\n\n  const mode: ScreenshotMode = cfg.mode ?? 'viewport';\n  const maxImages = Math.max(1, cfg.maxImages ?? 3);\n\n  if (cfg.capture) {\n    const imgs = await cfg.capture(mode);\n    return imgs.slice(0, maxImages);\n  }\n\n  const h2c = await loadHtml2Canvas();\n  if (!h2c) return [];\n\n  const quality = clamp(cfg.quality ?? 0.75, 0.1, 1);\n  const scale = clamp(cfg.scale ?? 0.75, 0.25, 2);\n  const baseOpts: H2COptions = {\n    scale,\n    useCORS: true,\n    logging: false,\n    backgroundColor: null,\n  };\n\n  if (mode === 'viewport') {\n    const canvas = await h2c(document.body, {\n      ...baseOpts,\n      x: window.scrollX,\n      y: window.scrollY,\n      width: window.innerWidth,\n      height: window.innerHeight,\n      windowWidth: window.innerWidth,\n      windowHeight: window.innerHeight,\n    });\n    return [canvas.toDataURL('image/jpeg', quality)];\n  }\n\n  // full-page: capture the whole document, segmented when very tall.\n  const maxSeg = Math.max(800, cfg.maxSegmentHeight ?? 4000);\n  const docHeight = Math.max(\n    document.body.scrollHeight,\n    document.documentElement.scrollHeight,\n  );\n  const width = Math.max(document.documentElement.clientWidth, window.innerWidth);\n  const segments: string[] = [];\n\n  for (let y = 0; y < docHeight && segments.length < maxImages; y += maxSeg) {\n    const segHeight = Math.min(maxSeg, docHeight - y);\n    const canvas = await h2c(document.body, {\n      ...baseOpts,\n      x: 0,\n      y,\n      width,\n      height: segHeight,\n      windowWidth: width,\n      windowHeight: docHeight,\n    });\n    segments.push(canvas.toDataURL('image/jpeg', quality));\n  }\n  return segments;\n}\n\nfunction clamp(n: number, lo: number, hi: number): number {\n  return Math.max(lo, Math.min(hi, n));\n}\n","/**\n * The two top-level loops: classic single-tool and CoT envelope.\n *\n * Both consume the WebAgent instance through its `@internal` surface\n * (sessionRef / configRef / actionsRef / ...) so the main class file\n * stays focused on constructor + public API + state.\n */\n\nimport type { WebAgent } from '../webagent';\nimport type { AgentEvent, ActionResult } from '../types';\nimport type { ToolCall } from '../../llm/types';\nimport {\n  pushAgentStep,\n  pushAgentFinal,\n  lastUserTurn,\n} from '../session';\nimport { executeAction } from '../execute-action';\nimport {\n  AGENT_TURN_TOOL,\n  parseTurnResponse,\n  isNarrateAction,\n  isToolAction,\n} from '../cot';\nimport { sdkString } from '../../../utils/sdk-i18n';\nimport {\n  awaitNavSettle,\n  extractTargetSelector,\n  isUserEditingInPalette,\n  narrateAction,\n  sleep,\n} from './helpers';\nimport { recordParseFail, recordTurn } from './debug';\nimport { callLlmStream } from './messages';\nimport type { EnvelopeStreamEvent } from './streaming-envelope';\n\n/**\n * Per-turn mutable dispatch state. The cot loop uses one of these and\n * both the streaming dispatch path AND the JSON-parse fallback path\n * thread the same instance through `dispatchOneAction` so flags +\n * results aggregate identically.\n */\ninterface DispatchState {\n  actionResults: Array<\n    | { type: 'narrate'; text: string }\n    | { type: 'tool'; name: string; ok: boolean; reason?: string; data?: unknown }\n    | { type: 'done' }\n  >;\n  pageChanged: boolean;\n  endLoopRequested: boolean;\n  executedReactionRequiringTool: boolean;\n  actionErrorThisTurn: number;\n}\n\nconst TOOLS_REQUIRING_NEXT_REACTION_SET = new Set(['ask_user', 'ask_user_choice', 'navigate']);\n\n/**\n * Look for a visible <a href> whose target matches `path`. Used by the\n * `preferClickLinkOverNavigate` config flag — when the host opts in we\n * trigger this anchor's `.click()` instead of calling the navigate bridge\n * directly, so demos look like a real human clicking nav.\n *\n * Matches an anchor when either:\n *   - href equals path exactly (`/dashboard`)\n *   - href equals path with trailing slash trimmed\n *   - the anchor's `pathname` matches path (handles fully-qualified hrefs)\n *\n * Skips disabled / `aria-disabled` / hidden anchors. Returns the first\n * match in document order — usually the primary nav link.\n */\nfunction findNavLink(path: string): HTMLAnchorElement | null {\n  if (typeof document === 'undefined' || !path) return null;\n  const want = path.replace(/\\/$/, '') || '/';\n  const anchors = document.querySelectorAll<HTMLAnchorElement>('a[href]');\n  for (const a of Array.from(anchors)) {\n    if (a.getAttribute('aria-disabled') === 'true') continue;\n    if (a.hasAttribute('disabled')) continue;\n    if (!(a.offsetParent || a.getClientRects().length > 0)) continue; // not visible\n    const raw = a.getAttribute('href') ?? '';\n    const trimmed = raw.replace(/\\/$/, '') || '/';\n    if (trimmed === want) return a;\n    try {\n      const u = new URL(a.href, location.origin);\n      const pn = u.pathname.replace(/\\/$/, '') || '/';\n      if (pn === want) return a;\n    } catch { /* ignore malformed hrefs */ }\n  }\n  return null;\n}\n\nexport async function* executeLoop(\n  agent: WebAgent,\n  signal: AbortSignal,\n): AsyncIterable<AgentEvent> {\n  const session = agent.sessionRef;\n  if (!session) return;\n  let errorCount = 0;\n\n  for (let stepIdx = 0; stepIdx < agent.configRef.maxSteps; stepIdx++) {\n    if (signal.aborted) {\n      agent.setStatusInternal('idle');\n      return;\n    }\n\n    // SPA nav detection between iterations.\n    const nowUrl = typeof location !== 'undefined' ? location.pathname + location.search : null;\n    if (nowUrl && session.currentPage !== nowUrl) {\n      const from = session.currentPage;\n      session.currentPage = nowUrl;\n      agent.persistSessionInternal();\n      yield { kind: 'navigated', from, to: nowUrl };\n    }\n\n    agent.setStatusInternal('thinking');\n    yield { kind: 'thinking' };\n\n    let toolCall: ToolCall | undefined;\n    let textBuffer = '';\n    try {\n      for await (const ev of callLlmStream(agent, signal)) {\n        if (signal.aborted) { agent.setStatusInternal('idle'); return; }\n        if (ev.kind === 'text-delta' && ev.delta) {\n          textBuffer += ev.delta;\n          yield ev;\n        } else if (ev.kind === 'tool-call') {\n          toolCall = ev.call;\n          // Let the stream finish so finishReason / usage land; no more\n          // text deltas matter once the tool is known.\n        }\n      }\n      errorCount = 0;\n    } catch (err) {\n      if (signal.aborted) { agent.setStatusInternal('idle'); return; }\n      errorCount += 1;\n      const retrying = errorCount < agent.configRef.maxErrors;\n      yield { kind: 'error', error: err as Error, retrying };\n      if (!retrying) {\n        agent.setStatusInternal('failed');\n        return;\n      }\n      await sleep(400 * Math.pow(2, errorCount - 1));\n      continue;\n    }\n\n    // No tool call → final paragraph. Done.\n    if (!toolCall) {\n      if (textBuffer) pushAgentFinal(session, textBuffer);\n      agent.setStatusInternal('idle');\n      yield { kind: 'final' };\n      return;\n    }\n\n    const matched = agent.actionsRef.get(toolCall.name);\n\n    const needsConfirm = await agent.needsConfirmationInternal(toolCall, matched, signal);\n    if (needsConfirm) {\n      const locale = agent.configRef.locale ?? 'en';\n      // Precedence: per-action override → host-level override → SDK default.\n      const message = matched?.confirmationMessage?.(toolCall.arguments as never)\n        ?? agent.configRef.buildConfirmMessage?.(toolCall.name, toolCall.arguments, locale)\n        ?? narrateAction(toolCall.name, toolCall.arguments, locale);\n      let resolveConfirm!: (ok: boolean) => void;\n      const approvedPromise = new Promise<boolean>((r) => { resolveConfirm = r; });\n      agent.setStatusInternal('waiting');\n      yield {\n        kind: 'confirm',\n        actionName: toolCall.name,\n        args: toolCall.arguments,\n        message,\n        decide: resolveConfirm,\n      };\n      const approved = await Promise.race([\n        approvedPromise,\n        new Promise<boolean>((_, reject) => {\n          const onAbort = (): void => { signal.removeEventListener('abort', onAbort); reject(new Error('aborted')); };\n          signal.addEventListener('abort', onAbort, { once: true });\n        }),\n      ]).catch(() => false);\n      if (!approved) {\n        const result: ActionResult = { ok: false, reason: 'user_declined' };\n        pushAgentStep(session, {\n          preText: textBuffer || undefined,\n          toolCall: { name: toolCall.name, arguments: toolCall.arguments },\n          toolCallId: toolCall.id,\n          result,\n        });\n        agent.persistSessionInternal();\n        yield { kind: 'tool-end', name: toolCall.name, result, toolCallId: toolCall.id };\n        continue;\n      }\n    }\n\n    const targetSelector = extractTargetSelector(toolCall.arguments);\n    yield {\n      kind: 'tool-start',\n      name: toolCall.name,\n      args: toolCall.arguments,\n      targetSelector,\n      toolCallId: toolCall.id,\n    };\n\n    let result: ActionResult;\n    if (toolCall.name === 'navigate') {\n      agent.setStatusInternal('navigating');\n      const path = String(toolCall.arguments.path ?? '');\n      const from = session.currentPage;\n      // Validate against the sitemap when one is configured. Without\n      // this, small models invent paths from labels they read in route\n      // descriptions (\"Coming soon\" → /coming-soon, \"roadmap\" →\n      // /roadmap) and land on 404. With it on, the SDK rejects unknown\n      // paths with a clear message + the actual path list, so the\n      // model retries with a real route on the next turn.\n      const sm = agent.configRef.sitemap;\n      const knownPaths: string[] = [];\n      if (Array.isArray(sm)) {\n        for (const e of sm) if (typeof e?.path === 'string') knownPaths.push(e.path);\n      } else if (sm && typeof sm === 'object') {\n        // SitemapNode tree — walk recursively for `.path` fields\n        const stack: unknown[] = [sm];\n        while (stack.length) {\n          const node = stack.pop() as { path?: string; children?: unknown[] } | undefined;\n          if (!node || typeof node !== 'object') continue;\n          if (typeof node.path === 'string') knownPaths.push(node.path);\n          if (Array.isArray(node.children)) stack.push(...node.children);\n        }\n      }\n      if (knownPaths.length > 0 && path && !knownPaths.includes(path)) {\n        result = {\n          ok: false,\n          reason: 'navigation',\n          message: `Path \"${path}\" is not in this site's sitemap. The valid paths are: ${knownPaths.map((p) => `\"${p}\"`).join(', ')}. Pick one of those and retry. Do not invent paths from label words.`,\n        };\n        yield { kind: 'tool-end', name: 'navigate', result, toolCallId: toolCall.id };\n        pushAgentStep(session, {\n          preText: textBuffer || undefined,\n          toolCall: { name: toolCall.name, arguments: toolCall.arguments },\n          toolCallId: toolCall.id,\n          result,\n        });\n        agent.persistSessionInternal();\n        continue;\n      }\n      // Surface the loading beat BEFORE the router fires so the host can\n      // show a loading indicator until `navigated` arrives.\n      yield { kind: 'navigating', from, to: path };\n\n      // preferClickLinkOverNavigate.\n      // When the host opts in, look for a visible <a href=\"${path}\"> on\n      // the page and trigger it like a user click (with the synthetic\n      // cursor if cursorTrail is also on). This keeps demos looking like\n      // a human navigating instead of a history.pushState ghost. Falls\n      // through to the standard bridge when no matching link exists.\n      let linkClicked = false;\n      if (agent.configRef.preferClickLinkOverNavigate && typeof document !== 'undefined') {\n        const anchor = findNavLink(path);\n        if (anchor) {\n          try {\n            if (agent.configRef.cursorTrail) {\n              const { moveCursorAndTap } = await import('../cursor');\n              await moveCursorAndTap(anchor);\n            }\n            anchor.click();\n            linkClicked = true;\n            await new Promise((r) => setTimeout(r, 80));\n          } catch {\n            linkClicked = false;\n          }\n        }\n      }\n      try {\n        if (!linkClicked) {\n          const bridgeResult = agent.navigateBridgeRef?.(path);\n          // Hosts whose router returns a Promise: await for the real\n          // \"render complete\" signal before declaring nav done.\n          if (bridgeResult && typeof (bridgeResult as Promise<void>).then === 'function') {\n            await bridgeResult;\n          }\n        }\n      } catch (err) {\n        result = { ok: false, reason: 'navigation', message: (err as Error).message };\n        yield { kind: 'tool-end', name: 'navigate', result, toolCallId: toolCall.id };\n        pushAgentStep(session, {\n          preText: textBuffer || undefined,\n          toolCall: { name: toolCall.name, arguments: toolCall.arguments },\n          toolCallId: toolCall.id,\n          result,\n        });\n        agent.persistSessionInternal();\n        continue;\n      }\n      // Stabilisation — components may still be hydrating / lazy chunks\n      // fetching even after the router resolves. Idle-watch with 250ms\n      // quiet window, 2.5s ceiling.\n      await awaitNavSettle(2500);\n      yield { kind: 'navigated', from, to: path };\n      // Continuation hint in the tool result so the next LLM turn sees,\n      // in the tool message itself, that arrival isn't the end. Without\n      // this, smaller models often emit finish_reason=stop right after\n      // navigate succeeds.\n      result = {\n        ok: true,\n        data: {\n          path,\n          arrivedAt: path,\n          note: 'Navigation complete — you are NOW at this URL. The user\\'s original task is not done yet; the navigate was a means to an end. Continue immediately: read the new page DOM in the next message, pick the first subject in reading order, border it, narrate 1-3 sentences quoting the actual visible text, then call pause. Do NOT stop the loop here.',\n        },\n      };\n    } else {\n      const wasUserFacing = toolCall.name === 'ask_user' || toolCall.name === 'ask_user_choice';\n      agent.setStatusInternal(wasUserFacing ? 'waiting' : 'executing');\n      result = await executeAction(\n        {\n          actions: agent.actionsRef,\n          indexMap: agent.currentIndexMap,\n          registerPendingResolver: (r) => agent.registerPendingResolverInternal(r),\n          emitAskUser: (payload) => {\n            if (agent.askUserHandlerRef) agent.askUserHandlerRef(payload);\n            else payload.resolve('');\n          },\n          emitAskUserChoice: (payload) => {\n            if (agent.askUserChoiceHandlerRef) agent.askUserChoiceHandlerRef(payload);\n            else payload.resolve('');\n          },\n          emitPause: (payload) => {\n            if (agent.pauseHandlerRef) agent.pauseHandlerRef(payload);\n            // Fallback: ask_user envelope so the gesture still works\n            // when the host hasn't wired setPauseHandler.\n            else if (agent.askUserHandlerRef) {\n              agent.askUserHandlerRef({ question: payload.hint, resolve: payload.resolve });\n            } else {\n              payload.resolve('');\n            }\n          },\n          emitPresentSurface: agent.surfaceMounterRef\n            ? (payload) => agent.surfaceMounterRef!(payload)\n            : undefined,\n          session,\n          defaultPauseNote:\n            agent.configRef.defaultPauseNote ?? sdkString(agent.configRef.locale, 'agent.press_space_continue'),\n          uiHints: {\n            cursorTrail: agent.configRef.cursorTrail,\n            preferClickLinkOverNavigate: agent.configRef.preferClickLinkOverNavigate,\n          },\n        },\n        toolCall.name,\n        toolCall.arguments,\n        signal,\n      );\n    }\n\n    yield { kind: 'tool-end', name: toolCall.name, result, toolCallId: toolCall.id };\n\n    pushAgentStep(session, {\n      preText: textBuffer || undefined,\n      toolCall: { name: toolCall.name, arguments: toolCall.arguments },\n      toolCallId: toolCall.id,\n      result,\n    });\n    agent.persistSessionInternal();\n\n    if (!result.ok) {\n      errorCount += 1;\n      if (errorCount >= agent.configRef.maxErrors) {\n        agent.setStatusInternal('failed');\n        return;\n      }\n    } else {\n      errorCount = 0;\n    }\n  }\n\n  // maxSteps hit. Yield `final` so the orchestrator's closure hook still\n  // renders the closing UI (otherwise the subtitle bar just disappears,\n  // which reads as broken).\n  agent.setStatusInternal('failed');\n  yield { kind: 'final' };\n}\n\n/**\n * One-shot planning call run before the CoT turn loop. Resulting TaskPlan\n * is stored on session.plan so subsequent turns render `# Master plan`\n * in the system prompt and mutate via todo_adjust. Fail-loud — a thrown\n * error propagates to the consumer's runStream() iterator.\n *\n * Returns `true` if the loop should continue, `false` to abort.\n */\nexport async function* executePlanningPhase(\n  agent: WebAgent,\n  signal: AbortSignal,\n): AsyncGenerator<AgentEvent, boolean, void> {\n  const session = agent.sessionRef!;\n  if (!agent.configRef.planner || session.plan) return true;\n\n  agent.setStatusInternal('thinking');\n  yield { kind: 'thinking' };\n  const latestUser = lastUserTurn(session);\n  const taskText = latestUser?.text ?? '';\n  console.info('[dddk webagent] planning start', { task: taskText });\n  try {\n    // Streaming announcement: the planner calls onSummaryDelta as nano\n    // types each char of `task_summary`. We push deltas to a queue +\n    // resume a waiter so the outer for-loop can yield them as\n    // text-delta AgentEvents WHILE the planner promise is still\n    // in-flight. After plan resolves we drain any tail deltas then\n    // pause for Space.\n    const announce = agent.configRef.announcePlan;\n    const deltaQueue: string[] = [];\n    let waiter: (() => void) | null = null;\n    let plannerDone = false;\n    // The planner always reads the current page DOM. It needs to know\n    // (a) what page the user is currently on and (b) what nav links\n    // are reachable from here, otherwise it would be planning blind.\n    // `plannerDomMaxLength` (default 8000) caps the snapshot so the\n    // strategic one-shot stays cheap — the per-turn DOM budget\n    // (domMaxLength, default 40000) is independent.\n    let pageContextForPlanner: string | undefined;\n    if (typeof document !== 'undefined') {\n      try {\n        const { readDOM } = await import('../dom-reader');\n        const cap = agent.configRef.plannerDomMaxLength ?? 8000;\n        const snap = readDOM({ filter: agent.configRef.domFilter, maxLength: cap });\n        if (snap.text) {\n          pageContextForPlanner = `# Current page DOM\\n\\n` + snap.text;\n        }\n      } catch { /* planner falls back to host route descriptions only */ }\n    }\n    const plannerPromise = agent.configRef.planner({\n      task: taskText,\n      sitemap: agent.configRef.sitemap,\n      brand: agent.configRef.brand,\n      persona: agent.configRef.persona,\n      locale: agent.configRef.locale,\n      selection: agent.currentSelectionRef ?? undefined,\n      hostContext: pageContextForPlanner,\n      onSummaryDelta: announce\n        ? (delta: string) => {\n            if (!delta) return;\n            deltaQueue.push(delta);\n            if (waiter) { const w = waiter; waiter = null; w(); }\n          }\n        : undefined,\n    } as Parameters<NonNullable<typeof agent.configRef.planner>>[0]);\n    plannerPromise.finally(() => {\n      plannerDone = true;\n      if (waiter) { const w = waiter; waiter = null; w(); }\n    });\n    // Drain loop: yield deltas as they arrive, sleep on a waiter when\n    // empty, exit when planner resolved AND queue empty.\n    while (!plannerDone || deltaQueue.length > 0) {\n      if (deltaQueue.length > 0) {\n        yield { kind: 'text-delta', delta: deltaQueue.shift()! };\n        continue;\n      }\n      if (!plannerDone) {\n        await new Promise<void>((resolve) => { waiter = resolve; });\n      }\n    }\n    const plan = await plannerPromise;\n    session.plan = plan;\n    agent.persistSessionInternal();\n    console.info('[dddk webagent] planning result', {\n      task_summary: plan.task_summary,\n      todoCount: plan.todos.length,\n      todos: plan.todos,\n    });\n    if (announce && plan.task_summary?.trim()) {\n      // Newline after summary for visual breathing room before pause hint.\n      yield { kind: 'text-delta', delta: '\\n' };\n      // Wait for user ack before turn 1 — otherwise the first turn's\n      // confirm dialog covers the announce before the user can read it.\n      if (agent.pauseHandlerRef) {\n        agent.setStatusInternal('waiting');\n        const pauseHint = sdkString(agent.configRef.locale, 'agent.press_space_continue');\n        const resolution = await new Promise<string>((resolve) => {\n          agent.pauseHandlerRef!({ hint: pauseHint, resolve });\n        });\n        if (signal.aborted || resolution === '') {\n          agent.setStatusInternal('idle');\n          return false;\n        }\n      }\n    }\n    return true;\n  } catch (err) {\n    if (signal.aborted) { agent.setStatusInternal('idle'); return false; }\n    console.warn('[dddk webagent] planning failed', err);\n    yield { kind: 'error', error: err as Error, retrying: false };\n    agent.setStatusInternal('failed');\n    return false;\n  }\n}\n\n/**\n * Dispatch a single CoT-envelope action (narrate or tool). Yields\n * AgentEvents and mutates `state` so the caller can observe whether\n * the page changed, whether an end was requested, etc.\n *\n * Two callers in v0.2.0:\n *\n *   1. Streaming path — fires from `executeCotLoop` as the envelope\n *      parser emits `narrate_complete` / `tool_args_complete` events.\n *      Each action runs to completion before the next parser event\n *      is consumed (the LLM stream buffers in the meantime).\n *\n *   2. Non-streaming fallback — fires from `executeCotLoop` after the\n *      full agent_turn tool call lands, iterating turn.actions[] in\n *      order. Same code path so behavior is identical.\n *\n * `skipNarrateTypewriter=true` is used by the streaming path because\n * narrate text was already streamed live via `narrate_delta` events.\n * Fallback path leaves it false → original 4ms/char paced typewriter.\n */\nasync function* dispatchOneAction(\n  agent: WebAgent,\n  signal: AbortSignal,\n  stepIdx: number,\n  ai: number,\n  action: { narrate?: string; about?: string; tool?: string; args?: Record<string, unknown> },\n  state: DispatchState,\n  options: { skipNarrateTypewriter?: boolean },\n): AsyncIterable<AgentEvent> {\n  const session = agent.sessionRef;\n  if (!session) return;\n\n  if (isNarrateAction(action as never)) {\n    agent.setStatusInternal('executing');\n    const narrateAction = action as { narrate: string; about?: string };\n    const about = narrateAction.about;\n    if (about && about.trim().length > 0) {\n      const borderAction = agent.actionsRef.get('border');\n      if (borderAction) {\n        const synthId = `cot_about_${stepIdx}_${ai}_${Math.random().toString(36).slice(2, 6)}`;\n        yield {\n          kind: 'tool-start',\n          name: 'border',\n          args: { selector: about },\n          targetSelector: about,\n          toolCallId: synthId,\n        };\n        const borderResult = await executeAction(\n          {\n            actions: agent.actionsRef,\n            indexMap: agent.currentIndexMap,\n            registerPendingResolver: (r) => agent.registerPendingResolverInternal(r),\n            emitAskUser: () => {},\n            emitAskUserChoice: () => {},\n            emitPause: () => {},\n            emitPresentSurface: undefined,\n            session,\n            defaultPauseNote: '',\n            // Without this, the cursor + tap pulse never fire on the\n            // narrate-about beat — the synthesized border call has to\n            // see the same cursorTrail flag the regular tool path\n            // passes through. Same hint shape, same source of truth.\n            uiHints: {\n              cursorTrail: agent.configRef.cursorTrail,\n              preferClickLinkOverNavigate: agent.configRef.preferClickLinkOverNavigate,\n            },\n          },\n          'border',\n          { selector: about },\n          signal,\n        );\n        yield { kind: 'tool-end', name: 'border', result: borderResult, toolCallId: synthId };\n        state.actionResults.push({\n          type: 'tool',\n          name: 'border',\n          ok: borderResult.ok,\n          reason: borderResult.ok ? undefined : borderResult.reason,\n          data: borderResult.ok ? borderResult.data : undefined,\n        });\n      }\n    }\n\n    // Skip the typewriter when narrate already streamed live via parser.\n    if (!options.skipNarrateTypewriter) {\n      const NARRATE_CHUNK_SIZE = 2;\n      const NARRATE_CHUNK_DELAY_MS = 8;\n      for (let i = 0; i < narrateAction.narrate.length; i += NARRATE_CHUNK_SIZE) {\n        if (signal.aborted) { agent.setStatusInternal('idle'); return; }\n        yield { kind: 'text-delta', delta: narrateAction.narrate.slice(i, i + NARRATE_CHUNK_SIZE) };\n        await sleep(NARRATE_CHUNK_DELAY_MS);\n      }\n    }\n    state.actionResults.push({ type: 'narrate', text: narrateAction.narrate });\n\n    let skipPause = false;\n    if (isUserEditingInPalette()) skipPause = true;\n    if (agent.configRef.disableAutoPauseAfterNarrate === true) skipPause = true;\n\n    if (!skipPause && agent.pauseHandlerRef) {\n      agent.setStatusInternal('waiting');\n      const pauseHint = sdkString(agent.configRef.locale, 'agent.press_space_continue');\n      const resolution = await new Promise<string>((resolve) => {\n        agent.pauseHandlerRef!({ hint: pauseHint, resolve });\n      });\n      if (signal.aborted || resolution === '') {\n        agent.setStatusInternal('idle');\n        return;\n      }\n    }\n    return;\n  }\n\n  if (isToolAction(action as never)) {\n    const toolAction = action as { tool: string; args?: Record<string, unknown> };\n    const synth: ToolCall = {\n      id: `cot_${stepIdx}_${Math.random().toString(36).slice(2, 8)}`,\n      name: toolAction.tool,\n      arguments: toolAction.args ?? {},\n    };\n    if (TOOLS_REQUIRING_NEXT_REACTION_SET.has(synth.name)) {\n      state.executedReactionRequiringTool = true;\n    }\n    const matched = agent.actionsRef.get(synth.name);\n\n    const needsConfirm = await agent.needsConfirmationInternal(synth, matched, signal);\n    if (needsConfirm) {\n      const locale = agent.configRef.locale ?? 'en';\n      const message = matched?.confirmationMessage?.(synth.arguments as never)\n        ?? agent.configRef.buildConfirmMessage?.(synth.name, synth.arguments, locale)\n        ?? narrateAction(synth.name, synth.arguments, locale);\n      let resolveConfirm!: (ok: boolean) => void;\n      const approvedPromise = new Promise<boolean>((r) => { resolveConfirm = r; });\n      agent.setStatusInternal('waiting');\n      yield {\n        kind: 'confirm',\n        actionName: synth.name,\n        args: synth.arguments,\n        message,\n        decide: resolveConfirm,\n      };\n      const approved = await Promise.race([\n        approvedPromise,\n        new Promise<boolean>((_, reject) => {\n          const onAbort = (): void => { signal.removeEventListener('abort', onAbort); reject(new Error('aborted')); };\n          signal.addEventListener('abort', onAbort, { once: true });\n        }),\n      ]).catch(() => false);\n      if (!approved) {\n        const result: ActionResult = { ok: false, reason: 'user_declined' };\n        yield { kind: 'tool-end', name: synth.name, result, toolCallId: synth.id };\n        state.actionResults.push({ type: 'tool', name: synth.name, ok: false, reason: 'user_declined' });\n        return;\n      }\n    }\n\n    const targetSelector = extractTargetSelector(synth.arguments);\n    yield { kind: 'tool-start', name: synth.name, args: synth.arguments, targetSelector, toolCallId: synth.id };\n\n    let result: ActionResult;\n    if (synth.name === 'navigate') {\n      const path = String(synth.arguments.path ?? '').trim();\n      if (!path) {\n        result = { ok: false, reason: 'unknown', message: 'navigate requires a non-empty `path` arg (e.g. \"/docs\")' };\n        yield { kind: 'tool-end', name: 'navigate', result, toolCallId: synth.id };\n        state.actionResults.push({ type: 'tool', name: 'navigate', ok: false, reason: 'missing path' });\n        state.actionErrorThisTurn += 1;\n        return;\n      }\n      agent.setStatusInternal('navigating');\n      const from = session.currentPage;\n      yield { kind: 'navigating', from, to: path };\n      try {\n        const bridgeResult = agent.navigateBridgeRef?.(path);\n        if (bridgeResult && typeof (bridgeResult as Promise<void>).then === 'function') {\n          await bridgeResult;\n        }\n      } catch (err) {\n        result = { ok: false, reason: 'navigation', message: (err as Error).message };\n        yield { kind: 'tool-end', name: 'navigate', result, toolCallId: synth.id };\n        state.actionResults.push({ type: 'tool', name: synth.name, ok: false, reason: 'navigation' });\n        state.actionErrorThisTurn += 1;\n        return;\n      }\n      await awaitNavSettle(2500);\n      yield { kind: 'navigated', from, to: path };\n      result = { ok: true, data: { path, arrivedAt: path } };\n      state.pageChanged = true;\n    } else {\n      const wasUserFacing = synth.name === 'ask_user' || synth.name === 'ask_user_choice';\n      agent.setStatusInternal(wasUserFacing ? 'waiting' : 'executing');\n      result = await executeAction(\n        {\n          actions: agent.actionsRef,\n          indexMap: agent.currentIndexMap,\n          registerPendingResolver: (r) => agent.registerPendingResolverInternal(r),\n          emitAskUser: (payload) => {\n            if (agent.askUserHandlerRef) agent.askUserHandlerRef(payload);\n            else payload.resolve('');\n          },\n          emitAskUserChoice: (payload) => {\n            if (agent.askUserChoiceHandlerRef) agent.askUserChoiceHandlerRef(payload);\n            else payload.resolve('');\n          },\n          emitPause: (payload) => {\n            if (agent.pauseHandlerRef) agent.pauseHandlerRef(payload);\n            else if (agent.askUserHandlerRef) {\n              agent.askUserHandlerRef({ question: payload.hint, resolve: payload.resolve });\n            } else {\n              payload.resolve('');\n            }\n          },\n          emitPresentSurface: agent.surfaceMounterRef\n            ? (payload) => agent.surfaceMounterRef!(payload)\n            : undefined,\n          session,\n          defaultPauseNote:\n            agent.configRef.defaultPauseNote ?? sdkString(agent.configRef.locale, 'agent.press_space_continue'),\n        },\n        synth.name,\n        synth.arguments,\n        signal,\n      );\n    }\n\n    yield { kind: 'tool-end', name: synth.name, result, toolCallId: synth.id };\n    state.actionResults.push({\n      type: 'tool',\n      name: synth.name,\n      ok: result.ok,\n      reason: result.ok ? undefined : result.reason,\n      data: result.ok ? result.data : undefined,\n    });\n    if (!result.ok) state.actionErrorThisTurn += 1;\n  }\n}\n\nexport async function* executeCotLoop(\n  agent: WebAgent,\n  signal: AbortSignal,\n): AsyncIterable<AgentEvent> {\n  const session = agent.sessionRef;\n  if (!session) return;\n\n  const planContinue = yield* executePlanningPhase(agent, signal);\n  if (!planContinue) return;\n\n  let errorCount = 0;\n\n  // Reaction-requiring tools whose result the model MUST observe before\n  // the run can finish. If is_final lands in the same turn as any of\n  // these, we drop is_final (the run isn't actually done yet).\n  const TOOLS_REQUIRING_NEXT_REACTION = new Set(['ask_user_choice', 'ask_user', 'navigate']);\n\n  for (let stepIdx = 0; stepIdx < agent.configRef.maxSteps; stepIdx++) {\n    if (signal.aborted) { agent.setStatusInternal('idle'); return; }\n\n    // SPA nav detection between iterations.\n    const nowUrl = typeof location !== 'undefined' ? location.pathname + location.search : null;\n    if (nowUrl && session.currentPage !== nowUrl) {\n      const from = session.currentPage;\n      session.currentPage = nowUrl;\n      agent.persistSessionInternal();\n      yield { kind: 'navigated', from, to: nowUrl };\n    }\n\n    agent.setStatusInternal('thinking');\n    yield { kind: 'thinking' };\n\n    // Single forced tool call to `agent_turn`. Stray text deltas are\n    // ignored (schema doesn't allow them; we tolerate misbehaving providers).\n    let agentTurnCall: ToolCall | undefined;\n    // v0.2.0 streaming-envelope: when the flag is on, the parser\n    // dispatches each action AS the LLM types it, instead of waiting\n    // for the full envelope JSON to settle. Per-action mid-stream\n    // dispatch — narrate text typewriters live in the subtitle bar\n    // AND the first tool action fires before the LLM has finished\n    // emitting later actions.\n    const useStreamingEnvelope = !!agent.configRef.enableStreamingEnvelope;\n    let envelopeParser: import('./streaming-envelope').StreamingEnvelopeParser | null = null;\n    let envelopeParserBailed = false;\n    if (useStreamingEnvelope) {\n      const { StreamingEnvelopeParser } = await import('./streaming-envelope');\n      envelopeParser = new StreamingEnvelopeParser();\n    }\n\n    // Streaming dispatch state — shared with the fallback path so the\n    // turn finalisation block at the bottom doesn't need to branch.\n    const dispatchState: DispatchState = {\n      actionResults: [],\n      pageChanged: false,\n      endLoopRequested: false,\n      executedReactionRequiringTool: false,\n      actionErrorThisTurn: 0,\n    };\n    // Per-index field accumulators — about_complete fires before the\n    // matching narrate_complete, so stash and pick up on the completion.\n    const perActionAbout = new Map<number, string>();\n    // Envelope-scoped fields the parser surfaces for finalisation.\n    let envelopeMemory: string | undefined;\n    let envelopeTodoAdjust: { remove?: string[]; replace?: Array<{ id: string; new_description: string; new_intent?: string }> } | undefined;\n    let envelopeTodosRemaining: string[] | undefined;\n    let envelopeIsFinal = false;\n    let envelopeCompleteFired = false;\n    let dispatchedAnyStreaming = false;\n    // Once pageChanged / endLoopRequested fires mid-stream, the remaining\n    // queued actions (next turn would re-plan against the new DOM) should\n    // be skipped. We keep draining the LLM stream so the request closes\n    // cleanly, but ignore further `*_complete` events from the parser.\n    let stopDispatchingFurther = false;\n\n    // Apply todo_adjust to the session plan. Mirrors the original\n    // post-parse logic, just done as soon as parser surfaces it so any\n    // ensuing actions see the updated plan.\n    const applyTodoAdjust = (adjust: typeof envelopeTodoAdjust): void => {\n      if (!adjust || !session.plan) return;\n      if (adjust.remove?.length) {\n        for (const id of adjust.remove) {\n          session.plan.todos = session.plan.todos.filter((t) => t.id !== id);\n        }\n      }\n      if (adjust.replace?.length) {\n        for (const r of adjust.replace) {\n          const idx = session.plan.todos.findIndex((t) => t.id === r.id);\n          if (idx < 0) continue;\n          session.plan.todos[idx] = {\n            ...session.plan.todos[idx]!,\n            description: r.new_description,\n            ...(r.new_intent ? { intent: r.new_intent } : {}),\n          };\n        }\n      }\n      agent.persistSessionInternal();\n    };\n\n    // Inner generator: dispatch one event from the parser. Yields any\n    // AgentEvents emitted by sub-dispatches. Sets stopDispatchingFurther\n    // when the action causes a navigate or signals end-of-loop.\n    async function* handleParserEvent(e: EnvelopeStreamEvent): AsyncIterable<AgentEvent> {\n      switch (e.kind) {\n        case 'memory_complete':\n          envelopeMemory = e.value;\n          break;\n        case 'turn_planning_complete':\n          // No mid-stream side effect — planning is informational.\n          break;\n        case 'todo_adjust_complete':\n          envelopeTodoAdjust = e.value as typeof envelopeTodoAdjust;\n          applyTodoAdjust(envelopeTodoAdjust);\n          break;\n        case 'todos_remaining_complete':\n          envelopeTodosRemaining = e.value;\n          break;\n        case 'action_start':\n          // Reset per-action accumulator slot.\n          perActionAbout.delete(e.index);\n          break;\n        case 'about_complete':\n          perActionAbout.set(e.index, e.value);\n          break;\n        case 'narrate_delta':\n          if (e.delta) {\n            console.info('[dddk stream] narrate_delta', { idx: e.index, delta: e.delta });\n            yield { kind: 'text-delta', delta: e.delta };\n          }\n          break;\n        case 'narrate_complete': {\n          console.info('[dddk stream] narrate_complete', { idx: e.index, len: e.full.length });\n          if (stopDispatchingFurther) break;\n          dispatchedAnyStreaming = true;\n          const about = perActionAbout.get(e.index);\n          yield* dispatchOneAction(\n            agent,\n            signal,\n            stepIdx,\n            e.index,\n            { narrate: e.full, about },\n            dispatchState,\n            { skipNarrateTypewriter: true },\n          );\n          if (dispatchState.pageChanged) stopDispatchingFurther = true;\n          break;\n        }\n        case 'tool_args_complete': {\n          console.info('[dddk stream] tool_args_complete', { idx: e.index, tool: e.tool, args: e.args });\n          if (stopDispatchingFurther) break;\n          dispatchedAnyStreaming = true;\n          yield* dispatchOneAction(\n            agent,\n            signal,\n            stepIdx,\n            e.index,\n            { tool: e.tool, args: e.args as Record<string, unknown> },\n            dispatchState,\n            { skipNarrateTypewriter: true },\n          );\n          if (dispatchState.pageChanged) stopDispatchingFurther = true;\n          break;\n        }\n        case 'is_final_complete':\n          envelopeIsFinal = e.value;\n          break;\n        case 'envelope_complete':\n          envelopeCompleteFired = true;\n          console.info('[dddk stream] envelope_complete (turn finished streaming)');\n          break;\n      }\n    }\n\n    let streamFragCount = 0;\n    try {\n      for await (const ev of callLlmStream(agent, signal)) {\n        if (signal.aborted) { agent.setStatusInternal('idle'); return; }\n        if (ev.kind === 'tool-args-delta' && ev.name === AGENT_TURN_TOOL) {\n          streamFragCount += 1;\n          // Log EVERY fragment regardless of parser state. The previous\n          // version gated logging on `!envelopeParserBailed`, which made\n          // post-bail fragments invisible — looked like \"stream ended\n          // after 1 fragment\" when actually 300+ kept flowing through.\n          console.info(`[dddk stream] frag #${streamFragCount}`, { len: ev.deltaText.length, text: ev.deltaText });\n          if (envelopeParser && !envelopeParserBailed) {\n            const events = envelopeParser.feed(ev.deltaText);\n            if (events === null) {\n              envelopeParserBailed = true; // unknown shape — fall back to JSON-parse path\n              console.warn(`[dddk stream] parser bailed at frag #${streamFragCount} — falling back to JSON-parse path`);\n            } else {\n              for (const e of events) {\n                yield* handleParserEvent(e);\n              }\n            }\n          }\n        }\n        if (ev.kind === 'tool-call' && ev.call.name === AGENT_TURN_TOOL) {\n          agentTurnCall = ev.call;\n        }\n      }\n      if (streamFragCount > 0) {\n        console.info(`[dddk stream] LLM stream ended after ${streamFragCount} fragments`);\n      }\n      // Flush any tail-end envelope events.\n      if (envelopeParser && !envelopeParserBailed) {\n        const tail = envelopeParser.finish();\n        if (tail) {\n          for (const e of tail) {\n            yield* handleParserEvent(e);\n          }\n        }\n      }\n      errorCount = 0;\n    } catch (err) {\n      if (signal.aborted) { agent.setStatusInternal('idle'); return; }\n      errorCount += 1;\n      const retrying = errorCount < agent.configRef.maxErrors;\n      yield { kind: 'error', error: err as Error, retrying };\n      if (!retrying) { agent.setStatusInternal('failed'); return; }\n      await sleep(400 * Math.pow(2, errorCount - 1));\n      continue;\n    }\n\n    if (!agentTurnCall) {\n      // Provider didn't comply with toolChoice — treat as done so the\n      // user isn't stuck in an empty loop.\n      agent.setStatusInternal('idle');\n      yield { kind: 'final' };\n      return;\n    }\n\n    // Decide which path finalises this turn:\n    //  - Streaming path: parser saw envelope_complete AND we dispatched\n    //    at least one action. Skip JSON-parse, trust dispatchState.\n    //  - Streaming partial: we dispatched some actions but stream broke\n    //    or parser bailed mid-way. Don't re-dispatch — finalise with\n    //    what we have so action history doesn't double up.\n    //  - Fallback path: streaming off, or parser bailed before any\n    //    dispatch. Parse the full tool-call args + run the dispatch\n    //    loop using the same helper.\n    const useStreamingFinalize = dispatchedAnyStreaming;\n\n    if (useStreamingFinalize) {\n      // Apply is_final closure under the same reaction-requiring-tool\n      // rule the fallback path uses.\n      if (envelopeIsFinal && !dispatchState.executedReactionRequiringTool) {\n        dispatchState.actionResults.push({ type: 'done' });\n        dispatchState.endLoopRequested = true;\n      } else if (envelopeIsFinal && dispatchState.executedReactionRequiringTool) {\n        console.warn('[dddk webagent] dropping is_final=true — turn included a reaction-requiring tool; the run is not actually finished yet');\n      }\n\n      const envelopeData = {\n        memory: envelopeMemory,\n        todos_remaining: envelopeTodosRemaining,\n        action_results: dispatchState.actionResults,\n        page_changed: dispatchState.pageChanged,\n        streamed: true,\n      };\n      const turnSummary: Record<string, unknown> = {\n        turn: stepIdx + 1,\n        url: session.currentPage,\n        memory: envelopeMemory,\n        streamed: true,\n      };\n      if (envelopeTodosRemaining !== undefined) turnSummary.todos_remaining = envelopeTodosRemaining;\n      if (envelopeTodoAdjust) turnSummary.todo_adjust = envelopeTodoAdjust;\n      if (session.plan) {\n        turnSummary.master_todos = session.plan.todos.map((t) => `${t.id}:${t.intent}:${t.description}`);\n      }\n      turnSummary.action_results = dispatchState.actionResults;\n      if (envelopeIsFinal) turnSummary.is_final = true;\n      console.info('[dddk webagent] turn summary (after-the-fact)', turnSummary);\n\n      pushAgentStep(session, {\n        toolCall: { name: AGENT_TURN_TOOL, arguments: agentTurnCall.arguments },\n        toolCallId: agentTurnCall.id,\n        result: dispatchState.actionErrorThisTurn === 0\n          ? { ok: true, data: envelopeData }\n          : { ok: false, reason: 'unknown', message: JSON.stringify(envelopeData) },\n      });\n      agent.persistSessionInternal();\n\n      if (dispatchState.actionErrorThisTurn > 0) {\n        errorCount += 1;\n        if (errorCount >= agent.configRef.maxErrors) {\n          agent.setStatusInternal('failed');\n          return;\n        }\n      } else {\n        errorCount = 0;\n      }\n\n      if (dispatchState.endLoopRequested) {\n        agent.setStatusInternal('idle');\n        yield { kind: 'final' };\n        return;\n      }\n      continue;\n    }\n\n    // Fallback: streaming disabled, or parser bailed before any\n    // action dispatched. Parse the full envelope and run the dispatch\n    // loop sequentially.\n    const turn = parseTurnResponse(agentTurnCall.arguments);\n    if (!turn) {\n      errorCount += 1;\n      const result: ActionResult = { ok: false, reason: 'unknown', message: 'invalid agent_turn envelope' };\n      console.warn('[dddk webagent] turn parse failed', {\n        rawArguments: agentTurnCall.arguments,\n      });\n      recordParseFail(agentTurnCall.arguments);\n      pushAgentStep(session, {\n        toolCall: { name: AGENT_TURN_TOOL, arguments: agentTurnCall.arguments },\n        toolCallId: agentTurnCall.id,\n        result,\n      });\n      agent.persistSessionInternal();\n      yield { kind: 'tool-end', name: AGENT_TURN_TOOL, result, toolCallId: agentTurnCall.id };\n      if (errorCount >= agent.configRef.maxErrors) { agent.setStatusInternal('failed'); return; }\n      continue;\n    }\n\n    const turnSummary: Record<string, unknown> = {\n      turn: stepIdx + 1,\n      url: session.currentPage,\n      memory: turn.memory,\n    };\n    if (turn.todos_remaining !== undefined) turnSummary.todos_remaining = turn.todos_remaining;\n    if (turn.turn_planning) turnSummary.turn_planning = turn.turn_planning;\n    if (turn.todo_adjust) turnSummary.todo_adjust = turn.todo_adjust;\n    if (session.plan) {\n      turnSummary.master_todos = session.plan.todos.map((t) => `${t.id}:${t.intent}:${t.description}`);\n    }\n    turnSummary.actions = turn.actions.map((a) => {\n      if (isNarrateAction(a)) {\n        return { narrate: a.narrate.length > 100 ? a.narrate.slice(0, 100) + '…' : a.narrate };\n      }\n      return { tool: (a as { tool: string }).tool, args: (a as { args?: unknown }).args };\n    });\n    if (turn.is_final) turnSummary.is_final = true;\n    console.info('[dddk webagent] turn', turnSummary);\n    recordTurn(turnSummary, turn);\n\n    // Apply todo_adjust mutations BEFORE dispatching actions.\n    if (turn.todo_adjust && session.plan) {\n      if (turn.todo_adjust.remove?.length) {\n        for (const id of turn.todo_adjust.remove) {\n          session.plan.todos = session.plan.todos.filter((t) => t.id !== id);\n        }\n      }\n      if (turn.todo_adjust.replace?.length) {\n        for (const r of turn.todo_adjust.replace) {\n          const idx = session.plan.todos.findIndex((t) => t.id === r.id);\n          if (idx < 0) continue;\n          session.plan.todos[idx] = {\n            ...session.plan.todos[idx]!,\n            description: r.new_description,\n            ...(r.new_intent ? { intent: r.new_intent } : {}),\n          };\n        }\n      }\n      agent.persistSessionInternal();\n    }\n\n    // Legacy-mode orphan-tool normalisation.\n    if (turn.todos_remaining !== undefined && turn.todos_remaining.length === 0 && turn.actions.length > 0) {\n      const hasNarrate = turn.actions.some((a) => isNarrateAction(a));\n      if (!turn.is_final && !hasNarrate) {\n        if (typeof console !== 'undefined') {\n          console.info('[dddk webagent] todos empty + actions has only tools without is_final → ' + turn.actions.length + ' queued actions normalized away; loop ends');\n        }\n        turn.actions = [];\n      }\n    }\n\n    if (turn.actions.length === 0) {\n      pushAgentStep(session, {\n        toolCall: { name: AGENT_TURN_TOOL, arguments: agentTurnCall.arguments },\n        toolCallId: agentTurnCall.id,\n        result: {\n          ok: true,\n          data: {\n            memory: turn.memory,\n            todos_remaining: turn.todos_remaining,\n            action_count: 0,\n            action_results: [],\n          },\n        },\n      });\n      agent.persistSessionInternal();\n      agent.setStatusInternal('idle');\n      yield { kind: 'final' };\n      return;\n    }\n\n    // Dispatch each action via the shared helper. Same DispatchState\n    // shape as the streaming path so the finalisation block below is\n    // common.\n    for (let ai = 0; ai < turn.actions.length; ai++) {\n      if (signal.aborted) { agent.setStatusInternal('idle'); return; }\n      if (dispatchState.pageChanged) break;\n      yield* dispatchOneAction(\n        agent,\n        signal,\n        stepIdx,\n        ai,\n        turn.actions[ai] as never,\n        dispatchState,\n        { skipNarrateTypewriter: false },\n      );\n    }\n\n    if (turn.is_final && !dispatchState.executedReactionRequiringTool) {\n      dispatchState.actionResults.push({ type: 'done' });\n      dispatchState.endLoopRequested = true;\n    } else if (turn.is_final && dispatchState.executedReactionRequiringTool) {\n      console.warn('[dddk webagent] dropping is_final=true — turn included a reaction-requiring tool; the run is not actually finished yet');\n    }\n\n    const envelopeData = {\n      memory: turn.memory,\n      todos_remaining: turn.todos_remaining,\n      action_results: dispatchState.actionResults,\n      page_changed: dispatchState.pageChanged,\n    };\n    pushAgentStep(session, {\n      toolCall: { name: AGENT_TURN_TOOL, arguments: agentTurnCall.arguments },\n      toolCallId: agentTurnCall.id,\n      result: dispatchState.actionErrorThisTurn === 0\n        ? { ok: true, data: envelopeData }\n        : { ok: false, reason: 'unknown', message: JSON.stringify(envelopeData) },\n    });\n    agent.persistSessionInternal();\n\n    if (dispatchState.actionErrorThisTurn > 0) {\n      errorCount += 1;\n      if (errorCount >= agent.configRef.maxErrors) {\n        agent.setStatusInternal('failed');\n        return;\n      }\n    } else {\n      errorCount = 0;\n    }\n\n    if (dispatchState.endLoopRequested) {\n      agent.setStatusInternal('idle');\n      yield { kind: 'final' };\n      return;\n    }\n  }\n\n  // maxSteps hit. Yield `final` so the orchestrator's closure hook still\n  // renders the closing UI.\n  agent.setStatusInternal('failed');\n  yield { kind: 'final' };\n}\n","/**\n * Default `url` context provider.\n *\n * Emits the current path + query + hash, one line. The runtime\n * splices this into the per-turn prompt's location context.\n *\n * Hosts override via `webagent.registerContextProvider('url', fn)` —\n * useful when a SPA represents routes outside `location.pathname`\n * (e.g. fragment-only routing, query-encoded view state).\n */\n\nimport type { ContextProvider } from '../types';\n\nexport const defaultUrlProvider: ContextProvider = () => {\n  if (typeof location === 'undefined') return null;\n  return location.pathname + location.search + location.hash;\n};\n","/**\n * Default `page_summary` context provider.\n *\n * Emits `<title>` + `<meta name=\"description\">` content, one line\n * each. The runtime uses this so the LLM knows what the page is\n * \"for\" without scanning the whole DOM.\n *\n * Hosts override when the page's real summary lives in app state\n * (e.g. a single-page editor where `<title>` is generic and the\n * actual document title is in a React store).\n */\n\nimport type { ContextProvider } from '../types';\n\nexport const defaultPageSummaryProvider: ContextProvider = () => {\n  if (typeof document === 'undefined') return null;\n  const title = document.title?.trim() || null;\n  const metaDesc = document.querySelector<HTMLMetaElement>('meta[name=\"description\"]')?.content?.trim() || null;\n  if (!title && !metaDesc) return null;\n  const lines: string[] = [];\n  if (title) lines.push(`TITLE: ${truncate(title, 200)}`);\n  if (metaDesc) lines.push(`DESCRIPTION: ${truncate(metaDesc, 400)}`);\n  return lines.join('\\n');\n};\n\nfunction truncate(s: string, max: number): string {\n  if (s.length <= max) return s;\n  return s.slice(0, max - 1) + '…';\n}\n","/**\n * Default `dom` context provider.\n *\n * Wraps the SDK's `readDOM` — same logic the runtime calls inline\n * today. Hosts who want different DOM serialization (filtered scope,\n * smaller token budget, custom indexing rules) override via\n * `webagent.registerContextProvider('dom', fn)`.\n *\n * Caveat: the runtime's internal `currentIndexMap` (the map from\n * `[3]`-style indices back to live elements for selector resolution)\n * is owned by the runtime's direct `readDOM` call, NOT by this\n * provider. Currently the runtime continues to use its own\n * `readDOM` invocation for that path; the provider is consulted\n * only where the runtime is being migrated. A host that overrides\n * the dom provider AND wants the runtime to actually consult it\n * will need to wait for the upcoming runtime patch (tracked in\n * docs/v0.2.0-task-agent-and-multi-instance.md).\n *\n * For now the provider is useful for:\n *   - Inspecting what the runtime would land in the prompt\n *     (`agent.contextProviders.get('dom')?.(req)`).\n *   - Composing with other tools (e.g. you want to ship the DOM\n *     dump to an audit log alongside the agent prompt).\n */\n\nimport type { ContextProvider } from '../types';\nimport { readDOM } from '../dom-reader';\n\nexport const defaultDomProvider: ContextProvider = () => {\n  if (typeof document === 'undefined') return null;\n  const result = readDOM();\n  return result.text;\n};\n","/**\n * Default `screenshot` context provider.\n *\n * Returns the viewport as a data-URL PNG. Lazy-resolves\n * `captureScreenshots` from the SDK's screenshot module so this\n * file doesn't pull the html2canvas peer dep until a host actually\n * asks for a screenshot.\n *\n * Returns `null` when:\n *   - There's no `document` (SSR / Node).\n *   - `html2canvas` is missing (silent — matches the runtime's\n *     existing screenshot-config behavior).\n *\n * Hosts override when the page is canvas / WebGL based and the\n * default rasterizer can't capture it — e.g. they already have a\n * scene-graph snapshot and just want to hand it off as a data URL.\n */\n\nimport type { ContextProvider } from '../types';\nimport { captureScreenshots } from '../screenshot';\n\nexport const defaultScreenshotProvider: ContextProvider = async () => {\n  if (typeof document === 'undefined') return null;\n  try {\n    const images = await captureScreenshots({ mode: 'viewport' });\n    return images.length > 0 ? images[0]! : null;\n  } catch {\n    return null;\n  }\n};\n","/**\n * Default `history` context provider.\n *\n * Pulls recent paths from `window.history` — best-effort only. The\n * History API doesn't expose the actual stack to JS, so this\n * provider returns the current entry plus whatever sessionStorage\n * trail the SDK may have stamped during earlier navigations.\n *\n * Hosts with a real router (React Router, Vue Router, SvelteKit)\n * override to surface the actual app-level route history, including\n * route NAMES (not just paths) — `webagent.registerContextProvider('history', fn)`.\n */\n\nimport type { ContextProvider } from '../types';\n\nconst TRAIL_KEY = 'dddk.history.trail';\nconst TRAIL_MAX = 10;\n\n/**\n * Default trail tracker: hosts that don't push to the trail get an\n * empty list. The orchestrator's navigation handler can wire calls\n * to `recordNavigation(path)` to keep the trail filled.\n */\nexport function recordNavigation(path: string): void {\n  if (typeof sessionStorage === 'undefined') return;\n  try {\n    const raw = sessionStorage.getItem(TRAIL_KEY);\n    const trail: string[] = raw ? (JSON.parse(raw) as string[]) : [];\n    if (trail[trail.length - 1] === path) return; // dedupe consecutive duplicates\n    trail.push(path);\n    while (trail.length > TRAIL_MAX) trail.shift();\n    sessionStorage.setItem(TRAIL_KEY, JSON.stringify(trail));\n  } catch {\n    /* quota / disabled */\n  }\n}\n\nexport const defaultHistoryProvider: ContextProvider = () => {\n  if (typeof sessionStorage === 'undefined') return null;\n  try {\n    const raw = sessionStorage.getItem(TRAIL_KEY);\n    if (!raw) return null;\n    const trail = JSON.parse(raw) as string[];\n    if (!Array.isArray(trail) || trail.length === 0) return null;\n    return `RECENT_PATHS:\\n${trail.map((p, i) => `  ${i + 1}. ${p}`).join('\\n')}`;\n  } catch {\n    return null;\n  }\n};\n","/**\n * Default `selection` context provider.\n *\n * Returns the live `window.getSelection()` text (if any) so the\n * agent can ground its next action on what the user just\n * highlighted. The runtime independently captures Dwell-anchored\n * selections; this provider is the OS-level selection fallback.\n *\n * Hosts override when the editable layer is non-standard — e.g. a\n * canvas-based editor that maintains its own selection model.\n */\n\nimport type { ContextProvider } from '../types';\n\nexport const defaultSelectionProvider: ContextProvider = () => {\n  if (typeof window === 'undefined') return null;\n  const sel = window.getSelection?.();\n  if (!sel || sel.isCollapsed) return null;\n  const text = sel.toString().trim();\n  if (!text) return null;\n  return `SELECTION: ${text.length > 500 ? text.slice(0, 499) + '…' : text}`;\n};\n","/**\n * Default context providers for the six `ContextRole` slots WebAgent\n * recognises. SDK installs these into `webagent.contextProviders`\n * lazily in the constructor; hosts replace any single slot via\n * `webagent.registerContextProvider(role, fn)` — the registration\n * automatically restores the SDK default on `handle.remove()`.\n *\n * v0.2.0.\n */\n\nimport type { ContextProvider, ContextRole } from '../types';\nimport { defaultUrlProvider } from './url';\nimport { defaultPageSummaryProvider } from './page-summary';\nimport { defaultDomProvider } from './dom';\nimport { defaultScreenshotProvider } from './screenshot';\nimport { defaultHistoryProvider, recordNavigation } from './history';\nimport { defaultSelectionProvider } from './selection';\n\nexport {\n  defaultUrlProvider,\n  defaultPageSummaryProvider,\n  defaultDomProvider,\n  defaultScreenshotProvider,\n  defaultHistoryProvider,\n  defaultSelectionProvider,\n  recordNavigation,\n};\n\n/**\n * Lookup table — `getDefaultContextProvider('url')` returns the\n * SDK default for that slot. Use this when you want to compose with\n * the default (e.g. wrap it with extra logging) rather than replace\n * it outright.\n */\nexport const DEFAULT_CONTEXT_PROVIDERS: Readonly<Record<ContextRole, ContextProvider>> = Object.freeze({\n  url:           defaultUrlProvider,\n  page_summary:  defaultPageSummaryProvider,\n  dom:           defaultDomProvider,\n  screenshot:    defaultScreenshotProvider,\n  history:       defaultHistoryProvider,\n  selection:     defaultSelectionProvider,\n});\n\nexport function getDefaultContextProvider(role: ContextRole): ContextProvider {\n  return DEFAULT_CONTEXT_PROVIDERS[role];\n}\n","/**\n * WebAgent — DOM-grounded narrator agent.\n *\n * Public surface: constructor / configure (via setter helpers) / runStream\n * / continueStream / resumeStream / session lifecycle / handler setters.\n *\n * Loop bodies, message assembly, and `__dddkDebug` writes live under\n * ./runtime so this file stays focused on state + public API. The runtime\n * modules consume the agent through `@internal` accessors below.\n */\n\nimport type {\n  WebAgentConfig,\n  AgentSession,\n  AgentEvent,\n  ActionDefinition,\n  RunOptions,\n  SelectionContext,\n  AgentStatus,\n  ToolHandle,\n  ContextProvider,\n  ContextProviderHandle,\n  ContextRole,\n} from './types';\nimport type { ToolDefinition, ToolCall } from '../llm/types';\nimport {\n  createSession,\n  loadSession,\n  saveSession,\n  clearSession,\n  pushUserTurn,\n  isSessionLive,\n  shouldAutoResume,\n  DEFAULT_SESSION_KEY,\n} from './session';\nimport { coreActions, presentSurface } from './actions';\nimport { setupCrossTabSync, publishCrossTab } from './cross-tab';\nimport { DEFAULT_DESTRUCTIVE_PATTERNS, isDestructiveByPattern } from './destructive';\nimport {\n  buildAgentTurnTool,\n  type CotToolRef,\n} from './cot';\nimport type {\n  AskUserPayload,\n  AskUserChoicePayload,\n  PausePayload,\n  PresentSurfacePayload,\n} from './execute-action';\nimport { executeLoop, executeCotLoop } from './runtime/loops';\nimport { emptyStream } from './runtime/helpers';\nimport { DEFAULT_CONTEXT_PROVIDERS } from './context-providers';\n\nconst DEFAULT_MAX_STEPS = 30;\nconst DEFAULT_MAX_ERRORS = 3;\nconst DEFAULT_LLM_TIMEOUT_MS = 60_000;\n// Default = 0 (cross-query continuity OFF). Within ONE user query\n// the agent's loop already carries memory / master_todos across all\n// its internal turns — that's the loop, not \"continuity\". Continuity\n// is about the NEXT user query reusing the prior query's session;\n// almost nobody wants that by default. Hosts building chat-style\n// follow-up agents opt in by setting e.g. 60_000.\nconst DEFAULT_CONTINUITY_MS = 0;\n\n/**\n * Per-LLM-call performance sample emitted to the orchestrator after each\n * streaming call. The orchestrator decorates with `runId` and forwards as\n * an `agent_llm_call` IntentEvent for the analytics dashboard.\n */\nexport interface LlmCallInfo {\n  role: 'webagent' | 'vision';\n  /** Time-to-first-token in ms (request issued → first non-empty delta). */\n  ttftMs: number;\n  /** Total stream wall-time in ms (request issued → final chunk). */\n  durationMs: number;\n  /** Provider-reported output tokens (if available). */\n  outputTokens?: number;\n  /** Provider-reported input tokens (if available). */\n  inputTokens?: number;\n  /** Resolved model id, when the provider exposes it. */\n  model?: string;\n}\n\ntype ResolvedConfig = WebAgentConfig & Required<Pick<\n  WebAgentConfig,\n  'locale' | 'maxSteps' | 'maxErrors' | 'llmTimeoutMs' | 'agentName' |\n  'sessionStorageKey' | 'sessionContinuityMs' | 'sessionScope'\n>>;\n\nexport class WebAgent {\n  /** @internal */ config: ResolvedConfig;\n  /** @internal */ actions: Map<string, ActionDefinition> = new Map();\n  /** @internal */ session: AgentSession | null = null;\n  /**\n   * True when the host injected a `session` via config — disables\n   * the agent's own auto-create / auto-load + auto-persist paths\n   * because the session is owned upstream (typically `dddk.sessions`).\n   * @internal\n   */\n  private sessionInjected = false;\n  /** @internal */ currentSelection: SelectionContext | null = null;\n  /** @internal */ currentIndexMap: Map<string, Element> = new Map();\n  /** @internal */ navigateBridge: ((path: string) => void | Promise<void>) | null = null;\n  /** @internal */ llmCallListener: ((info: LlmCallInfo) => void) | null = null;\n  /** @internal */ askUserHandler: ((payload: AskUserPayload) => void) | null = null;\n  /** @internal */ askUserChoiceHandler: ((payload: AskUserChoicePayload) => void) | null = null;\n  /** @internal */ pauseHandler: ((payload: PausePayload) => void) | null = null;\n  /** @internal */ surfaceMounter: ((payload: PresentSurfacePayload) => void) | null = null;\n\n  private currentAbort: AbortController | null = null;\n  private pendingResolvers: Map<string, (raw: string) => void> = new Map();\n  private pendingOrder: string[] = [];\n  private broadcastChannel: BroadcastChannel | null = null;\n  private crossTabKey: string;\n  private pendingCounter = 0;\n  private destructivePatterns: RegExp[];\n  /** Host signalled \"end continuity now\" — next runStream() starts fresh. */\n  private continuityEnded = false;\n\n  constructor(config: WebAgentConfig) {\n    // Spread input FIRST so the defaults below win for any property the\n    // host left undefined. Locale auto-detect from navigator.language is\n    // a starting guess only; the prompt's language framing makes the\n    // user's actual input language override the hint every turn.\n    this.config = {\n      ...config,\n      locale:\n        config.locale ??\n        ((typeof navigator !== 'undefined' && navigator.language?.startsWith('zh')\n          ? 'zh-TW'\n          : 'en')),\n      maxSteps: config.maxSteps ?? DEFAULT_MAX_STEPS,\n      maxErrors: config.maxErrors ?? DEFAULT_MAX_ERRORS,\n      llmTimeoutMs: config.llmTimeoutMs ?? DEFAULT_LLM_TIMEOUT_MS,\n      agentName: config.agentName ?? 'Agent',\n      sessionStorageKey: config.sessionStorageKey ?? DEFAULT_SESSION_KEY,\n      sessionContinuityMs: config.sessionContinuityMs ?? DEFAULT_CONTINUITY_MS,\n      sessionScope: config.sessionScope ?? 'time',\n    };\n\n    // Tool exclusion: legacy `disableBuiltinActions` is an alias for the\n    // new `excludeTools` field as of v0.2.0. Union both sets.\n    const excluded = new Set([\n      ...(config.disableBuiltinActions ?? []),\n      ...(config.excludeTools ?? []),\n    ]);\n    if (\n      typeof console !== 'undefined' &&\n      config.disableBuiltinActions !== undefined &&\n      config.disableBuiltinActions.length > 0\n    ) {\n      // One-line deprecation notice. Removed in v0.3.0.\n      console.warn(\n        '[dddk] `disableBuiltinActions` is deprecated since v0.2.0; rename to `excludeTools` (and consider `disableAutoPauseAfterNarrate` to control the runtime auto-pause separately).',\n      );\n    }\n    // v0.2.0 — default install is `coreActions` (navigate / click /\n    // border / scroll_to). Form, flow, and extra bundles are opt-in\n    // via `customActions`. Hosts who want the v0.1 \"all installed\"\n    // behaviour pass `customActions: builtinActions`. `excludeTools`\n    // operates on whatever ended up installed (core ± opt-ins).\n    for (const action of coreActions) {\n      if (!excluded.has(action.name)) this.actions.set(action.name, action);\n    }\n    // present_surface is opt-in: registered only when the host enables it\n    // AND wires setSurfaceMounter. Still honours the exclusion set.\n    if (config.allowPresent && !excluded.has(presentSurface.name)) {\n      this.actions.set(presentSurface.name, presentSurface as ActionDefinition);\n    }\n    for (const action of config.customActions ?? []) this.actions.set(action.name, action);\n\n    this.destructivePatterns = config.destructivePatterns ?? DEFAULT_DESTRUCTIVE_PATTERNS;\n\n    // Host injected a shared session — adopt it as the initial session\n    // and stop the agent from auto-loading / auto-replacing it. This is\n    // the entry point for multi-instance session sharing.\n    if (config.session) {\n      this.session = config.session;\n      this.sessionInjected = true;\n    }\n\n    // Install default context providers for all six roles. Hosts that\n    // call `registerContextProvider(role, fn)` swap the default out;\n    // calling `handle.remove()` later restores the default. The\n    // runtime hasn't been migrated to consult `contextProviders` for\n    // every slot yet (DOM still goes through `readDOM` directly to\n    // keep the index map intact); the providers are available for\n    // host-side inspection / extension regardless.\n    for (const [role, fn] of Object.entries(DEFAULT_CONTEXT_PROVIDERS) as Array<[ContextRole, ContextProvider]>) {\n      this.contextProviders.set(role, fn);\n    }\n\n    this.crossTabKey = `${this.config.sessionStorageKey}.crosstab`;\n    if (config.crossTabSync) {\n      this.broadcastChannel = setupCrossTabSync({\n        crossTabKey: this.crossTabKey,\n        getCurrentSessionId: () => this.session?.id,\n        isLocalRunActive: () => this.isRunning(),\n        getLocalUpdatedAt: () => this.session?.updatedAt,\n        adoptSession: (s) => { this.session = s; },\n      });\n    }\n  }\n\n  /**\n   * Context provider registry — one slot per `ContextRole`. SDK\n   * ships defaults (wired in v0.2.0); hosts can replace\n   * a single slot without re-implementing the others. v0.2.0.\n   */\n  /** @internal */ contextProviders: Map<ContextRole, ContextProvider> = new Map();\n\n  // ─── public API ─────────────────────────────────────────────────\n\n  /**\n   * Register a tool. Returns a `ToolHandle` so the host can later\n   * `handle.remove()` to unregister — useful when a feature module\n   * is unmounted and its tool should disappear with it.\n   *\n   * Backward compat: the return value was `void` in v0.1; the\n   * `ToolHandle` shape is additive so existing callers ignoring the\n   * return keep working unchanged.\n   *\n   * Live semantics: the in-flight step finishes on its frozen action\n   * snapshot, the next step / turn sees the new entry. There is no\n   * \"this turn must not see the new tool\" guarantee — the action\n   * map is read at each step boundary.\n   */\n  registerAction(action: ActionDefinition): ToolHandle {\n    this.actions.set(action.name, action);\n    return {\n      remove: () => { this.actions.delete(action.name); },\n    };\n  }\n\n  /** Alias for `registerAction` — symmetric with `registerContextProvider`\n   *  + matches the \"tool\" wording the host-facing docs use. */\n  registerTool(tool: ActionDefinition): ToolHandle {\n    return this.registerAction(tool);\n  }\n\n  /**\n   * Explicit unregister by name. Returns `true` when an action was\n   * actually removed. Hosts who don't keep the `ToolHandle` around\n   * can call this instead. v0.2.0.\n   */\n  unregisterAction(name: string): boolean {\n    return this.actions.delete(name);\n  }\n\n  /**\n   * Replace the producer for one context slot (`url`, `page_summary`,\n   * `dom`, `screenshot`, `history`, `selection`). Returns a\n   * `ContextProviderHandle` that restores the previous binding on\n   * `remove()`. SDK defaults are installed lazily in v0.2.0;\n   * registering here before defaults are wired still works — the\n   * registered provider replaces the SDK default at lookup time.\n   */\n  registerContextProvider(role: ContextRole, provider: ContextProvider): ContextProviderHandle {\n    const previous = this.contextProviders.get(role);\n    this.contextProviders.set(role, provider);\n    let removed = false;\n    return {\n      remove: () => {\n        if (removed) return;\n        removed = true;\n        // Restore the prior binding (likely the SDK default) so\n        // un-mounting a host feature doesn't strand a stale provider.\n        if (previous) this.contextProviders.set(role, previous);\n        else this.contextProviders.delete(role);\n      },\n    };\n  }\n\n  /**\n   * Drop a registered provider for `role`. Returns `true` when one\n   * was removed. After removal, the SDK default (when present)\n   * applies at lookup time. v0.2.0.\n   */\n  unregisterContextProvider(role: ContextRole): boolean {\n    return this.contextProviders.delete(role);\n  }\n\n  /** Update the locale used for confirmation copy + system-prompt output\n   *  language hint. The currently-running turn keeps its prompt; the next\n   *  turn picks up the new locale. */\n  setLocale(locale: string): void {\n    this.config.locale = locale;\n  }\n\n  /** Set by the orchestrator — called when the agent picks `navigate`.\n   *  Hosts may return a Promise (most SPA routers do); the webagent\n   *  awaits it before declaring the navigation complete. */\n  setNavigateBridge(fn: (path: string) => void | Promise<void>): void {\n    this.navigateBridge = fn;\n  }\n\n  /** Orchestrator wires this to emit `agent_llm_call` IntentEvents. */\n  setLlmCallListener(fn: (info: LlmCallInfo) => void): void {\n    this.llmCallListener = fn;\n  }\n\n  getSession(): AgentSession | null {\n    return this.session;\n  }\n\n  clearSession(): void {\n    this.session = null;\n    this.continuityEnded = false;\n    // Injected mode: don't touch localStorage — the registry persists.\n    if (!this.sessionInjected) {\n      clearSession(this.config.sessionStorageKey);\n    }\n  }\n\n  /**\n   * Resolve a tool-call selector argument to a live element. Accepts\n   * either a numeric index from the latest indexed DOM dump (`3` /\n   * `\"3\"` / `\"[3]\"` / `\"↓3\"`) or a CSS selector string. Returns null\n   * for invalid CSS, unknown indexes, or pre-DOM (SSR) environments.\n   */\n  resolveSelector(target: string | number): Element | null {\n    if (typeof target === 'number') return this.currentIndexMap.get(String(target)) ?? null;\n    if (typeof target !== 'string') return null;\n    const trimmed = target.trim();\n    const m = /^[↑↓]?\\s*\\[?([A-Za-z0-9_-]+)\\]?$/.exec(trimmed);\n    if (m) {\n      const el = this.currentIndexMap.get(m[1]!);\n      if (el) return el;\n    }\n    if (typeof document === 'undefined') return null;\n    try { return document.querySelector(trimmed); } catch { return null; }\n  }\n\n  isRunning(): boolean {\n    if (!this.session) return false;\n    return this.session.status === 'thinking'\n      || this.session.status === 'executing'\n      || this.session.status === 'navigating'\n      || this.session.status === 'waiting';\n  }\n\n  /** End the continuity window now — next runStream() starts fresh. */\n  endContinuity(): void {\n    this.continuityEnded = true;\n  }\n\n  stop(): void {\n    if (this.currentAbort) {\n      this.currentAbort.abort('user_stopped');\n      this.currentAbort = null;\n    }\n    for (const id of this.pendingOrder) {\n      const r = this.pendingResolvers.get(id);\n      if (r) r('');\n    }\n    this.pendingResolvers.clear();\n    this.pendingOrder = [];\n    if (this.session) {\n      this.session.status = 'idle';\n      this.persistSessionInternal();\n    }\n  }\n\n  /**\n   * Soft stop the loop while keeping the session \"live\" so the next\n   * runStream(task) appends to it as a follow-up turn instead of starting\n   * fresh. Use when the user interrupts the agent to deliver a NEW prompt\n   * mid-task (palette open, voice hold) — naturally a continuation even\n   * if the prior task was abandoned.\n   *\n   * Differs from `stop()`: status is set to `waiting` (which counts as\n   * live in `isSessionLive`) instead of `idle`, so a host with\n   * `sessionContinuityMs: 0` still gets continuity across the intentional\n   * interrupt.\n   */\n  interruptForFollowup(): void {\n    if (this.currentAbort) {\n      this.currentAbort.abort('user_followup');\n      this.currentAbort = null;\n    }\n    for (const id of this.pendingOrder) {\n      const r = this.pendingResolvers.get(id);\n      if (r) r('');\n    }\n    this.pendingResolvers.clear();\n    this.pendingOrder = [];\n    if (this.session) {\n      this.session.status = 'waiting';\n      this.persistSessionInternal();\n    }\n  }\n\n  destroy(): void {\n    this.stop();\n    this.broadcastChannel?.close();\n    this.broadcastChannel = null;\n  }\n\n  /** Resolve the oldest pending host interaction (ask_user / ask_user_choice). */\n  respond(answer: string | Record<string, unknown>): void {\n    const id = this.pendingOrder.shift();\n    if (!id) return;\n    const resolver = this.pendingResolvers.get(id);\n    if (!resolver) return;\n    this.pendingResolvers.delete(id);\n    resolver(typeof answer === 'string' ? answer : JSON.stringify(answer));\n  }\n\n  /**\n   * Run a fresh task. If a session is still live within the continuity\n   * window AND `opts.freshSession` is not set, the task is appended as\n   * a follow-up user turn to the existing session instead.\n   */\n  runStream(task: string, opts: RunOptions = {}): AsyncIterable<AgentEvent> {\n    const currentPath = typeof location !== 'undefined' ? location.pathname + location.search : '/';\n\n    // Continuity / fresh-session logic only applies to agents that own\n    // their own session. Injected sessions are upstream-owned: the\n    // host (or `dddk.sessions.reset`) decides when a session ends,\n    // not this agent. We still respect an explicit `opts.freshSession`\n    // — that's a per-call override the host can pass through.\n    const fresh = this.sessionInjected\n      ? opts.freshSession === true || !this.session\n      : opts.freshSession === true || this.continuityEnded ||\n        !this.session ||\n        !isSessionLive(this.session, this.config.sessionContinuityMs) ||\n        (this.config.sessionScope === 'palette' && this.continuityEnded);\n\n    if (fresh) {\n      this.stop();\n      this.session = createSession(currentPath);\n      this.continuityEnded = false;\n    }\n\n    pushUserTurn(this.session!, { text: task, selection: opts.selection });\n    this.currentSelection = opts.selection ?? null;\n    this.persistSessionInternal();\n\n    return this.startLoop();\n  }\n\n  /** Force-append as a follow-up turn (no continuity check). */\n  continueStream(task: string, opts: RunOptions = {}): AsyncIterable<AgentEvent> {\n    return this.runStream(task, { ...opts, freshSession: false });\n  }\n\n  /**\n   * Resume a saved session — used by the host's onMount when the page\n   * reloaded mid-task or after SPA nav. Reads `loadSession()` first; if\n   * the loaded session has a non-terminal status AND its `currentPage`\n   * differs from the current URL, the loop picks back up.\n   */\n  resumeStream(): AsyncIterable<AgentEvent> {\n    if (!this.session) {\n      // Injected mode skips the localStorage lookup — the registry\n      // owns the session and will have already wired one in.\n      if (this.sessionInjected) return emptyStream();\n      const saved = loadSession(this.config.sessionStorageKey);\n      if (!saved) return emptyStream();\n      this.session = saved;\n    }\n    const currentPath = typeof location !== 'undefined' ? location.pathname + location.search : '/';\n    if (!shouldAutoResume(this.session, currentPath)) return emptyStream();\n    return this.startLoop();\n  }\n\n  // ─── handler wiring ─────────────────────────────────────────────\n\n  /** Orchestrator wires the UI route for ask_user. */\n  setAskUserHandler(fn: (payload: AskUserPayload) => void): void {\n    this.askUserHandler = fn;\n  }\n  setAskUserChoiceHandler(fn: (payload: AskUserChoicePayload) => void): void {\n    this.askUserChoiceHandler = fn;\n  }\n  /** Orchestrator wires the UI route for the `pause` tool. Default\n   *  behaviour (no handler set) falls back to the ask_user envelope. */\n  setPauseHandler(fn: (payload: PausePayload) => void): void {\n    this.pauseHandler = fn;\n  }\n  /** Orchestrator wires the host mounter for `present_surface`. The\n   *  mounter receives a PieceSurface + placement and renders the surface,\n   *  calling `resolve({ value, cancelled })` once the user picks or\n   *  dismisses. Only consulted when `allowPresent: true`. */\n  setSurfaceMounter(fn: (payload: PresentSurfacePayload) => void): void {\n    this.surfaceMounter = fn;\n  }\n\n  // ─── loop dispatch ──────────────────────────────────────────────\n\n  private startLoop(): AsyncIterable<AgentEvent> {\n    this.currentAbort = new AbortController();\n    return this.config.cotMode\n      ? executeCotLoop(this, this.currentAbort.signal)\n      : executeLoop(this, this.currentAbort.signal);\n  }\n\n  // ─── runtime-shared internals ───────────────────────────────────\n  // The runtime/* modules access these through their `*Ref` aliases\n  // declared below so the names stay short there without leaking into\n  // the public class API.\n\n  /** @internal */ get sessionRef(): AgentSession | null { return this.session; }\n  /** @internal */ get configRef(): ResolvedConfig { return this.config; }\n  /** @internal */ get actionsRef(): Map<string, ActionDefinition> { return this.actions; }\n  /** @internal */ get currentSelectionRef(): SelectionContext | null { return this.currentSelection; }\n  /** @internal */ get navigateBridgeRef(): ((path: string) => void | Promise<void>) | null { return this.navigateBridge; }\n  /** @internal */ get llmCallListenerRef(): ((info: LlmCallInfo) => void) | null { return this.llmCallListener; }\n  /** @internal */ get askUserHandlerRef(): ((payload: AskUserPayload) => void) | null { return this.askUserHandler; }\n  /** @internal */ get askUserChoiceHandlerRef(): ((payload: AskUserChoicePayload) => void) | null { return this.askUserChoiceHandler; }\n  /** @internal */ get pauseHandlerRef(): ((payload: PausePayload) => void) | null { return this.pauseHandler; }\n  /** @internal */ get surfaceMounterRef(): ((payload: PresentSurfacePayload) => void) | null { return this.surfaceMounter; }\n\n  /** @internal */\n  setStatusInternal(status: AgentStatus): void {\n    if (!this.session) return;\n    if (this.session.status === status) return;\n    this.session.status = status;\n    this.persistSessionInternal();\n  }\n\n  /** @internal */\n  persistSessionInternal(): void {\n    if (!this.session) return;\n    // Injected sessions are owned by `dddk.sessions` (or the host\n    // directly) — persisting per-agent would race a sibling agent's\n    // save under the same key. Skip the localStorage write; the\n    // upstream session registry is responsible. Cross-tab sync is\n    // also disabled in injected mode since the registry mediates.\n    if (this.sessionInjected) return;\n    saveSession(this.session, this.config.sessionStorageKey);\n    publishCrossTab(this.session, this.crossTabKey, this.broadcastChannel);\n  }\n\n  /** @internal */\n  registerPendingResolverInternal(resolver: (raw: string) => void): string {\n    const id = `pr_${++this.pendingCounter}_${Date.now().toString(36)}`;\n    this.pendingResolvers.set(id, resolver);\n    this.pendingOrder.push(id);\n    return id;\n  }\n\n  /** @internal */\n  async needsConfirmationInternal(\n    toolCall: ToolCall,\n    matched: ActionDefinition | undefined,\n    signal: AbortSignal,\n  ): Promise<boolean> {\n    if (!this.session) return false;\n    if (this.config.disableConfirmations) return false;\n    const explicit = matched?.requireConfirmation;\n    if (explicit === false) return false;\n    if (explicit === true) return true;\n    if (typeof explicit === 'function') {\n      try {\n        return await explicit(toolCall.arguments as never, {\n          session: this.session,\n          signal,\n          resolveTarget: (target: string | number) => {\n            if (typeof target === 'number') return this.currentIndexMap.get(String(target)) ?? null;\n            const trimmed = target.trim();\n            const m = /^\\[?([A-Za-z0-9_-]+)\\]?$/.exec(trimmed);\n            if (m) {\n              const el = this.currentIndexMap.get(m[1]!);\n              if (el) return el;\n            }\n            try { return document.querySelector(trimmed); } catch { return null; }\n          },\n        });\n      } catch {\n        return true; // fail-safe\n      }\n    }\n    return isDestructiveByPattern(toolCall.name, this.destructivePatterns);\n  }\n\n  /**\n   * Resolve the effective description for an action, applying any\n   * `actionOverrides` entry. Hard `description` wins over\n   * `appendDescription`; both unset returns the SDK default verbatim.\n   * Centralised so CoT (`buildCotToolRefs`) and classic (`buildToolDefinitions`)\n   * paths can't drift in override behaviour.\n   * @internal\n   */\n  resolveActionDescription(action: ActionDefinition): string {\n    const ov = this.config.actionOverrides?.[action.name];\n    if (!ov) return action.description;\n    if (typeof ov.description === 'string') return ov.description;\n    if (typeof ov.appendDescription === 'string' && ov.appendDescription.length > 0) {\n      return action.description + '\\n' + ov.appendDescription;\n    }\n    return action.description;\n  }\n\n  /**\n   * Build the CoT tool reference list once per turn. Skipped from the\n   * model's reference:\n   *   - `pause` — CoT auto-pauses after every narrate; exposing the tool\n   *     invites double-pauses.\n   *   - `border` — element framing is done structurally via `narrate.about`\n   *     (runtime auto-borders). Exposing the standalone tool creates two\n   *     ways to do the same thing and the model picks inconsistently.\n   *\n   * Actions still live in `this.actions` so internal dispatch\n   * (narrate.about, legacy executeLoop, host customActions) keeps working.\n   * @internal\n   */\n  buildCotToolRefs(): CotToolRef[] {\n    const refs: CotToolRef[] = [];\n    for (const action of this.actions.values()) {\n      if (action.name === 'pause' || action.name === 'border') continue;\n      refs.push({\n        name: action.name,\n        description: this.resolveActionDescription(action),\n        parameters: action.parameters,\n      });\n    }\n    return refs;\n  }\n\n  /** @internal */\n  buildToolDefinitions(): ToolDefinition[] {\n    if (this.config.toolDefinitions) return this.config.toolDefinitions;\n\n    if (this.config.cotMode) {\n      return [buildAgentTurnTool(this.buildCotToolRefs(), { planned: !!this.session?.plan })];\n    }\n\n    // Classic (non-CoT) mode: each action becomes a top-level tool.\n    const defs: ToolDefinition[] = [];\n    for (const action of this.actions.values()) {\n      defs.push({\n        name: action.name,\n        description: this.resolveActionDescription(action),\n        parameters: action.parameters,\n      });\n    }\n    return defs;\n  }\n}\n","/**\n * Agent subsystem — every LLM-driven engine in dddk lives here.\n *\n *   webagent/  — the DOM-grounded autonomous loop (read DOM → pick tool → act)\n *   inline/    — InlineAgent for editing text inside inputs / contenteditables\n *   llm/       — providers (OpenAI / Google / Proxy), router, adapter registry\n *   sitemap/   — sitemap tree + helpers + runtime SitemapLearner\n *   memory/    — long-term recall layer (BM25 over verbatim drawers)\n *   cursor.ts  — visible cursor overlay that previews each agent action\n *\n * Reachable from hosts via `@perhapxin/dddk/agent` (tree-shake friendly) or\n * from the root `@perhapxin/dddk` re-exports.\n */\n\n// ─── WebAgent (DOM-grounded loop) ──────────────────────────────────\n\nexport { WebAgent } from './webagent/webagent';\n\n// streaming envelope parser, public so adapters\n// and tests can feed it tool-call args deltas.\nexport { StreamingEnvelopeParser } from './webagent/runtime/streaming-envelope';\nexport type { EnvelopeStreamEvent } from './webagent/runtime/streaming-envelope';\n\nexport {\n  border,\n  highlight,\n  spotlight,\n  inject,\n  removeOverlay,\n  clearOverlays,\n  listOverlays,\n} from './webagent/overlay';\n\nexport { readDOM, type DomReadOptions } from './webagent/dom-reader';\n\nexport {\n  // v0.2.0 — bundled action sets. Default install = `coreActions`;\n  // opt in to the rest via `customActions`. `builtinActions` is the\n  // union (back-compat). See actions.ts for the picking guide.\n  coreActions,\n  formActions,\n  flowActions,\n  extraActions,\n  builtinActions,\n  // Individual opt-in action exports — registered via `customActions`.\n  escalateToHuman,\n  trackIntent,\n  workflowActions,\n  validateForm,\n  waitUntil,\n} from './webagent/actions';\n\n// form widget adapter registry\nexport {\n  registerFormWidget,\n  unregisterFormWidget,\n  listFormWidgets,\n  findFormWidget,\n} from './webagent/form-widgets';\nexport type {\n  FormWidgetAdapter,\n  FormWidgetFillContext,\n} from './webagent/form-widgets';\n\nexport type {\n  WebAgentConfig,\n  AgentSession,\n  AgentTurn,\n  UserTurn,\n  AgentStepTurn,\n  AgentFinalTurn,\n  AgentStatus,\n  AgentEvent,\n  ActionDefinition,\n  ActionResult,\n  ActionFailureReason,\n  ActionContext,\n  SitemapEntry,\n  SitemapConfig,\n  OverlayItem,\n  OverlayType,\n  PiecePlacement,\n  RunOptions,\n  SelectionContext,\n} from './webagent/types';\n\nexport { DEFAULT_DESTRUCTIVE_PATTERNS } from './webagent/destructive';\n\nexport type { ScreenshotConfig, ScreenshotMode } from './webagent/screenshot';\nexport { captureScreenshots } from './webagent/screenshot';\n\nexport type {\n  BrandPrompt,\n  PromptContext,\n  SystemPromptOverride,\n} from './webagent/prompt';\n\n// ─── Inline agent ──────────────────────────────────────────────────\n\nexport {\n  InlineAgent,\n  type InlineAgentConfig,\n  type InlineAction,\n  type InlineScopeConfig,\n  type ScopeHandle,\n  type ScopeResolver,\n} from './inline';\n\nexport type {\n  ToolHandle,\n  ContextProvider,\n  ContextProviderHandle,\n  ContextRole,\n  ContextRequest,\n} from './webagent/types';\n\nexport { TaskAgent } from './task';\nexport type { TaskAgentConfig, TaskRunOptions, TaskTool } from './task';\n\nexport {\n  defaultUrlProvider,\n  defaultPageSummaryProvider,\n  defaultDomProvider,\n  defaultScreenshotProvider,\n  defaultHistoryProvider,\n  defaultSelectionProvider,\n  recordNavigation,\n  DEFAULT_CONTEXT_PROVIDERS,\n  getDefaultContextProvider,\n} from './webagent/context-providers';\n\n// ─── Agent cursor (visual layer) ───────────────────────────────────\n\nexport { AgentCursor, type AgentCursorConfig } from './cursor';\n\n// ─── Sitemap ───────────────────────────────────────────────────────\n\nexport {\n  serializeSitemap,\n  resolvePath,\n  searchSitemap,\n  listAuthGatedPaths,\n  SAAS_SITEMAP_TEMPLATE,\n} from './sitemap/helpers';\nexport type { SitemapNode, SitemapResolution } from './sitemap/types';\nexport { buildSitemap } from './sitemap/build';\nexport type { NavTarget, BuildSitemapOpts } from './sitemap/build';\nexport {\n  SitemapLearner,\n  type SitemapLearnerOptions,\n  type SitemapLearnerStorage,\n} from './sitemap/learner';\n\n// ─── Memory (agent's long-term recall + 3-tier hybrid memory) ──────\n\nexport {\n  Memory,\n  CoreMemory,\n  EpisodicMemory,\n  SemanticMemory,\n  DrawerMemory,\n  createDrawerMemory,\n  // unified facade\n  UnifiedMemory,\n  createUnifiedMemory,\n} from './memory';\nexport type {\n  MemoryConfig, CoreMemoryConfig, CoreMemorySchema, CoreFieldType,\n  EpisodicMemoryConfig, EpisodicEntry,\n  SemanticMemoryConfig, SemanticMemoryEntry, MemoryProvider,\n  MemoryPrivacyConfig,\n  Drawer, DrawerMemoryOpts, DrawerSearchOpts,\n  // unified facade types\n  UnifiedMemoryConfig, RememberOpts, RecallResult,\n} from './memory';\n\n// ─── Plan (LLM-mediated structured artifact module) ────────────────\n// Standalone module — owns `todos` (used by webagent.planner) +\n// `markdown` artifacts. Attach with `plan.attachTo(dddk)` then wire\n// `webagent.planner: (input) => plan.makeTodos(input)`.\nexport {\n  Plan,\n  TodosArtifact,\n  MarkdownArtifact,\n  type PlanConfig,\n  type PlanInput,\n  type TaskPlan,\n  type TodoItem,\n  type MarkdownDoc,\n  type PlanSnapshot,\n  type PlanStorageAdapter,\n} from './plan';\n","/**\n * form widget adapter registry.\n *\n * Real product forms wrap their inputs in UI-library widgets:\n * react-select, antd Select, MUI Autocomplete, headless-ui Listbox,\n * Chakra DatePicker. The actual <input> behind the widget is hidden\n * or proxied through a custom handler, so the SDK's `fill_input` /\n * `select_option` defaults (set .value + dispatch input event) don't\n * actually update the widget's internal state.\n *\n * This registry lets a host plug in matchers + fillers for the\n * widget libraries their product actually uses. The runtime walks\n * registered widgets in priority order BEFORE the default fill path;\n * first match wins.\n *\n *   import { registerFormWidget } from '@perhapxin/dddk';\n *   registerFormWidget({\n *     id: 'react-select',\n *     priority: 100,\n *     match: (el) => el.closest('.react-select__control') != null,\n *     fill: async (el, value, ctx) => {\n *       const control = el.closest('.react-select__control')!;\n *       control.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));\n *       await ctx.wait(60);\n *       const opt = [...document.querySelectorAll('.react-select__option')]\n *         .find((o) => o.textContent?.trim() === value);\n *       opt?.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));\n *       return opt != null;\n *     },\n *   });\n *\n * The default fallback (set .value + dispatch input) is unchanged for\n * vanilla <input> / <textarea> / <select> — only non-trivial widgets\n * need adapters.\n */\n\nexport interface FormWidgetFillContext {\n  /** Polite delay between DOM events. Always use this, not setTimeout,\n   *  so the agent's abort signal can interrupt long fills. */\n  wait(ms: number): Promise<void>;\n  /** Async fill triggered by an agent — for sub-fill on dependent fields. */\n  signal: AbortSignal;\n}\n\nexport interface FormWidgetAdapter {\n  /** Stable id — same string overwrites prior registration. */\n  id: string;\n  /** Higher priority wins when multiple match. Default 0. */\n  priority?: number;\n  /** Predicate: does this adapter own this input element? */\n  match(el: Element): boolean;\n  /** Fill the widget. Return true if the value landed. */\n  fill(el: Element, value: string, ctx: FormWidgetFillContext): Promise<boolean>;\n}\n\nconst widgets = new Map<string, FormWidgetAdapter>();\n\nexport function registerFormWidget(adapter: FormWidgetAdapter): void {\n  widgets.set(adapter.id, adapter);\n}\n\nexport function unregisterFormWidget(id: string): boolean {\n  return widgets.delete(id);\n}\n\nexport function listFormWidgets(): FormWidgetAdapter[] {\n  return Array.from(widgets.values()).sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));\n}\n\n/**\n * Find the first registered adapter that matches `el` (by priority),\n * or null if no custom widget applies — caller falls back to the default\n * `.value + input event` path.\n */\nexport function findFormWidget(el: Element): FormWidgetAdapter | null {\n  for (const adapter of listFormWidgets()) {\n    try {\n      if (adapter.match(el)) return adapter;\n    } catch {\n      // Adapter match threw — skip it and keep walking. A broken adapter\n      // shouldn't poison the whole fill chain.\n    }\n  }\n  return null;\n}\n","// Shared CSS for the inline-effects primitives — processing line + diff panel.\n// Injected once via injectScopedStyle (idempotent). UI_ATTR scopes everything so\n// host page styles don't bleed in or out.\n\nimport { injectScopedStyle, UI_ATTR } from '../../utils/dom';\n\nexport { UI_ATTR };\nexport const STYLE_ID = 'dddk-inline-effects-style';\n\nexport function ensureInlineEffectsStyles(): void {\n  injectScopedStyle(STYLE_ID, `\n    /* Processing line — a slim \"AI is working\" indicator anchored under the\n       line being edited. Pure presentational; the host positions it. */\n    [${UI_ATTR}=\"processing-line\"] {\n      position: absolute;\n      display: inline-flex; align-items: center; gap: 8px;\n      padding: 6px 10px;\n      background: var(--dddk-bg-elevated, #fff);\n      border: 1px dashed var(--dddk-accent-soft-border, rgba(99,102,241,0.35));\n      border-radius: var(--dddk-radius, 10px);\n      box-shadow: var(--dddk-shadow-sm, 0 2px 8px rgba(0,0,0,0.06));\n      font-family: var(--dddk-font, system-ui, sans-serif);\n      font-size: 12px; color: var(--dddk-text-muted, #6b6b6b);\n      z-index: var(--dddk-z-bar, 9700);\n      pointer-events: none;\n      animation: dddk-pl-fadein 120ms ease;\n    }\n    [${UI_ATTR}=\"processing-line\"] .pl-spinner {\n      width: 12px; height: 12px;\n      border: 1.5px solid var(--dddk-border, rgba(0,0,0,0.15));\n      border-top-color: var(--dddk-accent, #6366f1);\n      border-radius: 50%;\n      animation: dddk-pl-spin 0.8s linear infinite;\n    }\n    [${UI_ATTR}=\"processing-line\"] .pl-label { white-space: nowrap; }\n    @keyframes dddk-pl-spin { to { transform: rotate(360deg); } }\n    @keyframes dddk-pl-fadein { from { opacity: 0; transform: translateY(-2px); } to { opacity: 1; transform: none; } }\n\n    /* Inline diff panel — strikethrough old + new + action toolbar + optional\n       chat composer for follow-up edits. Anchored to a host-supplied rect. */\n    [${UI_ATTR}=\"inline-diff\"] {\n      position: absolute;\n      display: flex; flex-direction: column; gap: 8px;\n      min-width: 280px; max-width: min(92vw, 480px);\n      padding: 10px 12px 10px 14px;\n      background: var(--dddk-bg-elevated, #fff);\n      border: 1px solid var(--dddk-border, rgba(0,0,0,0.1));\n      border-radius: var(--dddk-radius, 10px);\n      box-shadow: var(--dddk-shadow-md, 0 12px 36px rgba(0,0,0,0.18));\n      font-family: var(--dddk-font, system-ui, sans-serif);\n      font-size: 13px; color: var(--dddk-text, #18181b);\n      z-index: var(--dddk-z-bar, 9700);\n      animation: dddk-pl-fadein 120ms ease;\n    }\n    /* Mascot signature — small duck watermark in the top-right corner\n       of the inline-diff panel. Signals \"this rewrite is from your\n       duck\", reinforces the surface's brand identity. Uses the shared\n       avatar URL var; absent when host hasn't wired it. */\n    [${UI_ATTR}=\"inline-diff\"]::before {\n      content: '';\n      position: absolute;\n      top: 6px; right: 8px;\n      width: 16px; height: 16px;\n      background-image: var(--dddk-avatar-url, none);\n      background-size: contain;\n      background-repeat: no-repeat;\n      background-position: center;\n      opacity: 0.55;\n      pointer-events: none;\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-history {\n      display: flex; flex-direction: column; gap: 4px;\n      padding-bottom: 6px; margin-bottom: 2px;\n      border-bottom: 1px dashed var(--dddk-border, rgba(0,0,0,0.08));\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-history-chip {\n      display: flex; align-items: center; gap: 6px;\n      font-size: 11px; color: var(--dddk-text-muted, #6b6b6b);\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-history-chip::before {\n      content: '↳';\n      color: var(--dddk-text-faint, #a8a8a8);\n      flex: 0 0 auto;\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-history-prompt {\n      flex: 1; min-width: 0;\n      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-history-toggle {\n      align-self: flex-start;\n      padding: 2px 6px; margin-bottom: 2px;\n      background: transparent; border: 0; border-radius: 4px;\n      color: var(--dddk-text-muted, #6b6b6b);\n      font: inherit; font-size: 10.5px; cursor: pointer;\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-history-toggle:hover {\n      background: var(--dddk-bg-soft, rgba(0,0,0,0.04));\n      color: var(--dddk-text, #18181b);\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-diff {\n      display: block; max-height: 280px; overflow-y: auto;\n      padding: 8px 10px;\n      background: var(--dddk-bg-soft, rgba(0,0,0,0.02));\n      border-radius: 6px; line-height: 1.5;\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-old {\n      color: var(--dddk-text-faint, #9b9b9b);\n      text-decoration: line-through; text-decoration-thickness: 1px;\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-new {\n      color: var(--dddk-accent, #6366f1);\n      font-weight: 500;\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-new-streaming::after {\n      content: '▍';\n      display: inline-block;\n      margin-left: 1px;\n      animation: dddk-pl-blink 1s steps(2) infinite;\n      color: var(--dddk-accent, #6366f1);\n    }\n    @keyframes dddk-pl-blink { to { opacity: 0; } }\n    [${UI_ATTR}=\"inline-diff\"] .id-arrow {\n      display: inline-block; margin: 0 6px;\n      color: var(--dddk-text-faint, #9b9b9b);\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-actions {\n      display: flex; align-items: center; gap: 4px;\n      flex-wrap: wrap;\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-btn {\n      display: inline-flex; align-items: center; gap: 5px;\n      padding: 5px 10px;\n      background: transparent; border: 1px solid var(--dddk-border, rgba(0,0,0,0.12));\n      border-radius: 6px;\n      color: var(--dddk-text, #18181b);\n      font: inherit; font-size: 12px;\n      cursor: pointer;\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-btn:hover {\n      background: var(--dddk-bg-soft, rgba(0,0,0,0.04));\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-btn[data-primary] {\n      background: var(--dddk-accent, #6366f1);\n      border-color: var(--dddk-accent, #6366f1);\n      color: var(--dddk-accent-on, #fff);\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-btn[data-primary]:hover {\n      filter: brightness(0.95);\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-btn[disabled] { opacity: 0.5; cursor: not-allowed; }\n    [${UI_ATTR}=\"inline-diff\"] .id-spacer { flex: 1; }\n    [${UI_ATTR}=\"inline-diff\"] .id-composer {\n      display: flex; gap: 6px; align-items: center;\n      padding-top: 8px;\n      border-top: 1px solid var(--dddk-border, rgba(0,0,0,0.08));\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-input {\n      flex: 1; min-width: 0;\n      padding: 6px 9px;\n      background: var(--dddk-bg-soft, rgba(0,0,0,0.03));\n      border: 1px solid var(--dddk-border, rgba(0,0,0,0.1));\n      border-radius: 6px;\n      color: var(--dddk-text, #18181b);\n      font: inherit; font-size: 12px;\n      outline: none;\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-input:focus {\n      border-color: var(--dddk-accent, #6366f1);\n    }\n    [${UI_ATTR}=\"inline-diff\"] .id-spinner {\n      width: 11px; height: 11px;\n      border: 1.5px solid var(--dddk-border, rgba(0,0,0,0.15));\n      border-top-color: var(--dddk-accent, #6366f1);\n      border-radius: 50%;\n      animation: dddk-pl-spin 0.8s linear infinite;\n      flex: 0 0 auto;\n    }\n  `);\n}\n","// mountInlineDiff — present an AI edit as a diff (strikethrough old + new) with\n// an action toolbar and optional chat composer for follow-up prompts. The host\n// decides what to do with each user choice via the returned promise / callbacks.\n//\n// Designed for \"user selected a span, AI edited it, before committing show\n// what would happen\" — works for plain text inputs (perhapxin's doc editor)\n// and for richer surfaces (Tiptap leaves, contenteditable lines).\n\nimport { ensureInlineEffectsStyles } from './styles';\nimport { UI_ATTR } from '../../utils/dom';\nimport type { InlineChatTurn } from './chatSession';\n\nexport type InlineDiffOutcome =\n  | { kind: 'accept'; text: string }\n  | { kind: 'reject' }\n  | { kind: 'insert-after'; text: string }\n  | { kind: 'copy'; text: string }\n  | { kind: 'follow-up'; prompt: string };\n\nexport interface InlineDiffLabels {\n  /** Accept the AI edit and commit it. Default 'Accept'. */\n  accept?: string;\n  /** Reject the AI edit and restore the original. Default 'Reject'. */\n  reject?: string;\n  /** Insert AI result as new line AFTER the selection. Default 'Insert below'. */\n  insertAfter?: string;\n  /** Copy AI result. Default 'Copy'. */\n  copy?: string;\n  /** Prompt placeholder for follow-up. Default 'Make it shorter / formal / …'. */\n  followUpPlaceholder?: string;\n  /** Send follow-up button. Default 'Send'. */\n  send?: string;\n  /** History collapse toggle when hidden — `{n}` substitutes the hidden count.\n   *  Default 'Show {n} earlier edits'. */\n  expandHistory?: string;\n  /** History collapse toggle when expanded — `{n}` substitutes the hidden count.\n   *  Default 'Hide {n} earlier edits'. */\n  collapseHistory?: string;\n}\n\nexport interface InlineDiffOpts {\n  /** Anchor rect — usually the selection bounding box. */\n  rect: { left: number; top: number; bottom: number; width?: number };\n  /** Element to mount into. Default `document.body`. */\n  host?: HTMLElement;\n  /** Extra px below the anchor's bottom edge. Default 6. */\n  gap?: number;\n  /** Show the \"Insert below\" button. Default false. */\n  enableInsertAfter?: boolean;\n  /** Show the follow-up composer. Default true. */\n  enableFollowUp?: boolean;\n  /** UI strings — defaults are English. */\n  labels?: InlineDiffLabels;\n  /** Called for each user choice that does NOT close the panel\n   *  (`'follow-up'` while session is in chat mode). The panel waits for the\n   *  caller to settle the new text via `.applyNewText(newText)`. */\n  onFollowUp?: (prompt: string) => Promise<string | null>;\n  /** Fires the instant the user clicks Reject (or hits Escape) BEFORE the\n   *  result Promise settles. Use this to abort an in-flight stream so the\n   *  network call doesn't keep running after the user has decided to discard\n   *  the edit. Also fires on `.dispose()`. */\n  onCancel?: () => void;\n}\n\nexport interface InlineDiffHandle {\n  /** Re-anchor on scroll / resize. */\n  update(rect: { left: number; top: number; bottom: number }): void;\n  /** Replace the \"new\" text — used after a follow-up returns. */\n  applyNewText(newText: string): void;\n  /** Append a streamed chunk to the current \"new\" text. Used by the caller\n   *  during SSE — tokens land character by character, then `streamDone()`\n   *  flips the panel out of busy state. Safe to mix with `applyNewText` for\n   *  follow-up rounds (the next stream starts fresh from the new baseline). */\n  applyStreamChunk(chunk: string): void;\n  /** Mark the in-flight stream as finished. Re-enables follow-up + action\n   *  buttons. Idempotent. */\n  streamDone(): void;\n  /** Begin a fresh stream — clears the current \"new\" text and disables\n   *  buttons. Used at the start of EVERY follow-up so the user sees the\n   *  panel reset before the next stream lands. */\n  streamStart(): void;\n  /** Append a turn to the history chip stack above the diff. Used after a\n   *  successful follow-up to remind the user what they have asked so far. */\n  pushHistoryTurn(turn: InlineChatTurn): void;\n  /** Programmatically reject + dispose. */\n  dispose(): void;\n  /** Promise that resolves with the user's final decision (accept / reject /\n   *  insert-after / copy). Follow-up rounds keep the promise pending. */\n  result: Promise<Exclude<InlineDiffOutcome, { kind: 'follow-up' }>>;\n}\n\n/**\n * Show a strikethrough-old → new-text diff panel anchored under `rect`.\n * The promise resolves when the user picks a terminal action. Follow-up\n * prompts (chat continuation) are surfaced via `opts.onFollowUp`.\n */\nexport function mountInlineDiff(\n  oldText: string,\n  newText: string,\n  opts: InlineDiffOpts,\n): InlineDiffHandle {\n  ensureInlineEffectsStyles();\n  const host = opts.host ?? document.body;\n  const gap = opts.gap ?? 6;\n  const labels: Required<InlineDiffLabels> = {\n    accept: opts.labels?.accept ?? 'Accept',\n    reject: opts.labels?.reject ?? 'Reject',\n    insertAfter: opts.labels?.insertAfter ?? 'Insert below',\n    copy: opts.labels?.copy ?? 'Copy',\n    followUpPlaceholder: opts.labels?.followUpPlaceholder ?? 'Make it shorter / formal / …',\n    send: opts.labels?.send ?? 'Send',\n    expandHistory: opts.labels?.expandHistory ?? 'Show {n} earlier edits',\n    collapseHistory: opts.labels?.collapseHistory ?? 'Hide {n} earlier edits',\n  };\n\n  const el = document.createElement('div');\n  el.setAttribute(UI_ATTR, 'inline-diff');\n\n  // Optional history strip — populated by pushHistoryTurn() after each\n  // successful follow-up. The strip stays hidden until the first turn lands.\n  const history = document.createElement('div');\n  history.className = 'id-history';\n  history.style.display = 'none';\n  el.appendChild(history);\n\n  const diff = document.createElement('div');\n  diff.className = 'id-diff';\n  const oldSpan = document.createElement('span');\n  oldSpan.className = 'id-old';\n  oldSpan.textContent = oldText;\n  const arrow = document.createElement('span');\n  arrow.className = 'id-arrow';\n  arrow.textContent = '→';\n  const newSpan = document.createElement('span');\n  newSpan.className = 'id-new';\n  newSpan.textContent = newText;\n  diff.appendChild(oldSpan);\n  diff.appendChild(arrow);\n  diff.appendChild(newSpan);\n  el.appendChild(diff);\n\n  const actions = document.createElement('div');\n  actions.className = 'id-actions';\n  const acceptBtn = mkBtn(labels.accept, true);\n  const rejectBtn = mkBtn(labels.reject);\n  const insertBtn = opts.enableInsertAfter ? mkBtn(labels.insertAfter) : null;\n  const copyBtn = mkBtn(labels.copy);\n  actions.appendChild(acceptBtn);\n  actions.appendChild(rejectBtn);\n  if (insertBtn) actions.appendChild(insertBtn);\n  actions.appendChild(copyBtn);\n  el.appendChild(actions);\n\n  let composer: HTMLDivElement | null = null;\n  let input: HTMLInputElement | null = null;\n  let sendBtn: HTMLButtonElement | null = null;\n  let spinner: HTMLSpanElement | null = null;\n  if (opts.enableFollowUp !== false && opts.onFollowUp) {\n    composer = document.createElement('div');\n    composer.className = 'id-composer';\n    input = document.createElement('input');\n    input.className = 'id-input';\n    input.type = 'text';\n    input.placeholder = labels.followUpPlaceholder;\n    sendBtn = mkBtn(labels.send);\n    spinner = document.createElement('span');\n    spinner.className = 'id-spinner';\n    spinner.style.display = 'none';\n    composer.appendChild(input);\n    composer.appendChild(spinner);\n    composer.appendChild(sendBtn);\n    el.appendChild(composer);\n  }\n\n  host.appendChild(el);\n\n  const place = (r: { left: number; top: number; bottom: number }) => {\n    const scrollX = window.scrollX || window.pageXOffset || 0;\n    const scrollY = window.scrollY || window.pageYOffset || 0;\n    el.style.left = `${r.left + scrollX}px`;\n    el.style.top = `${r.bottom + scrollY + gap}px`;\n    // Clamp inside viewport on the right edge.\n    const rect = el.getBoundingClientRect();\n    const overflowR = rect.right - window.innerWidth + 8;\n    if (overflowR > 0) el.style.left = `${r.left + scrollX - overflowR}px`;\n  };\n  place(opts.rect);\n\n  let disposed = false;\n  let resolveOuter: (v: Exclude<InlineDiffOutcome, { kind: 'follow-up' }>) => void = () => {};\n  const result = new Promise<Exclude<InlineDiffOutcome, { kind: 'follow-up' }>>((res) => { resolveOuter = res; });\n\n  let currentNew = newText;\n  const finish = (out: Exclude<InlineDiffOutcome, { kind: 'follow-up' }>) => {\n    if (disposed) return;\n    disposed = true;\n    el.remove();\n    resolveOuter(out);\n  };\n\n  const cancel = (out: Exclude<InlineDiffOutcome, { kind: 'follow-up' }>) => {\n    try { opts.onCancel?.(); } catch { /* listener threw, still close */ }\n    finish(out);\n  };\n  acceptBtn.addEventListener('click', () => finish({ kind: 'accept', text: currentNew }));\n  rejectBtn.addEventListener('click', () => cancel({ kind: 'reject' }));\n  if (insertBtn) insertBtn.addEventListener('click', () => finish({ kind: 'insert-after', text: currentNew }));\n  copyBtn.addEventListener('click', async () => {\n    try { await navigator.clipboard.writeText(currentNew); } catch { /* ignore */ }\n    finish({ kind: 'copy', text: currentNew });\n  });\n\n  const sendFollowUp = async () => {\n    if (!input || !sendBtn || !spinner) return;\n    const prompt = input.value.trim();\n    if (!prompt) return;\n    input.value = '';\n    input.disabled = true;\n    sendBtn.disabled = true;\n    acceptBtn.disabled = true;\n    rejectBtn.disabled = true;\n    if (insertBtn) insertBtn.disabled = true;\n    copyBtn.disabled = true;\n    spinner.style.display = '';\n    try {\n      const next = await opts.onFollowUp!(prompt);\n      if (disposed) return;\n      if (next != null) {\n        currentNew = next;\n        newSpan.textContent = next;\n      }\n    } finally {\n      if (!disposed) {\n        input.disabled = false;\n        sendBtn.disabled = false;\n        acceptBtn.disabled = false;\n        rejectBtn.disabled = false;\n        if (insertBtn) insertBtn.disabled = false;\n        copyBtn.disabled = false;\n        spinner.style.display = 'none';\n        input.focus();\n      }\n    }\n  };\n  if (input && sendBtn) {\n    sendBtn.addEventListener('click', () => { void sendFollowUp(); });\n    input.addEventListener('keydown', (e) => {\n      if (e.key === 'Enter' && !e.isComposing) {\n        e.preventDefault();\n        void sendFollowUp();\n      }\n      if (e.key === 'Escape') cancel({ kind: 'reject' });\n    });\n  }\n\n  // How many recent history turns stay visible by default before the strip\n  // collapses to \"↳ N earlier ▼\". Click the toggle to expand back to all.\n  const HISTORY_VISIBLE = 3;\n  let historyExpanded = false;\n  let historyToggle: HTMLButtonElement | null = null;\n  const reflowHistory = () => {\n    const chips = Array.from(history.querySelectorAll<HTMLElement>('.id-history-chip'));\n    if (chips.length <= HISTORY_VISIBLE) {\n      if (historyToggle) {\n        historyToggle.remove();\n        historyToggle = null;\n      }\n      for (const c of chips) c.style.display = '';\n      return;\n    }\n    const hidden = chips.length - HISTORY_VISIBLE;\n    if (!historyToggle) {\n      historyToggle = document.createElement('button');\n      historyToggle.type = 'button';\n      historyToggle.className = 'id-history-toggle';\n      historyToggle.addEventListener('click', () => {\n        historyExpanded = !historyExpanded;\n        reflowHistory();\n      });\n      history.insertBefore(historyToggle, history.firstChild);\n    }\n    historyToggle.textContent = historyExpanded\n      ? `▲ ${labels.collapseHistory.replace('{n}', String(hidden))}`\n      : `▼ ${labels.expandHistory.replace('{n}', String(hidden))}`;\n    chips.forEach((c, i) => {\n      const fromEnd = chips.length - 1 - i;\n      c.style.display = historyExpanded || fromEnd < HISTORY_VISIBLE ? '' : 'none';\n    });\n  };\n\n  const setBusy = (busy: boolean) => {\n    acceptBtn.disabled = busy;\n    if (insertBtn) insertBtn.disabled = busy;\n    copyBtn.disabled = busy;\n    if (input) input.disabled = busy;\n    if (sendBtn) sendBtn.disabled = busy;\n    // Reject stays enabled so the user can always bail out.\n    if (busy) newSpan.classList.add('id-new-streaming');\n    else newSpan.classList.remove('id-new-streaming');\n  };\n\n  return {\n    update(nextRect) { if (!disposed) place(nextRect); },\n    applyNewText(text) {\n      if (disposed) return;\n      currentNew = text;\n      newSpan.textContent = text;\n    },\n    applyStreamChunk(chunk) {\n      if (disposed) return;\n      currentNew += chunk;\n      newSpan.textContent = currentNew;\n    },\n    streamStart() {\n      if (disposed) return;\n      currentNew = '';\n      newSpan.textContent = '';\n      setBusy(true);\n    },\n    streamDone() {\n      if (disposed) return;\n      setBusy(false);\n    },\n    pushHistoryTurn(turn) {\n      if (disposed) return;\n      const chip = document.createElement('div');\n      chip.className = 'id-history-chip';\n      const promptEl = document.createElement('span');\n      promptEl.className = 'id-history-prompt';\n      promptEl.textContent = turn.prompt;\n      chip.appendChild(promptEl);\n      history.appendChild(chip);\n      history.style.display = '';\n      // Collapse beyond N visible turns. The most recent N stay visible; older\n      // ones are hidden behind a \"show all\" toggle so the chip strip never\n      // grows past a comfortable height.\n      reflowHistory();\n      place(opts.rect);\n    },\n    dispose() { cancel({ kind: 'reject' }); },\n    result,\n  };\n}\n\nfunction mkBtn(label: string, primary?: boolean): HTMLButtonElement {\n  const b = document.createElement('button');\n  b.type = 'button';\n  b.className = 'id-btn';\n  if (primary) b.setAttribute('data-primary', '');\n  b.textContent = label;\n  return b;\n}\n","// InlineChatSession — minimal turn history for \"follow-up\" inline edits.\n// Keeps original selection + every (instruction, result) round, so a follow-up\n// prompt can reference prior context. The transport (LLM call) is host-supplied;\n// the session is just a state container.\n\nexport interface InlineChatTurn {\n  /** User prompt for this turn ('improve writing' for the initial, follow-ups thereafter). */\n  prompt: string;\n  /** AI text after this turn. */\n  result: string;\n}\n\nexport interface InlineChatSendArgs {\n  /** The original text the user selected (never changes across the session). */\n  original: string;\n  /** Every turn so far, oldest first. */\n  history: InlineChatTurn[];\n  /** The latest user prompt. */\n  prompt: string;\n}\n\nexport type InlineChatTransport = (args: InlineChatSendArgs) => Promise<string | null>;\n\nexport class InlineChatSession {\n  private readonly transport: InlineChatTransport;\n  private readonly original: string;\n  private readonly history: InlineChatTurn[] = [];\n\n  constructor(original: string, transport: InlineChatTransport) {\n    this.original = original;\n    this.transport = transport;\n  }\n\n  /** Current best result (the last turn's text, or the original if nothing yet). */\n  current(): string {\n    const last = this.history[this.history.length - 1];\n    return last ? last.result : this.original;\n  }\n\n  /** Send a follow-up prompt; on success records the turn and returns the new\n   *  text. Returns null on transport failure. */\n  async send(prompt: string): Promise<string | null> {\n    const result = await this.transport({\n      original: this.original,\n      history: this.history.slice(),\n      prompt,\n    });\n    if (result == null) return null;\n    this.history.push({ prompt, result });\n    return result;\n  }\n\n  /** Recorded turns (immutable copy). */\n  turns(): InlineChatTurn[] {\n    return this.history.slice();\n  }\n}\n","/**\n * Built-in i18n strings + default translate targets for InlineAgent.\n * Kept separate so the main module stays focused on UI / LLM wiring.\n */\n\nexport const I18N = {\n  en: {\n    header: 'EDIT WITH AI',\n    translate: 'Translate',\n    improve: 'Improve writing',\n    fix: 'Fix spelling & grammar',\n    shorter: 'Make shorter',\n    longer: 'Make longer',\n    tone: 'Change to professional tone',\n    explain: 'Explain this',\n    pickLanguage: 'Translate to…',\n    cancel: 'Cancel',\n    processing: 'Working…',\n    failed: 'Failed',\n    // inline-diff panel\n    accept: 'Accept',\n    reject: 'Reject',\n    insertAfter: 'Insert below',\n    copy: 'Copy',\n    followUpPlaceholder: 'Make it shorter / formal / translate…',\n    send: 'Send',\n  },\n  'zh-TW': {\n    header: '用 AI 編輯',\n    translate: '翻譯',\n    improve: '改寫',\n    fix: '修文法',\n    shorter: '縮短',\n    longer: '延長',\n    tone: '改成正式語氣',\n    explain: '解釋',\n    pickLanguage: '翻譯成…',\n    cancel: '取消',\n    processing: '處理中…',\n    failed: '失敗',\n    accept: '接受',\n    reject: '還原',\n    insertAfter: '插到下一行',\n    copy: '複製',\n    followUpPlaceholder: '再短一點 / 改正式語氣 / 翻譯⋯',\n    send: '送出',\n  },\n} as const;\n\nexport type InlineLocale = keyof typeof I18N;\nexport type InlineI18nKey = keyof typeof I18N['en'];\n\nexport const DEFAULT_TRANSLATE_TARGETS = [\n  { code: 'en',    label: 'English' },\n  { code: 'zh-TW', label: '繁體中文' },\n  { code: 'zh-CN', label: '简体中文' },\n  { code: 'ja',    label: '日本語' },\n  { code: 'ko',    label: '한국어' },\n  { code: 'es',    label: 'Español' },\n  { code: 'fr',    label: 'Français' },\n  { code: 'de',    label: 'Deutsch' },\n];\n","import { injectScopedStyle, UI_ATTR } from '../../utils/dom';\r\n\r\nexport { UI_ATTR };\r\nexport const STYLE_ID = 'dddk-inline-agent-style';\r\n\r\nexport function ensureInlineAgentStyles(): void {\r\n  injectScopedStyle(STYLE_ID, `\r\n    [${UI_ATTR}=\"inline-agent\"] {\r\n      position: absolute; display: none;\r\n      min-width: 220px; max-width: 280px;\r\n      background: var(--dddk-bg-elevated, #fff);\r\n      border: 1px solid var(--dddk-border, rgba(0,0,0,0.1));\r\n      border-radius: var(--dddk-radius, 10px);\r\n      box-shadow: var(--dddk-shadow-md, 0 8px 24px rgba(0,0,0,0.15));\r\n      padding: 6px;\r\n      z-index: var(--dddk-z-bar, 9700);\r\n      font-family: var(--dddk-font, system-ui, sans-serif);\r\n    }\r\n    /* Two-column layout — for hosts (note-taking apps etc.) that want a\r\n       column of formatting actions next to a column of AI actions. */\r\n    [${UI_ATTR}=\"inline-agent\"][data-layout=\"two-column\"] { max-width: 460px; }\r\n    [${UI_ATTR}=\"inline-agent\"] .ia-two-col {\r\n      display: grid; grid-template-columns: 1fr 1fr; gap: 4px;\r\n    }\r\n    [${UI_ATTR}=\"inline-agent\"] .ia-col {\r\n      display: flex; flex-direction: column; gap: 1px;\r\n    }\r\n    [${UI_ATTR}=\"inline-agent\"] .ia-col-label {\r\n      font-size: 10px; font-weight: 600;\r\n      letter-spacing: 0.06em; text-transform: uppercase;\r\n      color: var(--dddk-text-muted, #6b6b6b);\r\n      padding: 4px 8px 2px;\r\n    }\r\n    /* Toolbar layout — a horizontal, icon-only formatting bar anchored\r\n       above the selection (AFFiNE / Notion style). */\r\n    [${UI_ATTR}=\"inline-agent\"][data-layout=\"toolbar\"] {\r\n      min-width: 0; max-width: none; width: auto;\r\n      padding: 3px;\r\n    }\r\n    [${UI_ATTR}=\"inline-agent\"] .ia-toolbar {\r\n      flex-direction: row; align-items: center; gap: 2px;\r\n    }\r\n    [${UI_ATTR}=\"inline-agent\"] .ia-tool {\r\n      display: inline-flex; align-items: center; justify-content: center;\r\n      gap: 1px;\r\n      min-width: 30px; height: 30px; padding: 0 6px;\r\n      background: transparent; border: 0; cursor: pointer;\r\n      color: var(--dddk-text, #18181b);\r\n      font: inherit; font-size: 14px;\r\n      border-radius: 6px;\r\n    }\r\n    [${UI_ATTR}=\"inline-agent\"] .ia-tool:hover,\r\n    [${UI_ATTR}=\"inline-agent\"] .ia-tool[data-active] {\r\n      background: var(--dddk-accent-soft, rgba(99,102,241,0.1));\r\n    }\r\n    [${UI_ATTR}=\"inline-agent\"] .ia-tool .ia-icon {\r\n      width: auto; height: auto;\r\n      color: inherit;\r\n    }\r\n    [${UI_ATTR}=\"inline-agent\"] .ia-chevron {\r\n      font-size: 9px; line-height: 1;\r\n      color: var(--dddk-text-muted, #6b6b6b);\r\n      margin-left: 1px;\r\n    }\r\n    [${UI_ATTR}=\"inline-agent\"] .ia-toolbar-sep {\r\n      width: 1px; height: 18px; margin: 0 3px;\r\n      background: var(--dddk-border, rgba(0,0,0,0.12));\r\n      flex: 0 0 auto;\r\n    }\r\n    /* Dropdown sub-menu for toolbar dropdown buttons — vertical list,\r\n       anchored under the button. Reuses the .ia-submenu shell. */\r\n    [${UI_ATTR}=\"inline-agent\"].ia-submenu[data-dropdown] {\r\n      min-width: 160px; max-width: 240px; padding: 4px;\r\n    }\r\n    [${UI_ATTR}=\"inline-agent\"].ia-submenu { display: block; }\r\n    [${UI_ATTR}=\"inline-agent\"] .ia-header {\r\n      font-size: 10px; font-weight: 700;\r\n      letter-spacing: 0.08em; text-transform: uppercase;\r\n      color: var(--dddk-accent, #6366f1);\r\n      padding: 6px 8px 4px;\r\n    }\r\n    [${UI_ATTR}=\"inline-agent\"] .ia-list {\r\n      display: flex; flex-direction: column; gap: 1px;\r\n    }\r\n    [${UI_ATTR}=\"inline-agent\"] .ia-row {\r\n      display: flex; align-items: center; gap: 10px;\r\n      width: 100%; padding: 8px 10px;\r\n      background: transparent; border: 0; cursor: pointer;\r\n      color: var(--dddk-text, #18181b);\r\n      font: inherit; font-size: 13px;\r\n      border-radius: 6px;\r\n      text-align: left;\r\n    }\r\n    [${UI_ATTR}=\"inline-agent\"] .ia-row:hover,\r\n    [${UI_ATTR}=\"inline-agent\"] .ia-row[data-active] {\r\n      background: var(--dddk-accent-soft, rgba(99,102,241,0.1));\r\n    }\r\n    [${UI_ATTR}=\"inline-agent\"] .ia-icon {\r\n      display: inline-flex; align-items: center; justify-content: center;\r\n      width: 18px; height: 18px;\r\n      color: var(--dddk-accent, #6366f1);\r\n      font-size: 13px;\r\n    }\r\n  `);\r\n}\r\n","/**\n * InlineAgent scope registry.\n *\n * A \"scope\" is a per-region override of the root InlineAgent config: a\n * different action set, a different LLM, a different system prompt, a\n * different menu layout. Hosts attach scopes by CSS selector; when the\n * user makes a selection inside a matching element, the InlineAgent\n * resolves the innermost matching scope and uses its config instead of\n * the root config.\n *\n * Resolution flow per selection:\n *   1. If the host set a `scopeResolver` callback AND it returns a\n *      non-null config, that config wins (callback bypass).\n *   2. Else walk UP from the selection's anchor element. The FIRST\n *      ancestor that matches any registered selector is the innermost\n *      scope — its config wins.\n *   3. If nothing matches, the root config applies as before.\n *\n * Live registry — `attachScope` / `setScopeResolver` may be called at\n * any time. The next selection sees the new registration; an in-flight\n * menu doesn't change underneath the user.\n */\n\nimport type { ActionDefinition } from '../webagent/types';\nimport type { LLMSource } from '../llm/router';\n// Type-only import — TS erases this at runtime so the index ↔ scoping\n// cycle is purely a dependency-graph artifact, not a real module cycle.\nimport type { InlineAction } from './index';\n\n/**\n * Per-scope override. Every field is optional — what the scope doesn't\n * set inherits from the root InlineAgent config.\n */\nexport interface InlineScopeConfig {\n  /**\n   * Replace the action set for selections inside this scope. When set,\n   * the root's actions are NOT included — use `appendActions` instead\n   * if you want to extend rather than replace.\n   */\n  actions?: InlineAction[];\n  /**\n   * Append these actions AFTER the root actions (or after `actions`\n   * if this scope also sets that). Stacks cleanly with `disabledActions`\n   * for \"root actions minus some, plus my new ones\".\n   */\n  appendActions?: InlineAction[];\n  /**\n   * Drop root actions by id. Only meaningful when this scope doesn't\n   * set its own `actions` (because that already replaces the root set).\n   */\n  disabledActions?: string[];\n  /** Override the LLM used for runs initiated from this scope. */\n  llm?: LLMSource;\n  /**\n   * Replace the system prompt for runs from this scope. Use\n   * `appendSystemPrompt` if you want to keep the base prompt and add\n   * a tone / domain hint.\n   */\n  systemPrompt?: string;\n  /**\n   * Append text to the base system prompt. The base is whatever was\n   * effective WITHOUT the scope — either root's `systemPrompt` or the\n   * SDK default if root didn't set one. Combined: `${base}\\n\\n${append}`.\n   */\n  appendSystemPrompt?: string;\n  /** Override menu layout (single-column / two-column / toolbar). */\n  layout?: 'single-column' | 'two-column' | 'toolbar';\n  /** Override two-column header labels. */\n  columnLabels?: { col1?: string; col2?: string };\n  /** Override translate-target language list. */\n  translateTargets?: Array<{ code: string; label: string }>;\n  /**\n   * Override the tool-call layer. Setting this enables a tool-call\n   * loop for this scope even if the root has no tools; pass empty\n   * array to explicitly disable tools for this scope.\n   */\n  tools?: ActionDefinition[];\n}\n\n/** Handle returned by `attachScope`; lets the host unregister later. */\nexport interface ScopeHandle {\n  /** Remove this scope from the registry. Idempotent. */\n  remove(): void;\n}\n\n/**\n * Callback fallback for cases CSS selectors can't express (e.g.\n * \"selections longer than 1000 chars use the long-form scope\" or\n * \"any element inside a Shadow DOM uses the shadow scope\"). Return\n * `null` to fall through to selector matching.\n */\nexport type ScopeResolver = (selection: {\n  text: string;\n  element: HTMLElement;\n}) => InlineScopeConfig | null;\n\n/** Internal — what `attachScope` stores in the registry. */\nexport interface ScopeEntry {\n  id: string;\n  selector: string;\n  config: InlineScopeConfig;\n}\n\n/**\n * Resolve which scope (if any) applies to a selection anchored at\n * `element`. Returns the scope's config or `null` if no scope matches.\n *\n * Walk semantics: starts at `element` and walks UP through ancestors.\n * The FIRST ancestor that matches any registered selector wins —\n * that's the innermost scope by definition. Ties at the same DOM\n * depth are broken by registration order (earlier registration wins,\n * which matches the host's mental model of \"first wired first\").\n */\nexport function resolveInlineScope(\n  element: HTMLElement,\n  scopes: readonly ScopeEntry[],\n  resolver: ScopeResolver | undefined,\n  selectionText: string,\n): InlineScopeConfig | null {\n  // Callback bypass takes precedence — host knows things selectors can't.\n  if (resolver) {\n    const cb = resolver({ text: selectionText, element });\n    if (cb) return cb;\n  }\n  if (scopes.length === 0) return null;\n  // Walk up. The closest ancestor that matches any selector is the\n  // innermost scope — selector-based resolution.\n  let cur: HTMLElement | null = element;\n  while (cur) {\n    for (const scope of scopes) {\n      try {\n        if (cur.matches(scope.selector)) return scope.config;\n      } catch {\n        // Invalid selector — skip, don't crash the selection flow.\n      }\n    }\n    cur = cur.parentElement;\n  }\n  return null;\n}\n","/**\r\n * InlineAgent — inline AI menu for text inside editable surfaces\r\n * (`<input>`, `<textarea>`, `[contenteditable]`).\r\n *\r\n * UX:\r\n *   1. User selects text inside an editable.\r\n *   2. A small floating menu pops next to the selection (top-right).\r\n *   3. Menu stays visible while the selection is active. Scroll repositions\r\n *      it; the menu does NOT auto-hide on idle.\r\n *   4. User picks an action (mouse OR keyboard — Ctrl/Cmd+. opens the menu\r\n *      programmatically, arrows + Enter navigate).\r\n *   5. Selected text is replaced with the LLM's result.\r\n *\r\n * Actions are host-customizable:\r\n *   - `actions` config replaces the default set\r\n *   - `addAction` / `removeAction` / `updateAction` at runtime\r\n *   - Per-action `build()` returns the LLM instruction dynamically — used by\r\n *     the default Translate action to pick a target language via sub-menu.\r\n *\r\n * Output cleanup: a wrapper system prompt forces the LLM to return ONLY\r\n * the result between `<<<RESULT>>>` markers. We strip everything else.\r\n * Avoids \"thinking out loud\" / preamble leaking into the editable.\r\n */\r\n\r\nimport { resolveLLM, type LLMSource } from '../llm/router';\r\nimport type { ToolCall } from '../llm/types';\r\nimport type { StreamingProvider, StreamChunk } from '../llm/stream';\r\nimport {\r\n  mountInlineDiff,\r\n  InlineChatSession,\r\n  type InlineDiffHandle,\r\n} from '../../ui/inline-effects';\r\nimport type { ActionDefinition } from '../webagent/types';\r\nimport type { DotDotDuck } from '../../orchestrator';\r\nimport { escapeHtml } from '../../utils/dom';\r\nimport { I18N, DEFAULT_TRANSLATE_TARGETS } from './i18n';\r\nimport {\r\n  extractReplacement,\r\n  findEndMarker,\r\n  REPLACEMENT_END_VARIANTS,\r\n  buildContextPrompt,\r\n  REPLACEMENT_START,\r\n} from './parse';\r\nimport { PROMPT_IDS, promptRegistry } from '../../prompts/registry';\r\nimport { registerBuiltinPrompts } from '../../prompts/defaults';\r\n\r\n// Register SDK prompt defaults on module load. Idempotent.\r\nregisterBuiltinPrompts();\r\nimport { ensureInlineAgentStyles, UI_ATTR } from './styles';\r\nimport {\r\n  resolveInlineScope,\r\n  type InlineScopeConfig,\r\n  type ScopeHandle,\r\n  type ScopeResolver,\r\n  type ScopeEntry,\r\n} from './scoping';\r\n\r\nexport type { InlineScopeConfig, ScopeHandle, ScopeResolver } from './scoping';\r\n\r\nexport interface InlineAgentConfig {\r\n  llm: LLMSource;\r\n  /**\r\n   * Replace the entire default action set. When provided, defaults are\r\n   * NOT included. Use `appendActions` if you want to keep defaults +\r\n   * add your own, or `disabledActions` to drop specific defaults.\r\n   */\r\n  actions?: InlineAction[];\r\n  /**\r\n   * Append your actions AFTER the (filtered) defaults. Combine with\r\n   * `disabledActions` to keep some defaults, drop others, add your own.\r\n   */\r\n  appendActions?: InlineAction[];\r\n  /**\r\n   * Drop these default actions by id. Useful when you want most of the\r\n   * defaults but not, say, \"translate\". Default ids: translate / improve /\r\n   * fix / shorter / longer / tone / explain.\r\n   */\r\n  disabledActions?: string[];\r\n  /**\r\n   * Menu layout:\r\n   *  - `'single-column'` (default): one column, all actions stacked.\r\n   *  - `'two-column'`: two columns side-by-side. Each action's `row` (1 | 2)\r\n   *    decides which column it belongs to. Optional `rowLabel` on each\r\n   *    action surfaces a small header above the first action of that row.\r\n   *  - `'toolbar'`: a horizontal, icon-only formatting bar (AFFiNE / Notion\r\n   *    style) anchored ABOVE the selection, horizontally centred. No header.\r\n   *    Each action renders as a square icon button — its `label` becomes the\r\n   *    `title` / `aria-label` (no visible text). Use `group` to draw a thin\r\n   *    divider between adjacent actions of different groups (e.g. format /\r\n   *    block / AI). Use `kind: 'dropdown'` + `items` to collapse a cluster\r\n   *    (turn-into, AI rewrite/translate/summarise) behind a single button\r\n   *    that opens a vertical sub-menu on click.\r\n   *\r\n   * Two-column is the recommended layout for note-taking / editor hosts\r\n   * that want one column of formatting actions (Bold / Italic / H1 / Color)\r\n   * and another of AI actions (Translate / Improve / …).\r\n   */\r\n  layout?: 'single-column' | 'two-column' | 'toolbar';\r\n  /** Optional headers shown above column 1 / column 2 in `two-column` layout. */\r\n  columnLabels?: { col1?: string; col2?: string };\r\n  /**\r\n   * Locale for built-in i18n labels. Default `'en'`. SDK ships `'en'` and\r\n   * `'zh-TW'` translations; any other value falls back to `'en'` so the\r\n   * UI never breaks. Hosts that want native labels (`'ja'`, `'es'`, …)\r\n   * pass `actions` / `appendActions` with their own translated labels.\r\n   */\r\n  locale?: string;\r\n  /** Languages offered when the user picks Translate. Default: en / zh-TW / ja. */\r\n  translateTargets?: Array<{ code: string; label: string }>;\r\n  /** Auto-hide after this many ms with no selection change. `0` = never (default). */\r\n  hideAfterMs?: number;\r\n  /** CSS selector — never trigger inside elements matching this. */\r\n  ignoreSelector?: string;\r\n  /**\r\n   * Keyboard shortcut to open the menu when text is selected. Default `mod+.`\r\n   * Format: `mod+<key>` where `mod` = Ctrl on Win/Linux, Cmd on Mac.\r\n   * Alternative modifiers: `alt+<key>`, `shift+<key>`, combinations like\r\n   * `mod+alt+<key>`.\r\n   */\r\n  shortcut?: string;\r\n  /**\r\n   * Default `displayAs` for actions that don't set their own. Overrides\r\n   * the per-action default ('inline-diff' for rewrites, 'subtitle' for\r\n   * explain). Set to `'replace'` to restore the pre-0.3 instant-splice\r\n   * behaviour globally without editing every action's config.\r\n   */\r\n  defaultDisplayAs?: 'replace' | 'subtitle' | 'confirm' | 'inline-diff';\r\n  /**\r\n   * Override the system prompt sent to the LLM for inline edits. The\r\n   * default is universal (works for any input language — the LLM detects\r\n   * + replies in the same language) and enforces a strict JSON output\r\n   * shape (`{ replacement: string }`) so the host can splice the result\r\n   * back deterministically. Set this only if you need fully custom edit\r\n   * semantics — your prompt MUST still produce the same JSON shape or\r\n   * the splice will fail.\r\n   */\r\n  systemPrompt?: string;\r\n  /**\r\n   * Opt-in: type a prefix anywhere in an editable surface to fire an LLM\r\n   * call with the rest of the text as instruction. Default OFF — has to\r\n   * be enabled explicitly because it hijacks the input.\r\n   *\r\n   * Example: with `prefix: '/inline ai '` and `submitOn: 'enter'`, the\r\n   * user types `/inline ai write me a haiku about ducks` and presses\r\n   * Enter — the editable's whole value is replaced with the LLM result.\r\n   *\r\n   * Submit semantics:\r\n   *  - `'enter'` (default): plain Enter submits. Newlines in textareas\r\n   *    are NOT possible while a prefix is active.\r\n   *  - `'mod-enter'`: Cmd/Ctrl+Enter submits, Enter still adds a newline.\r\n   *  - `'double-newline'`: two consecutive `\\n` submit (typing two Enters).\r\n   */\r\n  prefixTrigger?: {\r\n    enabled: boolean;\r\n    prefix?: string;\r\n    minChars?: number;\r\n    submitOn?: 'enter' | 'mod-enter' | 'double-newline';\r\n    /** Show a \"AI will replace this\" confirmation step before commit. */\r\n    confirmBeforeReplace?: boolean;\r\n  };\r\n  /**\r\n   * Optional tool-call layer for inline-agent actions. **Default OFF.**\r\n   *\r\n   * When this array is non-empty the inline agent switches from a\r\n   * single-shot LLM call to a small tool-call loop. The LLM can call\r\n   * any tool listed here BEFORE producing the final `{ replacement }`\r\n   * JSON — useful for \"look up the customer in the CRM before\r\n   * rewriting\", \"fetch the glossary term before translating\", or any\r\n   * other host-side data fetch that should ground the answer.\r\n   *\r\n   * Tools follow webagent's `ActionDefinition` shape so anything you\r\n   * can hand to WebAgent works here unchanged. The loop stops as soon\r\n   * as the LLM produces content without a tool call, or after\r\n   * `maxToolRounds` rounds (safety cap).\r\n   *\r\n   * Leave undefined / empty to keep the original single-shot behaviour\r\n   * — no tool calls, no extra latency.\r\n   */\r\n  tools?: ActionDefinition[];\r\n  /**\r\n   * When `true` and `tools` is non-empty, the inline agent uses\r\n   * `dddk.subtitle` to narrate progress during the tool loop (\"Looking\r\n   * up customer record…\", \"Done — applying the rewrite\"). Requires\r\n   * `attachTo(dddk)` so the agent has a Subtitle handle. **Default false.**\r\n   */\r\n  enableSubtitle?: boolean;\r\n  /**\r\n   * Safety cap on the tool-call loop. Default `3`. Hosts with chained\r\n   * lookups (search → fetch → verify) may want 4-5.\r\n   */\r\n  maxToolRounds?: number;\r\n}\r\n\r\nexport interface InlineActionHandlerCtx {\r\n  text: string;\r\n  target: HTMLElement;\r\n  selection: { start: number; end: number };\r\n  agent: InlineAgent;\r\n}\r\n\r\nexport interface InlineAction {\r\n  id: string;\r\n  /** Visible label. Pass an `{ en, 'zh-TW' }` object for i18n. */\r\n  label: string | { en: string; 'zh-TW': string };\r\n  icon?: string;\r\n  /** Which column this action lives in when `layout: 'two-column'`. Default 1. Ignored in single-column. */\r\n  row?: 1 | 2;\r\n  /**\r\n   * `layout: 'toolbar'` only. A group key for visual clustering. A thin\r\n   * vertical divider is drawn between two adjacent toolbar buttons whose\r\n   * `group` differs — e.g. tag format actions `'format'`, block actions\r\n   * `'block'`, AI actions `'ai'` to get three visually separated clusters.\r\n   * Ignored in single / two-column layouts.\r\n   */\r\n  group?: string;\r\n  /**\r\n   * Action kind. Default `'button'` — runs the action directly.\r\n   * `'dropdown'` (toolbar layout) renders the button with a small chevron;\r\n   * clicking it opens a vertical sub-menu of `items` instead of running an\r\n   * action. Each item is itself an `InlineAction` and runs through the\r\n   * normal handler / build / instruction flow when picked.\r\n   */\r\n  kind?: 'button' | 'dropdown';\r\n  /**\r\n   * Sub-menu entries for a `kind: 'dropdown'` action. Each item runs through\r\n   * the same `runAction` pipeline (handler > build > instruction) when the\r\n   * user picks it. Lets a host fold a \"Turn into\" menu (H1 / H2 / bullet /\r\n   * quote, each with a `handler` that reformats the block) or an \"AI\" menu\r\n   * (rewrite / translate / summarise, each with an `instruction`) behind one\r\n   * toolbar button so the bar stays compact.\r\n   */\r\n  items?: InlineAction[];\r\n  /**\r\n   * Where to put the LLM result.\r\n   *  - `'replace'` (default): splice the result back over the user's\r\n   *    selection immediately. The canonical inline edit (Translate,\r\n   *    Rewrite, Fix grammar, …).\r\n   *  - `'subtitle'`: don't touch the editable. Show the result in the\r\n   *    subtitle bar — the right behaviour for actions like Explain /\r\n   *    Summarise / Define where the user wants info, not to destroy\r\n   *    their original text.\r\n   *  - `'confirm'`: show the result in the subtitle bar with accept /\r\n   *    reject buttons. ONLY on accept do we splice it back. Use this\r\n   *    for risky / opinionated edits where the user wants to preview\r\n   *    before commit. Space accepts, double-tap Space rejects (same as\r\n   *    every other subtitle action prompt).\r\n   *  - `'inline-diff'`: anchor a strikethrough-old → new diff panel under\r\n   *    the selection. Streams tokens into the panel; on accept splices into\r\n   *    the editable, on `insert-after` inserts as new text just after the\r\n   *    selection (use for translation), on copy writes to clipboard. The\r\n   *    panel carries a follow-up composer so the user can keep refining\r\n   *    (\"make it shorter\", \"more formal\") with full chat history grounded\r\n   *    on the original selection. Reject aborts the in-flight stream.\r\n   */\r\n  displayAs?: 'replace' | 'subtitle' | 'confirm' | 'inline-diff';\r\n  /**\r\n   * Static LLM instruction. Either set this OR `build` OR `handler`.\r\n   * Precedence: `handler` > `build` > `instruction`.\r\n   */\r\n  instruction?: string;\r\n  /**\r\n   * Dynamic instruction. Use this when you need to ask the user for more\r\n   * info first (e.g. Translate sub-menu picks a target language). Return\r\n   * `null` to cancel without running the LLM.\r\n   */\r\n  build?: (ctx: { text: string; agent: InlineAgent }) => Promise<string | null> | string | null;\r\n  /**\r\n   * Custom handler — runs INSTEAD of the LLM round-trip. Use for non-AI\r\n   * actions like \"wrap selection in **bold**\", \"insert markdown table\",\r\n   * \"change color via document.execCommand\". When defined, the LLM is\r\n   * not called. The handler can read selection text + boundary indices\r\n   * and mutate the editable directly.\r\n   */\r\n  handler?: (ctx: InlineActionHandlerCtx) => void | Promise<void>;\r\n}\r\n\r\nexport class InlineAgent {\r\n  private cfg: Required<Pick<InlineAgentConfig, 'locale' | 'hideAfterMs' | 'translateTargets' | 'layout' | 'enableSubtitle' | 'maxToolRounds'>>\r\n    & Pick<InlineAgentConfig, 'ignoreSelector' | 'llm' | 'columnLabels' | 'prefixTrigger' | 'systemPrompt' | 'tools' | 'defaultDisplayAs'>;\r\n  private llm: LLMSource;\r\n  private actions: InlineAction[];\r\n  private menu: HTMLDivElement | null = null;\r\n  private menuList: HTMLDivElement | null = null;\r\n  private subMenu: HTMLDivElement | null = null;\r\n  private currentEditable: HTMLElement | null = null;\r\n  private currentSelection: { text: string; start: number; end: number } | null = null;\r\n  private currentRect: DOMRect | null = null;\r\n  private hideTimer: ReturnType<typeof setTimeout> | null = null;\r\n  private cleanups: Array<() => void> = [];\r\n  private dddk: DotDotDuck | null = null;\r\n  private cursor = 0;\r\n  private enabled = true;\r\n  /** IME composing flag — `selectionchange` fires mid-composition for CJK\r\n   *  input. We suppress menu show/hide while composing to avoid flicker.\r\n   *  Set on `compositionstart`, cleared on `compositionend`. */\r\n  private isComposing = false;\r\n  /** Parsed shortcut spec (`{ ctrl, alt, shift, key }`) or `null`. */\r\n  private shortcutSpec: { ctrl?: boolean; alt?: boolean; shift?: boolean; key: string } | null = null;\r\n  /** In-flight run token — drops stale LLM results when the user fires a\r\n   *  second action before the first finishes. */\r\n  private runToken = 0;\r\n  /** Prefix-trigger state: tracks whether the focused editable is currently\r\n   *  in \"prefix mode\" (text starts with the configured prefix). */\r\n  private prefixActive = false;\r\n  /** Scope registry: per-selector config overrides set via `attachScope`. */\r\n  private scopes: ScopeEntry[] = [];\r\n  /** Optional callback fallback for cases selectors can't express. */\r\n  private scopeResolver?: ScopeResolver;\r\n  /** Snapshot of the scope that matched the current selection's anchor\r\n   *  element. `null` means \"no scope matched, use root config\". Refreshed\r\n   *  in `handleSelectionChange`, frozen for the lifetime of the menu so\r\n   *  an in-flight action sees the same scope as the menu that opened it. */\r\n  private activeScopeConfig: InlineScopeConfig | null = null;\r\n  /** Monotonic id for scope entries. */\r\n  private scopeIdCounter = 0;\r\n\r\n  constructor(config: InlineAgentConfig) {\r\n    this.cfg = {\r\n      llm: config.llm,\r\n      locale: config.locale ?? 'en',\r\n      hideAfterMs: config.hideAfterMs ?? 0,\r\n      translateTargets: config.translateTargets ?? DEFAULT_TRANSLATE_TARGETS,\r\n      ignoreSelector: config.ignoreSelector,\r\n      layout: config.layout ?? 'single-column',\r\n      columnLabels: config.columnLabels,\r\n      prefixTrigger: config.prefixTrigger,\r\n      systemPrompt: config.systemPrompt,\r\n      tools: config.tools && config.tools.length > 0 ? config.tools : undefined,\r\n      enableSubtitle: config.enableSubtitle ?? false,\r\n      maxToolRounds: config.maxToolRounds ?? 3,\r\n      defaultDisplayAs: config.defaultDisplayAs,\r\n    };\r\n    this.llm = config.llm;\r\n\r\n    // Action set assembly:\r\n    //   - `actions` (when provided) REPLACES defaults entirely.\r\n    //   - `disabledActions` filters specific defaults by id.\r\n    //   - `appendActions` adds to whatever remained after the above.\r\n    const base = config.actions ?? this.buildDefaultActions();\r\n    const filtered = config.disabledActions?.length\r\n      ? base.filter((a) => !config.disabledActions!.includes(a.id))\r\n      : base;\r\n    this.actions = config.appendActions?.length\r\n      ? [...filtered, ...config.appendActions]\r\n      : filtered;\r\n\r\n    // Parse keyboard shortcut. Format: `mod+<key>` / `alt+<key>` etc.\r\n    // `mod` resolves to Cmd on Mac, Ctrl elsewhere — checked at runtime\r\n    // via `e.metaKey || e.ctrlKey`. Default `mod+.` so the menu can be\r\n    // opened without a mouse selection (e.g. user typed something, wants\r\n    // to invoke AI without re-selecting it — they can just hit Cmd+.).\r\n    this.shortcutSpec = parseShortcut(config.shortcut ?? 'mod+.');\r\n  }\r\n\r\n  /**\r\n   * Switch the menu / dialog locale at runtime. Pass any BCP-47-ish tag —\r\n   * the bundled `en` / `zh-TW` translations are picked when they match;\r\n   * other tags fall back to `en`.\r\n   */\r\n  setLocale(locale: string): void {\r\n    this.cfg.locale = locale;\r\n    // Menu DOM was painted at mount time with the construction-time locale.\r\n    // Switching language (e.g. sidebar toggle) without refreshing leaves the\r\n    // header + row labels in the previous language.\r\n    if (this.menu) {\r\n      const header = this.menu.querySelector('.ia-header');\r\n      if (header) header.textContent = this.t('header');\r\n    }\r\n    this.refreshMenu();\r\n  }\r\n\r\n  private t(key: keyof typeof I18N['en']): string {\r\n    const dict = (I18N as unknown as Record<string, Record<string, string>>)[this.cfg.locale];\r\n    return dict?.[key] ?? I18N.en[key];\r\n  }\r\n\r\n  private buildDefaultActions(): InlineAction[] {\r\n    const t = (k: keyof typeof I18N['en']) => this.t(k);\r\n    return [\r\n      {\r\n        id: 'translate', icon: '文',\r\n        label: { en: I18N.en.translate, 'zh-TW': I18N['zh-TW'].translate },\r\n        // Dynamic — ask user for target language first.\r\n        build: async (ctx) => {\r\n          const target = await this.pickFromSubmenu(\r\n            this.t('pickLanguage'),\r\n            this.cfg.translateTargets.map((l) => ({ id: l.code, label: l.label })),\r\n          );\r\n          if (!target) return null;\r\n          return `Translate the text to ${target.label} (locale ${target.id}). Keep the same tone. Output only the translation. Source text:\\n\"\"\"\\n${ctx.text}\\n\"\"\"`;\r\n        },\r\n        // Translation flow: Insert-below is the obvious choice (keep original\r\n        // line, drop translation underneath) so default to inline-diff.\r\n        displayAs: 'inline-diff',\r\n      },\r\n      { id: 'improve', icon: '✦',\r\n        label: { en: I18N.en.improve, 'zh-TW': I18N['zh-TW'].improve },\r\n        instruction: `Rewrite to improve clarity, flow, and grammar. Keep the same meaning AND the same language. Output only the rewritten text.`,\r\n        displayAs: 'inline-diff',\r\n      },\r\n      { id: 'fix', icon: '✓',\r\n        label: { en: I18N.en.fix, 'zh-TW': I18N['zh-TW'].fix },\r\n        instruction: `Fix spelling and grammar. Do not change meaning, language, or style. Output only the corrected text.`,\r\n        displayAs: 'inline-diff',\r\n      },\r\n      { id: 'shorter', icon: '↤',\r\n        label: { en: I18N.en.shorter, 'zh-TW': I18N['zh-TW'].shorter },\r\n        // Aggressive shortening — the previous prompt (\"~30% shorter while\r\n        // keeping all key information\") asked the model to do two opposing\r\n        // things at once, so most outputs only trimmed a couple of filler\r\n        // words. We name concrete things to drop (hedging, repetition,\r\n        // examples, qualifiers) and set a HARD floor of \"at least half\".\r\n        instruction: `Aggressively shorten this text to AT MOST half its original length. Keep only the core point. Drop: filler words, hedging (\"perhaps\", \"I think\", \"可能\", \"或許\"), repetition, redundant clauses, examples, qualifiers, and any sentence that merely restates a previous one. If two sentences can be one, make it one. Keep the same language as the input. Output ONLY the shortened text — no preamble, no explanation, no quotes.`,\r\n        displayAs: 'inline-diff',\r\n      },\r\n      { id: 'longer', icon: '↦',\r\n        label: { en: I18N.en.longer, 'zh-TW': I18N['zh-TW'].longer },\r\n        instruction: `Expand the text with more detail and examples. Keep the same language. Output only the result.`,\r\n        displayAs: 'inline-diff',\r\n      },\r\n      { id: 'tone', icon: '◐',\r\n        label: { en: I18N.en.tone, 'zh-TW': I18N['zh-TW'].tone },\r\n        instruction: `Rewrite the text in a more professional, formal tone. Keep the same language. Output only the result.`,\r\n        displayAs: 'inline-diff',\r\n      },\r\n      { id: 'explain', icon: '?',\r\n        label: { en: I18N.en.explain, 'zh-TW': I18N['zh-TW'].explain },\r\n        instruction: `Explain the text in plain language as 2-3 short sentences. Keep the same language as the original. Output only the explanation.`,\r\n        // The user wants information about the selection, NOT to\r\n        // overwrite it. Show the explanation in the subtitle bar.\r\n        displayAs: 'subtitle',\r\n      },\r\n    ];\r\n  }\r\n\r\n  // ─── Lifecycle ──────────────────────────────────────────────\r\n\r\n  attachTo(dddk: DotDotDuck): void {\r\n    if (typeof document === 'undefined') return;\r\n    this.dddk = dddk;\r\n    ensureInlineAgentStyles();\r\n\r\n    const onSelChange = () => this.handleSelectionChange();\r\n    // Scroll: reposition the menu rather than hiding it.\r\n    const onScroll = () => this.repositionMenu();\r\n    const onMouseDown = (e: MouseEvent) => {\r\n      if (this.menu && e.target instanceof Element && !this.menu.contains(e.target)\r\n          && (!this.subMenu || !this.subMenu.contains(e.target))) {\r\n        // Click outside menu — but ONLY hide if user is no longer in an\r\n        // editable with selection (handleSelectionChange handles that on its\r\n        // own via the next `selectionchange` event).\r\n        // Defer to allow selectionchange to fire first.\r\n        setTimeout(() => this.maybeHide(), 0);\r\n      }\r\n    };\r\n    const onKey = (e: KeyboardEvent) => this.handleKey(e);\r\n    // IME guard: while the user is composing a CJK / accent character,\r\n    // `selectionchange` fires mid-composition and a half-typed character\r\n    // would trigger the menu to flash open/closed. Suppress show/hide\r\n    // entirely during composition.\r\n    const onCompStart = () => { this.isComposing = true; };\r\n    const onCompEnd = () => {\r\n      this.isComposing = false;\r\n      // Re-evaluate after composition ends — the final character may now\r\n      // satisfy the 2-char selection threshold.\r\n      this.handleSelectionChange();\r\n    };\r\n    // Shortcut listener — `mod+.` (default) opens the menu for the current\r\n    // selection without requiring `selectionchange` to have fired first.\r\n    const onShortcut = (e: KeyboardEvent) => this.handleShortcut(e);\r\n    // Prefix-trigger input listener (opt-in). Scans for the configured\r\n    // prefix in any focused editable's value on every `input`.\r\n    const onInput = (e: Event) => this.handlePrefixInput(e);\r\n\r\n    document.addEventListener('selectionchange', onSelChange);\r\n    document.addEventListener('scroll', onScroll, true);\r\n    document.addEventListener('mousedown', onMouseDown, true);\r\n    document.addEventListener('keydown', onKey);\r\n    document.addEventListener('compositionstart', onCompStart, true);\r\n    document.addEventListener('compositionend', onCompEnd, true);\r\n    document.addEventListener('keydown', onShortcut, true);\r\n    if (this.cfg.prefixTrigger?.enabled) {\r\n      document.addEventListener('input', onInput, true);\r\n    }\r\n    this.cleanups.push(\r\n      () => document.removeEventListener('selectionchange', onSelChange),\r\n      () => document.removeEventListener('scroll', onScroll, true),\r\n      () => document.removeEventListener('mousedown', onMouseDown, true),\r\n      () => document.removeEventListener('keydown', onKey),\r\n      () => document.removeEventListener('compositionstart', onCompStart, true),\r\n      () => document.removeEventListener('compositionend', onCompEnd, true),\r\n      () => document.removeEventListener('keydown', onShortcut, true),\r\n      () => document.removeEventListener('input', onInput, true),\r\n    );\r\n  }\r\n\r\n  destroy(): void {\r\n    for (const c of this.cleanups) c();\r\n    this.cleanups = [];\r\n    this.hide();\r\n    this.menu?.remove();\r\n    this.menu = null;\r\n    this.subMenu?.remove();\r\n    this.subMenu = null;\r\n  }\r\n\r\n  // ─── Public runtime customisation ───────────────────────────\r\n\r\n  /** Append a new action to the bottom of the menu. */\r\n  addAction(action: InlineAction): void {\r\n    this.actions.push(action);\r\n    this.refreshMenu();\r\n  }\r\n  /** Remove an action by id. */\r\n  removeAction(id: string): void {\r\n    this.actions = this.actions.filter((a) => a.id !== id);\r\n    this.refreshMenu();\r\n  }\r\n  /** Partial update of an existing action's fields. */\r\n  updateAction(id: string, patch: Partial<InlineAction>): void {\r\n    this.actions = this.actions.map((a) => (a.id === id ? { ...a, ...patch } : a));\r\n    this.refreshMenu();\r\n  }\r\n  /** Replace the entire action list. */\r\n  setActions(actions: InlineAction[]): void {\r\n    this.actions = actions;\r\n    this.refreshMenu();\r\n  }\r\n\r\n  // ─── Scoping ────────────────────────────────────────────────\r\n  // Per-selector overrides of the root config. Innermost-wins on the\r\n  // selection's anchor element; live registry — call `attachScope` /\r\n  // `setScopeResolver` any time, the next selection sees it.\r\n\r\n  /**\r\n   * Register a per-region override. Any selection whose anchor element\r\n   * matches `selector` (or has an ancestor that does) will use\r\n   * `config` instead of the root InlineAgent config. Innermost match\r\n   * wins when scopes nest.\r\n   *\r\n   * Returns a handle whose `remove()` unregisters the scope.\r\n   *\r\n   * ```ts\r\n   * const handle = inline.attachScope('[data-region=\"docs-comment\"]', {\r\n   *   actions: [translate, friendlyRewrite],\r\n   *   appendSystemPrompt: 'Tone: friendly, customer-facing.',\r\n   * });\r\n   * // …later\r\n   * handle.remove();\r\n   * ```\r\n   */\r\n  attachScope(selector: string, config: InlineScopeConfig): ScopeHandle {\r\n    const id = `scope-${++this.scopeIdCounter}`;\r\n    this.scopes.push({ id, selector, config });\r\n    return {\r\n      remove: () => {\r\n        const idx = this.scopes.findIndex((s) => s.id === id);\r\n        if (idx >= 0) this.scopes.splice(idx, 1);\r\n      },\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Set a callback fallback for cases CSS selectors can't express. The\r\n   * resolver runs BEFORE selector matching — if it returns a non-null\r\n   * config, that wins. Return `null` to fall through to selectors.\r\n   */\r\n  setScopeResolver(resolver: ScopeResolver | undefined): void {\r\n    this.scopeResolver = resolver;\r\n  }\r\n\r\n  /**\r\n   * Compute the effective config for the current selection. Merges the\r\n   * matched scope (if any) onto the root config. Called from menu\r\n   * builders + `runAction` so a single resolved view is reused.\r\n   */\r\n  private active(): {\r\n    actions: InlineAction[];\r\n    llm: LLMSource;\r\n    systemPrompt: string | undefined;\r\n    layout: 'single-column' | 'two-column' | 'toolbar';\r\n    columnLabels: { col1?: string; col2?: string } | undefined;\r\n    translateTargets: Array<{ code: string; label: string }>;\r\n    tools: ActionDefinition[] | undefined;\r\n  } {\r\n    const s = this.activeScopeConfig;\r\n    if (!s) {\r\n      return {\r\n        actions: this.actions,\r\n        llm: this.llm,\r\n        systemPrompt: this.cfg.systemPrompt,\r\n        layout: this.cfg.layout,\r\n        columnLabels: this.cfg.columnLabels,\r\n        translateTargets: this.cfg.translateTargets,\r\n        tools: this.cfg.tools,\r\n      };\r\n    }\r\n    // Action merge: `actions` replaces root; `disabledActions` filters\r\n    // root (only if scope didn't replace); `appendActions` extends.\r\n    let actions: InlineAction[];\r\n    if (s.actions) {\r\n      actions = s.actions.slice();\r\n    } else if (s.disabledActions?.length) {\r\n      const drop = new Set(s.disabledActions);\r\n      actions = this.actions.filter((a) => !drop.has(a.id));\r\n    } else {\r\n      actions = this.actions.slice();\r\n    }\r\n    if (s.appendActions?.length) {\r\n      actions = [...actions, ...s.appendActions];\r\n    }\r\n    // System prompt merge: `systemPrompt` replaces; `appendSystemPrompt`\r\n    // adds to whatever the effective base prompt is.\r\n    let systemPrompt = s.systemPrompt ?? this.cfg.systemPrompt;\r\n    if (s.appendSystemPrompt) {\r\n      systemPrompt = systemPrompt\r\n        ? `${systemPrompt}\\n\\n${s.appendSystemPrompt}`\r\n        : s.appendSystemPrompt;\r\n    }\r\n    // Tools: explicit empty array = \"no tools for this scope\"; undefined\r\n    // = inherit root. (You can't disable root tools with a missing field.)\r\n    const tools = s.tools !== undefined ? (s.tools.length > 0 ? s.tools : undefined) : this.cfg.tools;\r\n    return {\r\n      actions,\r\n      llm: s.llm ?? this.llm,\r\n      systemPrompt,\r\n      layout: s.layout ?? this.cfg.layout,\r\n      columnLabels: s.columnLabels ?? this.cfg.columnLabels,\r\n      translateTargets: s.translateTargets ?? this.cfg.translateTargets,\r\n      tools,\r\n    };\r\n  }\r\n\r\n  /** Toggle module on/off without unmounting. */\r\n  setEnabled(on: boolean): void {\r\n    this.enabled = on;\r\n    if (!on) this.hide();\r\n  }\r\n  isEnabled(): boolean { return this.enabled; }\r\n\r\n  // ─── Selection detection ────────────────────────────────────\r\n\r\n  private handleSelectionChange(): void {\r\n    if (!this.enabled) return;\r\n    // IME composition window: bail. compositionend re-fires this method,\r\n    // so the menu still surfaces correctly when the composed char lands.\r\n    if (this.isComposing) return;\r\n    const active = document.activeElement;\r\n    if (!(active instanceof HTMLElement)) { this.hide(); return; }\r\n    if (this.cfg.ignoreSelector && active.closest(this.cfg.ignoreSelector)) { this.hide(); return; }\r\n\r\n    if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement) {\r\n      const start = active.selectionStart ?? -1;\r\n      const end = active.selectionEnd ?? -1;\r\n      if (start < 0 || end <= start) { this.hide(); return; }\r\n      const text = active.value.slice(start, end).trim();\r\n      if (text.length < 2) { this.hide(); return; }\r\n      this.currentEditable = active;\r\n      this.currentSelection = { text, start, end };\r\n      this.currentRect = this.getSelectionRect(active);\r\n      this.activeScopeConfig = resolveInlineScope(active, this.scopes, this.scopeResolver, text);\r\n      this.showMenu();\r\n      return;\r\n    }\r\n\r\n    if (active.isContentEditable) {\r\n      const sel = window.getSelection();\r\n      if (!sel || sel.rangeCount === 0) { this.hide(); return; }\r\n      const text = sel.toString().trim();\r\n      if (text.length < 2) { this.hide(); return; }\r\n      this.currentEditable = active;\r\n      this.currentSelection = { text, start: -1, end: -1 };\r\n      this.currentRect = sel.getRangeAt(0).getBoundingClientRect();\r\n      this.activeScopeConfig = resolveInlineScope(active, this.scopes, this.scopeResolver, text);\r\n      this.showMenu();\r\n      return;\r\n    }\r\n\r\n    // Non-editable: leave it to the palette flow.\r\n    this.hide();\r\n  }\r\n\r\n  // ─── Menu ───────────────────────────────────────────────────\r\n\r\n  private showMenu(): void {\r\n    if (!this.menu) this.mountMenu();\r\n    if (!this.menu || !this.currentRect) return;\r\n    this.menu.style.display = 'block';\r\n    this.cursor = 0;\r\n    this.paintActive();\r\n    this.repositionMenu();\r\n    // Re-arm auto-hide if configured (default 0 = never).\r\n    if (this.hideTimer) clearTimeout(this.hideTimer);\r\n    if (this.cfg.hideAfterMs > 0) {\r\n      this.hideTimer = setTimeout(() => this.hide(), this.cfg.hideAfterMs);\r\n    }\r\n  }\r\n\r\n  private repositionMenu(): void {\r\n    if (!this.menu || !this.currentRect || !this.currentEditable) return;\r\n    if (this.menu.style.display === 'none') return;\r\n    // Recompute selection rect (it moves with scroll / DOM changes).\r\n    const rect = this.getSelectionRect(this.currentEditable);\r\n    if (!rect) return;\r\n    this.currentRect = rect;\r\n\r\n    const menuW = this.menu.offsetWidth || 260;\r\n    const menuH = this.menu.offsetHeight || 240;\r\n    const viewportRight = window.scrollX + document.documentElement.clientWidth;\r\n    const viewportBottom = window.scrollY + document.documentElement.clientHeight;\r\n\r\n    // Toolbar: anchor ABOVE the selection, horizontally centred (AFFiNE /\r\n    // Notion style). Flip below only when there isn't room above.\r\n    if (this.active().layout === 'toolbar') {\r\n      const selCenter = rect.left + rect.width / 2 + window.scrollX;\r\n      let tLeft = selCenter - menuW / 2;\r\n      tLeft = Math.max(8, Math.min(tLeft, viewportRight - menuW - 8));\r\n      let tTop = rect.top + window.scrollY - menuH - 8;\r\n      if (tTop < window.scrollY + 4) {\r\n        // Not enough room above — drop below the selection.\r\n        tTop = rect.bottom + window.scrollY + 8;\r\n      }\r\n      this.menu.style.left = `${tLeft}px`;\r\n      this.menu.style.top = `${Math.max(8, tTop)}px`;\r\n      return;\r\n    }\r\n\r\n    // Horizontal: anchor at the right edge of the selection. Flip left\r\n    // if it'd overflow the viewport.\r\n    let left = rect.right + window.scrollX + 8;\r\n    if (left + menuW > viewportRight) {\r\n      left = rect.left + window.scrollX - menuW - 8;\r\n    }\r\n\r\n    // Vertical: open BELOW the selection by default. Opening alongside\r\n    // (top-aligned with the selection) used to overlap the user's text\r\n    // on narrow screens — they complained the menu was covering the\r\n    // sentence they were trying to edit. We flip back to ABOVE only\r\n    // when there isn't enough room below AND there's more room above\r\n    // it than below.\r\n    const viewportTopY = window.scrollY;\r\n    let top = rect.bottom + window.scrollY + 6;\r\n    if (top + menuH > viewportBottom) {\r\n      const above = (rect.top + window.scrollY) - viewportTopY;\r\n      const below = viewportBottom - (rect.bottom + window.scrollY);\r\n      if (above > below) {\r\n        top = rect.top + window.scrollY - menuH - 6;\r\n      }\r\n    }\r\n\r\n    this.menu.style.left = `${Math.max(8, left)}px`;\r\n    this.menu.style.top = `${Math.max(8, top)}px`;\r\n  }\r\n\r\n  private mountMenu(): void {\r\n    const layout = this.active().layout;\r\n    const menu = document.createElement('div');\r\n    menu.setAttribute(UI_ATTR, 'inline-agent');\r\n    if (layout === 'two-column') menu.setAttribute('data-layout', 'two-column');\r\n    else if (layout === 'toolbar') menu.setAttribute('data-layout', 'toolbar');\r\n    const list = document.createElement('div');\r\n    list.className = 'ia-list';\r\n    // Toolbar is icon-only and intentionally has no title row.\r\n    if (layout !== 'toolbar') {\r\n      const header = document.createElement('div');\r\n      header.className = 'ia-header';\r\n      header.textContent = this.t('header');\r\n      menu.appendChild(header);\r\n    }\r\n    menu.appendChild(list);\r\n    document.body.appendChild(menu);\r\n    this.menu = menu;\r\n    this.menuList = list;\r\n    this.renderActions();\r\n  }\r\n\r\n  private refreshMenu(): void {\r\n    if (!this.menuList) return;\r\n    this.renderActions();\r\n  }\r\n\r\n  private renderActions(): void {\r\n    if (!this.menuList) return;\r\n    this.menuList.innerHTML = '';\r\n\r\n    const layout = this.active().layout;\r\n    if (layout === 'two-column') {\r\n      this.renderTwoColumn();\r\n    } else if (layout === 'toolbar') {\r\n      this.renderToolbar();\r\n    } else {\r\n      this.renderSingleColumn();\r\n    }\r\n  }\r\n\r\n  private renderToolbar(): void {\r\n    if (!this.menuList) return;\r\n    this.menuList.className = 'ia-list ia-toolbar';\r\n    let prevGroup: string | undefined;\r\n    const actions = this.active().actions;\r\n    actions.forEach((action, idx) => {\r\n      // Divider between adjacent buttons whose group differs.\r\n      if (idx > 0 && action.group !== prevGroup) {\r\n        const sep = document.createElement('span');\r\n        sep.className = 'ia-toolbar-sep';\r\n        sep.setAttribute('aria-hidden', 'true');\r\n        this.menuList!.appendChild(sep);\r\n      }\r\n      prevGroup = action.group;\r\n      this.menuList!.appendChild(this.buildToolbarButton(action, idx));\r\n    });\r\n  }\r\n\r\n  private buildToolbarButton(action: InlineAction, idx: number): HTMLButtonElement {\r\n    const btn = document.createElement('button');\r\n    btn.type = 'button';\r\n    btn.className = 'ia-tool';\r\n    btn.dataset.idx = String(idx);\r\n    const label = typeof action.label === 'string'\r\n      ? action.label\r\n      : (action.label as Record<string, string>)[this.cfg.locale] ?? action.label.en;\r\n    btn.title = label;\r\n    btn.setAttribute('aria-label', label);\r\n    const isDropdown = action.kind === 'dropdown';\r\n    if (isDropdown) {\r\n      btn.setAttribute('aria-haspopup', 'menu');\r\n      btn.innerHTML = `<span class=\"ia-icon\">${action.icon ?? '·'}</span><span class=\"ia-chevron\" aria-hidden=\"true\">▾</span>`;\r\n    } else {\r\n      btn.innerHTML = `<span class=\"ia-icon\">${action.icon ?? '·'}</span>`;\r\n    }\r\n    // mousedown preserves the editable's focus / selection.\r\n    btn.addEventListener('mousedown', (e) => {\r\n      e.preventDefault();\r\n      if (isDropdown) this.openDropdown(action, btn);\r\n      else this.runAction(action);\r\n    });\r\n    btn.addEventListener('mouseenter', () => { this.cursor = idx; this.paintActive(); });\r\n    return btn;\r\n  }\r\n\r\n  /**\r\n   * Open a vertical sub-menu under a toolbar dropdown button. Reuses the\r\n   * `.ia-submenu` shell + click-away / Esc handling. Picking an item runs\r\n   * it through the normal `runAction` pipeline and closes the dropdown.\r\n   */\r\n  private openDropdown(action: InlineAction, anchor: HTMLElement): void {\r\n    if (typeof document === 'undefined') return;\r\n    if (this.subMenu) { this.subMenu.remove(); this.subMenu = null; }\r\n    const items = action.items ?? [];\r\n    if (items.length === 0) return;\r\n\r\n    const wrap = document.createElement('div');\r\n    wrap.setAttribute(UI_ATTR, 'inline-agent');\r\n    wrap.className = 'ia-submenu';\r\n    wrap.setAttribute('data-dropdown', '');\r\n    const list = document.createElement('div');\r\n    list.className = 'ia-list';\r\n    wrap.appendChild(list);\r\n\r\n    let cursor = 0;\r\n    const paint = () => {\r\n      list.querySelectorAll<HTMLButtonElement>('[data-idx]').forEach((b) => {\r\n        if (Number(b.dataset.idx) === cursor) b.setAttribute('data-active', '');\r\n        else b.removeAttribute('data-active');\r\n      });\r\n    };\r\n    const cleanup = () => {\r\n      wrap.remove();\r\n      document.removeEventListener('keydown', onKey, true);\r\n      document.removeEventListener('mousedown', onAway, true);\r\n      if (this.subMenu === wrap) this.subMenu = null;\r\n    };\r\n    const onAway = (e: MouseEvent) => {\r\n      if (e.target instanceof Node && (wrap.contains(e.target) || anchor.contains(e.target))) return;\r\n      cleanup();\r\n    };\r\n    const onKey = (e: KeyboardEvent) => {\r\n      if (e.key === 'Escape') { e.preventDefault(); cleanup(); }\r\n      else if (e.key === 'ArrowDown') { e.preventDefault(); cursor = (cursor + 1) % items.length; paint(); }\r\n      else if (e.key === 'ArrowUp') { e.preventDefault(); cursor = (cursor - 1 + items.length) % items.length; paint(); }\r\n      else if (e.key === 'Enter') {\r\n        e.preventDefault();\r\n        const it = items[cursor];\r\n        cleanup();\r\n        if (it) void this.runAction(it);\r\n      }\r\n    };\r\n\r\n    items.forEach((it, i) => {\r\n      const b = document.createElement('button');\r\n      b.type = 'button';\r\n      b.className = 'ia-row';\r\n      b.dataset.idx = String(i);\r\n      const itLabel = typeof it.label === 'string'\r\n        ? it.label\r\n        : (it.label as Record<string, string>)[this.cfg.locale] ?? it.label.en;\r\n      b.innerHTML = `<span class=\"ia-icon\">${it.icon ?? '·'}</span><span class=\"ia-label\">${escapeHtml(itLabel)}</span>`;\r\n      b.addEventListener('mousedown', (e) => {\r\n        e.preventDefault();\r\n        cleanup();\r\n        void this.runAction(it);\r\n      });\r\n      b.addEventListener('mouseenter', () => { cursor = i; paint(); });\r\n      list.appendChild(b);\r\n    });\r\n\r\n    document.body.appendChild(wrap);\r\n    this.subMenu = wrap;\r\n    // Anchor under the button, left-aligned; flip up if it would overflow.\r\n    const r = anchor.getBoundingClientRect();\r\n    const subH = wrap.offsetHeight || 200;\r\n    const subW = wrap.offsetWidth || 180;\r\n    const viewportBottom = window.scrollY + document.documentElement.clientHeight;\r\n    const viewportRight = window.scrollX + document.documentElement.clientWidth;\r\n    let top = r.bottom + window.scrollY + 4;\r\n    if (top + subH > viewportBottom && (r.top + window.scrollY) - subH - 4 > window.scrollY) {\r\n      top = r.top + window.scrollY - subH - 4;\r\n    }\r\n    let left = r.left + window.scrollX;\r\n    if (left + subW > viewportRight) left = viewportRight - subW - 8;\r\n    wrap.style.left = `${Math.max(8, left)}px`;\r\n    wrap.style.top = `${Math.max(8, top)}px`;\r\n\r\n    document.addEventListener('keydown', onKey, true);\r\n    document.addEventListener('mousedown', onAway, true);\r\n    paint();\r\n  }\r\n\r\n  private renderSingleColumn(): void {\r\n    if (!this.menuList) return;\r\n    this.menuList.className = 'ia-list';\r\n    this.active().actions.forEach((action, idx) => {\r\n      this.menuList!.appendChild(this.buildActionRow(action, idx));\r\n    });\r\n  }\r\n\r\n  private renderTwoColumn(): void {\r\n    if (!this.menuList) return;\r\n    this.menuList.className = 'ia-list ia-two-col';\r\n    const scope = this.active();\r\n    const col1 = document.createElement('div');\r\n    col1.className = 'ia-col';\r\n    const col2 = document.createElement('div');\r\n    col2.className = 'ia-col';\r\n\r\n    // Optional column headers (e.g. \"Format\" / \"AI\").\r\n    if (scope.columnLabels?.col1) {\r\n      const h = document.createElement('div');\r\n      h.className = 'ia-col-label';\r\n      h.textContent = scope.columnLabels.col1;\r\n      col1.appendChild(h);\r\n    }\r\n    if (scope.columnLabels?.col2) {\r\n      const h = document.createElement('div');\r\n      h.className = 'ia-col-label';\r\n      h.textContent = scope.columnLabels.col2;\r\n      col2.appendChild(h);\r\n    }\r\n\r\n    // Actions partition: row=2 goes to col2, everything else to col1.\r\n    // We pass each action its position in the effective list as `idx`\r\n    // so cursor / keyboard nav stays consistent across layouts.\r\n    scope.actions.forEach((action, idx) => {\r\n      const target = action.row === 2 ? col2 : col1;\r\n      target.appendChild(this.buildActionRow(action, idx));\r\n    });\r\n\r\n    this.menuList.appendChild(col1);\r\n    this.menuList.appendChild(col2);\r\n  }\r\n\r\n  private buildActionRow(action: InlineAction, idx: number): HTMLButtonElement {\r\n    const row = document.createElement('button');\r\n    row.type = 'button';\r\n    row.className = 'ia-row';\r\n    row.dataset.idx = String(idx);\r\n    const label = typeof action.label === 'string'\r\n      ? action.label\r\n      : (action.label as Record<string, string>)[this.cfg.locale] ?? action.label.en;\r\n    row.innerHTML = `\r\n      <span class=\"ia-icon\">${action.icon ?? '·'}</span>\r\n      <span class=\"ia-label\">${escapeHtml(label)}</span>\r\n    `;\r\n    // Use mousedown so editable focus is preserved.\r\n    row.addEventListener('mousedown', (e) => { e.preventDefault(); this.runAction(action); });\r\n    row.addEventListener('mouseenter', () => { this.cursor = idx; this.paintActive(); });\r\n    return row;\r\n  }\r\n\r\n  private paintActive(): void {\r\n    if (!this.menuList) return;\r\n    const rows = this.menuList.querySelectorAll<HTMLButtonElement>('[data-idx]');\r\n    rows.forEach((r) => {\r\n      if (Number(r.dataset.idx) === this.cursor) r.setAttribute('data-active', '');\r\n      else r.removeAttribute('data-active');\r\n    });\r\n  }\r\n\r\n  private hide(): void {\r\n    if (this.menu) this.menu.style.display = 'none';\r\n    if (this.subMenu) this.subMenu.remove();\r\n    this.subMenu = null;\r\n    this.currentEditable = null;\r\n    this.currentSelection = null;\r\n    this.currentRect = null;\r\n    this.activeScopeConfig = null;\r\n    if (this.hideTimer) { clearTimeout(this.hideTimer); this.hideTimer = null; }\r\n  }\r\n\r\n  /** Hide ONLY if there's currently no selection. Used after outside clicks\r\n   *  to avoid hiding while user is mid-drag re-selecting. */\r\n  private maybeHide(): void {\r\n    const active = document.activeElement;\r\n    let hasSel = false;\r\n    if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement) {\r\n      hasSel = (active.selectionEnd ?? 0) > (active.selectionStart ?? 0);\r\n    } else if (active instanceof HTMLElement && active.isContentEditable) {\r\n      const sel = window.getSelection();\r\n      hasSel = !!sel && sel.toString().trim().length >= 2;\r\n    }\r\n    if (!hasSel) this.hide();\r\n  }\r\n\r\n  // ─── Keyboard ───────────────────────────────────────────────\r\n\r\n  private handleKey(e: KeyboardEvent): void {\r\n    if (!this.menu || this.menu.style.display === 'none') return;\r\n    // Only handle navigation keys when an editable with selection is focused —\r\n    // we don't want to swallow Esc / ArrowDown in other contexts.\r\n    if (e.key === 'Escape') { this.hide(); return; }\r\n    const scopeActions = this.active().actions;\r\n    if (e.key === 'ArrowDown' || (e.ctrlKey && e.key === 'n')) {\r\n      e.preventDefault();\r\n      this.cursor = Math.min(scopeActions.length - 1, this.cursor + 1);\r\n      this.paintActive();\r\n    } else if (e.key === 'ArrowUp' || (e.ctrlKey && e.key === 'p')) {\r\n      e.preventDefault();\r\n      this.cursor = Math.max(0, this.cursor - 1);\r\n      this.paintActive();\r\n    } else if (e.key === 'Enter' && (e.metaKey || e.ctrlKey || e.altKey)) {\r\n      // Use modifier + Enter so plain Enter in the editable still adds a newline.\r\n      e.preventDefault();\r\n      const action = scopeActions[this.cursor];\r\n      if (!action) return;\r\n      if (this.active().layout === 'toolbar' && action.kind === 'dropdown') {\r\n        const btn = this.menuList?.querySelector<HTMLElement>(`.ia-tool[data-idx=\"${this.cursor}\"]`);\r\n        if (btn) this.openDropdown(action, btn);\r\n      } else {\r\n        this.runAction(action);\r\n      }\r\n    }\r\n  }\r\n\r\n  // ─── Sub-menu picker (for Translate target language etc.) ──\r\n\r\n  private pickFromSubmenu(\r\n    title: string,\r\n    items: Array<{ id: string; label: string }>,\r\n  ): Promise<{ id: string; label: string } | null> {\r\n    return new Promise((resolve) => {\r\n      if (this.subMenu) this.subMenu.remove();\r\n      const wrap = document.createElement('div');\r\n      wrap.setAttribute(UI_ATTR, 'inline-agent');\r\n      wrap.className = 'ia-submenu';\r\n      wrap.innerHTML = `<div class=\"ia-header\">${escapeHtml(title)}</div><div class=\"ia-list\"></div>`;\r\n      const list = wrap.querySelector<HTMLElement>('.ia-list')!;\r\n      let cursor = 0;\r\n      const paint = () => {\r\n        list.querySelectorAll<HTMLButtonElement>('[data-idx]').forEach((b) => {\r\n          if (Number(b.dataset.idx) === cursor) b.setAttribute('data-active', '');\r\n          else b.removeAttribute('data-active');\r\n        });\r\n      };\r\n      const cleanup = () => {\r\n        wrap.remove();\r\n        document.removeEventListener('keydown', onKey, true);\r\n        this.subMenu = null;\r\n      };\r\n      const choose = (idx: number) => {\r\n        const it = items[idx];\r\n        cleanup();\r\n        resolve(it ?? null);\r\n      };\r\n      const onKey = (e: KeyboardEvent) => {\r\n        if (e.key === 'Escape') { e.preventDefault(); cleanup(); resolve(null); }\r\n        else if (e.key === 'ArrowDown') { e.preventDefault(); cursor = (cursor + 1) % items.length; paint(); }\r\n        else if (e.key === 'ArrowUp')   { e.preventDefault(); cursor = (cursor - 1 + items.length) % items.length; paint(); }\r\n        else if (e.key === 'Enter')     { e.preventDefault(); choose(cursor); }\r\n      };\r\n      items.forEach((it, idx) => {\r\n        const b = document.createElement('button');\r\n        b.type = 'button';\r\n        b.className = 'ia-row';\r\n        b.dataset.idx = String(idx);\r\n        b.innerHTML = `<span class=\"ia-label\">${escapeHtml(it.label)}</span>`;\r\n        b.addEventListener('mousedown', (e) => { e.preventDefault(); choose(idx); });\r\n        b.addEventListener('mouseenter', () => { cursor = idx; paint(); });\r\n        list.appendChild(b);\r\n      });\r\n      // Position relative to the main menu (to the right of it).\r\n      document.body.appendChild(wrap);\r\n      this.subMenu = wrap;\r\n      if (this.menu && this.currentRect) {\r\n        const r = this.menu.getBoundingClientRect();\r\n        wrap.style.left = `${r.right + window.scrollX + 4}px`;\r\n        wrap.style.top = `${r.top + window.scrollY}px`;\r\n      }\r\n      document.addEventListener('keydown', onKey, true);\r\n      paint();\r\n    });\r\n  }\r\n\r\n  // ─── Run an action ──────────────────────────────────────────\r\n\r\n  private async runAction(action: InlineAction): Promise<void> {\r\n    if (!this.currentEditable || !this.currentSelection) return;\r\n    const target = this.currentEditable;\r\n    const sel = this.currentSelection;\r\n\r\n    // Custom handler — runs INSTEAD of the LLM round-trip. Use for\r\n    // formatting actions (bold / colour / insert table) where no LLM is\r\n    // needed; the host directly mutates the editable.\r\n    if (action.handler) {\r\n      this.hide();\r\n      try {\r\n        await action.handler({\r\n          text: sel.text,\r\n          target,\r\n          selection: { start: sel.start, end: sel.end },\r\n          agent: this,\r\n        });\r\n      } catch (err) {\r\n        if (typeof console !== 'undefined') console.warn('[inline-agent] handler threw:', (err as Error).message);\r\n      }\r\n      return;\r\n    }\r\n\r\n    // Resolve the instruction. Sub-menu handlers may abort.\r\n    let instruction = action.instruction;\r\n    if (action.build) {\r\n      const built = await action.build({ text: sel.text, agent: this });\r\n      if (built == null) return;          // user cancelled the sub-menu\r\n      instruction = built;\r\n    }\r\n    if (!instruction) return;\r\n\r\n    this.hide();\r\n    // No \"processing\" indicator here — the streaming diff overlay IS\r\n    // the loading state. Text arrives into the diff view chunk by\r\n    // chunk with a visible replacement/original strikeout, so a\r\n    // second \"🦆🦆🦆 處理中\" pill at the bottom just doubles up the\r\n    // same signal and (worse) sometimes lingers after the diff is\r\n    // fully rendered because the clear-on-first-delta path can race\r\n    // the diff finish.\r\n    this.runToken++;\r\n    const myToken = this.runToken;\r\n\r\n    // Build the context window — N chars around the selection. For\r\n    // contenteditable targets we don't have offset indices, so we use the\r\n    // selection's text alone as a degenerate \"context\" (LLM still gets the\r\n    // instruction; just no surrounding paragraph).\r\n    let contextPrompt: string;\r\n    if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {\r\n      contextPrompt = buildContextPrompt(target.value, sel.start, sel.end);\r\n    } else {\r\n      // contenteditable — use the parent element's textContent as context.\r\n      const parent = (target.closest('p, li, h1, h2, h3, h4, h5, h6, blockquote, div') ?? target) as HTMLElement;\r\n      const fullText = parent.innerText ?? parent.textContent ?? sel.text;\r\n      const idx = fullText.indexOf(sel.text);\r\n      if (idx >= 0) {\r\n        contextPrompt = buildContextPrompt(fullText, idx, idx + sel.text.length);\r\n      } else {\r\n        contextPrompt = `[[SEL]]${sel.text}[[/SEL]]`;\r\n      }\r\n    }\r\n\r\n    try {\r\n      // Snapshot the active scope's effective config for this run. Capture\r\n      // ONCE so the menu-time scope wins even if a later registration\r\n      // would have changed the resolution mid-flight.\r\n      const scope = this.active();\r\n      const llm = resolveLLM(scope.llm, 'inline');\r\n      const userMessage = `Instruction: ${instruction}\\n\\nContext (with selection marked):\\n\"\"\"\\n${contextPrompt}\\n\"\"\"`;\r\n      const systemMessage = scope.systemPrompt ?? promptRegistry.render(PROMPT_IDS.INLINE_EDIT, undefined, 'en');\r\n      const mode = action.displayAs ?? this.cfg.defaultDisplayAs ?? 'replace';\r\n      const scopeTools = scope.tools;\r\n\r\n      const streamingProvider = llm as unknown as StreamingProvider;\r\n      const canStream = typeof streamingProvider.streamComplete === 'function' && !scopeTools;\r\n\r\n      if (mode === 'inline-diff') {\r\n        await this.runInlineDiff({\r\n          target,\r\n          sel,\r\n          systemMessage,\r\n          userMessage,\r\n          instruction,\r\n          llm,\r\n          streamingProvider,\r\n          // Tools imply multi-round agentic flow which doesn't fit the\r\n          // single-turn diff panel; fall back to the non-stream path that\r\n          // runs runWithTools internally.\r\n          canStream: canStream && !scopeTools,\r\n          scopeTools,\r\n          myToken,\r\n        });\r\n      } else if (canStream && (mode === 'replace' || mode === 'subtitle' || mode === 'confirm')) {\r\n        const handle = streamingProvider.streamComplete!({\r\n          messages: [\r\n            { role: 'system', content: systemMessage },\r\n            { role: 'user', content: userMessage },\r\n          ],\r\n          thinking: 'off',\r\n          temperature: 0,\r\n          maxTokens: Math.max(256, sel.text.length * 4 + 200),\r\n        });\r\n        const replacement = await this.consumeStream(handle, target, sel, mode, myToken);\r\n        if (myToken !== this.runToken) return;\r\n        if (mode === 'confirm' && replacement) {\r\n          // Confirm mode: we streamed into the subtitle bar; finalize\r\n          // with accept/reject. The result is NOT applied until the\r\n          // user accepts.\r\n          this.dddk?.subtitle.finalizeStreamed({ autoHide: 0 });\r\n          // Replace the streaming bar with an accept/reject bar carrying\r\n          // the same text — the user gets a clear decision moment.\r\n          this.dddk?.subtitle.show({\r\n            text: replacement,\r\n            type: 'agent',\r\n            onAccept: () => this.applyResult(target, sel, replacement),\r\n            onReject: () => { /* discard */ },\r\n          });\r\n        } else if (mode === 'subtitle') {\r\n          this.dddk?.subtitle.finalizeStreamed({ autoHide: 0 });\r\n        }\r\n      } else {\r\n        const result = scopeTools\r\n          ? await this.runWithTools(llm, systemMessage, userMessage, sel.text.length, myToken, scopeTools)\r\n          : await llm.complete({\r\n              messages: [\r\n                { role: 'system', content: systemMessage },\r\n                { role: 'user', content: userMessage },\r\n              ],\r\n              thinking: 'off',\r\n              temperature: 0,\r\n              maxTokens: Math.max(256, sel.text.length * 4 + 200),\r\n            });\r\n        if (myToken !== this.runToken) return;\r\n        const replacement = extractReplacement(result.content);\r\n        if (replacement) {\r\n          if (mode === 'replace') {\r\n            this.applyResult(target, sel, replacement);\r\n          } else if (mode === 'subtitle') {\r\n            this.dddk?.subtitle.show({ text: replacement, type: 'agent' });\r\n          } else if (mode === 'confirm') {\r\n            this.dddk?.subtitle.show({\r\n              text: replacement,\r\n              type: 'agent',\r\n              onAccept: () => this.applyResult(target, sel, replacement),\r\n              onReject: () => { /* discard */ },\r\n            });\r\n          }\r\n        }\r\n      }\r\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n      (this.dddk as any)?.emitIntent?.({\r\n        kind: 'palette_activated',\r\n        itemId: `inline.${action.id}`,\r\n        arg: sel.text.slice(0, 60),\r\n        attachmentsCount: 0,\r\n        timestamp: Date.now(),\r\n      });\r\n    } catch (err) {\r\n      // Friendly subtitle — strip raw JSON error blobs that look like\r\n      // `Gemini HTTP 500: { \"error\": ... }` (LLM vendor errors). Surface\r\n      // only the human-readable hint so the user sees \"rewrite failed,\r\n      // try again\" instead of a stack trace. Full message still goes to\r\n      // console for diagnosis.\r\n      const rawMsg = (err as Error).message ?? '';\r\n      const friendly = humanizeLLMError(rawMsg, this.cfg.locale);\r\n      this.dddk?.subtitle.show({\r\n        text: `${this.t('failed')}: ${friendly}`,\r\n        type: 'info',\r\n        autoHide: 3500,\r\n      });\r\n      if (typeof console !== 'undefined') console.warn('[inline-agent] LLM call failed:', rawMsg);\r\n    } finally {\r\n      this.dddk?.subtitle.hideIndicator();\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Stream tokens from the LLM straight into the target — character by\r\n   * character into an input/textarea (mode=replace) or into the live\r\n   * subtitle bar (mode=subtitle/confirm). Watches for the\r\n   * `<<<REPLACEMENT>>>` start marker so we don't emit any preamble the\r\n   * model leaks, and stops at `<<<END>>>` so trailing tokens don't\r\n   * contaminate. Returns the final concatenated replacement string —\r\n   * mode=confirm uses it to build the accept/reject UI after streaming.\r\n   */\r\n  private async consumeStream(\r\n    handle: AsyncIterable<StreamChunk>,\r\n    target: HTMLElement,\r\n    sel: { text: string; start: number; end: number },\r\n    mode: 'replace' | 'subtitle' | 'confirm',\r\n    myToken: number,\r\n  ): Promise<string> {\r\n    let inReplacement = false;\r\n    let processedLen = 0;\r\n    let replacementBuf = '';\r\n    let replaceCursor = sel.start;\r\n    let replaceStarted = false;\r\n\r\n    // For replace mode: blank out the selection up-front. As deltas\r\n    // arrive we splice them in at cursor.\r\n    const isFormInput = target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement;\r\n\r\n    // Hide the indicator on first delta (we'll get the visual progress\r\n    // from the input or the streaming bar).\r\n    let indicatorCleared = false;\r\n\r\n    for await (const chunk of handle) {\r\n      if (myToken !== this.runToken) return replacementBuf;\r\n      if (!indicatorCleared) {\r\n        this.dddk?.subtitle.hideIndicator();\r\n        indicatorCleared = true;\r\n      }\r\n\r\n      const totalText = chunk.text;\r\n\r\n      if (!inReplacement) {\r\n        const startIdx = totalText.indexOf(REPLACEMENT_START);\r\n        if (startIdx < 0) continue;\r\n        inReplacement = true;\r\n        processedLen = startIdx + REPLACEMENT_START.length;\r\n        if (mode === 'replace' && isFormInput && !replaceStarted) {\r\n          // Blank the selection now — the model has committed to a\r\n          // replacement and we want the deletion to land on the SAME\r\n          // tick as the first character so the cursor doesn't dance.\r\n          const el = target as HTMLInputElement | HTMLTextAreaElement;\r\n          const before = el.value.slice(0, sel.start);\r\n          const after = el.value.slice(sel.end);\r\n          el.value = before + after;\r\n          el.setSelectionRange(sel.start, sel.start);\r\n          el.dispatchEvent(new Event('input', { bubbles: true }));\r\n          replaceStarted = true;\r\n        }\r\n      }\r\n\r\n      // Process whatever's new since last iteration, watching for any\r\n      // recognised end-marker variant (canonical `<<<END>>>` plus the\r\n      // hybrid SEL-style variants small models sometimes emit).\r\n      const newRaw = totalText.slice(processedLen);\r\n      const end = findEndMarker(newRaw);\r\n\r\n      let safeChunk: string;\r\n      let consumeLen: number;\r\n      let finished = false;\r\n      if (end !== null) {\r\n        safeChunk = newRaw.slice(0, end.idx);\r\n        consumeLen = end.idx + end.len;\r\n        finished = true;\r\n      } else {\r\n        // Hold back the tail if it could be the start of ANY end-marker\r\n        // variant. Otherwise a chunk boundary mid-marker would leak the\r\n        // marker's leading characters into the input.\r\n        let safeEnd = newRaw.length;\r\n        for (const variant of REPLACEMENT_END_VARIANTS) {\r\n          const partialIdx = findPartialMarkerTail(newRaw, variant);\r\n          if (partialIdx >= 0 && partialIdx < safeEnd) safeEnd = partialIdx;\r\n        }\r\n        safeChunk = newRaw.slice(0, safeEnd);\r\n        consumeLen = safeEnd;\r\n      }\r\n\r\n      // Trim the leading newline that the prompt encourages but the\r\n      // replacement body shouldn't carry. Only on the very first\r\n      // emitted chunk after the start marker.\r\n      let emit = safeChunk;\r\n      if (replacementBuf === '' && emit.startsWith('\\n')) emit = emit.slice(1);\r\n      else if (replacementBuf === '' && emit.startsWith('\\r\\n')) emit = emit.slice(2);\r\n\r\n      if (emit) {\r\n        replacementBuf += emit;\r\n        if (mode === 'replace' && isFormInput) {\r\n          this.insertAtCursor(target as HTMLInputElement | HTMLTextAreaElement, replaceCursor, emit);\r\n          replaceCursor += emit.length;\r\n        } else if (mode === 'subtitle' || mode === 'confirm') {\r\n          this.dddk?.subtitle.appendStreamed(emit);\r\n        }\r\n      }\r\n      processedLen += consumeLen;\r\n      if (finished) break;\r\n    }\r\n\r\n    // Strip trailing newline left over from the closing marker on its own line.\r\n    if (replacementBuf.endsWith('\\n')) {\r\n      replacementBuf = replacementBuf.slice(0, -1);\r\n      // No visual fix-up needed — the trailing newline is already on screen\r\n      // but harmless. We could trim from the input here, but a single\r\n      // newline at end-of-replacement isn't worth the splice ceremony.\r\n    }\r\n\r\n    return replacementBuf;\r\n  }\r\n\r\n  /** Splice text into an input / textarea at a known cursor position\r\n   *  and update the cursor. Uses the React-aware native value setter so\r\n   *  controlled inputs see the change. */\r\n  private insertAtCursor(\r\n    el: HTMLInputElement | HTMLTextAreaElement,\r\n    cursorPos: number,\r\n    text: string,\r\n  ): void {\r\n    const proto = el instanceof HTMLTextAreaElement\r\n      ? HTMLTextAreaElement.prototype\r\n      : HTMLInputElement.prototype;\r\n    const setter = Object.getOwnPropertyDescriptor(proto, 'value')?.set;\r\n    const cur = el.value;\r\n    const next = cur.slice(0, cursorPos) + text + cur.slice(cursorPos);\r\n    if (setter) setter.call(el, next);\r\n    else el.value = next;\r\n    const newCursor = cursorPos + text.length;\r\n    el.setSelectionRange(newCursor, newCursor);\r\n    el.dispatchEvent(new Event('input', { bubbles: true }));\r\n  }\r\n\r\n  /**\r\n   * Mini tool-call loop used when the host configured `tools` on\r\n   * `InlineAgentConfig`. The LLM may call any tool any number of\r\n   * times (up to `maxToolRounds`) before producing the final\r\n   * `{ replacement }` JSON. Optional subtitle narration surfaces\r\n   * the agent's progress so the user knows what's being looked up\r\n   * before their text changes.\r\n   */\r\n  private async runWithTools(\r\n    llm: ReturnType<typeof resolveLLM>,\r\n    systemMessage: string,\r\n    userMessage: string,\r\n    selLength: number,\r\n    myToken: number,\r\n    tools: ActionDefinition[],\r\n  ): Promise<{ content: string }> {\r\n    const toolDefs = tools.map((t) => ({\r\n      name: t.name,\r\n      description: t.description,\r\n      parameters: t.parameters,\r\n    }));\r\n    const messages: Array<{\r\n      role: 'system' | 'user' | 'assistant' | 'tool';\r\n      content: string;\r\n      toolCallId?: string;\r\n      toolCalls?: ToolCall[];\r\n    }> = [\r\n      { role: 'system', content: systemMessage + '\\n\\n' + this.toolSystemSuffix() },\r\n      { role: 'user', content: userMessage },\r\n    ];\r\n\r\n    const abort = new AbortController();\r\n    // If the user fires a second action mid-loop, runToken changes and\r\n    // we abort any in-flight tool fetch.\r\n    const tokenWatch = setInterval(() => {\r\n      if (myToken !== this.runToken) abort.abort();\r\n    }, 80);\r\n\r\n    try {\r\n      for (let round = 0; round < this.cfg.maxToolRounds; round++) {\r\n        const result = await llm.complete({\r\n          messages,\r\n          tools: toolDefs,\r\n          thinking: 'off',\r\n          temperature: 0,\r\n          maxTokens: Math.max(384, selLength * 4 + 320),\r\n          signal: abort.signal,\r\n        });\r\n        if (myToken !== this.runToken) return { content: '' };\r\n\r\n        const calls = result.toolCalls ?? [];\r\n        if (calls.length === 0) {\r\n          // No more tools — this is the final reply.\r\n          return { content: result.content ?? '' };\r\n        }\r\n\r\n        // Append the assistant's tool-call turn so the LLM keeps context.\r\n        messages.push({\r\n          role: 'assistant',\r\n          content: result.content ?? '',\r\n          toolCalls: calls,\r\n        });\r\n\r\n        // Execute each requested tool sequentially and append the\r\n        // result back as a `role: 'tool'` message.\r\n        for (const call of calls) {\r\n          if (myToken !== this.runToken) return { content: '' };\r\n          const def = tools.find((t) => t.name === call.name);\r\n          if (!def) {\r\n            messages.push({\r\n              role: 'tool',\r\n              toolCallId: call.id,\r\n              content: JSON.stringify({ ok: false, reason: 'unknown_tool' }),\r\n            });\r\n            continue;\r\n          }\r\n          if (this.cfg.enableSubtitle) {\r\n            const lookingUp = this.cfg.locale === 'zh-TW'\r\n              ? `查詢中:${def.name}…`\r\n              : `Looking up: ${def.name}…`;\r\n            this.dddk?.subtitle.show({ text: lookingUp, type: 'info' });\r\n          }\r\n          let toolResult: unknown;\r\n          try {\r\n            toolResult = await def.handler(\r\n              call.arguments as never,\r\n              {\r\n                // Inline tools don't have a real AgentSession; pass a thin\r\n                // shim with the bits a tool might actually consult.\r\n                session: {\r\n                  id: 'inline-' + myToken,\r\n                  task: userMessage,\r\n                  status: 'running',\r\n                  currentPage: typeof location !== 'undefined' ? location.pathname : '/',\r\n                  steps: [],\r\n                  startedAt: Date.now(),\r\n                } as never,\r\n                signal: abort.signal,\r\n                // Inline agent has no indexed DOM dump — pass CSS selectors\r\n                // through to querySelector. The numeric-index resolution path\r\n                // only matters for the webagent (tour mode).\r\n                resolveTarget: (target: string | number) => {\r\n                  if (typeof target !== 'string' || typeof document === 'undefined') return null;\r\n                  try { return document.querySelector(target); } catch { return null; }\r\n                },\r\n              },\r\n            );\r\n          } catch (err) {\r\n            toolResult = { ok: false, reason: 'thrown', message: (err as Error).message };\r\n          }\r\n          messages.push({\r\n            role: 'tool',\r\n            toolCallId: call.id,\r\n            content: JSON.stringify(toolResult),\r\n          });\r\n        }\r\n      }\r\n      // Safety cap reached — ask for the final answer with no tools.\r\n      const final = await llm.complete({\r\n        messages: [\r\n          ...messages,\r\n          {\r\n            role: 'user',\r\n            content: 'Max tool rounds reached. Produce the final JSON `{ \"replacement\": \"...\" }` now using whatever you already have.',\r\n          },\r\n        ],\r\n        thinking: 'off',\r\n        temperature: 0,\r\n        maxTokens: Math.max(256, selLength * 4 + 200),\r\n        signal: abort.signal,\r\n      });\r\n      return { content: final.content ?? '' };\r\n    } finally {\r\n      clearInterval(tokenWatch);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Suffix appended to the system prompt when tools are configured —\r\n   * tells the LLM the loop shape (call tools first, then return the\r\n   * final JSON) without rewriting the entire base prompt.\r\n   */\r\n  private toolSystemSuffix(): string {\r\n    return (\r\n      'You may call any of the provided tools to gather context before producing ' +\r\n      'the final answer. Each tool returns JSON. When you have enough information, ' +\r\n      'reply WITHOUT a tool call and produce the final `{ \"replacement\": \"...\" }` ' +\r\n      'object. Do not narrate your tool calls in the final reply — just the JSON.'\r\n    );\r\n  }\r\n\r\n  /**\r\n   * inline-diff mode. Mount the diff panel anchored under the selection,\r\n   * stream tokens into it, then await the user's accept / insert-after /\r\n   * copy / reject decision. Follow-up rounds keep the panel open and\r\n   * stream a refined result grounded on the original selection.\r\n   *\r\n   * Reject (button / Escape / dispose) aborts the in-flight stream via a\r\n   * per-stream AbortController — the upstream provider sees the disconnect\r\n   * and stops generating tokens (cooperative cancel).\r\n   */\r\n  private async runInlineDiff(args: {\r\n    target: HTMLElement;\r\n    sel: { text: string; start: number; end: number };\r\n    systemMessage: string;\r\n    userMessage: string;\r\n    instruction: string;\r\n    llm: ReturnType<typeof resolveLLM>;\r\n    streamingProvider: StreamingProvider;\r\n    canStream: boolean;\r\n    scopeTools?: ReturnType<typeof resolveLLM> extends never ? never : InlineAgentConfig['tools'];\r\n    myToken: number;\r\n  }): Promise<void> {\r\n    const { target, sel, systemMessage, llm, streamingProvider, canStream, scopeTools, myToken } = args;\r\n\r\n    // Anchor logic differs from the action menu on purpose. The MENU\r\n    // is narrow (~200 px), so `getSelectionRect` returning the END of\r\n    // a multi-line selection reads as \"attached to the caret\" — good.\r\n    // The DIFF PANEL is ~500-600 px wide though; anchoring at the end\r\n    // pushes it off the right edge and the panel's viewport clamp\r\n    // rebounds it to the wrong quadrant. Compute a panel-specific\r\n    // anchor that lands directly below the OPENING line of the\r\n    // selection: use the input's caret-coord helper for the START\r\n    // offset and reuse the shared rect's bottom for the last-line Y.\r\n    const rect = this.getSelectionRect(target);\r\n    let anchor = rect\r\n      ? { left: rect.left, top: rect.top, bottom: rect.bottom }\r\n      : { left: 0, top: 0, bottom: 0 };\r\n    if (rect && (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement)) {\r\n      const start = target.selectionStart ?? 0;\r\n      const startCoords = getCaretCoords(target, start);\r\n      anchor = { left: startCoords.left, top: rect.top, bottom: rect.bottom };\r\n    } else if (rect) {\r\n      // contenteditable path — the DOM Range's own left edge is the\r\n      // start of the selection, so `rect.left` is already correct.\r\n      anchor = { left: rect.left, top: rect.top, bottom: rect.bottom };\r\n    }\r\n\r\n    let abortCtrl = new AbortController();\r\n    let panel: InlineDiffHandle | null = null;\r\n\r\n    // Stream one round (initial OR follow-up) into the diff panel; returns\r\n    // the extracted replacement text or null on abort / empty.\r\n    const streamOnce = async (userMsg: string): Promise<string | null> => {\r\n      if (myToken !== this.runToken) return null;\r\n      abortCtrl = new AbortController();\r\n      if (panel) panel.streamStart();\r\n      try {\r\n        if (canStream) {\r\n          const streamOpts = {\r\n            messages: [\r\n              { role: 'system' as const, content: systemMessage },\r\n              { role: 'user' as const, content: userMsg },\r\n            ],\r\n            thinking: 'off' as const,\r\n            temperature: 0,\r\n            maxTokens: Math.max(256, sel.text.length * 4 + 200),\r\n            signal: abortCtrl.signal,\r\n          };\r\n          // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n          const handle = streamingProvider.streamComplete!(streamOpts as any);\r\n          let inReplacement = false;\r\n          let processedLen = 0;\r\n          let replacementBuf = '';\r\n          for await (const chunk of handle) {\r\n            if (myToken !== this.runToken || abortCtrl.signal.aborted) break;\r\n            const totalText = chunk.text;\r\n            if (!inReplacement) {\r\n              const startIdx = totalText.indexOf(REPLACEMENT_START);\r\n              if (startIdx < 0) continue;\r\n              inReplacement = true;\r\n              processedLen = startIdx + REPLACEMENT_START.length;\r\n            }\r\n            const newRaw = totalText.slice(processedLen);\r\n            const end = findEndMarker(newRaw);\r\n            let safeChunk: string;\r\n            let consumeLen: number;\r\n            let finished = false;\r\n            if (end !== null) {\r\n              safeChunk = newRaw.slice(0, end.idx);\r\n              consumeLen = end.idx + end.len;\r\n              finished = true;\r\n            } else {\r\n              let safeEnd = newRaw.length;\r\n              for (const variant of REPLACEMENT_END_VARIANTS) {\r\n                const partial = findPartialMarkerTail(newRaw, variant);\r\n                if (partial >= 0 && partial < safeEnd) safeEnd = partial;\r\n              }\r\n              safeChunk = newRaw.slice(0, safeEnd);\r\n              consumeLen = safeEnd;\r\n            }\r\n            let emit = safeChunk;\r\n            if (replacementBuf === '' && emit.startsWith('\\n')) emit = emit.slice(1);\r\n            else if (replacementBuf === '' && emit.startsWith('\\r\\n')) emit = emit.slice(2);\r\n            if (emit) {\r\n              replacementBuf += emit;\r\n              panel?.applyStreamChunk(emit);\r\n            }\r\n            processedLen += consumeLen;\r\n            if (finished) break;\r\n          }\r\n          return replacementBuf.trim() ? replacementBuf : null;\r\n        }\r\n        // Non-streaming fallback — either a vanilla complete() or, when the\r\n        // scope wires tools, the multi-round runWithTools loop (one whole\r\n        // body lands at the end; no token-by-token reveal in the panel).\r\n        const result = scopeTools\r\n          ? await this.runWithTools(llm, systemMessage, userMsg, sel.text.length, myToken, scopeTools)\r\n          : await llm.complete({\r\n              messages: [\r\n                { role: 'system', content: systemMessage },\r\n                { role: 'user', content: userMsg },\r\n              ],\r\n              thinking: 'off',\r\n              temperature: 0,\r\n              maxTokens: Math.max(256, sel.text.length * 4 + 200),\r\n            });\r\n        const replacement = extractReplacement(result.content);\r\n        if (replacement) panel?.applyNewText(replacement);\r\n        return replacement;\r\n      } catch (err) {\r\n        // AbortError (user clicked reject) — silent. Anything else surfaces\r\n        // via the existing catch in runAction.\r\n        if ((err as Error)?.name === 'AbortError') return null;\r\n        throw err;\r\n      } finally {\r\n        if (panel) panel.streamDone();\r\n      }\r\n    };\r\n\r\n    // Persistent chat session: every follow-up prompt carries the original\r\n    // selection + all prior turns so \"make it shorter\" / \"more formal\" stay\r\n    // grounded.\r\n    const session = new InlineChatSession(sel.text, async ({ original, history, prompt }) => {\r\n      const ask = history.length\r\n        ? `Original selection:\\n${original}\\n\\nPrior edits (oldest first):\\n${history\r\n            .map((t, i) => `${i + 1}. (${t.prompt})\\n→ ${t.result}`)\r\n            .join('\\n')}\\n\\nNow follow this instruction: ${prompt}`\r\n        : `Original selection:\\n${original}\\n\\nInstruction: ${prompt}`;\r\n      const userMsg = `Instruction: ${prompt}\\n\\nContext (with selection marked):\\n\"\"\"\\n${ask}\\n\"\"\"`;\r\n      return streamOnce(userMsg);\r\n    });\r\n\r\n    panel = mountInlineDiff(sel.text, '', {\r\n      rect: anchor,\r\n      enableInsertAfter: true,\r\n      enableFollowUp: true,\r\n      labels: {\r\n        accept: this.t('accept'),\r\n        reject: this.t('reject'),\r\n        insertAfter: this.t('insertAfter'),\r\n        copy: this.t('copy'),\r\n        followUpPlaceholder: this.t('followUpPlaceholder'),\r\n        send: this.t('send'),\r\n      },\r\n      onFollowUp: async (prompt) => {\r\n        const next = await session.send(prompt);\r\n        if (next != null) panel?.pushHistoryTurn({ prompt, result: next });\r\n        return next;\r\n      },\r\n      onCancel: () => { abortCtrl.abort(); this.runToken++; },\r\n    });\r\n\r\n    panel.streamStart();\r\n    const first = await streamOnce(args.userMessage);\r\n    panel.streamDone();\r\n    if (first == null) {\r\n      panel.dispose();\r\n      return;\r\n    }\r\n\r\n    const outcome = await panel.result;\r\n    if (myToken !== this.runToken) return;\r\n    if (outcome.kind === 'accept') {\r\n      this.applyResult(target, sel, outcome.text);\r\n    } else if (outcome.kind === 'insert-after') {\r\n      // Insert as new text immediately after the selection — original stays.\r\n      if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {\r\n        const ins = `\\n${outcome.text}`;\r\n        const before = target.value.slice(0, sel.end);\r\n        const after = target.value.slice(sel.end);\r\n        target.value = `${before}${ins}${after}`;\r\n        const cursor = sel.end + ins.length;\r\n        target.setSelectionRange(cursor, cursor);\r\n        target.dispatchEvent(new Event('input', { bubbles: true }));\r\n        target.dispatchEvent(new Event('change', { bubbles: true }));\r\n      } else if (target.isContentEditable) {\r\n        const winSel = window.getSelection();\r\n        if (winSel && winSel.rangeCount > 0) {\r\n          const range = winSel.getRangeAt(0);\r\n          range.collapse(false);\r\n          range.insertNode(document.createTextNode(`\\n${outcome.text}`));\r\n        }\r\n      }\r\n    }\r\n    // 'copy' wrote to clipboard inside the panel; 'reject' is a no-op.\r\n  }\r\n\r\n  private applyResult(\r\n    target: HTMLElement,\r\n    sel: { text: string; start: number; end: number },\r\n    result: string,\r\n  ): void {\r\n    if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {\r\n      const before = target.value.slice(0, sel.start);\r\n      const after = target.value.slice(sel.end);\r\n      target.value = `${before}${result}${after}`;\r\n      const cursor = before.length + result.length;\r\n      target.setSelectionRange(cursor, cursor);\r\n      target.dispatchEvent(new Event('input', { bubbles: true }));\r\n      target.dispatchEvent(new Event('change', { bubbles: true }));\r\n      return;\r\n    }\r\n    if (target.isContentEditable) {\r\n      const winSel = window.getSelection();\r\n      if (winSel && winSel.rangeCount > 0) {\r\n        const range = winSel.getRangeAt(0);\r\n        range.deleteContents();\r\n        range.insertNode(document.createTextNode(result));\r\n      }\r\n    }\r\n  }\r\n\r\n  // ─── helpers ────────────────────────────────────────────────\r\n\r\n  // ─── Shortcut + prefix trigger ─────────────────────────────\r\n\r\n  /**\r\n   * Keyboard shortcut handler — opens the menu for the current selection\r\n   * even if `selectionchange` didn't fire (e.g. user is typing and wants\r\n   * AI without re-selecting). When triggered with no active selection,\r\n   * we fall back to selecting the focused word OR opening the menu\r\n   * anchored at the caret with `prefixActive=false`.\r\n   */\r\n  private handleShortcut(e: KeyboardEvent): void {\r\n    if (!this.enabled || !this.shortcutSpec) return;\r\n    const sc = this.shortcutSpec;\r\n    const modOk = sc.ctrl ? (e.metaKey || e.ctrlKey) : true;\r\n    const altOk = sc.alt ? e.altKey : !e.altKey || sc.alt === false;\r\n    const shiftOk = sc.shift ? e.shiftKey : !e.shiftKey || sc.shift === false;\r\n    // Loose mod matching — we always accept Cmd OR Ctrl as `mod`.\r\n    if (!modOk) return;\r\n    if (sc.alt !== undefined && sc.alt !== e.altKey) return;\r\n    if (sc.shift !== undefined && sc.shift !== e.shiftKey) return;\r\n    if (e.key.toLowerCase() !== sc.key.toLowerCase()) return;\r\n    e.preventDefault();\r\n    // Re-run selection detection to pick up the current focused editable.\r\n    this.handleSelectionChange();\r\n  }\r\n\r\n  /**\r\n   * Prefix-trigger input handler. When `prefixTrigger.enabled` is true,\r\n   * we watch every focused editable for text starting with the configured\r\n   * prefix (default `/inline ai `). When detected, we mark `prefixActive`\r\n   * so the next Enter (or mod+Enter / double newline) submits.\r\n   *\r\n   * The detection runs on every `input` event so it captures both typing\r\n   * and paste. We do NOT auto-submit on typing — only on the configured\r\n   * submit gesture, so the user can edit their prompt mid-typing.\r\n   */\r\n  private handlePrefixInput(e: Event): void {\r\n    if (!this.enabled || !this.cfg.prefixTrigger?.enabled) return;\r\n    const target = e.target;\r\n    if (!(target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement)) return;\r\n    if (this.cfg.ignoreSelector && target.closest(this.cfg.ignoreSelector)) return;\r\n\r\n    const prefix = this.cfg.prefixTrigger.prefix ?? '/inline ai ';\r\n    const minChars = this.cfg.prefixTrigger.minChars ?? 4;\r\n    const value = target.value;\r\n    const wasActive = this.prefixActive;\r\n    this.prefixActive = value.startsWith(prefix) && value.length >= prefix.length + minChars;\r\n\r\n    // Subtle visual hint via the subtitle indicator when prefix becomes\r\n    // active (so the user knows \"AI is armed, press Enter to run\").\r\n    if (this.prefixActive && !wasActive) {\r\n      const zh = this.cfg.locale === 'zh-TW';\r\n      this.dddk?.subtitle.show({\r\n        text: zh ? `偵測到 ${prefix.trim()} — 按 Enter 跑 AI` : `${prefix.trim()} detected — press Enter to run AI`,\r\n        type: 'info',\r\n        autoHide: 2500,\r\n      });\r\n    }\r\n\r\n    // Wire the submit detector once. Plain Enter is the default — that\r\n    // means a textarea using prefix mode loses literal newlines while\r\n    // prefix is active (acceptable: prefix submissions are short prompts).\r\n    const onSubmit = this.makePrefixSubmitter(target, prefix) as EventListener;\r\n    target.addEventListener('keydown', onSubmit);\r\n    // Self-removing — runs once and unbinds. Re-attaches on the next\r\n    // input event if the user fires it again.\r\n    target.addEventListener(\r\n      'blur',\r\n      () => target.removeEventListener('keydown', onSubmit),\r\n      { once: true },\r\n    );\r\n  }\r\n\r\n  private makePrefixSubmitter(\r\n    target: HTMLInputElement | HTMLTextAreaElement,\r\n    prefix: string,\r\n  ): (e: KeyboardEvent) => void {\r\n    const submitOn = this.cfg.prefixTrigger?.submitOn ?? 'enter';\r\n    let lastWasNewline = false;\r\n    return (e: KeyboardEvent) => {\r\n      if (!this.prefixActive) { lastWasNewline = false; return; }\r\n      const shouldSubmit =\r\n        submitOn === 'enter'\r\n          ? e.key === 'Enter' && !e.shiftKey && !e.metaKey && !e.ctrlKey\r\n        : submitOn === 'mod-enter'\r\n          ? e.key === 'Enter' && (e.metaKey || e.ctrlKey)\r\n        : submitOn === 'double-newline'\r\n          ? e.key === 'Enter' && lastWasNewline\r\n        : false;\r\n      lastWasNewline = e.key === 'Enter';\r\n      if (!shouldSubmit) return;\r\n      e.preventDefault();\r\n      void this.runPrefixSubmit(target, prefix);\r\n    };\r\n  }\r\n\r\n  private async runPrefixSubmit(\r\n    target: HTMLInputElement | HTMLTextAreaElement,\r\n    prefix: string,\r\n  ): Promise<void> {\r\n    const fullValue = target.value;\r\n    if (!fullValue.startsWith(prefix)) return;\r\n    const instruction = fullValue.slice(prefix.length).trim();\r\n    if (!instruction) return;\r\n    // Resolve scope for the trigger element. The prefix flow doesn't go\r\n    // through `handleSelectionChange`, so `activeScopeConfig` isn't set\r\n    // yet — do it manually here so a scoped textarea still gets its\r\n    // overridden llm / systemPrompt for the prefix-AI replacement.\r\n    this.activeScopeConfig = resolveInlineScope(target, this.scopes, this.scopeResolver, instruction);\r\n\r\n    if (this.cfg.prefixTrigger?.confirmBeforeReplace) {\r\n      const zh = this.cfg.locale === 'zh-TW';\r\n      // Cheap confirm via window.confirm — the host can override by\r\n      // setting `confirmBeforeReplace: false` and adding their own UI.\r\n      const ok = window.confirm(\r\n        zh ? `用 AI 跑以下指令並覆蓋輸入框?\\n\\n${instruction}` : `Run AI with this prompt and replace the input?\\n\\n${instruction}`,\r\n      );\r\n      if (!ok) return;\r\n    }\r\n\r\n    // Prefix-submit path: no \"processing\" indicator either — the input\r\n    // itself gets replaced when the LLM returns; a bottom-of-screen\r\n    // pill during the wait is more noise than signal. Errors still\r\n    // surface via `subtitle.show({type:'info'})` in the catch below.\r\n    this.runToken++;\r\n    const myToken = this.runToken;\r\n    try {\r\n      const scope = this.active();\r\n      const llm = resolveLLM(scope.llm, 'inline');\r\n      const result = await llm.complete({\r\n        messages: [\r\n          { role: 'system', content: scope.systemPrompt ?? promptRegistry.render(PROMPT_IDS.INLINE_EDIT, undefined, 'en') },\r\n          { role: 'user', content: `Instruction: ${instruction}\\n\\nContext (with selection marked):\\n\"\"\"\\n[[SEL]][[/SEL]]\\n\"\"\"\\n\\nReturn JSON: { \"replacement\": \"...\" }` },\r\n        ],\r\n        thinking: 'off',\r\n        jsonMode: true,\r\n        temperature: 0,\r\n        maxTokens: 1024,\r\n      });\r\n      if (myToken !== this.runToken) return;\r\n      const replacement = extractReplacement(result.content) ?? result.content.trim();\r\n      target.value = replacement;\r\n      target.setSelectionRange(replacement.length, replacement.length);\r\n      target.dispatchEvent(new Event('input', { bubbles: true }));\r\n      target.dispatchEvent(new Event('change', { bubbles: true }));\r\n      this.prefixActive = false;\r\n    } catch (err) {\r\n      const rawMsg = (err as Error).message ?? '';\r\n      const friendly = humanizeLLMError(rawMsg, this.cfg.locale);\r\n      this.dddk?.subtitle.show({\r\n        text: `${this.t('failed')}: ${friendly}`,\r\n        type: 'info',\r\n        autoHide: 3500,\r\n      });\r\n      if (typeof console !== 'undefined') console.warn('[inline-agent] prefix submit failed:', rawMsg);\r\n    } finally {\r\n      this.dddk?.subtitle.hideIndicator();\r\n    }\r\n  }\r\n\r\n  // ─── helpers ────────────────────────────────────────────────\r\n\r\n  private getSelectionRect(target: HTMLElement): DOMRect | null {\r\n    if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {\r\n      // Mirror-div technique: clone the input's typographic styles into an\r\n      // off-screen <div>, set its text to the input's value up to the\r\n      // selection boundary, and read the caret span's coords. Without this,\r\n      // the menu would anchor to the input element's bbox — fine for a\r\n      // 200×40 input, completely wrong for a tall multiline textarea\r\n      // where the menu floats next to the textarea border instead of the\r\n      // selected text. Algorithm adapted from textarea-caret-position.\r\n      const start = target.selectionStart ?? 0;\r\n      const end = target.selectionEnd ?? start;\r\n      const startCoords = getCaretCoords(target, start);\r\n      const endCoords = getCaretCoords(target, end);\r\n      // Build a DOMRect that spans selectionStart → selectionEnd. The\r\n      // popover reads `rect.right` / `rect.top` from this to anchor at\r\n      // the end of the selection.\r\n      const top = Math.min(startCoords.top, endCoords.top);\r\n      const bottom = Math.max(\r\n        startCoords.top + startCoords.height,\r\n        endCoords.top + endCoords.height,\r\n      );\r\n      // Multi-line selection → anchor the menu at the END of the\r\n      // selection (where the user's cursor is) with zero width. This\r\n      // is right for the popover MENU (narrow, ~200 px, stays near\r\n      // the caret). The wider inline-diff panel needs a different\r\n      // anchor (start-of-selection); that's computed separately at\r\n      // the panel's call site — see `runInlineDiffFlow` → anchor.\r\n      const sameLine = Math.abs(endCoords.top - startCoords.top) < startCoords.height * 0.5;\r\n      if (!sameLine) {\r\n        return new DOMRect(endCoords.left, endCoords.top, 0, endCoords.height);\r\n      }\r\n      const left = Math.min(startCoords.left, endCoords.left);\r\n      const right = Math.max(startCoords.left, endCoords.left);\r\n      return new DOMRect(left, top, Math.max(0, right - left), bottom - top);\r\n    }\r\n    const sel = window.getSelection();\r\n    if (!sel || sel.rangeCount === 0) return null;\r\n    return sel.getRangeAt(0).getBoundingClientRect();\r\n  }\r\n}\r\n\r\n/**\r\n * Convert a raw LLM provider error into a short subtitle message.\r\n * Inputs are things like:\r\n *   `Gemini HTTP 500: { \"error\": { \"code\": 500, \"message\": \"Internal...\" } }`\r\n *   `OpenAI HTTP 429: { ... rate limit ... }`\r\n *   `Gemini HTTP 400: { ... Thinking budget is not supported ... }`\r\n *\r\n * We pluck the vendor + status, drop the JSON blob, and translate the\r\n * common cases into 1-line guidance. Full original message goes to\r\n * console for engineers to grep.\r\n */\r\n/**\r\n * Find the index in `text` where a prefix of `marker` starts at the tail.\r\n * Used by the streaming consumer to avoid emitting characters that\r\n * might be the leading edge of a closing marker we haven't fully\r\n * received yet (e.g. `<<<EN` is held back until the next chunk reveals\r\n * whether it's `<<<END>>>` or just literal text).\r\n * Returns -1 if no prefix overlap.\r\n */\r\nfunction findPartialMarkerTail(text: string, marker: string): number {\r\n  // Longest prefix of `marker` that the tail of `text` ends with.\r\n  const maxLen = Math.min(text.length, marker.length - 1);\r\n  for (let n = maxLen; n > 0; n--) {\r\n    if (text.endsWith(marker.slice(0, n))) return text.length - n;\r\n  }\r\n  return -1;\r\n}\r\n\r\nfunction humanizeLLMError(raw: string, locale: string): string {\r\n  const zh = locale === 'zh-TW';\r\n  const m = raw.match(/^(\\w+)\\s+HTTP\\s+(\\d+)/i);\r\n  if (!m) return raw.length > 80 ? raw.slice(0, 77) + '…' : raw;\r\n  const vendor = m[1];\r\n  const status = parseInt(m[2]!, 10);\r\n  if (status === 429) return zh ? `${vendor} 速率上限，稍等幾秒再試` : `${vendor} rate limit — wait a few seconds and retry`;\r\n  if (status >= 500 && status < 600) return zh ? `${vendor} 暫時忙線，請再試一次` : `${vendor} is having a moment — please retry`;\r\n  if (status === 400) return zh ? `${vendor} 拒絕請求(請求格式問題)` : `${vendor} rejected the request (bad shape)`;\r\n  if (status === 401 || status === 403) return zh ? `${vendor} 認證失敗` : `${vendor} auth failed`;\r\n  return zh ? `${vendor} 失敗 (${status})` : `${vendor} failed (${status})`;\r\n}\r\n\r\n/**\r\n * Parse a shortcut spec like `mod+.` / `ctrl+alt+k` / `shift+enter`.\r\n * `mod` is a synonym for Ctrl on non-Mac and Cmd on Mac (resolved at runtime).\r\n */\r\nfunction parseShortcut(spec: string): { ctrl?: boolean; alt?: boolean; shift?: boolean; key: string } | null {\r\n  if (!spec) return null;\r\n  const parts = spec.toLowerCase().split('+').map((s) => s.trim());\r\n  const out: { ctrl?: boolean; alt?: boolean; shift?: boolean; key: string } = { key: '' };\r\n  for (const p of parts) {\r\n    if (p === 'mod' || p === 'ctrl' || p === 'cmd' || p === 'meta') out.ctrl = true;\r\n    else if (p === 'alt' || p === 'option') out.alt = true;\r\n    else if (p === 'shift') out.shift = true;\r\n    else out.key = p;\r\n  }\r\n  return out.key ? out : null;\r\n}\r\n\r\n// ─── caret coords for inputs / textareas ─────────────────────────────\r\n//\r\n// Mirror-div technique: render the input's value into an invisible\r\n// absolutely-positioned <div> styled IDENTICALLY to the input, with a\r\n// <span> at the requested character position. The span's offset\r\n// coordinates give us the caret position in viewport space after\r\n// adding the input's bounding rect and adjusting for the input's own\r\n// scroll. Cached property list is the minimum subset of computed style\r\n// properties that affect text layout (font, padding, border, wrapping).\r\n\r\nconst MIRROR_PROPS = [\r\n  'direction', 'boxSizing',\r\n  'borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth', 'borderStyle',\r\n  'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft',\r\n  'fontStyle', 'fontVariant', 'fontWeight', 'fontStretch',\r\n  'fontSize', 'fontSizeAdjust', 'lineHeight', 'fontFamily',\r\n  'textAlign', 'textTransform', 'textIndent', 'textDecoration',\r\n  'letterSpacing', 'wordSpacing',\r\n  'tabSize', 'MozTabSize',\r\n] as const;\r\n\r\ninterface CaretCoords {\r\n  top: number;\r\n  left: number;\r\n  height: number;\r\n}\r\n\r\nfunction getCaretCoords(\r\n  el: HTMLInputElement | HTMLTextAreaElement,\r\n  position: number,\r\n): CaretCoords {\r\n  const isTextarea = el.tagName === 'TEXTAREA';\r\n  const computed = window.getComputedStyle(el);\r\n\r\n  const mirror = document.createElement('div');\r\n  document.body.appendChild(mirror);\r\n  const s = mirror.style;\r\n  // Take it out of layout flow.\r\n  s.position = 'absolute';\r\n  s.visibility = 'hidden';\r\n  s.top = '0';\r\n  s.left = '0';\r\n  s.whiteSpace = isTextarea ? 'pre-wrap' : 'pre';\r\n  s.wordWrap = isTextarea ? 'break-word' : 'normal';\r\n  s.overflow = 'hidden';\r\n  s.width = isTextarea ? `${el.clientWidth}px` : 'auto';\r\n  s.height = 'auto';\r\n\r\n  for (const prop of MIRROR_PROPS) {\r\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n    (s as any)[prop] = (computed as any)[prop];\r\n  }\r\n\r\n  const value = el.value;\r\n  // Single-line <input>: collapse whitespace to NBSPs so the mirror\r\n  // doesn't wrap differently from the input.\r\n  const before = value.substring(0, position);\r\n  mirror.textContent = isTextarea ? before : before.replace(/\\s/g, ' ');\r\n\r\n  // Span at the caret position. Need SOME content so it has dimensions —\r\n  // use the next character of value, or '.' as a placeholder.\r\n  const span = document.createElement('span');\r\n  span.textContent = value.substring(position) || '.';\r\n  mirror.appendChild(span);\r\n\r\n  const elRect = el.getBoundingClientRect();\r\n  const lineHeight = parseInt(computed.lineHeight, 10) ||\r\n    parseInt(computed.fontSize, 10) * 1.2;\r\n\r\n  const coords: CaretCoords = {\r\n    top: elRect.top + span.offsetTop - el.scrollTop,\r\n    left: elRect.left + span.offsetLeft - el.scrollLeft,\r\n    height: lineHeight,\r\n  };\r\n\r\n  document.body.removeChild(mirror);\r\n  return coords;\r\n}\r\n\r\n","/**\n * TaskAgent — conversation + host-defined tool calling.\n *\n * The third agent kind, alongside WebAgent (DOM-grounded page\n * operation) and InlineAgent (in-place text edits). TaskAgent has\n * no DOM dependency, no CoT envelope, no Space-gating — it's a\n * straight chat + tool-call loop. Plumbing for things hosts\n * actually build: customer-service Q&A, knowledge lookup,\n * back-end-call agents.\n *\n *   const taskAgent = new TaskAgent({\n *     llm: nano,\n *     systemPrompt: 'Answer Acme Co. support questions.',\n *     tools: [{\n *       name: 'lookup_order',\n *       description: 'Order status by id.',\n *       parameters: { type: 'object', properties: { id: { type: 'string' } } },\n *       handler: async ({ id }) => fetch(`/api/orders/${id}`).then((r) => r.json()),\n *     }],\n *   });\n *   taskAgent.attachTo(dddk);\n *   const reply = await taskAgent.ask('Where is order #12345?');\n *\n * Session sharing: pass `session` to share conversation history with\n * another TaskAgent. Cross-type sharing with WebAgent works at the\n * Session.turns[] level but the re-serialisation cost is non-trivial\n * — it's tracked as a v0.3 item.\n */\n\nimport { resolveLLM } from '../llm/router';\nimport { createSession, pushUserTurn } from '../webagent/session';\nimport type { AgentSession } from '../webagent/types';\nimport type { ActionDefinition } from '../webagent/types';\nimport type { ToolCall } from '../llm/types';\nimport type {\n  TaskAgentConfig,\n  TaskAgentDddkHandle,\n  TaskAgentStreamChunk,\n  TaskRunOptions,\n  TaskTool,\n} from './types';\nimport type { LLMProvider } from '../llm/types';\nimport type { StreamingProvider, StreamChunk } from '../llm/stream';\n\nexport type { TaskAgentConfig, TaskRunOptions, TaskTool, TaskAgentStreamChunk } from './types';\n\nconst DEFAULT_MAX_TOOL_ROUNDS = 4;\nconst DEFAULT_LLM_TIMEOUT_MS = 30_000;\n\n/** Per-step message shape the LLM provider expects. Mirrors what\n *  the inline tool-loop uses so the wire-level result is consistent. */\ninterface ChatMessage {\n  role: 'system' | 'user' | 'assistant' | 'tool';\n  content: string;\n  toolCallId?: string;\n  toolCalls?: ToolCall[];\n}\n\nexport class TaskAgent {\n  private cfg: Required<Pick<TaskAgentConfig, 'systemPrompt' | 'maxToolRounds' | 'enableSubtitle' | 'locale' | 'llmTimeoutMs'>>\n    & Pick<TaskAgentConfig, 'llm'>;\n  private tools: TaskTool[];\n  private session: AgentSession;\n  /** Whether session was injected — if true, we don't auto-replace. */\n  private sessionInjected: boolean;\n  private dddk: TaskAgentDddkHandle | null = null;\n\n  constructor(config: TaskAgentConfig) {\n    this.cfg = {\n      llm: config.llm,\n      systemPrompt: config.systemPrompt,\n      maxToolRounds: config.maxToolRounds ?? DEFAULT_MAX_TOOL_ROUNDS,\n      enableSubtitle: config.enableSubtitle ?? false,\n      locale: config.locale ?? 'en',\n      llmTimeoutMs: config.llmTimeoutMs ?? DEFAULT_LLM_TIMEOUT_MS,\n    };\n    this.tools = (config.tools ?? []).slice();\n    if (config.session) {\n      this.session = config.session;\n      this.sessionInjected = true;\n    } else {\n      const currentPath = typeof location !== 'undefined' ? location.pathname + location.search : '/';\n      this.session = createSession(currentPath);\n      this.sessionInjected = false;\n    }\n  }\n\n  // ─── public API ─────────────────────────────────────────────\n\n  /** Inject a DotDotDuck-like handle so subtitle narration works\n   *  when `enableSubtitle` is on. Same shape WebAgent / InlineAgent\n   *  use; the import-light type is on purpose to avoid circular deps. */\n  attachTo(dddk: TaskAgentDddkHandle): void {\n    this.dddk = dddk;\n  }\n\n  /** Read-only view of the current session — useful for inspection +\n   *  for wiring the session into a sibling TaskAgent. */\n  getSession(): AgentSession {\n    return this.session;\n  }\n\n  /**\n   * Swap the session out. Useful when host wants to reset\n   * conversation history mid-flight, or hand the agent a freshly\n   * registry-issued session. Returns the previous session in case\n   * the host wants to archive it.\n   */\n  setSession(session: AgentSession): AgentSession {\n    const prev = this.session;\n    this.session = session;\n    this.sessionInjected = true;\n    return prev;\n  }\n\n  /** Toggle whether to narrate progress in the subtitle bar. */\n  setEnableSubtitle(on: boolean): void {\n    this.cfg.enableSubtitle = on;\n  }\n\n  /** Register a new tool the LLM can call. Returns a handle whose\n   *  `remove()` unregisters it. Mid-loop registrations land in the\n   *  next LLM call within the same ask(); in-flight LLM calls keep\n   *  the snapshot they were made with. */\n  registerTool(tool: TaskTool): { remove(): void } {\n    this.tools.push(tool);\n    return {\n      remove: () => {\n        const idx = this.tools.findIndex((t) => t.name === tool.name);\n        if (idx >= 0) this.tools.splice(idx, 1);\n      },\n    };\n  }\n\n  /** Unregister a tool by name. Returns true when one was removed. */\n  unregisterTool(name: string): boolean {\n    const idx = this.tools.findIndex((t) => t.name === name);\n    if (idx < 0) return false;\n    this.tools.splice(idx, 1);\n    return true;\n  }\n\n  /**\n   * Ask the agent — single-shot conversational turn. Appends the\n   * task as a user turn to the session, runs the tool-call loop\n   * until the LLM produces text (or the round cap fires), appends\n   * the assistant's reply, returns the text.\n   *\n   * If the loop hits `maxToolRounds` without a text-only reply, the\n   * partial content from the last LLM call is returned (may be\n   * empty). Hosts who want to differentiate use the streaming\n   * variant — TBD in a follow-up.\n   */\n  async ask(task: string, opts: TaskRunOptions = {}): Promise<string> {\n    if (!task || !task.trim()) return '';\n    pushUserTurn(this.session, { text: task });\n\n    const maxRounds = opts.maxToolRounds ?? this.cfg.maxToolRounds;\n    const externalSignal = opts.signal;\n\n    // Local abort so we can cancel on signal abort + timeout.\n    const ac = new AbortController();\n    const cleanups: Array<() => void> = [];\n    if (externalSignal) {\n      const onAbort = () => ac.abort();\n      externalSignal.addEventListener('abort', onAbort);\n      cleanups.push(() => externalSignal.removeEventListener('abort', onAbort));\n    }\n    const timeoutId = setTimeout(() => ac.abort(), this.cfg.llmTimeoutMs);\n    cleanups.push(() => clearTimeout(timeoutId));\n\n    try {\n      const llm = resolveLLM(this.cfg.llm, 'task');\n      const toolDefs = this.tools.map((t) => ({\n        name: t.name,\n        description: t.description,\n        parameters: t.parameters,\n      }));\n\n      // Serialize prior session turns into chat messages so the LLM\n      // sees the conversation history. The just-pushed user turn for\n      // THIS call is the last one we serialize. This is what makes\n      // shared-session continuity actually work — both same-type\n      // (TaskAgent ↔ TaskAgent) and cross-type (TaskAgent reading a\n      // WebAgent-authored session). Cross-type is lossy: WebAgent's\n      // CoT `agent_step` turns are skipped here because TaskAgent\n      // doesn't need to replay each tool dispatch — only the\n      // user-facing conversation matters for the next reply.\n      const messages: ChatMessage[] = [{ role: 'system', content: this.cfg.systemPrompt }];\n      for (const turn of this.session.turns) {\n        if (turn.kind === 'user') {\n          messages.push({ role: 'user', content: turn.text });\n        } else if (turn.kind === 'agent_final') {\n          // FinalTurn doesn't carry a typed text field in the existing\n          // shape; we use whatever this TaskAgent stamped onto it.\n          // eslint-disable-next-line @typescript-eslint/no-explicit-any\n          const text = (turn as any).text as string | undefined;\n          if (text) messages.push({ role: 'assistant', content: text });\n        }\n        // agent_step (WebAgent CoT) intentionally skipped — see comment above.\n      }\n      // No user turn yet? Defensive — `pushUserTurn` above ensures\n      // there's always at least one, but `messages` should never be\n      // a system prompt alone.\n      if (messages.length === 1) {\n        messages.push({ role: 'user', content: task });\n      }\n\n      let finalText = '';\n      for (let round = 0; round < maxRounds; round++) {\n        if (ac.signal.aborted) break;\n        const result = await llm.complete({\n          messages,\n          tools: toolDefs.length > 0 ? toolDefs : undefined,\n          temperature: 0,\n          signal: ac.signal,\n        });\n        const calls = result.toolCalls ?? [];\n\n        if (calls.length === 0) {\n          // Final answer.\n          finalText = result.content ?? '';\n          break;\n        }\n\n        // Append the assistant's tool-call turn for LLM context.\n        messages.push({ role: 'assistant', content: result.content ?? '', toolCalls: calls });\n\n        // Execute each requested tool serially, append results.\n        for (const call of calls) {\n          if (ac.signal.aborted) break;\n          if (this.cfg.enableSubtitle && this.dddk?.subtitle) {\n            const msg = this.cfg.locale === 'zh-TW' ? `查詢中：${call.name}…` : `Looking up: ${call.name}…`;\n            try { this.dddk.subtitle.show({ text: msg, type: 'info', autoHide: 0 }); } catch { /* swallow */ }\n          }\n          const def = this.tools.find((t) => t.name === call.name);\n          if (!def) {\n            messages.push({\n              role: 'tool',\n              toolCallId: call.id,\n              content: JSON.stringify({ ok: false, reason: 'unknown_tool', name: call.name }),\n            });\n            continue;\n          }\n          const toolResult = await runToolSafe(def, call.arguments as Record<string, unknown> | undefined, ac.signal, this.session);\n          messages.push({\n            role: 'tool',\n            toolCallId: call.id,\n            content: JSON.stringify(toolResult ?? { ok: true }),\n          });\n        }\n        // Loop continues; LLM sees the tool results and either\n        // calls more tools or composes the final text.\n      }\n\n      // Append the assistant turn — store the reply text alongside\n      // the standard `kind: 'final'` shape so the NEXT ask() picks\n      // up the conversation correctly when serializing turns.\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      this.session.turns.push({ kind: 'agent_final', ts: Date.now(), text: finalText } as any);\n      this.session.updatedAt = Date.now();\n\n      return finalText;\n    } finally {\n      for (const fn of cleanups) fn();\n      // Avoid silently sitting on the injected-session flag if the\n      // host calls setSession again — nothing else needs cleanup\n      // here, the session reference is intentional.\n      void this.sessionInjected;\n    }\n  }\n\n  /**\n   * Streaming variant of `ask`. Yields `TaskAgentStreamChunk`s as\n   * the LLM types. Tool-call rounds emit empty `delta` chunks with\n   * `toolCallStart` / `toolCallEnd` markers so the host can drive\n   * a typewriter UI + \"looking up…\" indicator with a single loop.\n   *\n   * Falls back to non-streaming `complete` when the provider doesn't\n   * implement `streamComplete` — the final reply lands in one chunk\n   * instead of incrementally. Callers get the same iterator shape\n   * either way.\n   */\n  async *streamAsk(task: string, opts: TaskRunOptions = {}): AsyncIterable<TaskAgentStreamChunk> {\n    if (!task || !task.trim()) {\n      yield { delta: '', text: '', done: true };\n      return;\n    }\n    pushUserTurn(this.session, { text: task });\n\n    const maxRounds = opts.maxToolRounds ?? this.cfg.maxToolRounds;\n    const externalSignal = opts.signal;\n    const ac = new AbortController();\n    const cleanups: Array<() => void> = [];\n    if (externalSignal) {\n      const onAbort = () => ac.abort();\n      externalSignal.addEventListener('abort', onAbort);\n      cleanups.push(() => externalSignal.removeEventListener('abort', onAbort));\n    }\n    const timeoutId = setTimeout(() => ac.abort(), this.cfg.llmTimeoutMs);\n    cleanups.push(() => clearTimeout(timeoutId));\n\n    try {\n      const llm = resolveLLM(this.cfg.llm, 'task') as LLMProvider;\n      const streamer = llm as unknown as StreamingProvider;\n      const canStream = typeof streamer.streamComplete === 'function';\n\n      const toolDefs = this.tools.map((t) => ({\n        name: t.name,\n        description: t.description,\n        parameters: t.parameters,\n      }));\n\n      // Same serialization as `ask` — share-session continuity works\n      // for streaming too.\n      const messages: ChatMessage[] = [{ role: 'system', content: this.cfg.systemPrompt }];\n      for (const turn of this.session.turns) {\n        if (turn.kind === 'user') {\n          messages.push({ role: 'user', content: turn.text });\n        } else if (turn.kind === 'agent_final') {\n          // eslint-disable-next-line @typescript-eslint/no-explicit-any\n          const text = (turn as any).text as string | undefined;\n          if (text) messages.push({ role: 'assistant', content: text });\n        }\n      }\n      if (messages.length === 1) {\n        messages.push({ role: 'user', content: task });\n      }\n\n      let finalText = '';\n\n      for (let round = 0; round < maxRounds; round++) {\n        if (ac.signal.aborted) break;\n\n        let assistantText = '';\n        let toolCalls: import('../llm/types').ToolCall[] = [];\n\n        if (canStream && streamer.streamComplete) {\n          const handle = streamer.streamComplete({\n            messages,\n            tools: toolDefs.length > 0 ? toolDefs : undefined,\n            temperature: 0,\n            signal: ac.signal,\n          });\n          let prevText = '';\n          for await (const chunk of handle as AsyncIterable<StreamChunk>) {\n            if (ac.signal.aborted) break;\n            if (chunk.text !== undefined && chunk.text.length > prevText.length) {\n              const delta = chunk.text.slice(prevText.length);\n              prevText = chunk.text;\n              if (delta) yield { delta, text: finalText + chunk.text, done: false };\n            }\n            if (chunk.toolCalls && chunk.toolCalls.length > 0) {\n              toolCalls = chunk.toolCalls;\n            }\n            if (chunk.done) {\n              assistantText = chunk.text ?? prevText;\n              break;\n            }\n          }\n        } else {\n          // Non-streaming fallback — one big chunk per round.\n          const r = await llm.complete({\n            messages,\n            tools: toolDefs.length > 0 ? toolDefs : undefined,\n            temperature: 0,\n            signal: ac.signal,\n          });\n          assistantText = r.content ?? '';\n          toolCalls = r.toolCalls ?? [];\n          if (assistantText) {\n            yield { delta: assistantText, text: finalText + assistantText, done: false };\n          }\n        }\n\n        if (toolCalls.length === 0) {\n          finalText += assistantText;\n          break;\n        }\n\n        // Tool round — append the assistant's tool-call turn, run\n        // each tool, append results, loop.\n        messages.push({ role: 'assistant', content: assistantText, toolCalls });\n        finalText += assistantText;\n\n        for (const call of toolCalls) {\n          if (ac.signal.aborted) break;\n          yield { delta: '', text: finalText, done: false, toolCallStart: { name: call.name } };\n          const def = this.tools.find((t) => t.name === call.name);\n          let toolOk = false;\n          if (!def) {\n            messages.push({\n              role: 'tool',\n              toolCallId: call.id,\n              content: JSON.stringify({ ok: false, reason: 'unknown_tool', name: call.name }),\n            });\n          } else {\n            const toolResult = await runToolSafe(\n              def,\n              call.arguments as Record<string, unknown> | undefined,\n              ac.signal,\n              this.session,\n            );\n            toolOk = !!toolResult && (typeof toolResult !== 'object'\n              || (toolResult as { ok?: boolean }).ok !== false);\n            messages.push({\n              role: 'tool',\n              toolCallId: call.id,\n              content: JSON.stringify(toolResult ?? { ok: true }),\n            });\n          }\n          yield { delta: '', text: finalText, done: false, toolCallEnd: { name: call.name, ok: toolOk } };\n        }\n      }\n\n      // Persist + emit terminal chunk.\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      this.session.turns.push({ kind: 'agent_final', ts: Date.now(), text: finalText } as any);\n      this.session.updatedAt = Date.now();\n      yield { delta: '', text: finalText, done: true };\n    } finally {\n      for (const fn of cleanups) fn();\n    }\n  }\n}\n\nasync function runToolSafe(\n  def: ActionDefinition,\n  args: Record<string, unknown> | undefined,\n  signal: AbortSignal,\n  session: AgentSession,\n): Promise<unknown> {\n  try {\n    // Minimal context — TaskAgent tools shouldn't depend on DOM /\n    // selector resolution / event emitters that WebAgent's loop owns.\n    // Pass the session so tools can read prior history if they want to.\n    const ctx = {\n      session,\n      signal,\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      resolveSelector: () => null as any,\n      indexMap: new Map<string, Element>(),\n    };\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    return await (def.handler as any)(args ?? {}, ctx);\n  } catch (err) {\n    return { ok: false, reason: 'unknown', message: err instanceof Error ? err.message : String(err) };\n  }\n}\n","/**\r\n * AgentCursor — visible big cursor that shows what the agent is about to do.\r\n *\r\n * When the agent is about to click / type / scroll, a large floating cursor\r\n * smoothly travels to the target element and pauses for `preClickPauseMs`\r\n * before the action fires. The user sees what's about to happen in time to\r\n * cancel.\r\n *\r\n * This is purely a visualization layer — it does not drive actions. It\r\n * subscribes to the `before_action` event webagent emits before every\r\n * action handler runs.\r\n *\r\n * Usage:\r\n *   const cursor = new AgentCursor({ preClickPauseMs: 250 });\r\n *   cursor.attachTo(dddk);\r\n *\r\n * To disable mid-run:\r\n *   cursor.setEnabled(false);\r\n */\r\n\r\nimport type { DotDotDuck } from '../orchestrator';\r\nimport { injectScopedStyle } from '../utils/dom';\r\n\r\nexport interface AgentCursorConfig {\r\n  /** Pause (ms) between cursor arriving on target and action firing. Default 250. */\r\n  preClickPauseMs?: number;\r\n  /** Cursor size in px. Default 32. */\r\n  size?: number;\r\n  /** Tint of the cursor stroke. Default uses CSS var or accent fallback. */\r\n  color?: string;\r\n  /** Travel duration (ms) between targets. Default 350. */\r\n  travelMs?: number;\r\n  /** Disabled by default? Default false (enabled). */\r\n  enabled?: boolean;\r\n}\r\n\r\nimport { UI_ATTR } from '../utils/dom';\r\nconst STYLE_ID = 'dddk-agent-cursor-style';\r\n\r\ntype Resolver = () => void;\r\n\r\nexport class AgentCursor {\r\n  private cfg: Required<AgentCursorConfig>;\r\n  private cursorEl: HTMLDivElement | null = null;\r\n  private cleanups: Array<() => void> = [];\r\n  private enabled: boolean;\r\n  /** Resolves the pause promise — webagent's action handler awaits this gate. */\r\n  private pendingPause: Resolver | null = null;\r\n\r\n  constructor(config: AgentCursorConfig = {}) {\r\n    this.cfg = {\r\n      preClickPauseMs: config.preClickPauseMs ?? 250,\r\n      size: config.size ?? 32,\r\n      color: config.color ?? 'var(--dddk-accent, #ec4899)',\r\n      travelMs: config.travelMs ?? 350,\r\n      enabled: config.enabled ?? true,\r\n    };\r\n    this.enabled = this.cfg.enabled;\r\n  }\r\n\r\n  attachTo(dddk: DotDotDuck): void {\r\n    if (typeof document === 'undefined') return;\r\n    ensureStyles();\r\n    this.mount();\r\n\r\n    // agent_tool_start: travel to target, hold for preClickPauseMs.\r\n    const onToolStart = async (payload: { name: string; args: Record<string, unknown>; targetSelector?: string }) => {\r\n      if (!this.enabled) return;\r\n      if (!payload.targetSelector) return;\r\n      const el = document.querySelector<HTMLElement>(payload.targetSelector);\r\n      if (!el) return;\r\n      const rect = el.getBoundingClientRect();\r\n      const cx = rect.left + rect.width / 2 + window.scrollX;\r\n      const cy = rect.top + rect.height / 2 + window.scrollY;\r\n      this.moveTo(cx, cy);\r\n      this.flashTarget(el);\r\n      await this.wait(this.cfg.preClickPauseMs);\r\n    };\r\n\r\n    // agent_tool_end: brief click pulse animation.\r\n    const onToolEnd = (): void => {\r\n      if (!this.enabled || !this.cursorEl) return;\r\n      this.cursorEl.classList.remove('clicking');\r\n      void this.cursorEl.offsetHeight;\r\n      this.cursorEl.classList.add('clicking');\r\n    };\r\n\r\n    const onFinal = (): void => this.hide();\r\n    const onError = (): void => this.hide();\r\n\r\n    dddk.on('agent_tool_start', onToolStart);\r\n    dddk.on('agent_tool_end', onToolEnd);\r\n    dddk.on('agent_final', onFinal);\r\n    dddk.on('agent_error', onError);\r\n    this.cleanups.push(\r\n      () => dddk.off('agent_tool_start', onToolStart),\r\n      () => dddk.off('agent_tool_end', onToolEnd),\r\n      () => dddk.off('agent_final', onFinal),\r\n      () => dddk.off('agent_error', onError),\r\n    );\r\n  }\r\n\r\n  setEnabled(enabled: boolean): void {\r\n    this.enabled = enabled;\r\n    if (!enabled) this.hide();\r\n  }\r\n\r\n  destroy(): void {\r\n    for (const c of this.cleanups) c();\r\n    this.cleanups = [];\r\n    this.cursorEl?.remove();\r\n    this.cursorEl = null;\r\n  }\r\n\r\n  // ─── private ────────────────────────────────────────────────────\r\n\r\n  private mount(): void {\r\n    if (this.cursorEl) return;\r\n    const el = document.createElement('div');\r\n    el.setAttribute(UI_ATTR, 'agent-cursor');\r\n    el.style.setProperty('--ac-size', `${this.cfg.size}px`);\r\n    el.style.setProperty('--ac-color', this.cfg.color);\r\n    el.style.setProperty('--ac-travel', `${this.cfg.travelMs}ms`);\r\n    el.innerHTML = `\r\n      <svg viewBox=\"0 0 24 24\" width=\"100%\" height=\"100%\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n        <path d=\"M5 3l13 9-6 1.5L9.5 19z\" fill=\"currentColor\" fill-opacity=\"0.15\" />\r\n      </svg>\r\n      <div class=\"ac-ring\"></div>\r\n    `;\r\n    document.body.appendChild(el);\r\n    this.cursorEl = el;\r\n  }\r\n\r\n  private moveTo(x: number, y: number): void {\r\n    if (!this.cursorEl) this.mount();\r\n    if (!this.cursorEl) return;\r\n    this.cursorEl.style.left = `${x}px`;\r\n    this.cursorEl.style.top = `${y}px`;\r\n    this.cursorEl.style.opacity = '1';\r\n  }\r\n\r\n  private hide(): void {\r\n    if (!this.cursorEl) return;\r\n    this.cursorEl.style.opacity = '0';\r\n  }\r\n\r\n  private flashTarget(el: HTMLElement): void {\r\n    el.setAttribute('data-dddk-agent-target', '');\r\n    setTimeout(() => el.removeAttribute('data-dddk-agent-target'), 600);\r\n  }\r\n\r\n  private wait(ms: number): Promise<void> {\r\n    return new Promise((resolve) => {\r\n      // If a previous wait() is still pending (e.g. before_action fired twice\r\n      // back-to-back before the first pause elapsed), resolve the old resolver\r\n      // first so its Promise doesn't dangle forever and stall the agent loop.\r\n      if (this.pendingPause && this.pendingPause !== resolve) {\r\n        const prev = this.pendingPause;\r\n        this.pendingPause = null;\r\n        prev();\r\n      }\r\n      this.pendingPause = resolve;\r\n      setTimeout(() => {\r\n        if (this.pendingPause === resolve) {\r\n          this.pendingPause = null;\r\n          resolve();\r\n        }\r\n      }, ms);\r\n    });\r\n  }\r\n}\r\n\r\nfunction ensureStyles(): void {\r\n  injectScopedStyle(STYLE_ID, `\r\n    [${UI_ATTR}=\"agent-cursor\"] {\r\n      position: absolute;\r\n      width: var(--ac-size);\r\n      height: var(--ac-size);\r\n      pointer-events: none;\r\n      transform: translate(-25%, -25%);\r\n      transition: left var(--ac-travel) cubic-bezier(0.25, 0.8, 0.25, 1),\r\n                  top  var(--ac-travel) cubic-bezier(0.25, 0.8, 0.25, 1),\r\n                  opacity 0.25s;\r\n      color: var(--ac-color);\r\n      z-index: var(--dddk-z-cursor, 9800);\r\n      opacity: 0;\r\n      filter: drop-shadow(0 2px 6px rgba(0,0,0,0.25));\r\n    }\r\n    [${UI_ATTR}=\"agent-cursor\"] svg { display: block; }\r\n    [${UI_ATTR}=\"agent-cursor\"] .ac-ring {\r\n      position: absolute; inset: -8px;\r\n      border: 2px solid var(--ac-color);\r\n      border-radius: 50%;\r\n      opacity: 0;\r\n    }\r\n    [${UI_ATTR}=\"agent-cursor\"].clicking .ac-ring {\r\n      animation: dddkAcClick 380ms ease-out;\r\n    }\r\n    @keyframes dddkAcClick {\r\n      0%   { opacity: 0.8; transform: scale(0.4); }\r\n      100% { opacity: 0;   transform: scale(1.5); }\r\n    }\r\n    [data-dddk-agent-target] {\r\n      outline: 2px dashed var(--dddk-accent, #ec4899);\r\n      outline-offset: 2px;\r\n      transition: outline-color 0.2s;\r\n    }\r\n  `);\r\n}\r\n","/**\n * Runtime sitemap learning — extend a static sitemap with pages the agent\n * (or user) actually visits.\n *\n * Why: static sitemap covers known routes. But real apps have routes the\n * author forgot, or dynamic /:id pages with many instances. Learner observes\n * navigation events + DOM read summaries and augments the tree incrementally.\n *\n * Storage is host-supplied (any sync K/V — typically wrap dddk Cache).\n *\n * NOT enabled by default — host opts in:\n *   const learner = new SitemapLearner({ base: SAAS_SITEMAP_TEMPLATE, storage });\n *   learner.observePath(location.pathname, { title: document.title, ... });\n *   const augmented = learner.materialize();\n *   new WebAgent({ sitemap: augmented, ... });\n */\n\nimport type { SitemapNode } from './types';\n\nexport interface SitemapLearnerStorage {\n  get(key: string): string | null;\n  set(key: string, value: string): void;\n}\n\nexport interface SitemapLearnerOptions {\n  /** Base static sitemap. Learned data merges on top. */\n  base: SitemapNode;\n  /** Persistent storage (use dddk Cache or any K/V). */\n  storage: SitemapLearnerStorage;\n  /** Storage key. Default 'webagent.sitemap.learned'. */\n  storageKey?: string;\n  /** Cap on learned children per parent — prevents unbounded tree growth. Default 50. */\n  maxLearnedPerParent?: number;\n  /** Treat segments matching this as dynamic (collapse to :param). Default UUIDs / numeric ids. */\n  isDynamicSegment?: (segment: string) => boolean;\n}\n\ninterface LearnedNode {\n  title?: string;\n  description?: string;\n  actions?: string[];\n  visitCount: number;\n  lastVisited: number;\n}\n\ntype LearnedTree = Record<string, LearnedNode>;  // path → learned info\n\nconst DEFAULT_DYNAMIC_PATTERNS = [\n  /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, // UUID\n  /^\\d+$/,                          // pure numeric id\n  /^[A-Za-z0-9_-]{12,}$/,           // long opaque id\n];\n\nexport class SitemapLearner {\n  private opts: Required<Pick<SitemapLearnerOptions, 'storageKey' | 'maxLearnedPerParent' | 'isDynamicSegment'>> &\n    SitemapLearnerOptions;\n  private learned: LearnedTree;\n\n  constructor(opts: SitemapLearnerOptions) {\n    this.opts = {\n      storageKey: 'webagent.sitemap.learned',\n      maxLearnedPerParent: 50,\n      isDynamicSegment: (seg) => DEFAULT_DYNAMIC_PATTERNS.some((p) => p.test(seg)),\n      ...opts,\n    };\n    this.learned = this.read();\n  }\n\n  /**\n   * Record a page visit. Path is normalized (dynamic segments → :param).\n   * Optional `info` gets merged into the learned node (title / actions etc.).\n   */\n  observePath(\n    path: string,\n    info: { title?: string; description?: string; actions?: string[] } = {}\n  ): void {\n    const norm = this.normalizePath(path);\n    const cur = this.learned[norm] ?? { visitCount: 0, lastVisited: 0 };\n    cur.visitCount += 1;\n    cur.lastVisited = Date.now();\n    if (info.title) cur.title = info.title;\n    if (info.description) cur.description = info.description;\n    if (info.actions) cur.actions = Array.from(new Set([...(cur.actions ?? []), ...info.actions]));\n    this.learned[norm] = cur;\n    this.write();\n  }\n\n  /**\n   * Produce an augmented sitemap merging base + learned data.\n   * Learned nodes that already exist in base just merge metadata.\n   * Learned nodes that DON'T exist in base get added as new children.\n   */\n  materialize(): SitemapNode {\n    const cloned = structuredClone(this.opts.base);\n    for (const [path, info] of Object.entries(this.learned)) {\n      this.mergePath(cloned, path, info);\n    }\n    return cloned;\n  }\n\n  /** Drop all learned data — keep static base. */\n  reset(): void {\n    this.learned = {};\n    this.write();\n  }\n\n  /** Read raw learned tree (for inspection / export). */\n  inspect(): LearnedTree {\n    return { ...this.learned };\n  }\n\n  // ─── private ──────────────────────────────────────────────────────\n\n  private normalizePath(path: string): string {\n    const segments = path.replace(/^\\/+|\\/+$/g, '').split('/').filter(Boolean);\n    return '/' + segments.map((s) => (this.opts.isDynamicSegment(s) ? ':id' : s)).join('/');\n  }\n\n  private mergePath(root: SitemapNode, path: string, info: LearnedNode): void {\n    const segments = path.replace(/^\\/+|\\/+$/g, '').split('/').filter(Boolean);\n    let cur = root;\n    for (const seg of segments) {\n      cur.children = cur.children ?? {};\n      let next = cur.children[seg];\n      if (!next) {\n        const count = Object.keys(cur.children).length;\n        if (count >= this.opts.maxLearnedPerParent) return; // cap\n        next = {\n          title: seg.startsWith(':') ? `${seg.slice(1)} detail` : seg,\n        };\n        cur.children[seg] = next;\n      }\n      cur = next;\n    }\n    // Merge metadata into leaf\n    if (info.title && !cur.title) cur.title = info.title;\n    if (info.description && !cur.description) cur.description = info.description;\n    if (info.actions) {\n      cur.actions = Array.from(new Set([...(cur.actions ?? []), ...info.actions]));\n    }\n  }\n\n  private read(): LearnedTree {\n    const raw = this.opts.storage.get(this.opts.storageKey);\n    if (!raw) return {};\n    try {\n      return JSON.parse(raw) as LearnedTree;\n    } catch {\n      return {};\n    }\n  }\n\n  private write(): void {\n    this.opts.storage.set(this.opts.storageKey, JSON.stringify(this.learned));\n  }\n}\n","import type { CoreMemoryConfig, CoreMemorySchema } from './types';\n\nconst KEY = 'dddk:memory:core';\n\ntype StorageKind = NonNullable<CoreMemoryConfig['storage']>;\n\nfunction pickStorage(kind: StorageKind | undefined): Storage | null {\n  if (typeof window === 'undefined') return null;\n  if (kind === 'sessionStorage') return window.sessionStorage;\n  if (kind === 'memory') return null;\n  return window.localStorage;\n}\n\n/** Tier 1 — structured user profile, always in context. < maxBytes. */\nexport class CoreMemory {\n  private data: Record<string, unknown> = {};\n  private schema?: CoreMemorySchema;\n  private storage: Storage | null;\n  private maxBytes: number;\n\n  constructor(cfg: CoreMemoryConfig = {}) {\n    this.schema = cfg.schema;\n    this.maxBytes = cfg.maxBytes ?? 2048;\n    this.storage = pickStorage(cfg.storage);\n    this.load();\n  }\n\n  private load(): void {\n    if (!this.storage) return;\n    try {\n      const raw = this.storage.getItem(KEY);\n      if (raw) this.data = JSON.parse(raw) as Record<string, unknown>;\n    } catch { /* corrupt blob — start fresh */ }\n  }\n\n  private persist(): void {\n    if (!this.storage) return;\n    try { this.storage.setItem(KEY, JSON.stringify(this.data)); } catch { /* quota */ }\n  }\n\n  private validateField(key: string, value: unknown): boolean {\n    if (!this.schema) return true;\n    const t = this.schema[key];\n    if (!t) return false;\n    switch (t) {\n      case 'string': return typeof value === 'string';\n      case 'array': return Array.isArray(value);\n      case 'object': return value != null && typeof value === 'object' && !Array.isArray(value);\n      case 'number': return typeof value === 'number';\n      case 'boolean': return typeof value === 'boolean';\n    }\n  }\n\n  get(key: string): unknown {\n    return this.data[key];\n  }\n\n  set(key: string, value: unknown): boolean {\n    if (!this.validateField(key, value)) {\n      if (typeof console !== 'undefined') {\n        console.warn(`[dddk memory] core: field \"${key}\" rejected by schema`);\n      }\n      return false;\n    }\n    const next = { ...this.data, [key]: value };\n    const size = JSON.stringify(next).length;\n    if (size > this.maxBytes) {\n      if (typeof console !== 'undefined') {\n        console.warn(`[dddk memory] core: write would exceed ${this.maxBytes} bytes`);\n      }\n      return false;\n    }\n    this.data = next;\n    this.persist();\n    return true;\n  }\n\n  remove(key: string): void {\n    delete this.data[key];\n    this.persist();\n  }\n\n  snapshot(): Record<string, unknown> {\n    return { ...this.data };\n  }\n\n  clear(): void {\n    this.data = {};\n    if (this.storage) {\n      try { this.storage.removeItem(KEY); } catch { /* ignore */ }\n    }\n  }\n\n  /** Render as a system-prompt block. Empty string when no entries. */\n  toPromptBlock(): string {\n    const entries = Object.entries(this.data);\n    if (entries.length === 0) return '';\n    const lines = ['# About this user'];\n    for (const [k, v] of entries) {\n      const val = typeof v === 'string' ? v : JSON.stringify(v);\n      lines.push(`- ${k}: ${val}`);\n    }\n    return lines.join('\\n');\n  }\n}\n","import type { EpisodicEntry, EpisodicMemoryConfig } from './types';\n\nconst KEY = 'dddk:memory:episodic';\n\ntype StorageKind = NonNullable<EpisodicMemoryConfig['storage']>;\n\nfunction pickStorage(kind: StorageKind | undefined): Storage | null {\n  if (typeof window === 'undefined') return null;\n  if (kind === 'sessionStorage') return window.sessionStorage;\n  if (kind === 'memory') return null;\n  return window.localStorage;\n}\n\nfunction tokenize(s: string): Set<string> {\n  return new Set(s.toLowerCase().split(/[\\s\\p{P}]+/u).filter((t) => t.length > 1));\n}\n\nfunction overlapScore(query: Set<string>, doc: Set<string>): number {\n  let hit = 0;\n  for (const t of query) if (doc.has(t)) hit++;\n  return hit / Math.max(1, query.size);\n}\n\n/** Tier 2 — ring buffer of past session summaries. */\nexport class EpisodicMemory {\n  private entries: EpisodicEntry[] = [];\n  private maxEntries: number;\n  private replayTopK: number;\n  private relevance: 'recency' | 'keyword';\n  private storage: Storage | null;\n  private retentionDays: number;\n\n  constructor(cfg: EpisodicMemoryConfig = {}, retentionDays = 90) {\n    this.maxEntries = cfg.maxEntries ?? 50;\n    this.replayTopK = cfg.replayTopK ?? 3;\n    this.relevance = cfg.relevance ?? 'recency';\n    this.storage = pickStorage(cfg.storage);\n    this.retentionDays = retentionDays;\n    this.load();\n    this.pruneExpired();\n  }\n\n  private load(): void {\n    if (!this.storage) return;\n    try {\n      const raw = this.storage.getItem(KEY);\n      if (raw) this.entries = JSON.parse(raw) as EpisodicEntry[];\n    } catch { /* corrupt blob */ }\n  }\n\n  private persist(): void {\n    if (!this.storage) return;\n    try { this.storage.setItem(KEY, JSON.stringify(this.entries)); } catch { /* quota */ }\n  }\n\n  private pruneExpired(): void {\n    if (this.retentionDays <= 0) return;\n    const cutoff = Date.now() - this.retentionDays * 86_400_000;\n    const next = this.entries.filter((e) => e.timestamp >= cutoff);\n    if (next.length !== this.entries.length) {\n      this.entries = next;\n      this.persist();\n    }\n  }\n\n  add(entry: Omit<EpisodicEntry, 'id' | 'timestamp'> & { id?: string; timestamp?: number }): EpisodicEntry {\n    const e: EpisodicEntry = {\n      id: entry.id ?? `ep_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`,\n      summary: entry.summary,\n      tags: entry.tags,\n      timestamp: entry.timestamp ?? Date.now(),\n      turnCount: entry.turnCount,\n      taskSummary: entry.taskSummary,\n    };\n    this.entries.push(e);\n    if (this.entries.length > this.maxEntries) {\n      this.entries.splice(0, this.entries.length - this.maxEntries);\n    }\n    this.persist();\n    return e;\n  }\n\n  list(): EpisodicEntry[] {\n    return this.entries.slice();\n  }\n\n  remove(id: string): void {\n    const next = this.entries.filter((e) => e.id !== id);\n    if (next.length !== this.entries.length) {\n      this.entries = next;\n      this.persist();\n    }\n  }\n\n  topK(query: string | null, k: number): EpisodicEntry[] {\n    const limit = Math.min(k, this.entries.length);\n    if (limit === 0) return [];\n    if (this.relevance === 'recency' || !query) {\n      return this.entries.slice(-limit).reverse();\n    }\n    const qTokens = tokenize(query);\n    return this.entries\n      .map((e) => ({\n        entry: e,\n        score: overlapScore(qTokens, tokenize(e.summary + ' ' + (e.taskSummary ?? ''))),\n      }))\n      .filter((x) => x.score > 0)\n      .sort((a, b) => b.score - a.score)\n      .slice(0, limit)\n      .map((x) => x.entry);\n  }\n\n  clear(): void {\n    this.entries = [];\n    if (this.storage) {\n      try { this.storage.removeItem(KEY); } catch { /* ignore */ }\n    }\n  }\n\n  /** Render as a system-prompt block. Empty string when no replays. */\n  toPromptBlock(query?: string | null): string {\n    const picks = this.topK(query ?? null, this.replayTopK);\n    if (picks.length === 0) return '';\n    const lines = ['# Past relevant sessions'];\n    for (const e of picks) lines.push(`- ${e.summary}`);\n    return lines.join('\\n');\n  }\n}\n","import type { MemoryProvider, SemanticMemoryConfig, SemanticMemoryEntry } from './types';\n\n/** Tier 3 — thin wrapper over a host-provided MemoryProvider. dddk does\n *  NOT embed or persist; the host's provider owns infra. */\nexport class SemanticMemory {\n  private provider: MemoryProvider;\n  readonly writeMode: 'explicit' | 'auto';\n\n  constructor(cfg: SemanticMemoryConfig) {\n    this.provider = cfg.provider;\n    this.writeMode = cfg.writeMode ?? 'explicit';\n  }\n\n  recall(query: string, opts?: { topK?: number; tags?: string[] }): Promise<SemanticMemoryEntry[]> {\n    return this.provider.recall(query, opts);\n  }\n\n  remember(entry: Omit<SemanticMemoryEntry, 'id' | 'timestamp'>): Promise<string> {\n    return this.provider.remember(entry);\n  }\n\n  forget(id: string): Promise<void> {\n    return this.provider.forget(id);\n  }\n\n  async list(opts?: { tags?: string[]; limit?: number }): Promise<SemanticMemoryEntry[]> {\n    if (!this.provider.list) return [];\n    return this.provider.list(opts);\n  }\n\n  toPromptBlock(recalled: SemanticMemoryEntry[]): string {\n    if (recalled.length === 0) return '';\n    const lines = ['# Recalled facts'];\n    for (const e of recalled) lines.push(`- ${e.content}`);\n    return lines.join('\\n');\n  }\n}\n","/** Default PII patterns blocked from writing into memory. Hosts can extend\n *  via `MemoryPrivacyConfig.excludePatterns`. */\n\nexport const DEFAULT_PII_PATTERNS: RegExp[] = [\n  /\\b\\d{4}[-\\s]?\\d{4}[-\\s]?\\d{4}[-\\s]?\\d{4}\\b/,\n  /\\bpassword\\s*[:=]/i,\n  /\\bpasswd\\s*[:=]/i,\n  /\\bsecret\\s*[:=]/i,\n  /\\bsk-[a-zA-Z0-9]{20,}\\b/,\n  /\\bAKIA[0-9A-Z]{16}\\b/,\n  /-----BEGIN (?:RSA |EC )?PRIVATE KEY-----/,\n];\n\nexport function looksLikePII(text: string, extra: RegExp[] = []): boolean {\n  for (const re of DEFAULT_PII_PATTERNS) if (re.test(text)) return true;\n  for (const re of extra) if (re.test(text)) return true;\n  return false;\n}\n","/**\n * DrawerMemory — verbatim drawer store with BM25 retrieval. The host\n * decides what to put in (notes / past Q&A / preferences captured at\n * specific moments) and the agent calls `search(query)` to surface\n * matching drawers. Wing / room scope buckets large datasets.\n *\n * Locale-neutral; override `extractFeatures` only for domain tokenisers.\n */\nimport { extractFeatures as defaultExtract, bm25TermScore } from '../../utils/text/index.js';\nimport { resolveStorage } from '../../utils/storage/index.js';\nimport type { StorageAdapter, StorageKind } from '../../utils/storage/types.js';\n\nexport type Drawer = {\n  id: string;\n  text: string;          // verbatim, never summarized\n  ts: number;\n  wing?: string;\n  room?: string;\n  meta?: Record<string, unknown>;\n};\n\nexport type DrawerMemoryOpts = {\n  customerId: string;\n  storage?: StorageKind;\n  /**\n   * Optional host-supplied tokeniser. Receives the drawer text, returns\n   * the feature list used for BM25 recall. Default handles 200+ languages\n   * out of the box (no per-locale packs). See `dddk/utils/text`.\n   */\n  extractFeatures?: (text: string) => string[];\n  sync?: {\n    bootstrap?: () => Promise<{ drawers: Drawer[] }>;\n    pushChange?: (change: { op: 'add' | 'remove'; drawer?: Drawer; id?: string }) => Promise<void>;\n  };\n};\n\nexport type DrawerSearchOpts = {\n  topK?: number;\n  scope?: { wing?: string; room?: string };\n  recencyBoost?: boolean;\n};\n\nexport class DrawerMemory {\n  private customerId: string;\n  private storage: StorageAdapter;\n  private drawers = new Map<string, Drawer>();\n  private features = new Map<string, string[]>();\n  private opened = false;\n  private opts: DrawerMemoryOpts;\n  private extract: (text: string) => string[];\n\n  constructor(opts: DrawerMemoryOpts) {\n    this.customerId = opts.customerId;\n    // Default to 'memory' (session-only). Hosts that want persistence must\n    // explicitly opt in to 'indexeddb', or run their own backend sync.\n    this.storage = resolveStorage(opts.storage ?? 'memory');\n    this.extract = opts.extractFeatures ?? defaultExtract;\n    this.opts = opts;\n  }\n\n  async init(): Promise<void> {\n    await this.storage.open(`dddk-memory-${this.customerId}`);\n    this.opened = true;\n    const snap = (await this.storage.get('memory:snapshot')) as { drawers: Drawer[] } | undefined;\n    if (snap?.drawers) for (const d of snap.drawers) this.indexDrawer(d);\n    else if (this.opts.sync?.bootstrap) {\n      const fetched = await this.opts.sync.bootstrap();\n      for (const d of fetched.drawers) this.indexDrawer(d);\n      await this.persist();\n    }\n  }\n\n  private indexDrawer(d: Drawer): void {\n    this.drawers.set(d.id, d);\n    this.features.set(d.id, this.extract(d.text));\n  }\n\n  wing(name: string): WingScope {\n    return new WingScope(this, name);\n  }\n\n  async addDrawer(d: Omit<Drawer, 'id'> & { id?: string }): Promise<Drawer> {\n    const drawer: Drawer = {\n      id: d.id ?? `${d.wing ?? '_'}/${d.room ?? '_'}/${d.ts}/${Math.random().toString(36).slice(2, 8)}`,\n      text: d.text,\n      ts: d.ts ?? Date.now(),\n      wing: d.wing,\n      room: d.room,\n      meta: d.meta,\n    };\n    this.indexDrawer(drawer);\n    await this.persist();\n    if (this.opts.sync?.pushChange) {\n      try {\n        await this.opts.sync.pushChange({ op: 'add', drawer });\n      } catch {\n        /* offline */\n      }\n    }\n    return drawer;\n  }\n\n  async removeDrawer(id: string): Promise<void> {\n    this.drawers.delete(id);\n    this.features.delete(id);\n    await this.persist();\n    if (this.opts.sync?.pushChange) {\n      try {\n        await this.opts.sync.pushChange({ op: 'remove', id });\n      } catch {\n        /* offline */\n      }\n    }\n  }\n\n  async search(query: string, opts: DrawerSearchOpts = {}): Promise<Drawer[]> {\n    const qFeats = this.extract(query);\n    const qSet = new Set(qFeats);\n    const candidates: Drawer[] = [];\n    for (const [id, drawer] of this.drawers) {\n      if (opts.scope?.wing && drawer.wing !== opts.scope.wing) continue;\n      if (opts.scope?.room && drawer.room !== opts.scope.room) continue;\n      const feats = this.features.get(id) ?? [];\n      const tf = new Map<string, number>();\n      for (const f of feats) if (qSet.has(f)) tf.set(f, (tf.get(f) ?? 0) + 1);\n      if (tf.size === 0) continue;\n      let s = 0;\n      const N = this.drawers.size;\n      let avgLen = 0;\n      for (const arr of this.features.values()) avgLen += arr.length;\n      avgLen = avgLen / Math.max(1, N);\n      for (const [f, count] of tf) {\n        let df = 0;\n        for (const arr of this.features.values()) if (arr.includes(f)) df++;\n        s += bm25TermScore(count, df, N, feats.length, avgLen);\n      }\n      if (opts.recencyBoost !== false) {\n        const ageDays = (Date.now() - drawer.ts) / 86_400_000;\n        s *= Math.pow(0.5, ageDays / 365); // gentle decay\n      }\n      candidates.push(drawer);\n      (drawer as Drawer & { _score?: number })._score = s;\n    }\n    candidates.sort((a, b) => ((b as Drawer & { _score?: number })._score ?? 0) - ((a as Drawer & { _score?: number })._score ?? 0));\n    return candidates.slice(0, opts.topK ?? 10);\n  }\n\n  recent(opts: { wing?: string; room?: string; days?: number; limit?: number } = {}): Drawer[] {\n    const cutoff = Date.now() - (opts.days ?? 30) * 86_400_000;\n    return [...this.drawers.values()]\n      .filter((d) => {\n        if (opts.wing && d.wing !== opts.wing) return false;\n        if (opts.room && d.room !== opts.room) return false;\n        return d.ts >= cutoff;\n      })\n      .sort((a, b) => b.ts - a.ts)\n      .slice(0, opts.limit ?? 50);\n  }\n\n  private async persist(): Promise<void> {\n    if (!this.opened) return;\n    await this.storage.set('memory:snapshot', { drawers: [...this.drawers.values()] });\n  }\n\n  async dispose(): Promise<void> {\n    if (this.opened) await this.storage.close();\n    this.opened = false;\n  }\n}\n\nclass WingScope {\n  constructor(private mem: DrawerMemory, public name: string) {}\n  room(name: string) {\n    return new RoomScope(this.mem, this.name, name);\n  }\n  search(q: string, opts: DrawerSearchOpts = {}) {\n    return this.mem.search(q, { ...opts, scope: { ...opts.scope, wing: this.name } });\n  }\n  recent(opts: { days?: number; limit?: number } = {}) {\n    return this.mem.recent({ ...opts, wing: this.name });\n  }\n}\nclass RoomScope {\n  constructor(private mem: DrawerMemory, public wing: string, public room: string) {}\n  addDrawer(d: { text: string; ts?: number; meta?: Record<string, unknown> }) {\n    return this.mem.addDrawer({\n      text: d.text,\n      ts: d.ts ?? Date.now(),\n      meta: d.meta,\n      wing: this.wing,\n      room: this.room,\n    });\n  }\n  search(q: string, opts: DrawerSearchOpts = {}) {\n    return this.mem.search(q, { ...opts, scope: { wing: this.wing, room: this.room } });\n  }\n}\n\nexport function createDrawerMemory(opts: DrawerMemoryOpts): DrawerMemory {\n  return new DrawerMemory(opts);\n}\n","/**\n * Unified memory facade.\n *\n * The SDK has shipped TWO memory subsystems in parallel since v0.1.0:\n *\n *   - `Memory` (this module) — 3-tier structured: CoreMemory (persistent\n *     identity facts), EpisodicMemory (per-session summaries), SemanticMemory\n *     (vector retrieval). Strong typing, schema-driven.\n *   - `DrawerMemory` — wing/room/drawer free-form storage. Looser shape, used\n *     by the proactive module's `TriggerMemory = Memory | DrawerMemory`\n *     union.\n *\n * Hosts pick one and the two don't share state. The unification task is\n * NOT a destructive merge (which would break v0.1 host integrations) — it's\n * a facade that owns both, presents a single API, and routes writes/reads\n * to the right backend automatically.\n *\n *   const memory = new UnifiedMemory({\n *     core:     { schema: { tone: 'string', industry: 'string' } },\n *     episodic: { enabled: true },\n *     drawer:   { storage: 'localStorage', maxItems: 500 },\n *   });\n *\n *   await memory.remember('user prefers concise responses');     // → CoreMemory if matches schema, else Drawer\n *   await memory.remember('looking at pricing page for 2min');    // → Drawer / behavioural\n *   const ctx = await memory.buildContext('what should I show?'); // merges all tiers\n *\n * The original `Memory` and `DrawerMemory` classes stay exported, untouched,\n * for hosts on v0.1 integrations.\n */\n\nimport { Memory, type MemoryConfig } from './index';\nimport { DrawerMemory, type DrawerMemoryOpts, type Drawer } from './drawer';\n\nexport interface UnifiedMemoryConfig extends MemoryConfig {\n  /** Drawer subsystem opts. Omit to skip the drawer backend entirely. */\n  drawer?: DrawerMemoryOpts;\n}\n\nexport interface RememberOpts {\n  /** Routing hint. `auto` (default) picks based on shape. */\n  tier?: 'auto' | 'core' | 'drawer' | 'episodic';\n  /** Drawer-only metadata. */\n  wing?: string;\n  room?: string;\n  meta?: Record<string, unknown>;\n  /** Core-only: which field to set when tier=core (or auto routing decides). */\n  coreField?: string;\n}\n\nexport interface RecallResult {\n  source: 'core' | 'drawer' | 'episodic' | 'semantic';\n  text: string;\n  ts?: number;\n  meta?: Record<string, unknown>;\n  score?: number;\n}\n\nexport class UnifiedMemory {\n  readonly structured: Memory;\n  readonly drawer: DrawerMemory | null;\n\n  constructor(cfg: UnifiedMemoryConfig = {}) {\n    this.structured = new Memory(cfg);\n    this.drawer = cfg.drawer ? new DrawerMemory(cfg.drawer) : null;\n  }\n\n  async init(): Promise<void> {\n    if (this.drawer) await this.drawer.init();\n  }\n\n  isPII(text: string): boolean {\n    return this.structured.isPII(text);\n  }\n\n  /**\n   * Write a memory. Routing:\n   *   - `tier: 'core'` + `coreField` → CoreMemory.set(field, text)\n   *   - `tier: 'drawer'` (or auto when long-form) → DrawerMemory.addDrawer\n   *   - `tier: 'episodic'` → no-op here (use endSession to commit one)\n   *   - `tier: 'auto'` (default) → core if a coreField is supplied, else drawer\n   */\n  async remember(text: string, opts: RememberOpts = {}): Promise<void> {\n    if (!text.trim()) return;\n    if (this.isPII(text)) return; // honour the PII gate at facade level\n    const tier = opts.tier ?? 'auto';\n    if ((tier === 'core' || (tier === 'auto' && opts.coreField)) && opts.coreField && this.structured.core) {\n      this.structured.core.set(opts.coreField, text);\n      return;\n    }\n    if (this.drawer) {\n      await this.drawer.wing(opts.wing ?? 'default').room(opts.room ?? 'notes').addDrawer({\n        text,\n        meta: opts.meta,\n      });\n      return;\n    }\n    // No drawer configured and not a Core write — silently drop. The host\n    // either configured no backing storage or asked us to route somewhere\n    // we don't have. Loud failures here would break otherwise-working flows.\n  }\n\n  /**\n   * Read memory. Pulls from BOTH backends and merges by best-effort score.\n   * For backward compatibility, hosts that just want a system-prompt block\n   * can call `buildContext(query)` instead — same shape as the v0.1 Memory.\n   */\n  async recall(query: string, opts: { limit?: number } = {}): Promise<RecallResult[]> {\n    const limit = opts.limit ?? 10;\n    const out: RecallResult[] = [];\n\n    // Core: include every set field as a context item.\n    if (this.structured.core) {\n      const snap = this.structured.core.snapshot();\n      for (const [field, value] of Object.entries(snap)) {\n        if (value == null || value === '') continue;\n        out.push({ source: 'core', text: `${field}: ${String(value)}`, score: 1.0 });\n      }\n    }\n\n    // Drawer: keyword/feature search.\n    if (this.drawer) {\n      const drawers: Drawer[] = await this.drawer.search(query, { topK: limit });\n      for (const d of drawers) {\n        out.push({\n          source: 'drawer',\n          text: d.text,\n          ts: d.ts,\n          meta: d.meta,\n        });\n      }\n    }\n\n    // Semantic: vector retrieval (if configured).\n    if (this.structured.semantic) {\n      try {\n        const hits = await this.structured.semantic.recall(query, { topK: limit });\n        for (const h of hits) {\n          out.push({\n            source: 'semantic',\n            text: h.content,\n            ts: h.timestamp,\n            meta: h.metadata,\n          });\n        }\n      } catch {\n        // Semantic backend unreachable — fall through to whatever we have.\n      }\n    }\n\n    return out.slice(0, limit);\n  }\n\n  /** Build the system-prompt context block. Delegates to structured Memory,\n   *  then appends recent drawer entries if a drawer is configured. */\n  async buildContext(userQuery: string): Promise<string> {\n    const structured = await this.structured.buildContext(userQuery);\n    if (!this.drawer) return structured;\n    const recent = this.drawer.recent({ limit: 5 });\n    if (recent.length === 0) return structured;\n    const drawerBlock = recent.map((d) => `- ${d.text}`).join('\\n');\n    return [structured, '\\nRecent notes:', drawerBlock].filter(Boolean).join('\\n').trim();\n  }\n\n  endSession(input: { summary: string; taskSummary?: string; tags?: string[]; turnCount?: number }) {\n    return this.structured.endSession(input);\n  }\n\n  clear(): void {\n    this.structured.clear();\n    // Drawer has no clear method by design (host responsibility) — leave as-is.\n  }\n\n  async dispose(): Promise<void> {\n    if (this.drawer) await this.drawer.dispose();\n  }\n}\n\nexport function createUnifiedMemory(cfg: UnifiedMemoryConfig = {}): UnifiedMemory {\n  return new UnifiedMemory(cfg);\n}\n","/** Memory v1 — three-tier hybrid memory for the webagent.\n *\n *   core      — structured user profile, always in context\n *   episodic  — ring buffer of past session summaries\n *   semantic  — host-provided long-term recall (vector / KG / etc)\n *\n * All tiers are opt-in. A bare `new DotDotDuck({})` has memory disabled.\n *\n * The legacy verbatim-drawer store (formerly `Memory`) is still available\n * as `DrawerMemory` from `@perhapxin/dddk/agent` — they serve different\n * use cases and can coexist.\n */\n\nimport { CoreMemory } from './core';\nimport { EpisodicMemory } from './episodic';\nimport { SemanticMemory } from './semantic';\nimport { looksLikePII } from './pii';\nimport type {\n  CoreFieldType, CoreMemoryConfig, CoreMemorySchema,\n  EpisodicEntry, EpisodicMemoryConfig,\n  MemoryConfig, MemoryPrivacyConfig, MemoryProvider,\n  SemanticMemoryConfig, SemanticMemoryEntry,\n} from './types';\n\nexport class Memory {\n  readonly core: CoreMemory | null;\n  readonly episodic: EpisodicMemory | null;\n  readonly semantic: SemanticMemory | null;\n  private privacy: MemoryPrivacyConfig;\n\n  constructor(cfg: MemoryConfig = {}) {\n    this.privacy = cfg.privacy ?? {};\n    this.core = cfg.core ? new CoreMemory(cfg.core) : null;\n    this.episodic = cfg.episodic?.enabled !== false && cfg.episodic\n      ? new EpisodicMemory(cfg.episodic, this.privacy.retentionDays ?? 90)\n      : null;\n    this.semantic = cfg.semantic ? new SemanticMemory(cfg.semantic) : null;\n  }\n\n  /** Check if `text` would be blocked by PII patterns. */\n  isPII(text: string): boolean {\n    return looksLikePII(text, this.privacy.excludePatterns ?? []);\n  }\n\n  /** Build the system-prompt context block for a new agent run. Runs\n   *  semantic recall against `userQuery` when wired. Empty string when\n   *  no tier has content. */\n  async buildContext(userQuery: string): Promise<string> {\n    const blocks: string[] = [];\n    if (this.core) {\n      const b = this.core.toPromptBlock();\n      if (b) blocks.push(b);\n    }\n    if (this.episodic) {\n      const b = this.episodic.toPromptBlock(userQuery);\n      if (b) blocks.push(b);\n    }\n    if (this.semantic) {\n      try {\n        const recalled = await this.semantic.recall(userQuery, { topK: 5 });\n        const b = this.semantic.toPromptBlock(recalled);\n        if (b) blocks.push(b);\n      } catch (err) {\n        if (typeof console !== 'undefined') {\n          console.warn('[dddk memory] semantic recall failed:', err);\n        }\n      }\n    }\n    return blocks.join('\\n\\n');\n  }\n\n  /** Called when a session ends. Writes a short episodic summary if the\n   *  tier is on. Caller supplies the summary text — hosts that want an\n   *  LLM-generated summary should produce it before calling. */\n  endSession(input: { summary: string; taskSummary?: string; tags?: string[]; turnCount?: number }): EpisodicEntry | null {\n    if (!this.episodic) return null;\n    if (this.isPII(input.summary)) {\n      if (typeof console !== 'undefined') {\n        console.warn('[dddk memory] episodic write blocked by PII filter');\n      }\n      return null;\n    }\n    return this.episodic.add(input);\n  }\n\n  /** Wipe all tiers. */\n  clear(): void {\n    this.core?.clear();\n    this.episodic?.clear();\n  }\n}\n\nexport { CoreMemory, EpisodicMemory, SemanticMemory };\nexport { DrawerMemory, createDrawerMemory } from './drawer';\nexport type { Drawer, DrawerMemoryOpts, DrawerSearchOpts } from './drawer';\n// Unified memory facade (wraps Memory + DrawerMemory).\nexport { UnifiedMemory, createUnifiedMemory } from './unified';\nexport type { UnifiedMemoryConfig, RememberOpts, RecallResult } from './unified';\nexport type {\n  CoreMemoryConfig, CoreMemorySchema, CoreFieldType,\n  EpisodicMemoryConfig, EpisodicEntry,\n  SemanticMemoryConfig, SemanticMemoryEntry, MemoryProvider,\n  MemoryPrivacyConfig, MemoryConfig,\n};\n","/**\n * Todos artifact — in-memory CRUD for `TodoItem`s. Owned by a `Plan`\n * instance; the webagent reads the list to drive the loop and mutates\n * via the per-turn envelope's `todo_adjust` field (not by calling these\n * methods directly — runtime translates envelope ops to these calls).\n *\n * Mutations bump `version` and call the optional `onChange` hook so\n * persistence + UI subscribers can react. ids are short stable strings\n * (`t1`, `t2`, ...) — predictable so model output can reference them.\n */\n\nimport type { TodoItem } from './types';\n\nexport interface TodosArtifactOptions {\n  /** Optional change hook. Fires after every mutation with the new list. */\n  onChange?: (items: TodoItem[]) => void;\n  /** Seed items — used when restoring from a storage adapter. */\n  initial?: TodoItem[];\n  /** ID counter seed — used when restoring from a storage adapter. */\n  initialIdCounter?: number;\n}\n\nexport class TodosArtifact {\n  private items: TodoItem[] = [];\n  private idCounter: number;\n  private readonly onChange?: (items: TodoItem[]) => void;\n\n  constructor(opts: TodosArtifactOptions = {}) {\n    this.onChange = opts.onChange;\n    this.items = [...(opts.initial ?? [])];\n    this.idCounter = opts.initialIdCounter ?? this.items.length;\n  }\n\n  /** Returns a defensive copy so mutations don't leak. */\n  list(): TodoItem[] {\n    return this.items.map((t) => ({ ...t }));\n  }\n\n  get(id: string): TodoItem | null {\n    const found = this.items.find((t) => t.id === id);\n    return found ? { ...found } : null;\n  }\n\n  /** Create one item, returning the assigned id. */\n  create(item: Omit<TodoItem, 'id'>): TodoItem {\n    const id = `t${++this.idCounter}`;\n    const next: TodoItem = { id, ...item };\n    this.items.push(next);\n    this.notify();\n    return { ...next };\n  }\n\n  /** Bulk-create — used by `Plan.makeTodos()` after a planning call. */\n  createMany(items: Array<Omit<TodoItem, 'id'>>): TodoItem[] {\n    const created = items.map((it) => {\n      const id = `t${++this.idCounter}`;\n      const next: TodoItem = { id, ...it };\n      this.items.push(next);\n      return { ...next };\n    });\n    this.notify();\n    return created;\n  }\n\n  /** Partial update — id-preserving. Returns the new item or null if id\n   *  not found. The webagent uses this for `todo_adjust.replace`. */\n  edit(id: string, patch: Partial<Omit<TodoItem, 'id'>>): TodoItem | null {\n    const idx = this.items.findIndex((t) => t.id === id);\n    if (idx < 0) return null;\n    const next: TodoItem = { ...this.items[idx]!, ...patch };\n    this.items[idx] = next;\n    this.notify();\n    return { ...next };\n  }\n\n  /** Drop one item by id. Returns true if removed, false if not found. */\n  delete(id: string): boolean {\n    const before = this.items.length;\n    this.items = this.items.filter((t) => t.id !== id);\n    const removed = this.items.length < before;\n    if (removed) this.notify();\n    return removed;\n  }\n\n  /** Replace the entire list — used when a fresh `Plan.makeTodos()` is\n   *  triggered mid-session and the host wants a hard reset. */\n  reset(items: TodoItem[] = []): void {\n    this.items = items.map((t) => ({ ...t }));\n    this.idCounter = items.length;\n    this.notify();\n  }\n\n  /** For storage adapter — id counter must survive reload so future\n   *  `create()` calls don't collide with pre-existing ids. */\n  serialize(): { items: TodoItem[]; idCounter: number } {\n    return {\n      items: this.items.map((t) => ({ ...t })),\n      idCounter: this.idCounter,\n    };\n  }\n\n  private notify(): void {\n    if (this.onChange) this.onChange(this.list());\n  }\n}\n","/**\n * Plan — structured-artifact module. Owns two in-memory artifacts:\n *\n *   - `todos`     — `TodoItem[]` consumed by the webagent loop as its\n *                   master plan; mutated mid-loop via per-turn envelope\n *                   ops (the runtime translates envelope `todo_adjust`\n *                   to `todos.delete` / `todos.edit` here).\n *   - `markdown`  — `MarkdownDoc[]` for host-driven authoring surfaces\n *                   (meeting notes, drafts). Not used by the webagent.\n *\n * One LLM-mediated entry point lives here directly: `makeTodos(input)` —\n * a single planning call that produces a `TaskPlan` and seeds `todos`.\n * Hosts wire this into `webagent.planner` so the webagent runs a planning\n * pass before entering the turn loop.\n *\n * Two attach points:\n *   - `attachTo(dddk)` — exposes `dddk.plan` so anywhere in the host\n *     can read the artifacts or call CRUD without holding the instance\n *     reference. Same pattern as ImmersiveTranslate / Dwell.\n *   - `webagent.planner: (input) => plan.makeTodos(input)` — callback\n *     pattern, so the webagent has no hard dep on the Plan class.\n *\n * Storage: in-memory by default. Pass `storage` (an object with\n * `load()` / `save()`) to persist across reloads — same shape as\n * ImmersiveTranslate's cache option.\n */\n\nimport { resolveLLM, type LLMSource } from '../llm/router';\nimport type { CompleteResult } from '../llm/types';\nimport { stripCodeFence } from '../../utils/llm-parse';\nimport type { DotDotDuck } from '../../orchestrator';\nimport { buildPlanSystemPrompt } from './prompt';\nimport { PROMPT_IDS, promptRegistry } from '../../prompts/registry';\nimport { registerBuiltinPrompts } from '../../prompts/defaults';\n\nregisterBuiltinPrompts();\nimport { TodosArtifact } from './todos';\nimport { MarkdownArtifact } from './markdown';\nimport type {\n  PlanInput,\n  PlanSnapshot,\n  PlanStorageAdapter,\n  TaskPlan,\n  TodoItem,\n} from './types';\n\nexport type { PlanInput, TaskPlan, TodoItem } from './types';\nexport type { MarkdownDoc, PlanSnapshot, PlanStorageAdapter } from './types';\nexport { TodosArtifact } from './todos';\nexport { MarkdownArtifact } from './markdown';\n\nexport interface PlanConfig {\n  /** LLM source for the planning call AND markdown LLM edits. Single\n   *  provider OR a router — when a router, the `plan` role is used and\n   *  falls back to `webagent` if not registered. */\n  llm: LLMSource;\n  /** Extra strategic context appended to the SDK base planning prompt —\n   *  sitemap mental model, tour playbook, route-routing logic. Same idea\n   *  as `WebAgentConfig.appendSystemPrompt` but for the planning layer. */\n  appendSystemPrompt?: string;\n  /** Hard-replace the SDK planning prompt entirely. Rare — most hosts\n   *  just use `appendSystemPrompt`. */\n  systemPrompt?: string;\n  /** Display name shown to the user / used in the planner self-intro. */\n  agentName?: string;\n  /** Optional storage adapter for cross-reload persistence. */\n  storage?: PlanStorageAdapter;\n}\n\nconst PLAN_TIMEOUT_MS = 30_000;\n\nexport class Plan {\n  readonly todos: TodosArtifact;\n  readonly markdown: MarkdownArtifact;\n  private readonly config: PlanConfig;\n  private readonly storage?: PlanStorageAdapter;\n  private hydrated = false;\n\n  constructor(config: PlanConfig) {\n    this.config = config;\n    this.storage = config.storage;\n\n    this.todos = new TodosArtifact({\n      onChange: () => this.persist(),\n    });\n    this.markdown = new MarkdownArtifact({\n      llm: resolveLLM(config.llm, 'inline'),\n      onChange: () => this.persist(),\n    });\n  }\n\n  /**\n   * Wire to the orchestrator so callers can do `dddk.plan.todos.list()`\n   * without holding the Plan reference. Idempotent — re-attaching\n   * replaces the previous binding.\n   */\n  attachTo(dddk: DotDotDuck): void {\n    (dddk as unknown as { plan: Plan }).plan = this;\n    // Best-effort hydration — if storage is provided, restore artifacts\n    // now so the first webagent run sees prior state.\n    void this.hydrate();\n  }\n\n  /**\n   * One planning call → produces a TaskPlan and seeds `todos`.\n   * Wire this into `webagent.planner` so the webagent runs a planning\n   * pass before the turn loop.\n   */\n  async makeTodos(input: PlanInput & {\n    /**\n     * v0.2.0 streaming hook: invoked synchronously for each new character\n     * of the `task_summary` field AS the LLM types it. Lets the host\n     * stream the announcement into a subtitle bar instead of getting one\n     * monolithic post-parse blast. Optional — when omitted, the planning\n     * call still streams under the hood (so the LLM proxy doesn't buffer\n     * via Cloudflare AI-Gateway cache) but the host sees the same final\n     * `TaskPlan` it always did.\n     */\n    onSummaryDelta?: (delta: string) => void;\n  }): Promise<TaskPlan> {\n    const llm = resolveLLM(this.config.llm, 'plan');\n    // Route through the SDK prompt registry so hosts can override the\n    // planner prompt per-locale via `dddk.prompts.override('planner.system', locale, render)`.\n    // The `config.systemPrompt` legacy hook still wins for full replace.\n    const planCtx = {\n      locale: input.locale,\n      agentName: this.config.agentName,\n      sitemap: input.sitemap,\n      brand: input.brand,\n      persona: input.persona,\n      appendSystemPrompt: this.config.appendSystemPrompt,\n    };\n    const system = this.config.systemPrompt\n      ?? promptRegistry.render(PROMPT_IDS.PLANNER, planCtx, input.locale ?? 'en');\n\n    const userParts: string[] = [`# User task\\n\\n${input.task}`];\n    if (input.selection?.text) {\n      userParts.push(`# User selection at invocation\\n\\n\"\"\"\\n${input.selection.text}\\n\"\"\"`);\n    }\n    if (input.hostContext) {\n      userParts.push(`# Host context\\n\\n${input.hostContext}`);\n    }\n\n    const timeoutCtrl = new AbortController();\n    const timer = setTimeout(() => timeoutCtrl.abort('plan timeout'), PLAN_TIMEOUT_MS);\n    let raw = '';\n    try {\n      const completeOpts = {\n        messages: [\n          { role: 'system' as const, content: system },\n          { role: 'user' as const, content: userParts.join('\\n\\n') },\n        ],\n        thinking: 'low' as const,\n        jsonMode: true,\n        temperature: 0.2,\n        signal: timeoutCtrl.signal,\n      };\n      // Prefer streaming so Cloudflare AI-Gateway doesn't buffer the\n      // whole response under cf-aig-cache-ttl. Streamer scans the\n      // incremental JSON for `task_summary` chars and surfaces them\n      // synchronously to the host via `onSummaryDelta`.\n      const streamable = llm as { streamComplete?: (o: typeof completeOpts) => AsyncIterable<{ delta?: string; text: string }> & Promise<CompleteResult> };\n      if (typeof streamable.streamComplete === 'function') {\n        let fragCount = 0;\n        const streamer = new TaskSummaryStreamer((delta) => {\n          // Log every char of task_summary as it streams in so the\n          // user can see real-time arrival in console — not just\n          // the post-parse \"[dddk webagent] planning result\" blast.\n          console.info('[dddk stream] plan summary_delta', { char: delta });\n          input.onSummaryDelta?.(delta);\n        });\n        const handle = streamable.streamComplete(completeOpts);\n        for await (const chunk of handle) {\n          if (chunk.delta) {\n            fragCount += 1;\n            streamer.feed(chunk.delta);\n          }\n          raw = chunk.text;\n        }\n        streamer.finish();\n        console.info(`[dddk stream] plan stream ended after ${fragCount} fragments`);\n      } else {\n        const result = await llm.complete(completeOpts);\n        raw = result.content;\n      }\n    } finally {\n      clearTimeout(timer);\n    }\n\n    const plan = parseTaskPlan(raw);\n    if (!plan) {\n      throw new Error(`Plan: planner returned unparseable JSON. Raw: ${raw.slice(0, 200)}`);\n    }\n    // Seed todos with the planner's output, replacing any prior list.\n    this.todos.reset(plan.todos);\n    return plan;\n  }\n\n  /** Snapshot current state — used by storage adapter + host inspection. */\n  snapshot(): PlanSnapshot {\n    return {\n      todos: this.todos.list(),\n      markdownDocs: this.markdown.list(),\n    };\n  }\n\n  // ─── storage plumbing ─────────────────────────────────────────\n\n  private async hydrate(): Promise<void> {\n    if (this.hydrated || !this.storage) return;\n    this.hydrated = true;\n    try {\n      const snap = await this.storage.load();\n      if (!snap) return;\n      this.todos.reset(snap.todos);\n      // Markdown re-seed bypasses notify (we'd double-fire). Reconstruct\n      // via a fresh artifact + swap — simplest correct path.\n      for (const doc of snap.markdownDocs) {\n        this.markdown.create({ title: doc.title, content: doc.content });\n      }\n    } catch (err) {\n      console.warn('[dddk plan] hydrate failed', err);\n    }\n  }\n\n  private persist(): void {\n    if (!this.storage) return;\n    try {\n      const result = this.storage.save(this.snapshot());\n      if (result instanceof Promise) result.catch((err) => console.warn('[dddk plan] persist failed', err));\n    } catch (err) {\n      console.warn('[dddk plan] persist failed', err);\n    }\n  }\n}\n\n/**\n * Tiny streaming JSON scanner — finds `\"task_summary\":\"...\"` in an\n * incrementally-arriving stream of chars, calls `onDelta` for each\n * newly-revealed character of the summary's value. Robust to:\n *   - JSON key arriving before / split across chunks\n *   - Backslash-escaped quotes inside the value\n *   - Schema preamble before task_summary (e.g. todos first)\n *\n * Once the closing quote is found we stop scanning — todos / other\n * fields are irrelevant for the announcement UI.\n *\n * Pure char walker — no JSON.parse, so partial JSON never throws.\n */\nclass TaskSummaryStreamer {\n  private buf = '';\n  private pos = 0;\n  private state: 'before' | 'inside' | 'done' = 'before';\n  private prevEscape = false;\n  private readonly onDelta: ((delta: string) => void) | undefined;\n\n  constructor(onDelta?: (delta: string) => void) {\n    this.onDelta = onDelta;\n  }\n\n  feed(chunk: string): void {\n    if (this.state === 'done' || !this.onDelta) {\n      // Still let scanning consume buf so finish() doesn't double-process,\n      // but skip the emit cost when there's no listener.\n      this.buf += chunk;\n      return;\n    }\n    this.buf += chunk;\n    this.scan();\n  }\n\n  finish(): void {\n    if (this.state === 'inside') this.scan();\n  }\n\n  private scan(): void {\n    if (this.state === 'before') {\n      const m = this.buf.slice(this.pos).match(/\"task_summary\"\\s*:\\s*\"/);\n      if (!m) {\n        // Trim consumed prefix to keep buf bounded — leave a safety\n        // window for the key sequence to straddle chunk boundaries.\n        const trimAt = Math.max(0, this.buf.length - 32);\n        if (trimAt > this.pos) {\n          this.buf = this.buf.slice(trimAt);\n          this.pos = 0;\n        }\n        return;\n      }\n      this.pos += m.index! + m[0].length;\n      this.state = 'inside';\n    }\n    if (this.state === 'inside') {\n      let emitFrom = this.pos;\n      while (this.pos < this.buf.length) {\n        const ch = this.buf.charAt(this.pos);\n        if (this.prevEscape) {\n          this.prevEscape = false;\n          this.pos += 1;\n          continue;\n        }\n        if (ch === '\\\\') {\n          this.prevEscape = true;\n          this.pos += 1;\n          continue;\n        }\n        if (ch === '\"') {\n          // Flush any chars we haven't emitted, then close.\n          if (this.onDelta && this.pos > emitFrom) {\n            this.onDelta(this.unescapeJson(this.buf.slice(emitFrom, this.pos)));\n          }\n          this.state = 'done';\n          return;\n        }\n        this.pos += 1;\n      }\n      // Reached end of buf without a closing quote — emit what we have\n      // (minus the last char if it's a lone backslash mid-escape).\n      const emitTo = this.prevEscape ? this.pos - 1 : this.pos;\n      if (this.onDelta && emitTo > emitFrom) {\n        this.onDelta(this.unescapeJson(this.buf.slice(emitFrom, emitTo)));\n      }\n    }\n  }\n\n  private unescapeJson(s: string): string {\n    return s\n      .replace(/\\\\n/g, '\\n')\n      .replace(/\\\\t/g, '\\t')\n      .replace(/\\\\r/g, '\\r')\n      .replace(/\\\\\"/g, '\"')\n      .replace(/\\\\\\\\/g, '\\\\');\n  }\n}\n\nfunction parseTaskPlan(raw: string): TaskPlan | null {\n  const trimmed = stripCodeFence(raw).trim();\n  let obj: unknown;\n  try {\n    obj = JSON.parse(trimmed);\n  } catch {\n    return null;\n  }\n  if (!obj || typeof obj !== 'object') return null;\n  const o = obj as Record<string, unknown>;\n  if (typeof o.task_summary !== 'string') return null;\n  if (!Array.isArray(o.todos)) return null;\n  const todos: Omit<TodoItem, 'id'>[] = [];\n  for (const entry of o.todos as unknown[]) {\n    if (!entry || typeof entry !== 'object') continue;\n    const e = entry as Record<string, unknown>;\n    const description = typeof e.description === 'string' ? e.description : '';\n    if (!description) continue;\n    const intent = typeof e.intent === 'string' ? e.intent : 'narrate';\n    const expected_turn = typeof e.expected_turn === 'number' ? e.expected_turn : undefined;\n    todos.push({ intent, description, expected_turn });\n  }\n  if (todos.length === 0) return null;\n  // Assign ids after parse so they're stable AND match the artifact's\n  // future creates (which start from idCounter).\n  const planTodos: TodoItem[] = todos.map((t, i) => ({ id: `t${i + 1}`, ...t }));\n  return {\n    task_summary: o.task_summary,\n    todos: planTodos,\n  };\n}\n","/**\n * Agent lifecycle — owns building the WebAgent, the per-turn event\n * pump, confirm routing, loop-closure rendering, and all stop / resume\n * paths.\n *\n * Stateless helper class: receives the `DotDotDuck` host on construction\n * and reads / writes its internal `_*` fields. Wrapping these inside a\n * class keeps the file boundary stable without leaking a second public\n * type into the SDK surface.\n */\n\nimport {\n  WebAgent,\n  clearOverlays as clearWebagentOverlays,\n  type WebAgentConfig,\n  type AgentEvent,\n  type SelectionContext,\n} from '../agent';\nimport { hideCursor as hideWebagentCursor } from '../agent/webagent/cursor';\nimport type { OnLoopEnd } from '../agent/webagent/types';\nimport { sdkString } from '../utils/sdk-i18n';\nimport type { DotDotDuck } from './index';\nimport { blobToDataUrl } from './helpers';\n\nexport class AgentLifecycle {\n  constructor(private readonly host: DotDotDuck) {}\n\n  /**\n   * Kick the webagent. `selection` defaults to whatever was captured at the\n   * last palette open — pass `{ selection: null }` to force no selection\n   * context, or pass an explicit `SelectionContext` to override.\n   */\n  startAgent(task: string, options: { selection?: SelectionContext | null } = {}): void {\n    const host = this.host;\n    if (!host._config.llm) {\n      host.subtitle.show({\n        text: host._t('agent.no_webagent', 'No LLM configured — set `llm` on DotDotDuck.'),\n        type: 'info',\n        autoHide: 2500,\n      });\n      return;\n    }\n    if (!host._agentEnabled) {\n      host.subtitle.show({\n        text: host._t('agent.disabled', 'Agent is disabled.'),\n        type: 'info',\n        autoHide: 2000,\n      });\n      return;\n    }\n    if (!host._agentInstance) host._agentInstance = this.buildAgent();\n    if (host._agentInstance.isRunning()) host._agentInstance.stop();\n    // Wipe state from the previous round — borders / pin frames / subtitles\n    // left over from a prior agent run shouldn't bleed into this one.\n    // Without this the user sees stale \"Agent · border(...)\" pills and\n    // outlines from the previous question still hanging around when they\n    // start a new task.\n    host._highlight.clearHighlight();\n    clearWebagentOverlays();\n    hideWebagentCursor();\n    host.subtitle.hide();\n    let selection =\n      options.selection === undefined ? host._currentSelection : options.selection;\n\n    // If no live window-selection is set but the palette has a pinned\n    // context (Dwell-pinned element etc.), feed THAT into the agent's\n    // SelectionContext so the agent knows which element the user is asking\n    // about — without it the agent only sees the question + full DOM and\n    // has to guess. We read from `pinnedContext` (sticky across palette\n    // close) rather than `context.selectionText` (cleared on close) so this\n    // still works when the handler ran `p.close()` before `startAgent`.\n    if (!selection || (!selection.text && (!selection.elements || selection.elements.length === 0))) {\n      const pinned = host.palette.pinnedContext;\n      if (pinned.text || pinned.element) {\n        selection = {\n          ...(selection ?? {}),\n          text: pinned.text || selection?.text,\n          elements: pinned.element ? [pinned.element] : selection?.elements,\n        };\n      }\n    }\n\n    // Auto-attach images queued in the palette context (camera-captured PNGs)\n    // as base64 data URLs in the agent's SelectionContext.images. webagent\n    // already supports `images: string[]`. We also prepend a metadata note\n    // to the task with each image's `sourceUrl` so the agent knows WHICH\n    // page the screenshot is from — important when the user took the\n    // screenshot on page A and then asks the question from page B.\n    const queuedAttachments = host.palette.context.attachments.filter((a) => a.kind === 'image');\n    if (queuedAttachments.length > 0) {\n      void Promise.all(queuedAttachments.map((a) => blobToDataUrl(a.blob)))\n        .then((images) => {\n          const meta = queuedAttachments\n            .map((a, i) => {\n              const where = a.sourceUrl ? ` from ${a.sourceUrl}` : '';\n              return `Image ${i + 1} (${a.source}${where})`;\n            })\n            .join('\\n');\n          const augmentedTask = meta\n            ? `${task}\\n\\n[Attachments]\\n${meta}`\n            : task;\n          const sel: SelectionContext = { ...(selection ?? {}), images };\n          host._emitter.emit('agent_start', { task: augmentedTask });\n          this.beginAgentRun(augmentedTask);\n          this.runAgentStream(augmentedTask, { selection: sel });\n          host.palette.clearAttachments();\n        })\n        .catch((err) => {\n          console.warn('[dddk] failed to attach palette images, running without:', err);\n          host._emitter.emit('agent_start', { task });\n          this.beginAgentRun(task);\n          this.runAgentStream(task, selection ? { selection } : {});\n          host.palette.clearAttachments();\n        });\n      return;\n    }\n\n    host._emitter.emit('agent_start', { task });\n    this.beginAgentRun(task);\n    this.runAgentStream(task, selection ? { selection } : {});\n  }\n\n  runAgentStream(task: string, opts: { selection?: SelectionContext } = {}): void {\n    const agent = this.host._agentInstance;\n    if (!agent) return;\n    const memory = this.host.memory;\n    if (!memory) {\n      void this.pumpAgentStream(agent.runStream(task, opts));\n      return;\n    }\n    void memory.buildContext(task)\n      .then((ctx) => {\n        const augmented = ctx ? `${ctx}\\n\\n${task}` : task;\n        return this.pumpAgentStream(agent.runStream(augmented, opts));\n      })\n      .catch((err) => {\n        if (typeof console !== 'undefined') {\n          console.warn('[dddk memory] buildContext failed; running without memory:', err);\n        }\n        return this.pumpAgentStream(agent.runStream(task, opts));\n      });\n  }\n\n  private beginAgentRun(task: string): void {\n    const host = this.host;\n    host._intentBuffer.beginAgentRun(\n      host._emitter,\n      task,\n      host._agentInstance?.getSession()?.id ?? '',\n    );\n  }\n\n  endAgentRunCompleted(): void {\n    const host = this.host;\n    host._intentBuffer.endAgentRunCompleted(\n      host._emitter,\n      host._agentInstance?.getSession()?.id ?? '',\n      host._agentInstance?.getSession()?.turns.length ?? 0,\n    );\n  }\n\n  endAgentRunStopped(reason: 'close' | 'esc' | 'reject' | 'palette' | 'voice' | 'unknown'): void {\n    const host = this.host;\n    host._intentBuffer.endAgentRunStopped(\n      host._emitter,\n      host._agentInstance?.getSession()?.id ?? '',\n      reason,\n    );\n  }\n\n  /** Resume a saved session — used by the host's onMount after a full\n   *  page reload. If there's no saved session or it's in a terminal\n   *  state, no-ops. Otherwise pumps the stream into the dddk UI as if\n   *  the loop had never been interrupted. */\n  resumeAgent(): void {\n    const host = this.host;\n    if (!host._agentEnabled) return;\n    if (!host._config.llm) return;\n    if (!host._agentInstance) host._agentInstance = this.buildAgent();\n    void this.pumpAgentStream(host._agentInstance.resumeStream());\n  }\n\n  /**\n   * Fire the same \"accept\" gesture that single-tap Space fires on\n   * desktop — emits `gesture_accept`, advances script skills waiting\n   * on it, advances streaming pause hints, accepts confirm dialogs,\n   * etc. Use this from a mobile FAB tap or any host-built \"next\"\n   * button so touch users get the full Space-equivalent pipeline,\n   * not just `subtitle.invokeAccept()` (which alone misses script\n   * skills + intent analytics).\n   */\n  triggerAccept(): void {\n    const host = this.host;\n    host._emitter.emit('gesture_accept', undefined);\n    host.subtitle.invokeAccept();\n    host._intentBuffer.emitIntent(host._emitter, {\n      kind: 'agent_answered',\n      answer: 'accept',\n      via: 'gesture',\n      timestamp: Date.now(),\n    });\n  }\n\n  /**\n   * Fire the same \"reject\" gesture that double-tap Space fires on\n   * desktop — emits `gesture_reject`, exits script skills, rejects\n   * confirms, or stops an in-flight agent. Use this from a mobile\n   * double-tap on the FAB / subtitle bar.\n   */\n  triggerReject(): void {\n    const host = this.host;\n    host._emitter.emit('gesture_reject', undefined);\n    const hadReject = host.subtitle.invokeReject();\n    if (!hadReject) {\n      if (host._agentInstance?.isRunning()) {\n        this.handleUserStopAgent('reject');\n      } else {\n        host.subtitle.hide();\n      }\n    }\n    host._intentBuffer.emitIntent(host._emitter, {\n      kind: 'agent_answered',\n      answer: 'reject',\n      via: 'gesture',\n      timestamp: Date.now(),\n    });\n  }\n\n  /**\n   * Cross-cutting \"stop the agent now\" handler. Reasons:\n   *   - `close`: user clicked the × on the subtitle bar\n   *   - `esc`: Escape key while agent was running\n   *   - `palette`: user opened the command palette (which means they\n   *     want to send a new prompt)\n   *   - `reject`: user double-tapped Space to reject\n   *   - `voice`: user long-pressed Space to start a new voice prompt\n   *\n   * Surfaces a brief \"stopped — say something new\" subtitle so the user\n   * knows their gesture worked and the agent is safely halted. Skipped\n   * if the agent wasn't running (avoids \"stopped\" flashing on idle).\n   */\n  handleUserStopAgent(reason: 'close' | 'esc' | 'palette' | 'reject' | 'voice'): void {\n    const host = this.host;\n    const agent = host._agentInstance;\n    if (!agent || !agent.isRunning()) return;\n    // Emit BEFORE stop so the run still has its runId and dashboards\n    // see the cancellation cleanly. The Push goes into currentRunIntents\n    // too via emitIntent, so exportAgentRun() returns it.\n    this.endAgentRunStopped(reason);\n    // `palette` / `voice` are interruptions that come WITH a new prompt\n    // attached — the user wants to redirect mid-task, not abandon the\n    // conversation. Soft-stop so the next runStream() appends as a\n    // follow-up turn even when `sessionContinuityMs: 0`. Other reasons\n    // (× / Esc / double-tap reject) are explicit abandons → hard stop.\n    if (reason === 'palette' || reason === 'voice') {\n      agent.interruptForFollowup();\n    } else {\n      agent.stop();\n    }\n    host.subtitle.clearStreamed();\n    host.subtitle.hideIndicator();\n    host._highlight.clearHighlight();\n    clearWebagentOverlays();\n    hideWebagentCursor();\n    // Voice + palette have their own next UI (mic indicator / palette\n    // open) — don't double-up with a stopped subtitle that immediately\n    // gets replaced. Close / esc / reject show the feedback line.\n    if (reason === 'voice' || reason === 'palette') return;\n    const key = reason === 'close' ? 'agent.stop_close'\n      : reason === 'esc' ? 'agent.stop_esc'\n      : 'agent.stop_reject';\n    host.subtitle.show({ text: sdkString(host._config.locale, key), type: 'info', autoHide: 2500 });\n  }\n\n  /** Read a host-supplied indicator label override (`config.indicators\n   *  .processing` / `.listening`). Accepts string or per-locale map. */\n  private resolveIndicatorOverride(kind: 'processing' | 'listening'): string | null {\n    const v = this.host._config.indicators?.[kind];\n    if (!v) return null;\n    if (typeof v === 'string') return v;\n    return v[String(this.host._config.locale ?? 'en')] ?? v.en ?? null;\n  }\n\n  /** Pull the auto-hide ms for agent summary / error subtitles out of\n   *  config. Returns 0 (sticky) when the host didn't configure it. */\n  private resolveAgentAutoHide(kind: 'summary' | 'error'): number {\n    const v = this.host._config.agentSubtitleAutoHideMs;\n    if (v === undefined) return 0;\n    if (typeof v === 'number') return v;\n    return v[kind] ?? 0;\n  }\n\n  buildAgent(): WebAgent {\n    const host = this.host;\n    // Collect opted-in palette commands → expose as webagent custom actions.\n    const paletteTools = host._collectPaletteTools();\n    // Host-registered tools via `dddk.tools.register(...)` / `registerQA(...)`.\n    // Snapshot is one-shot for the initial customActions set; tools registered\n    // AFTER buildAgent() runs land via `this.tools.attachAgent(agent)` below.\n    const hostTools = host.tools.snapshot();\n\n    const agent = new WebAgent({\n      ...host._config.webAgent,\n      llm: host._config.llm!,\n      locale: host._config.locale ?? host._config.webAgent?.locale,\n      agentName: host._config.agentName ?? host._config.webAgent?.agentName,\n      siteName: host._config.siteName ?? host._config.webAgent?.siteName,\n      customActions: [\n        ...(host._config.webAgent?.customActions ?? []),\n        ...paletteTools,\n        ...hostTools,\n      ],\n    });\n\n    // Host router bridge — webagent emits `navigated` events; this\n    // callback also drives the SPA goto (the agent's own code calls\n    // this BEFORE the SPA settle window).\n    agent.setNavigateBridge((path: string) => host._navigate(path));\n\n    // Per-LLM-call performance sample → analytics dashboard. The webagent\n    // measures TTFT and total stream duration locally; we tack on runId\n    // and compute tokens-per-sec from the provider-reported output tokens.\n    agent.setLlmCallListener((info) => {\n      const runId = host._intentBuffer.currentRunId;\n      if (!runId) return;\n      const tokensPerSec = info.outputTokens && info.durationMs > 0\n        ? Math.round((info.outputTokens * 1000) / info.durationMs)\n        : undefined;\n      host._intentBuffer.emitIntent(host._emitter, {\n        kind: 'agent_llm_call',\n        runId,\n        role: info.role,\n        ttftMs: info.ttftMs,\n        durationMs: info.durationMs,\n        outputTokens: info.outputTokens,\n        inputTokens: info.inputTokens,\n        tokensPerSec,\n        model: info.model,\n        timestamp: Date.now(),\n      });\n    });\n\n    // ask_user / ask_user_choice are dispatched via the action handler;\n    // the handler calls back into these to render the host UI.\n    agent.setAskUserHandler(({ question, resolve }) => {\n      const askedAt = Date.now();\n      host._intentBuffer.emitIntent(host._emitter, { kind: 'agent_asked', question, timestamp: askedAt });\n      host.subtitle.show({\n        text: question,\n        type: 'agent',\n        onAccept: () => {\n          const now = Date.now();\n          host._intentBuffer.emitIntent(host._emitter, {\n            kind: 'agent_answered', question, answer: 'yes', via: 'gesture', latencyMs: now - askedAt, timestamp: now,\n          });\n          resolve('yes');\n        },\n        onReject: () => {\n          const now = Date.now();\n          host._intentBuffer.emitIntent(host._emitter, {\n            kind: 'agent_answered', question, answer: 'no', via: 'gesture', latencyMs: now - askedAt, timestamp: now,\n          });\n          resolve('no');\n        },\n        onCancel: () => resolve(''),\n      });\n    });\n\n    agent.setAskUserChoiceHandler(({ question, options, allowFreeText, resolve }) => {\n      const askedAt = Date.now();\n      host._intentBuffer.emitIntent(host._emitter, { kind: 'agent_asked', question, timestamp: askedAt });\n      host.subtitle.showChoice({\n        question,\n        options,\n        allowFreeText,\n        onChoose: (value, index) => {\n          const now = Date.now();\n          host._intentBuffer.emitIntent(host._emitter, {\n            kind: 'agent_answered',\n            question,\n            answer: value,\n            via: index === -1 ? 'text' : 'gesture',\n            latencyMs: now - askedAt,\n            timestamp: now,\n          });\n          resolve(value);\n        },\n        onCancel: () => resolve(''),\n      });\n    });\n\n    // `pause` is the narrator's mid-stream beat. We DON'T spawn a\n    // separate prompt subtitle — that would wipe the text the agent\n    // just streamed. Instead, attach a \"press space to continue\" hint\n    // to the existing streaming bar so the text remains visible while\n    // the user reads. If for some reason there's no streaming bar\n    // active (e.g. agent called pause as its first action), fall back\n    // to a regular ask_user-style prompt so the gesture still works.\n    agent.setPauseHandler(({ hint, resolve }) => {\n      const emitPauseDecision = (decision: 'continue' | 'stop'): void => {\n        const runId = host._intentBuffer.currentRunId;\n        if (!runId) return;\n        host._intentBuffer.emitIntent(host._emitter, {\n          kind: 'agent_pause_decision',\n          runId,\n          decision,\n          timestamp: Date.now(),\n        });\n      };\n      if (host.subtitle.isStreaming()) {\n        host.subtitle.applyStreamingPauseHint({\n          hint,\n          onAccept: () => {\n            // Tear the streaming bar down + immediately show the\n            // thinking pip. Previous design used `replaceStreamed('')`\n            // which only blanked the text but left the bar el mounted\n            // in 'streaming' mode — that kept `isStreaming()` true,\n            // suppressed the next `thinking` event's pip (see\n            // pumpAgentStream case 'thinking'), and the user stared at\n            // an empty bar with just a close × for the entire 1-3s\n            // LLM TTFT before the next turn streamed in.\n            // hide() removes the bar el; showIndicator drops in the\n            // pip so the user gets clear \"next step loading\" feedback\n            // until the next text-delta auto-replaces the pip with a\n            // fresh streaming bar via ensureStreamingBar.\n            host.subtitle.hide();\n            const label = this.resolveIndicatorOverride('processing')\n              ?? sdkString(host._config.locale, 'agent.thinking');\n            host.subtitle.showIndicator('processing', label);\n            emitPauseDecision('continue');\n            resolve('continue');\n          },\n          onReject: () => {\n            emitPauseDecision('stop');\n            resolve('');\n            this.handleUserStopAgent('reject');\n          },\n        });\n      } else {\n        // No streaming bar — fall back to the regular agent prompt.\n        host.subtitle.show({\n          text: hint,\n          type: 'agent',\n          onAccept: () => { emitPauseDecision('continue'); resolve('continue'); },\n          onReject: () => {\n            emitPauseDecision('stop');\n            resolve('');\n            this.handleUserStopAgent('reject');\n          },\n          onCancel: () => resolve(''),\n        });\n      }\n    });\n\n    // Attach the live agent to the tools registry so any future\n    // `dddk.tools.register(...)` calls flow into this running agent\n    // immediately, not just into the snapshot at build time.\n    host.tools.attachAgent(agent);\n\n    return agent;\n  }\n\n  // ─── agent event pump ──────────────────────────────────────────\n  /**\n   * Consume the agent's AsyncIterable<AgentEvent> stream and route each\n   * event to its dddk UI slot:\n   *\n   *   thinking     → showIndicator('processing')\n   *   text-delta   → subtitle.appendStreamed(delta) (cancels the indicator)\n   *   tool-start   → frame target element, hide indicator\n   *   tool-end     → no-op (next text-delta or next tool-start carries the visual)\n   *   confirm      → subtitle.show with onAccept / onReject calling decide()\n   *   navigated    → clear overlays (the bridge already moved the router)\n   *   final        → finalizeStreamed with autoHide\n   *   error        → subtitle.show error\n   *\n   * The async `for await` loop runs in the background — the host's\n   * `startAgent()` returns synchronously, and event handlers on the\n   * orchestrator (gestures, palette, voice) keep firing throughout.\n   */\n  async pumpAgentStream(stream: AsyncIterable<AgentEvent>): Promise<void> {\n    const host = this.host;\n    const thinkingLabel =\n      this.resolveIndicatorOverride('processing')\n      ?? sdkString(host._config.locale, 'agent.thinking');\n    const finalAutoHide = this.resolveAgentAutoHide('summary');\n\n    // Universal \"agent is no longer running\" cleanup. Fires on:\n    //   - natural completion (final / error)\n    //   - exception inside the pump\n    //   - external `agent.stop()` (stream exits with signal aborted)\n    //   - any other path that ends the for-await\n    // Symptom we're guarding against: thinking indicator camping on\n    // screen after the agent halted via click-outside / palette open /\n    // long-press voice / esc. ANY stop reason should clear it.\n    const safeCleanup = (): void => {\n      host.subtitle.hideIndicator();\n      host._highlight.clearHighlight();\n      clearWebagentOverlays();\n      hideWebagentCursor();\n    };\n\n    try {\n      for await (const ev of stream) {\n        switch (ev.kind) {\n          case 'thinking':\n            if (!host.subtitle.isStreaming()) {\n              host.subtitle.showIndicator('processing', thinkingLabel);\n            }\n            host._emitter.emit('agent_thinking', undefined);\n            break;\n\n          case 'text-delta':\n            host.subtitle.appendStreamed(ev.delta);\n            break;\n\n          case 'tool-start':\n            host.subtitle.hideIndicator();\n            if (ev.targetSelector) {\n              // Resolve numeric `[N]` indexes via the agent's per-turn\n              // map before falling through to CSS selector matching.\n              // Without this, the LLM passing a bare \"13\" would crash\n              // querySelector with SyntaxError.\n              const resolved = host._agentInstance?.resolveSelector(ev.targetSelector);\n              if (resolved) host._highlight.highlightElement(resolved as HTMLElement);\n              else host._highlight.highlightElement(ev.targetSelector);\n            }\n            host._emitter.emit('agent_tool_start', { name: ev.name, args: ev.args, targetSelector: ev.targetSelector });\n            break;\n\n          case 'tool-end':\n            host._emitter.emit('agent_tool_end', { name: ev.name, result: ev.result });\n            // v0.2.0 — also surface failures into the intent\n            // stream so dashboards can chart \"which tool is failing,\n            // why, how often\". `agent_tool_end` stays on the host\n            // emitter for runtime listeners; failed runs also fire\n            // `agent_tool_failed` into the intent buffer.\n            if (!ev.result.ok) {\n              const failedRunId = host._intentBuffer.currentRunId;\n              if (failedRunId) {\n                host._intentBuffer.emitIntent(host._emitter, {\n                  kind: 'agent_tool_failed',\n                  runId: failedRunId,\n                  name: ev.name,\n                  reason: ev.result.reason,\n                  message: ev.result.message,\n                  timestamp: Date.now(),\n                });\n              }\n            }\n            break;\n\n          case 'navigating':\n            // SPA route change kicked off but the new page isn't ready\n            // to read yet — show a polished loading indicator until\n            // `navigated` arrives.\n            host.subtitle.showIndicator('processing', sdkString(host._config.locale, 'agent.loading'));\n            clearWebagentOverlays();\n            host._highlight.clearHighlight();\n            break;\n\n          case 'navigated':\n            // New page settled. Hide the loading indicator; the next\n            // text-delta from the model will create the streaming bar\n            // for narration about the new page.\n            host.subtitle.hideIndicator();\n            break;\n\n          case 'confirm':\n            await this.routeConfirm(ev);\n            break;\n\n          case 'final':\n            // Close the streamed narration first, then render the\n            // host-configured loop-closure (text / feedback / ask_user\n            // / silent). Without this the bar just disappears, which\n            // reads as a broken UI rather than a finished run.\n            host.subtitle.finalizeStreamed(\n              finalAutoHide > 0 ? { autoHide: finalAutoHide } : {},\n            );\n            host._highlight.clearHighlight();\n            clearWebagentOverlays();\n            // Synthetic cursor sticks to its last viewport position\n            // by design (it's position:fixed). Once the loop has ended\n            // that \"last position\" is stale — anchored to an element\n            // that may have scrolled away, or just visually orphaned\n            // from the now-clean page. Hide it on every terminal\n            // event so it stops floating around.\n            hideWebagentCursor();\n            host._emitter.emit('agent_final', undefined);\n            await this.renderLoopClosure();\n            this.endAgentRunCompleted();\n            break;\n\n          case 'error':\n            host.subtitle.hideIndicator();\n            if (!ev.retrying) {\n              const errMsg = host._config.locale === 'zh-TW'\n                ? `出了點問題：${ev.error.message}`\n                : `Something went wrong: ${ev.error.message}`;\n              if (host.subtitle.isStreaming()) {\n                host.subtitle.appendStreamed('\\n\\n' + errMsg);\n                host.subtitle.finalizeStreamed({ autoHide: 6_000 });\n              } else {\n                host.subtitle.show({ text: errMsg, type: 'info', autoHide: 6_000 });\n              }\n              host._highlight.clearHighlight();\n              clearWebagentOverlays();\n              hideWebagentCursor();\n              host._emitter.emit('agent_error', { error: ev.error });\n            }\n            break;\n        }\n      }\n    } catch (err) {\n      // Pump itself threw (shouldn't normally — agent catches its own\n      // errors and emits `error` events). Defensive cleanup.\n      if (host.subtitle.isStreaming()) {\n        host.subtitle.finalizeStreamed({ autoHide: 4_000 });\n      }\n      safeCleanup();\n      if (typeof console !== 'undefined') {\n        console.warn('[dddk] agent pump threw:', err);\n      }\n    } finally {\n      // Always-fires cleanup. Handles the \"stream ended without firing\n      // a terminal event\" case — most commonly when an external\n      // `agent.stop()` (via close button, esc, palette open,\n      // long-press voice) aborts the loop mid-flight. Without this\n      // hook the thinking indicator stayed up forever.\n      safeCleanup();\n    }\n  }\n\n  /**\n   * Resolve the active `onLoopEnd` config — host override, or the SDK\n   * default of a temperate \"✓ Done\" line. Returning `{kind: 'silent'}`\n   * means legacy \"subtitle disappears\" behaviour.\n   */\n  private resolveLoopEnd(): OnLoopEnd {\n    const hostCfg = this.host._config.webAgent?.onLoopEnd;\n    if (hostCfg) return hostCfg;\n    return {\n      kind: 'text',\n      text: sdkString(this.host._config.locale, 'agent.done'),\n      autoHide: 3000,\n    };\n  }\n\n  /**\n   * Render the configured loop closure when the agent loop ends. Sits\n   * between `finalizeStreamed` and `endAgentRunCompleted` in\n   * pumpAgentStream.\n   *\n   * Each kind maps onto an existing subtitle surface:\n   *   text     → subtitle.show with autoHide; no gesture wiring.\n   *   feedback → subtitle.show with onAccept/onReject/onCancel, emits\n   *              `agent_feedback` with satisfied = true / false / null.\n   *   ask_user → subtitle.showChoice; the picked value flows into\n   *              `agent_feedback.summary`.\n   *   silent   → no-op; legacy \"subtitle disappears\" behavior.\n   */\n  private async renderLoopClosure(): Promise<void> {\n    const host = this.host;\n    const closure = this.resolveLoopEnd();\n    if (closure.kind === 'silent') return;\n\n    if (closure.kind === 'text') {\n      const autoHide = closure.autoHide ?? 3000;\n      host.subtitle.show({\n        text: closure.text,\n        type: 'agent',\n        autoHide,\n      });\n      // Don't block endAgentRunCompleted on the autoHide window — the\n      // run is logically complete already; the subtitle just dwells.\n      return;\n    }\n\n    // Snapshot the run + skill at closure render time. Both are stored\n    // on every agent_feedback IntentEvent so the dashboard can roll up\n    // satisfaction by run or by skill without time-window heuristics.\n    const runId = host._intentBuffer.currentRunId ?? undefined;\n    const skillId = host._intentBuffer.currentSkillId ?? undefined;\n\n    if (closure.kind === 'feedback') {\n      const now = (): number => Date.now();\n      // `persistent: true` removes every passive dismiss path — × close\n      // button hidden, Esc ignored, outside-click / any-key ignored.\n      // The bar can only close via Space (accept), double-tap (reject),\n      // or click on the ✓ / ✕ buttons. Trade-off: visitor can't skip the\n      // prompt, but we always get a labelled satisfied/not-satisfied\n      // signal — that's the whole point of opting into feedback mode.\n      await new Promise<void>((resolve) => {\n        const close = (satisfied: boolean): void => {\n          host._intentBuffer.emitIntent(host._emitter, {\n            kind: 'agent_feedback', runId, skillId, satisfied, summary: closure.text, timestamp: now(),\n          });\n          // Tear the bar down — accept / reject callbacks don't go through\n          // the gesture-manager `invokeAccept` path that normally hides\n          // the subtitle, so we hide it here. Without this the bar stays\n          // visible after the click and the user thinks ✓ / ✕ didn't fire.\n          host.subtitle.hide();\n          resolve();\n        };\n        host.subtitle.show({\n          text: closure.text,\n          type: 'agent',\n          persistent: true,\n          onAccept: () => close(true),\n          onReject: () => close(false),\n        });\n      });\n      return;\n    }\n\n    // ask_user — picker with the host's options. Picked value goes\n    // into the agent_feedback intent so dashboards can break down\n    // satisfaction by chosen bucket.\n    const optionLabels = closure.options.map((o) => o.label);\n    await new Promise<void>((resolve) => {\n      host.subtitle.showChoice({\n        question: closure.question,\n        options: optionLabels,\n        allowFreeText: false,\n        onChoose: (value, index) => {\n          const picked = closure.options[index];\n          host._intentBuffer.emitIntent(host._emitter, {\n            kind: 'agent_feedback',\n            runId,\n            skillId,\n            satisfied: null,\n            summary: picked?.value ?? value,\n            timestamp: Date.now(),\n          });\n          resolve();\n        },\n        onCancel: () => {\n          host._intentBuffer.emitIntent(host._emitter, {\n            kind: 'agent_feedback', runId, skillId, satisfied: null, summary: '', timestamp: Date.now(),\n          });\n          resolve();\n        },\n      });\n    });\n  }\n\n  /**\n   * Route a `confirm` event to the subtitle bar with Space-accept /\n   * double-tap-reject wiring. The agent is awaiting `decide()` — we\n   * resolve it from the user's gesture.\n   */\n  private async routeConfirm(ev: Extract<AgentEvent, { kind: 'confirm' }>): Promise<void> {\n    const host = this.host;\n    const targetSelector =\n      (typeof ev.args.selector === 'string' ? ev.args.selector : null) ??\n      (typeof ev.args.target === 'string' ? ev.args.target : null) ??\n      (typeof ev.args.element === 'string' ? ev.args.element : null);\n    if (targetSelector) {\n      const resolved = host._agentInstance?.resolveSelector(targetSelector);\n      if (resolved) host._highlight.highlightElement(resolved as HTMLElement);\n      else host._highlight.highlightElement(targetSelector);\n    } else {\n      host._highlight.clearHighlight();\n    }\n\n    await new Promise<void>((resolve) => {\n      host.subtitle.show({\n        text: ev.message,\n        type: 'agent',\n        onAccept: () => {\n          host._intentBuffer.emitIntent(host._emitter, {\n            kind: 'confirm_action', actionName: ev.actionName, params: ev.args, approved: true, timestamp: Date.now(),\n          });\n          ev.decide(true);\n          resolve();\n        },\n        onReject: () => {\n          host._intentBuffer.emitIntent(host._emitter, {\n            kind: 'confirm_action', actionName: ev.actionName, params: ev.args, approved: false, timestamp: Date.now(),\n          });\n          host._highlight.clearHighlight();\n          ev.decide(false);\n          resolve();\n        },\n        onCancel: () => {\n          host._highlight.clearHighlight();\n          ev.decide(false);\n          resolve();\n        },\n      });\n    });\n  }\n\n  /**\n   * Collect palette commands that have opted into agent exposure\n   * (via `agentTool: {...}`), turn them into WebAgent customActions.\n   */\n  collectPaletteTools(): NonNullable<WebAgentConfig['customActions']> {\n    const host = this.host;\n    const tools: NonNullable<WebAgentConfig['customActions']> = [];\n\n    // Per-item exposure — items the host opted into via `agentTool: {...}`\n    // become their own named agent tools. Same shape as before.\n    for (const item of host.palette.getItems()) {\n      if (!item.agentTool || !item.handler) continue;\n      tools.push({\n        name: this.toolNameOf(item),\n        description: item.agentTool.description,\n        parameters: item.agentTool.parameters,\n        requireConfirmation: item.agentTool.requireConfirmation,\n        handler: async (params) => {\n          const arg = (params as { arg?: string }).arg ?? '';\n          try {\n            // Reuse the palette item's handler — agent sees same result host expected\n            await item.handler!({\n              close: () => {},\n              replace: () => {},\n              get input() { return ''; },\n              setInput: () => {},\n              get context() {\n                return { selectionText: '', attachments: [] };\n              },\n              showResult: () => {},\n              clearResult: () => {},\n              setInputContext: () => {},\n              clearInputContext: () => {},\n            }, arg);\n            return { ok: true };\n          } catch (err) {\n            return { ok: false, reason: 'unknown' as const, message: (err as Error).message };\n          }\n        },\n      });\n    }\n\n    // `open_palette` was previously registered here as a generic \"show\n    // the UI and let the agent click into it\" tool. Removed in v0.1.0+:\n    // multi-step UI navigation (open → click row → click sub-menu) is\n    // unreliable on small models. Hosts that want the agent to invoke a\n    // palette command now register semantic intent tools instead — e.g.\n    // `immersive_translate({language})`, `start_site_tour()`,\n    // `search_docs({query})`. The host's tool handler drives the palette\n    // UI animation if visual feedback is desired. See\n    // `dddk-frontend/src/lib/agent-tools.ts` for the reference pattern.\n\n    return tools;\n  }\n\n  /** Normalize palette id → safe action name (a-z0-9_). */\n  private toolNameOf(item: import('../triggers/command-palette').PaletteItem): string {\n    return `palette_${item.id.replace(/[^a-zA-Z0-9_]/g, '_').toLowerCase()}`;\n  }\n}\n","/**\n * Pure-function helpers used by the orchestrator. Zero dependencies on\n * `DotDotDuck` state — safe to call from anywhere.\n */\n\nimport type { StorageAdapter } from '../types';\n\n/** Read a Blob into a base64 data URL for `selection.images[]`. */\nexport function blobToDataUrl(blob: Blob): Promise<string> {\n  return new Promise((resolve, reject) => {\n    const reader = new FileReader();\n    reader.onload = () => resolve(String(reader.result ?? ''));\n    reader.onerror = () => reject(reader.error);\n    reader.readAsDataURL(blob);\n  });\n}\n\nexport function defaultStorage(): StorageAdapter {\n  return {\n    get: (k) => (typeof localStorage !== 'undefined' ? localStorage.getItem(`dddk.${k}`) : null),\n    set: (k, v) => {\n      if (typeof localStorage !== 'undefined') localStorage.setItem(`dddk.${k}`, v);\n    },\n    remove: (k) => {\n      if (typeof localStorage !== 'undefined') localStorage.removeItem(`dddk.${k}`);\n    },\n  };\n}\n\n/**\n * Walk the current page's visible DOM text and return up to 20 hits whose\n * trimmed text content contains `q` (case-insensitive). Exported so hosts\n * can wire it into a `#`-prefix browse() — typing `#<query>` searches the\n * page in front of the user, distinct from `docs:` (full-text search across\n * the docs corpus).\n */\nexport function searchPageText(q: string): Array<{ text: string; element: HTMLElement }> {\n  if (typeof document === 'undefined' || !q.trim()) return [];\n  const out: Array<{ text: string; element: HTMLElement }> = [];\n  const needle = q.toLowerCase();\n  const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);\n  let node: Node | null;\n  while ((node = walker.nextNode())) {\n    const text = (node.textContent ?? '').trim();\n    if (text.toLowerCase().includes(needle)) {\n      const el = node.parentElement;\n      if (el && el.offsetParent !== null) {\n        out.push({ text: text.slice(0, 80), element: el });\n        if (out.length >= 20) break;\n      }\n    }\n  }\n  return out;\n}\n","/**\n * `dddk.sessions` — named session registry.\n *\n * Hosts wiring multiple agents (different personas per route, an\n * admin agent vs a docs agent, WebAgent + TaskAgent on the same\n * page) need a shared place to hold `AgentSession` objects so the\n * agents can read + append to the same conversation history. The\n * registry mediates: agents inject the session by reference, the\n * registry owns the lifecycle (create, reset, persist, clear).\n *\n * Persistence is OPT-IN per session via `persistKey` so the agent\n * pattern from v0.1 (one session, one localStorage key) keeps\n * working. Sessions without a `persistKey` live in memory only.\n *\n * v0.2.0.\n */\n\nimport type { AgentSession } from '../agent/webagent/types';\nimport {\n  createSession,\n  loadSession,\n  saveSession,\n  clearSession as wipeSession,\n} from '../agent/webagent/session';\n\nexport interface SessionRegistration {\n  /** Identifier the host uses to reference this session. */\n  name: string;\n  /**\n   * sessionStorage key for persistence. When set, the registry tries\n   * `loadSession(persistKey)` on first `get()` and writes via\n   * `saveSession(session, persistKey)` after `update()`. When unset,\n   * the session lives in-memory for the page's lifetime.\n   */\n  persistKey?: string;\n}\n\nexport class SessionsRegistry {\n  private map = new Map<string, AgentSession>();\n  /** Track persistKey per name so reset / clear can update storage. */\n  private persistKeys = new Map<string, string>();\n\n  /**\n   * Fetch (or create-on-first-call) a named session. If `persistKey`\n   * is provided AND a saved session exists under that key, it's\n   * loaded once and cached; subsequent calls return the same in-memory\n   * object so multiple agents share by reference.\n   */\n  get(name: string, opts: { persistKey?: string; currentPage?: string } = {}): AgentSession {\n    const cached = this.map.get(name);\n    if (cached) return cached;\n    const persistKey = opts.persistKey;\n    let session: AgentSession | null = null;\n    if (persistKey) {\n      session = loadSession(persistKey);\n      this.persistKeys.set(name, persistKey);\n    }\n    if (!session) {\n      const currentPage = opts.currentPage\n        ?? (typeof location !== 'undefined' ? location.pathname + location.search : '/');\n      session = createSession(currentPage);\n    }\n    this.map.set(name, session);\n    return session;\n  }\n\n  /** True when the registry has a session under this name. */\n  has(name: string): boolean {\n    return this.map.has(name);\n  }\n\n  /** All registered session names. */\n  list(): string[] {\n    return Array.from(this.map.keys());\n  }\n\n  /**\n   * Replace the session under `name` with a fresh one. All agents\n   * holding a reference to the OLD session keep that reference —\n   * they should call `dddk.sessions.get(name)` again to pick up the\n   * new object. This is the \"user explicitly started a new\n   * conversation\" path.\n   */\n  reset(name: string, opts: { currentPage?: string } = {}): AgentSession {\n    const currentPage = opts.currentPage\n      ?? (typeof location !== 'undefined' ? location.pathname + location.search : '/');\n    const fresh = createSession(currentPage);\n    this.map.set(name, fresh);\n    const persistKey = this.persistKeys.get(name);\n    if (persistKey) saveSession(fresh, persistKey);\n    return fresh;\n  }\n\n  /** Persist the cached session under `name`. No-op for in-memory sessions. */\n  persist(name: string): void {\n    const persistKey = this.persistKeys.get(name);\n    const session = this.map.get(name);\n    if (persistKey && session) saveSession(session, persistKey);\n  }\n\n  /**\n   * Remove the session from the registry. If it was persisted, also\n   * wipes the underlying storage entry. Agents holding a reference\n   * to the prior object see no change until they re-fetch via\n   * `get(name)`.\n   */\n  clear(name: string): void {\n    const persistKey = this.persistKeys.get(name);\n    this.map.delete(name);\n    this.persistKeys.delete(name);\n    if (persistKey) wipeSession(persistKey);\n  }\n\n  /** Drop every session from the registry (memory + storage). */\n  clearAll(): void {\n    for (const name of this.list()) this.clear(name);\n  }\n}\n","/**\n * `dddk.agents` — named agent registry + active-agent slot.\n *\n * Hosts wiring multiple agents (different prompts / sitemaps /\n * personas per route) register each one by name; the orchestrator\n * routes the \"current\" agent's calls (palette commands, voice\n * captures, dwell selections) through whatever the host has set\n * active. Switching active on a route change preserves cross-page\n * continuity when the agents share a session via `dddk.sessions`.\n *\n * Holds WebAgent instances today; TaskAgent slots in via the same\n * interface\n *\n * v0.2.0.\n */\n\nimport type { WebAgent } from '../agent';\n\n/**\n * Minimum the orchestrator + registry needs from any registered\n * agent. WebAgent satisfies this naturally; TaskAgent will once\n * \n */\nexport interface RegisterableAgent {\n  isRunning?(): boolean;\n  stop?(): void;\n  destroy?(): void;\n  setLocale?(locale: string): void;\n}\n\nexport class AgentsRegistry {\n  private map = new Map<string, WebAgent>();\n  private activeName: string | null = null;\n\n  /**\n   * Register an agent under `name`. If `name` is already registered\n   * the previous entry is replaced; the previous agent's `destroy()`\n   * is NOT called automatically — host owns the lifecycle.\n   *\n   * The first register call also becomes the active agent unless\n   * another was already set.\n   */\n  register(name: string, agent: WebAgent): void {\n    this.map.set(name, agent);\n    if (this.activeName === null) this.activeName = name;\n  }\n\n  /**\n   * Remove an agent from the registry. If it was the active one,\n   * clears the active slot (host must `setActive` again).\n   */\n  unregister(name: string): void {\n    this.map.delete(name);\n    if (this.activeName === name) this.activeName = null;\n  }\n\n  /** Lookup by name. Returns `undefined` when not registered. */\n  get(name: string): WebAgent | undefined {\n    return this.map.get(name);\n  }\n\n  /** True when the registry has an agent under this name. */\n  has(name: string): boolean {\n    return this.map.has(name);\n  }\n\n  /** All registered agent names. */\n  list(): string[] {\n    return Array.from(this.map.keys());\n  }\n\n  /**\n   * Make `name` the active agent. Throws when no agent is registered\n   * under that name — silently swallowing would mask host config\n   * bugs that are otherwise hard to spot.\n   */\n  setActive(name: string): void {\n    if (!this.map.has(name)) {\n      throw new Error(`AgentsRegistry.setActive: no agent registered under '${name}'`);\n    }\n    this.activeName = name;\n  }\n\n  /** Currently-active agent. `null` when nothing is registered. */\n  getActive(): WebAgent | null {\n    if (!this.activeName) return null;\n    return this.map.get(this.activeName) ?? null;\n  }\n\n  /** Name of the active agent, or `null` if unset. */\n  getActiveName(): string | null {\n    return this.activeName;\n  }\n}\n","/**\n * Skill dispatch — looks up a skill by id / slash command, gates on\n * preferences, then routes by skill type (script / prompt / action /\n * surface / panel). Also owns the ad-hoc surface tools (`showSurface\n * AndAwait` / `submitSurface` / `cancelSurface`) used by ScriptSkill\n * steps and host code.\n *\n * Wrapped as a helper class taking the `DotDotDuck` host so it can\n * reach into `_prefs`, `_pendingSurface`, etc., without leaking a\n * second public type into the SDK surface.\n */\n\nimport type { PaletteItem } from '../triggers/command-palette';\nimport type { Skill, ScriptSkill, ActionSkillContext, SkillTools, SurfacePlacement } from '../skills/types';\nimport type { DotDotDuck } from './index';\n\nexport class SkillDispatcher {\n  constructor(private readonly host: DotDotDuck) {}\n\n  async runSkill(idOrCommand: string, vars: Record<string, string> = {}): Promise<void> {\n    const host = this.host;\n    const skill = host.skills.match(idOrCommand) ?? host.skills.get(idOrCommand);\n    if (!skill) return;\n\n    // Preferences gate — if any required pref missing, render setup surface first.\n    if (skill.preferences && skill.preferences.length > 0) {\n      const schema = { skillId: skill.id, fields: skill.preferences };\n      const ctx = host._prefs.contextFor(schema);\n      if (!ctx.isComplete()) {\n        const surface = host._prefs.buildSetupSurface(schema);\n        const ok = await new Promise<boolean>((resolve) => {\n          host._pendingPrefs = {\n            skillId: skill.id,\n            resolve: () => {\n              host._pendingPrefs = null;\n              resolve(true);\n            },\n            reject: () => {\n              host._pendingPrefs = null;\n              resolve(false);\n            },\n          };\n          host._emitter.emit('surface', { surface, placement: 'modal' });\n        });\n        if (!ok || !ctx.isComplete()) return;\n      }\n    }\n\n    host._emitter.emit('skill_start', { skillId: skill.id });\n    host._intentBuffer.emitIntent(host._emitter, {\n      kind: 'skill_started', skillId: skill.id, timestamp: Date.now(),\n    });\n    host._intentBuffer.currentSkillId = skill.id;\n\n    try {\n      switch (skill.type) {\n        case 'script':\n          await this.runScriptSkill(skill);\n          break;\n        case 'prompt': {\n          const args = host.skills.parseArgs(idOrCommand);\n          const merged = args ? { ...vars, args } : vars;\n          const prompt = host.skills.resolvePrompt(skill, merged);\n          host.startAgent(prompt);\n          break;\n        }\n        case 'action':\n          await skill.handler(this.buildActionContext(skill.id));\n          break;\n        case 'surface': {\n          const surface = await skill.build(this.buildActionContext(skill.id));\n          host._emitter.emit('surface', { surface, placement: 'modal' });\n          // Host listens to the `surface` event and calls onSubmit upon submission.\n          break;\n        }\n        case 'panel': {\n          await host._ensurePanelRuntime().enter(skill);\n          break;\n        }\n      }\n    } finally {\n      host._emitter.emit('skill_done', { skillId: skill.id });\n      host._intentBuffer.emitIntent(host._emitter, {\n        kind: 'skill_finished', skillId: skill.id, timestamp: Date.now(),\n      });\n      if (host._intentBuffer.currentSkillId === skill.id) host._intentBuffer.currentSkillId = null;\n    }\n  }\n\n  // ─── helpers ────────────────────────────────────────────────────\n\n  private async runScriptSkill(skill: ScriptSkill): Promise<void> {\n    const host = this.host;\n    let i = 0;\n    try {\n      for (const step of skill.steps) {\n        host._emitter.emit('skill_step', { skillId: skill.id, stepIndex: i });\n\n        if (step.page) host._navigate(step.page);\n        if (step.subtitle) {\n          host.subtitle.show({ text: step.subtitle, type: 'agent' });\n        }\n        if (step.action) {\n          await step.action(this.buildSkillTools());\n        }\n        if (step.waitForUser !== false) {\n          const outcome = await this.waitForAcceptOrEscape();\n          // Esc OR double-tap space both exit the tour early — double-tap\n          // is the canonical \"no/dismiss\" gesture and should behave like Esc.\n          if (outcome !== 'accept') {\n            break;\n          }\n        }\n        host.subtitle.hide();\n        i++;\n      }\n    } finally {\n      // Every exit path (normal completion, user double-tap exit, esc,\n      // thrown step) clears ALL agent / tour surface state. Without this\n      // the last subtitle / streaming indicator / highlight could linger\n      // and the user thinks the agent is still working when the tour\n      // actually ended. Belt-and-braces — individual break paths used\n      // to clear partially; centralising it here means there is exactly\n      // one \"skill is over\" cleanup contract.\n      host.subtitle.hide();\n      host.subtitle.hideIndicator();\n      host._highlight.clearHighlight();\n      // If a webagent loop happened to be running alongside the script\n      // (rare — host might have started one for unrelated work), stop it\n      // so the user's idea of \"the tour ended\" matches reality. Safe\n      // no-op when no agent is running.\n      try { host.stopAgent(); } catch { /* swallow */ }\n    }\n  }\n\n  /**\n   * Resolves on the next user gesture:\n   *   - `'accept'`  → single space tap or accept-button click\n   *   - `'escape'`  → Esc key\n   *   - `'reject'`  → double space tap (treated as exit by ScriptSkill)\n   *\n   * Callers can branch on the outcome to advance vs. bail out of a\n   * multi-step flow.\n   */\n  private waitForAcceptOrEscape(): Promise<'accept' | 'escape' | 'reject'> {\n    const host = this.host;\n    return new Promise((resolve) => {\n      const cleanup = () => {\n        host.off('gesture_accept', onAccept);\n        host.off('gesture_escape', onEsc);\n        host.off('gesture_reject', onReject);\n      };\n      const onAccept = () => { cleanup(); resolve('accept'); };\n      const onEsc    = () => { cleanup(); resolve('escape'); };\n      const onReject = () => { cleanup(); resolve('reject'); };\n      host.on('gesture_accept', onAccept);\n      host.on('gesture_escape', onEsc);\n      host.on('gesture_reject', onReject);\n    });\n  }\n\n  buildSkillTools(): SkillTools {\n    const host = this.host;\n    return {\n      navigate: (path) => host._navigate(path),\n      // All three overlay primitives map to the same Dwell-style frame —\n      // visual consistency with long-press selection. `color` / `label`\n      // params are accepted but currently ignored; the frame is themed via\n      // `--dddk-dwell-frame-*` CSS vars on the host.\n      highlight: (selector) => { host.highlightElement(selector); return selector; },\n      border:    (selector) => { host.highlightElement(selector); return selector; },\n      spotlight: (selector) => { host.highlightElement(selector); return selector; },\n      inject: () => '',\n      subtitle: (text) => host.subtitle.show({ text, type: 'agent' }),\n      clearOverlays: () => host.clearHighlight(),\n      ask: async () => '',\n      wait: (ms) => new Promise((r) => setTimeout(r, ms)),\n      surface: (surface, opts) => this.showSurfaceAndAwait(surface, opts?.placement ?? 'modal'),\n    };\n  }\n\n  /**\n   * Show a Surface and await the host's submission. Used by skill tools and\n   * any host code that wants the same \"emit → user fills → resolve\" pattern.\n   */\n  showSurfaceAndAwait(\n    surface: unknown,\n    placement: SurfacePlacement = 'modal',\n  ): Promise<Record<string, unknown> | null> {\n    const host = this.host;\n    // If something is already pending, cancel it before starting a new one —\n    // surfaces are modal-ish; two at once would deadlock the script.\n    if (host._pendingSurface) {\n      host._pendingSurface.resolve(null);\n      host._pendingSurface = null;\n    }\n    return new Promise((resolve) => {\n      host._pendingSurface = {\n        resolve: (data) => {\n          host._pendingSurface = null;\n          resolve(data);\n        },\n      };\n      host._emitter.emit('surface', { surface, placement });\n    });\n  }\n\n  /**\n   * Host calls this when the user submits the active Surface form. Routes\n   * to whichever subsystem opened the surface:\n   *   - If a ScriptSkill called `tools.surface(...)` → resolves that promise\n   *   - If webagent was awaiting a host interaction → resumes the agent loop\n   * (Both can be pending at once in theory — we resolve both for safety.)\n   */\n  submitSurface(data: Record<string, unknown>): void {\n    const host = this.host;\n    if (host._pendingSurface) {\n      host._pendingSurface.resolve(data);\n    }\n    host._agentInstance?.respond(data);\n  }\n\n  /** Host calls this when the user cancels the Surface (Esc / backdrop click). */\n  cancelSurface(): void {\n    const host = this.host;\n    if (host._pendingSurface) {\n      host._pendingSurface.resolve(null);\n    }\n    // Tell webagent the user cancelled — it gets an empty answer.\n    host._agentInstance?.respond('');\n  }\n\n  buildActionContext(skillId?: string): ActionSkillContext {\n    const host = this.host;\n    return {\n      getPreferences<T = Record<string, unknown>>(): T {\n        if (!skillId) return {} as T;\n        return host._prefs.read(skillId) as T;\n      },\n      palette: {\n        close: () => host.palette.close(),\n        replace: (items) =>\n          host.palette.setItems(items.map((i) => ({ id: i.id, name: i.name, handler: i.handler }))),\n      },\n      subtitle: {\n        show: (opts) =>\n          host.subtitle.show({\n            text: opts.text,\n            type: (opts.type as never) ?? 'info',\n            autoHide: opts.autoHide,\n          }),\n        hide: () => host.subtitle.hide(),\n      },\n      storage: {\n        get: <T,>(key: string) => {\n          const raw = host._storage.get(key);\n          if (raw == null) return null;\n          const s = raw as string;\n          try {\n            return JSON.parse(s) as T;\n          } catch {\n            return s as unknown as T;\n          }\n        },\n        set: (key, value) => {\n          host._storage.set(key, typeof value === 'string' ? value : JSON.stringify(value));\n        },\n      },\n      agent: (task) => host.startAgent(task),\n      navigate: (path) => host._navigate(path),\n    };\n  }\n\n  buildPaletteItems(): PaletteItem[] {\n    const host = this.host;\n    const items: PaletteItem[] = [];\n\n    for (const skill of host.skills.list()) {\n      // Skills marked `hidden: true` are still callable (host can fire\n      // them via `dddk.runSkill(id)` or wire their own palette items\n      // pointing at them), but they don't auto-appear in the default\n      // \"Skills\" section. Use this when you want explicit control over\n      // section / placement / labelling in the palette.\n      if (skill.hidden) continue;\n      // If skill.name already looks like `/command`, use it as-is to avoid\n      // duplication (\"/introduce — /introduce\"). Otherwise prefix `/<id>` so\n      // the palette can route the slash command, and append name for context.\n      const looksLikeSlashCommand = skill.name.trim().startsWith('/');\n      const displayName = looksLikeSlashCommand\n        ? skill.name\n        : `/${skill.id} — ${skill.name}`;\n      items.push({\n        id: skill.id,\n        name: displayName,\n        description: skill.description,\n        section: 'Skills',\n        // No `icon` field — skills are intentionally rendered without icons\n        // in the palette (host-defined PaletteItems can opt in via their own\n        // `icon` field; skills stay neutral so they read as text actions).\n        handler: (h) => {\n          h.close();\n          host.runSkill(skill.id);\n        },\n      });\n    }\n\n    for (const cmd of host._config.paletteCommands ?? []) {\n      items.push(cmd);\n    }\n\n    return items;\n  }\n}\n\n// Helper — extract Skill from a skills.list() entry without depending on\n// the host. Exists so test code can drive `buildPaletteItems` without a\n// full DotDotDuck instance.\nexport type { Skill };\n","import { injectScopedStyle, UI_ATTR } from '../../utils/dom';\n\nexport const POPOVER_ATTR = UI_ATTR;\nexport const POPOVER_STYLE_ID = 'dddk-dwell-style';\n\nexport function ensureDwellStyles(): void {\n  injectScopedStyle(POPOVER_STYLE_ID, `\n    [${POPOVER_ATTR}=\"dwell\"] {\n      position: absolute; display: none;\n      max-width: 300px;\n      background: var(--dddk-bg-elevated, #fff);\n      border: 1px solid var(--dddk-border, rgba(0,0,0,0.1));\n      border-radius: 10px;\n      padding: 10px 12px;\n      box-shadow: var(--dddk-shadow-md, 0 4px 16px rgba(0,0,0,0.12));\n      font-size: 13px;\n      color: var(--dddk-text, #111);\n      z-index: var(--dddk-z-bar, 9500);\n      animation: dddkMpIn 140ms ease-out;\n    }\n    [${POPOVER_ATTR}=\"dwell\"] .dwell-head {\n      display: flex; align-items: flex-start; justify-content: space-between;\n      gap: 8px; margin-bottom: 8px;\n    }\n    /* Mascot duck perches on the popover — turns the dwell selection\n       menu into an obvious dddk surface at a glance. Uses a CSS\n       variable so the host controls the URL (nothing baked into\n       the library). Off by default (empty var). */\n    [${POPOVER_ATTR}=\"dwell\"] .dwell-head::before {\n      content: '';\n      display: var(--dddk-dwell-avatar-display, block);\n      width: 22px;\n      height: 22px;\n      background-image: var(--dddk-avatar-url, none);\n      background-size: contain;\n      background-repeat: no-repeat;\n      background-position: center;\n      flex-shrink: 0;\n      animation: dddkDwellAvatarBob var(--dddk-dwell-avatar-bob-duration, 2.6s) ease-in-out infinite;\n    }\n    @keyframes dddkDwellAvatarBob {\n      0%, 100% { transform: translateY(0); }\n      50%      { transform: translateY(-2px); }\n    }\n    [${POPOVER_ATTR}=\"dwell\"] .dwell-label { font-weight: 600; flex: 1; }\n    [${POPOVER_ATTR}=\"dwell\"] .dwell-close {\n      background: transparent; border: 0; cursor: pointer;\n      color: var(--dddk-text-muted, #71717a);\n      font-size: 14px; line-height: 1; padding: 0 2px;\n    }\n    [${POPOVER_ATTR}=\"dwell\"] .dwell-close:hover { color: var(--dddk-text, #111); }\n    [${POPOVER_ATTR}=\"dwell\"] .dwell-actions {\n      display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 6px;\n    }\n    [${POPOVER_ATTR}=\"dwell\"] .dwell-actions button {\n      background: var(--dddk-accent-soft, rgba(236,72,153,0.12));\n      color: inherit; border: 0; cursor: pointer;\n      padding: 4px 8px; border-radius: 5px; font: inherit; font-size: 12px;\n    }\n    [${POPOVER_ATTR}=\"dwell\"] .dwell-actions button:hover {\n      background: var(--dddk-accent, #ec4899); color: #fff;\n    }\n    [${POPOVER_ATTR}=\"dwell\"] .dwell-hint {\n      font-size: 10px; color: var(--dddk-text-muted, #71717a);\n      text-align: right;\n      padding-right: 22px; /* clear space for the corner duck badge */\n    }\n    /* Corner duck badge — the \"mascot signed this analysis\" mark. Sits\n       in the bottom-right of the popover, small, tilted a hair, gently\n       winking. Uses the same avatar URL as the header. Absent when the\n       host hasn't set the URL. */\n    [${POPOVER_ATTR}=\"dwell\"]::after {\n      content: '';\n      position: absolute;\n      right: 8px; bottom: 8px;\n      width: 18px; height: 18px;\n      background-image: var(--dddk-avatar-url, none);\n      background-size: contain;\n      background-repeat: no-repeat;\n      background-position: center;\n      transform: rotate(-8deg);\n      pointer-events: none;\n      opacity: 0.85;\n      animation: dddkDwellCornerWink 3s ease-in-out infinite;\n    }\n    @keyframes dddkDwellCornerWink {\n      0%, 90%, 100% { transform: rotate(-8deg) scale(1); }\n      92%           { transform: rotate(-8deg) scale(1.15); }\n      96%           { transform: rotate(-8deg) scale(0.95); }\n    }\n    @keyframes dddkMpIn {\n      from { opacity: 0; transform: translateY(-4px); }\n      to   { opacity: 1; transform: translateY(0); }\n    }\n\n    /* ── Swim overlay — real spritesheet cycle, on the outline ────\n       The duck sprite sits AT the outline's y-position (not floating\n       above), swims left→right→left at a CONSTANT PIXELS/SEC velocity\n       (JS sets --dddk-swim-duration from element width), and cycles\n       through a 4-frame spritesheet for a real \"kick-swim\" feel via\n       CSS steps(4). A background strip on the container acts as\n       an eraser that visibly breaks the outline where the duck is,\n       reading as \"duck IS the line's break-point\". */\n    [${POPOVER_ATTR}=\"dwell-swim\"] {\n      position: fixed;\n      /* Wider than the sprite; the extra area is used by the eraser\n         strip that covers the outline behind the duck. */\n      width: 56px;\n      height: 38px;\n      pointer-events: none;\n      z-index: var(--dddk-z-bar, 9500);\n      overflow: visible;\n      /* Eraser strip: horizontal white bar centred vertically in the\n         container, fades out at left/right so the outline reappears\n         smoothly. Positioned via background-* so it doesn't need an\n         extra element and always tracks the container. */\n      background:\n        linear-gradient(\n          90deg,\n          transparent 0%,\n          var(--dddk-dwell-swim-eraser, #ffffff) 20%,\n          var(--dddk-dwell-swim-eraser, #ffffff) 80%,\n          transparent 100%\n        );\n      background-repeat: no-repeat;\n      /* The strip is the height of the outline stroke plus a bit; JS\n         reads outline width to size this dynamically. */\n      background-size: 100% var(--dddk-dwell-swim-eraser-height, 7px);\n      background-position: 50% var(--dddk-dwell-swim-eraser-y, 50%);\n      /* Constant velocity is JS-set: --dddk-swim-duration = W_px / 30. */\n      /* ease-in-out per full loop so the duck decelerates naturally\n         at each end and the FLIP feels intentional rather than a\n         hard stop. Linear made the turn read as \"sudden stop then\n         teleport back\". */\n      animation: dddkDwellSwimMove var(--dddk-swim-duration, 8s) ease-in-out infinite;\n      /* JS sets --dddk-swim-range so the animation stops at the right\n         boundary regardless of duck sprite width. */\n    }\n    [${POPOVER_ATTR}=\"dwell-swim-duck\"] {\n      position: absolute;\n      /* Container height is 38px, sprite is 32px — sprite bottom sits\n         6px above container bottom so the duck's water ripple aligns\n         with the outline. Vertical centre of sprite = container centre.\n         Horizontally CENTRED in the shell so the eraser gap is\n         symmetric on head side and tail side (was left-anchored → all\n         the whitespace bunched behind the tail). */\n      top: 3px;\n      left: 50%;\n      margin-left: -20px;\n      width: 40px;\n      height: 32px;\n      /* Spritesheet: 8 frames × 256px wide, at 40px display width each\n         frame is 40px. Total sheet display width = 320px. Doubling\n         from 4 → 8 frames removes the stop-motion staccato feel. */\n      background-image: var(--dddk-swim-cycle-url, none);\n      background-size: 320px 32px;\n      background-repeat: no-repeat;\n      /* Frame cycle: 8 frames at ~12 fps × 2 (ping-pong via alternate)\n         = 1.33s total loop. The LLM-generated frames aren't a perfect\n         circular cycle — frame 8 back to frame 1 was a jarring jump.\n         Ping-pong (0→7→0) uses each endpoint as a natural pause where\n         the ease-in-out timing decelerates, so the transitions land\n         smoothly instead of teleporting. */\n      animation: dddkDwellSwimFrames 0.66s steps(8) infinite alternate;\n      filter: drop-shadow(0 2px 3px rgba(0,60,100,0.18));\n    }\n    @keyframes dddkDwellSwimFrames {\n      from { background-position: 0 0; }\n      to   { background-position: -320px 0; }\n    }\n    @keyframes dddkDwellSwimMove {\n      /* Sprite naturally faces LEFT. scaleX(-1) flips to face right. */\n      0%   { transform: translateX(0) scaleX(-1); }\n      48%  { transform: translateX(var(--dddk-swim-range, 100px)) scaleX(-1); }\n      52%  { transform: translateX(var(--dddk-swim-range, 100px)) scaleX(1); }\n      100% { transform: translateX(0) scaleX(1); }\n    }\n    @media (prefers-reduced-motion: reduce) {\n      [${POPOVER_ATTR}=\"dwell-swim\"] { animation: none; opacity: 0.7; }\n      [${POPOVER_ATTR}=\"dwell-swim-duck\"] { animation: none; }\n    }\n\n    /* ── Chill mascot in the bottom-right corner of the framed target\n       — a side-view duck wearing sunglasses, statically perched. No\n       animation (that's the whole vibe: the swim duck is doing the\n       work, this one is on vacation). JS positions it via inline\n       top/left each rAF tick so it stays glued to the target rect. */\n    [${POPOVER_ATTR}=\"dwell-chill\"] {\n      position: fixed;\n      width: 42px;\n      height: 34px;\n      pointer-events: none;\n      z-index: var(--dddk-z-bar, 9500);\n      background-image: var(--dddk-chill-url, none);\n      background-size: contain;\n      background-repeat: no-repeat;\n      background-position: center;\n      filter: drop-shadow(0 2px 3px rgba(0,60,100,0.18));\n      /* Very slow, near-imperceptible float — reads as breath rather\n         than motion. Add ONE frame per second so it's not a corpse. */\n      animation: dddkDwellChillBreath var(--dddk-dwell-chill-breath-duration, 3.6s) ease-in-out infinite;\n    }\n    @keyframes dddkDwellChillBreath {\n      0%, 100% { transform: translateY(0); }\n      50%      { transform: translateY(-1.5px); }\n    }\n    @media (prefers-reduced-motion: reduce) {\n      [${POPOVER_ATTR}=\"dwell-chill\"] { animation: none; }\n    }\n\n    /* The target frame — applied to the long-pressed element. Dual\n       outline: outer warm-yellow (thick) + inner navy dashed via a\n       box-shadow inset. Reads as \"picked out and framed by the duck\"\n       — the outer ring pulses gently so the frame feels alive rather\n       than static. Fully themeable via these tokens. */\n    [data-dddk-dwell-target] {\n      outline:\n        var(--dddk-dwell-frame-width, 3px)\n        var(--dddk-dwell-frame-style, solid)\n        var(--dddk-dwell-frame-color, var(--dddk-dwell-outer, #ffd93d));\n      outline-offset: var(--dddk-dwell-frame-offset, 7px);\n      border-radius: var(--dddk-dwell-frame-radius, var(--dddk-radius-sm, 6px));\n      transition: outline-color 120ms ease-out;\n      /* No inner navy stroke (was box-shadow inset — read as a second\n         competing ring). No breathe/pulse on outline-offset — the\n         frame stays fixed, only the swimming duck moves. */\n    }\n    @media (prefers-reduced-motion: reduce) {\n      [data-dddk-dwell-target] { animation: none; }\n      [${POPOVER_ATTR}=\"dwell\"] .dwell-head::before { animation: none; }\n    }\n  `);\n}\n","/**\n * Highlight overlay — frame any DOM element with the same outline Dwell\n * uses on long-press selection.\n *\n * Self-contained module: owns `highlightedEl` + `highlightDismissTimer`\n * state. The orchestrator forwards `highlightElement` / `clearHighlight`\n * to a single instance held on the class.\n *\n * Frame style shares the `[data-dddk-dwell-target]` attribute defined\n * in `dwell/styles.ts` so only one element is framed at a time and\n * theming flows through `--dddk-dwell-frame-*` CSS vars.\n */\n\nimport { ensureDwellStyles } from '../triggers/dwell/styles';\n\nexport class HighlightOverlay {\n  private highlightedEl: HTMLElement | null = null;\n  private highlightDismissTimer: ReturnType<typeof setTimeout> | null = null;\n\n  /**\n   * Frame an element with the same outline Dwell uses on long-press.\n   * Replaces any existing highlight (only one frame at a time).\n   *\n   * @returns true if the element was found and framed\n   */\n  highlightElement(\n    target: string | HTMLElement,\n    opts?: { autoDismiss?: number; scroll?: boolean },\n  ): boolean {\n    if (typeof document === 'undefined') return false;\n    this.clearHighlight();\n    ensureDwellStyles();\n    // String input is treated as a CSS selector. The querySelector call\n    // throws SyntaxError on invalid syntax (e.g. a bare numeric agent\n    // index like \"13\") — swallow it instead of letting the pump die.\n    // Callers that have a numeric index from the indexed DOM dump should\n    // resolve via `WebAgent.resolveSelector(...)` first.\n    let el: HTMLElement | null;\n    if (typeof target === 'string') {\n      try {\n        el = document.querySelector<HTMLElement>(target);\n      } catch {\n        return false;\n      }\n    } else {\n      el = target;\n    }\n    if (!el) return false;\n    // Clear any pre-existing frame (Dwell pin, prior highlight) — we own\n    // the attribute now.\n    document\n      .querySelectorAll('[data-dddk-dwell-target]')\n      .forEach((n) => n.removeAttribute('data-dddk-dwell-target'));\n    el.setAttribute('data-dddk-dwell-target', '');\n    this.highlightedEl = el;\n    if (opts?.scroll !== false) {\n      // Position the element's TOP near the upper third of the viewport\n      // (~18% from the top) rather than centering it. Centering pushes\n      // long sections halfway off-screen and crops the title; pinning to\n      // the very top hides any context above (heading / breadcrumb / nav).\n      // 18% leaves room for site chrome + a bit of breathing space.\n      try {\n        const rect = el.getBoundingClientRect();\n        const targetTop = Math.round(window.innerHeight * 0.18);\n        const desiredScrollY = window.scrollY + rect.top - targetTop;\n        window.scrollTo({ top: Math.max(0, desiredScrollY), behavior: 'smooth' });\n      } catch { /* noop */ }\n    }\n    if (opts?.autoDismiss && opts.autoDismiss > 0) {\n      this.highlightDismissTimer = setTimeout(() => this.clearHighlight(), opts.autoDismiss);\n    }\n    return true;\n  }\n\n  /** Remove any active highlight frame. */\n  clearHighlight(): void {\n    if (this.highlightDismissTimer) {\n      clearTimeout(this.highlightDismissTimer);\n      this.highlightDismissTimer = null;\n    }\n    if (this.highlightedEl) {\n      this.highlightedEl.removeAttribute('data-dddk-dwell-target');\n      this.highlightedEl = null;\n    }\n  }\n}\n","/**\n * Per-run intent bookkeeping.\n *\n * A \"run\" is one user query and everything that follows it — narrations,\n * tool calls, confirms, pauses, until the loop ends (final / stopped).\n * We give it an id at start time and buffer every intent emitted while\n * it's active. Hosts call `exportAgentRun()` to get the whole thing\n * (session + intents) as one JSON blob.\n */\n\nimport type { AgentSession } from '../agent/webagent/types';\nimport type { IntentEvent } from '../types';\nimport type { TypedEmitter } from '../event-emitter';\n\nexport class IntentBuffer {\n  private _currentRunId: string | null = null;\n  private _currentRunIntents: IntentEvent[] = [];\n  /**\n   * Active skill id while a skill is running. Set on skill_started and\n   * cleared on skill_finished. Read by `renderLoopClosure` so the\n   * `agent_feedback` IntentEvent can attribute satisfaction back to the\n   * skill that triggered the run — enables per-skill quality breakdown\n   * on the dashboard without after-the-fact time-window heuristics.\n   */\n  currentSkillId: string | null = null;\n\n  get currentRunId(): string | null { return this._currentRunId; }\n  get currentRunIntents(): IntentEvent[] { return this._currentRunIntents; }\n\n  /** Emit + buffer. Routes through the host's TypedEmitter, then appends\n   *  to the active run if any. */\n  emitIntent(emitter: TypedEmitter, event: IntentEvent): void {\n    emitter.emit('intent', event);\n    // Buffer into the current run so `exportAgentRun()` returns the full\n    // sequence of decisions alongside the session turn log. We accept\n    // anything emitted between `beginAgentRun` and the next one — that\n    // includes confirm gates, ask_user answers, pause decisions, etc.\n    if (this._currentRunId) this._currentRunIntents.push(event);\n  }\n\n  beginAgentRun(emitter: TypedEmitter, task: string, sessionId: string): void {\n    this._currentRunId = `run_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;\n    this._currentRunIntents = [];\n    this.emitIntent(emitter, {\n      kind: 'agent_run_started',\n      runId: this._currentRunId,\n      task,\n      sessionId,\n      timestamp: Date.now(),\n    });\n  }\n\n  endAgentRunCompleted(emitter: TypedEmitter, sessionId: string, turnCount: number): void {\n    if (!this._currentRunId) return;\n    this.emitIntent(emitter, {\n      kind: 'agent_run_completed',\n      runId: this._currentRunId,\n      sessionId,\n      turnCount,\n      timestamp: Date.now(),\n    });\n    // Keep runId / intents around until next run starts so an\n    // `exportAgentRun()` call right after the loop ends still works.\n  }\n\n  endAgentRunStopped(\n    emitter: TypedEmitter,\n    sessionId: string,\n    reason: 'close' | 'esc' | 'reject' | 'palette' | 'voice' | 'unknown',\n  ): void {\n    if (!this._currentRunId) return;\n    this.emitIntent(emitter, {\n      kind: 'agent_run_stopped',\n      runId: this._currentRunId,\n      sessionId,\n      reason,\n      timestamp: Date.now(),\n    });\n  }\n\n  /**\n   * Snapshot the current (or most-recent) agent run as a single JSON\n   * blob — session turns + every intent emitted during the run. Useful\n   * for shipping a complete query record to a dashboard / DB after the\n   * loop ends. Returns `null` if no session is provided.\n   */\n  exportAgentRun(session: AgentSession | null | undefined): {\n    runId: string;\n    sessionId: string;\n    session: AgentSession;\n    intents: IntentEvent[];\n    exportedAt: number;\n  } | null {\n    if (!session) return null;\n    return {\n      runId: this._currentRunId ?? '',\n      sessionId: session.id,\n      session: JSON.parse(JSON.stringify(session)) as AgentSession,\n      intents: this._currentRunIntents.slice(),\n      exportedAt: Date.now(),\n    };\n  }\n}\n","/**\n * DotDotDuck — main orchestrator.\n * Wires gestures + palette + dwell + skills + subtitle UI together.\n *\n * Webagent integration is OPTIONAL — pass a factory and it'll be used for skill\n * agent runs; otherwise dddk works standalone for palette + skills + voice.\n *\n * See ../docs/00-overview.md for the full design.\n *\n * This file is the shell — constructor / mount / destroy / events /\n * runtime toggles / public getters. The heavy lifting lives in sibling\n * modules under `./orchestrator/`:\n *\n *   - agent-lifecycle.ts  — build / pump / stop / route the WebAgent loop\n *   - skill-dispatcher.ts — runSkill, ScriptSkill, surface tools, palette items\n *   - highlight.ts        — frame any DOM element (shared with Dwell)\n *   - intent-buffer.ts    — per-run IntentEvent buffer + exportAgentRun\n *   - helpers.ts          — pure functions (blobToDataUrl, defaultStorage, searchPageText)\n *   - types.ts            — DotDotDuckConfig\n */\n\nimport {\n  WebAgent,\n  type SelectionContext,\n} from '../agent';\n\nimport { GestureManager, type GestureCallbacks } from '../triggers/space-gesture';\nimport { CommandPalette } from '../triggers/command-palette';\nimport { Spotter } from '../triggers/spotter';\nimport { SkillRegistry } from '../skills/registry';\nimport { promptRegistry } from '../prompts/registry';\nimport { registerBuiltinPrompts } from '../prompts/defaults';\n\n// Register SDK-shipped prompt defaults so `dddk.prompts` is populated\n// as soon as any DotDotDuck instance is constructed, without waiting\n// for a subsystem-side-effect import to fire.\nregisterBuiltinPrompts();\nimport { PanelRuntime } from '../triggers/panel-runtime';\nimport { Placements } from '../ui/placement';\nimport { sdkString } from '../utils/sdk-i18n';\nimport { PinnedPanelRegistry } from '../modules/pinned-panel';\nimport { ToolsRegistry } from '../tools-registry';\nimport { PreferenceStore } from '../skills/preferences';\nimport { Subtitle } from '../ui/subtitle';\nimport { TypedEmitter } from '../event-emitter';\nimport type {\n  Locale,\n  StorageAdapter,\n  DddkEventName,\n  DddkEventHandler,\n  IntentEvent,\n} from '../types';\n\nimport type { DotDotDuckConfig } from './types';\nimport { AgentLifecycle } from './agent-lifecycle';\nimport { SessionsRegistry } from './sessions-registry';\nimport { AgentsRegistry } from './agents-registry';\nimport { SkillDispatcher } from './skill-dispatcher';\nimport { HighlightOverlay } from './highlight';\nimport { IntentBuffer } from './intent-buffer';\nimport { Memory } from '../agent/memory';\nimport { defaultStorage, searchPageText } from './helpers';\n\nexport type { DotDotDuckConfig } from './types';\nexport { searchPageText, blobToDataUrl, defaultStorage } from './helpers';\nexport { SessionsRegistry } from './sessions-registry';\nexport type { SessionRegistration } from './sessions-registry';\nexport { AgentsRegistry } from './agents-registry';\nexport type { RegisterableAgent } from './agents-registry';\n\nexport class DotDotDuck {\n  readonly skills: SkillRegistry;\n  /** @internal */\n  _panelRuntime: PanelRuntime | null = null;\n  readonly subtitle: Subtitle;\n  readonly palette: CommandPalette;\n  readonly spotter: Spotter;\n  /**\n   * Mount custom DOM into one of the canonical screen slots\n   * (`subtitle` / `indicator` / `palette` / `dock` / `modal` / `banner`\n   * / `fab` / `toast`). The slot's position, z-index, and max-width are\n   * already defined by the shared placement stylesheet — hosts only\n   * style the content, not the chrome.\n   *\n   *   const h = dddk.placement.mount('banner', '<div>Maintenance at 10pm</div>');\n   *   // ... later:\n   *   h.unmount();\n   */\n  readonly placement = new Placements();\n\n  /**\n   * Pinned-panel registry — small persistent cards anchored to one of\n   * the four screen corners. Use for onboarding checklists, \"powered by\"\n   * widgets, multi-step forms.\n   *\n   *   const h = dddk.panel.create({\n   *     id: 'getting-started',\n   *     title: 'The Basics',\n   *     items: [\n   *       { kind: 'task', id: 'a', label: 'Create your first project' },\n   *       { kind: 'task', id: 'b', label: 'Invite your team' },\n   *     ],\n   *     onSubmit: (data) => analytics.track('onboarding.done', data.values),\n   *   });\n   *   h.complete('a');\n   *   h.unmount();\n   */\n  readonly panel = new PinnedPanelRegistry();\n\n  /**\n   * Tool registry — host registers capabilities (QA / search / recommend /\n   * custom domain actions) and the webagent picks them up automatically.\n   * The LLM sees each tool's name + description + JSON-schema parameters,\n   * decides when to call them, and the result feeds back into the loop.\n   *\n   *   dddk.tools.register({ name, description, parameters, handler });\n   *   dddk.tools.registerQA({ items: customerFAQ });\n   *   dddk.tools.unregister('qa_lookup');\n   *   dddk.tools.list();\n   *\n   * Tools registered BEFORE the webagent is first invoked land in the\n   * initial customActions set. Tools registered AFTER are injected into\n   * the live agent via `agent.registerAction()`, so order doesn't matter.\n   * Details + the QA convenience helper live in `tools-registry.ts`.\n   */\n  readonly tools = new ToolsRegistry();\n\n  /**\n   * Prompt registry — one place to see, override, and localise every\n   * LLM system prompt the SDK ships (WebAgent narrator, planner,\n   * InlineAgent, translate, voice-cleanup, Dwell classifier, etc.).\n   *\n   *   dddk.prompts.list();                                              // enumerate ids\n   *   dddk.prompts.override('inline-edit.system', 'ja', () => `…`);     // localise\n   *   dddk.prompts.append('webagent-narrator.system', () => 'Always cite sources.');\n   *\n   * Uses the process-wide singleton so subsystems that don't hold a\n   * DotDotDuck reference (module-level module inits) can still register\n   * defaults. Hosts are expected to reach for this same registry via\n   * `dddk.prompts` for the more discoverable API.\n   */\n  readonly prompts = promptRegistry;\n\n  // ─── internal state (consumed by sibling modules under ./orchestrator/) ──\n  // All fields below carry a leading `_` and the `@internal` JSDoc tag —\n  // they're public-by-TS so the helper classes can read/write them, but\n  // host code should never touch them. The public API surface flows\n  // through the `runSkill` / `startAgent` / etc. methods below.\n\n  /** @internal */ _config: DotDotDuckConfig;\n  /** @internal */ _gestures?: GestureManager;\n  /** @internal */ _emitter = new TypedEmitter();\n  /** @internal */ _storage: StorageAdapter;\n  /** @internal */ _prefs: PreferenceStore;\n  /** @internal */ _pendingPrefs: { skillId: string; resolve: () => void; reject: () => void } | null = null;\n  /**\n   * Ad-hoc Surface awaiting host submission. Lifecycle:\n   *   1. ScriptSkill step calls `tools.surface(...)` → emits `surface` event\n   *   2. Host renders + collects user input\n   *   3. Host calls `dddk.submitSurface(data)` or `dddk.cancelSurface()`\n   *   4. The promise returned to the skill resolves with data (or null)\n   * @internal\n   */\n  _pendingSurface: { resolve: (data: Record<string, unknown> | null) => void } | null = null;\n  /** @internal */ _agentInstance: WebAgent | null = null;\n  /**\n   * Named session registry — `dddk.sessions`. Hosts use this to share\n   * a single `AgentSession` across multiple agents (one persona per\n   * route, etc.) so cross-page conversation history + memory carry\n   * over even when the active agent changes. v0.2.0.\n   */\n  readonly sessions: SessionsRegistry = new SessionsRegistry();\n  /**\n   * Named agent registry — `dddk.agents`. Hosts register multiple\n   * `WebAgent` instances by name + designate which one is \"active\"\n   * (the one palette / voice / dwell routes to). Singleton\n   * `dddk.getAgent()` keeps working — it returns the active agent\n   * when the registry is in use, otherwise the lazy-built one.\n   * v0.2.0.\n   */\n  readonly agents: AgentsRegistry = new AgentsRegistry();\n  /** @internal */ _voiceEnabled: boolean;\n  /** @internal */ _agentEnabled: boolean;\n  /** @internal */ _currentSelection: SelectionContext | null = null;\n\n  /** @internal */ readonly _highlight = new HighlightOverlay();\n  /** @internal */ readonly _intentBuffer = new IntentBuffer();\n  /** @internal */ readonly _lifecycle: AgentLifecycle;\n  /** @internal */ readonly _dispatcher: SkillDispatcher;\n  readonly memory: Memory | null;\n\n  constructor(config: DotDotDuckConfig = {}) {\n    this._config = config;\n    this.memory = config.memory ? new Memory(config.memory) : null;\n    this.skills = new SkillRegistry(config.skills);\n    this.subtitle = new Subtitle({ locale: config.locale === 'en' ? 'en' : 'zh-TW' });\n    // Indicator label overrides — host can pass a string OR a\n    // { [locale]: string } map. We resolve to the active locale, falling\n    // back to English if the locale isn't in the map.\n    const resolveIndicator = (\n      v: string | Record<string, string> | undefined,\n    ): string | null => {\n      if (!v) return null;\n      if (typeof v === 'string') return v;\n      return v[String(config.locale ?? 'en')] ?? v.en ?? null;\n    };\n    const running = resolveIndicator(config.indicators?.running);\n    if (running) this.subtitle.setRunningLabel(running);\n    // Helper classes — created AFTER all fields they touch are initialised.\n    this._lifecycle = new AgentLifecycle(this);\n    this._dispatcher = new SkillDispatcher(this);\n    // Wire the × close button on the subtitle bar to:\n    //   1. stop a running agent (with stopped-feedback subtitle)\n    //   2. fire gesture_escape so a running ScriptSkill cancels too\n    //      (its `waitForAcceptOrEscape` listens on this event; without\n    //      this hook a click-outside during a script just hid the\n    //      subtitle and the NEXT step's subtitle would silently appear)\n    this.subtitle.setCloseHandler(() => {\n      this._lifecycle.handleUserStopAgent('close');\n      this._emitter.emit('gesture_escape', undefined);\n    });\n    this._storage = config.storage ?? defaultStorage();\n    this._prefs = new PreferenceStore(this._storage, this._config.locale);\n    this._voiceEnabled = config.voice?.enabled ?? true;\n    this._agentEnabled = config.agent?.enabled ?? true;\n\n    this.palette = new CommandPalette({\n      initialItems: this._dispatcher.buildPaletteItems(),\n      locale: config.locale,\n      placeholder: this._t('palette.placeholder', sdkString(config.locale, 'palette.placeholder')),\n      searchPage: (q) => searchPageText(q),\n      // Camera button is OFF unless the host passes a `camera` config — the SDK\n      // ships zero defaults. Hosts who want the screenshot button wire it up\n      // explicitly via DotDotDuckConfig.camera.\n      camera: this._config.camera === false ? undefined : this._config.camera,\n      submitButton: this._config.submitButton,\n      categories: this._config.paletteCategories,\n      allCategoriesLabel: this._config.paletteAllCategoriesLabel,\n      onActivate: (info) => {\n        this.emitIntent({\n          kind: 'palette_activated',\n          itemId: info.itemId,\n          arg: info.arg,\n          selectionText: info.selectionText,\n          attachmentsCount: info.attachmentsCount,\n          timestamp: Date.now(),\n        });\n      },\n    });\n\n    this.spotter = new Spotter({\n      // Spotter is wired but the auto-ring (the pink frame that appears around\n      // whatever element you hover for 200ms) is OFF by default. It was a UX\n      // misfire — text-rich pages produce a frame around every paragraph the\n      // user pauses on. Hosts that want the ring (e.g. for a \"pick an\n      // element\" picker UI) can call `dddk.spotter.start()` themselves.\n      ignoreSelector: '[data-dddk-ui]',\n      enableRing: false,\n      onLock: ({ selector }) => {\n        this._emitter.emit('pointer_lock', {\n          selector,\n          element: document.querySelector<HTMLElement>(selector)!,\n        });\n      },\n      onLassoComplete: (info) => this._emitter.emit('pointer_lasso', info),\n      onRingShow: ({ selector }) => this._emitter.emit('pointer_ring_show', { selector }),\n      onRingHide: () => this._emitter.emit('pointer_ring_hide', undefined),\n    });\n  }\n\n  /**\n   * Update the active locale at runtime. Used by hosts that flip\n   * `en` / `zh-TW` via an in-page toggle (no full reload). Updates the\n   * orchestrator's own copy plus owned components (`subtitle`). Sibling\n   * modules the host owns (`InlineAgent`, `VoiceModule`, …) need their\n   * own `setLocale` call from the host.\n   */\n  setLocale(locale: Locale): void {\n    this._config.locale = locale;\n    this.subtitle.setLocale(locale);\n    try { this.palette.setLocale(locale); } catch { /* palette torn down */ }\n    try { this._agentInstance?.setLocale(locale); } catch { /* agent not built */ }\n  }\n\n  // ─── lifecycle ──────────────────────────────────────────────────\n\n  mount(): void {\n    const callbacks: GestureCallbacks = {\n      onAccept: () => {\n        this._emitter.emit('gesture_accept', undefined);\n        // The subtitle bar accepts callbacks (onAccept) from callers\n        // (Proactive prompt, agent ask_user, etc.) but its DOM only\n        // wires button clicks. Bridge the gesture here so a space tap\n        // also fires the same callback. Returns false when no callback\n        // is registered — we don't suppress the gesture in that case.\n        this.subtitle.invokeAccept();\n        this.emitIntent({ kind: 'agent_answered', answer: 'accept', via: 'gesture', timestamp: Date.now() });\n      },\n      onReject: () => {\n        this._emitter.emit('gesture_reject', undefined);\n        const hadReject = this.subtitle.invokeReject();\n        // If the subtitle had its own reject (e.g. confirm dialog: \"no\"),\n        // that handler already fired and the bar is gone. If not, this\n        // is a \"user dismissed the agent\" double-tap — stop the loop\n        // with a polished feedback line.\n        if (!hadReject) {\n          if (this._agentInstance?.isRunning()) {\n            this._lifecycle.handleUserStopAgent('reject');\n          } else {\n            this.subtitle.hide();\n          }\n        }\n        this.emitIntent({ kind: 'agent_answered', answer: 'reject', via: 'gesture', timestamp: Date.now() });\n      },\n      onAcceptLine: () => {\n        this._emitter.emit('gesture_accept', undefined);\n        this.subtitle.invokeAccept();\n      },\n      onVoiceStart: () => {\n        if (!this._voiceEnabled) return;\n        // Long-press space while agent is running = \"I have a new\n        // prompt to say\". Stop the current agent loop cleanly first,\n        // then let voice take over.\n        this._lifecycle.handleUserStopAgent('voice');\n        this._emitter.emit('voice_start', undefined);\n      },\n      onVoiceEnd: () => {\n        if (!this._voiceEnabled) return;\n        this._emitter.emit('voice_end', { text: '' });\n      },\n      onPaletteToggle: (selection) => {\n        this._currentSelection = selection ? this._captureSelection(selection) : null;\n        // Opening the palette signals \"I want to type a new prompt\" —\n        // stop the agent so the next message is a clean start, not a\n        // race with the in-flight loop.\n        this._lifecycle.handleUserStopAgent('palette');\n        this._emitter.emit('palette_open', { selection });\n        this.palette.toggle(selection);\n      },\n      onEscape: () => {\n        this._emitter.emit('gesture_escape', undefined);\n        // PanelRuntime owns Esc when a panel skill is open — esc\n        // means \"go back one step / close this panel\", NOT \"stop\n        // the agent\" / \"close the palette\". Bail before any of the\n        // cross-cutting stop handlers fire.\n        if (this._panelRuntime?.isOpen()) return;\n        // Palette owns Esc when it's in result-mode or a sub-menu —\n        // esc means \"back one level\" there, not \"close the whole\n        // palette\". Let the palette's own keydown handler take care\n        // of it. (Palette's plain list mode still falls through to\n        // the close() call below.)\n        if (this.palette.hasInternalEsc()) return;\n        this._lifecycle.handleUserStopAgent('esc');\n        this.palette.close();\n        this.spotter.unlock();\n      },\n    };\n\n    this._gestures = new GestureManager({\n      callbacks,\n      gestureKey: this._config.gestureKey,\n      holdThresholdMs: this._config.holdThresholdMs,\n      doubleTapWindowMs: this._config.doubleTapWindowMs,\n      shouldIntercept: () => this.subtitle.isVisible() || this.palette.isOpen(),\n    });\n    this._gestures.start();\n    // Keep GestureManager.hasSuggestion in sync with subtitle visibility —\n    // single space tap → accept ONLY fires when hasSuggestion is true.\n    // Without this hook a proactive prompt would render but space taps\n    // would be no-ops; double-tap reject still works because it doesn't\n    // gate on hasSuggestion.\n    const gestures = this._gestures;\n    this.subtitle.setVisibilityListener((visible) => {\n      gestures.hasSuggestion = visible;\n    });\n\n    // Touch-tap relay: the subtitle bar's internal touch handler emits\n    // DOM events instead of calling invokeAccept/Reject directly, so\n    // we can run the SAME full pipeline desktop Space goes through —\n    // emit `gesture_accept` for script skills, log intent, etc.\n    const onBarTapAccept = (): void => this.triggerAccept();\n    const onBarTapReject = (): void => this.triggerReject();\n    document.addEventListener('dddk:bar-tap-accept', onBarTapAccept);\n    document.addEventListener('dddk:bar-tap-reject', onBarTapReject);\n\n    // NOTE: Spotter is NOT auto-started. Its hover-ring fires on plain\n    // mousemove and would shadow every paragraph on a text-rich page. Hosts\n    // that need it call `dddk.spotter.start()` themselves.\n  }\n\n  destroy(): void {\n    this._gestures?.destroy();\n    this.spotter.destroy();\n    this.palette.close();\n    this.subtitle.hide();\n    this.subtitle.hideIndicator();\n    this._agentInstance?.destroy();\n    this._emitter.clear();\n  }\n\n  // ─── events ─────────────────────────────────────────────────────\n\n  on<E extends DddkEventName>(event: E, handler: DddkEventHandler<E>): void {\n    this._emitter.on(event, handler);\n  }\n\n  off<E extends DddkEventName>(event: E, handler: DddkEventHandler<E>): void {\n    this._emitter.off(event, handler);\n  }\n\n  // ─── skill dispatch ─────────────────────────────────────────────\n\n  async runSkill(idOrCommand: string, vars: Record<string, string> = {}): Promise<void> {\n    return this._dispatcher.runSkill(idOrCommand, vars);\n  }\n\n  /** Emit a structured intent event. Public so other modules can push too. */\n  emitIntent(event: IntentEvent): void {\n    this._intentBuffer.emitIntent(this._emitter, event);\n  }\n\n  /**\n   *\n   * Public host-facing `track(name, props?)` API. Mirrors the standard\n   * product-analytics surface — engineers recognise this from existing\n   * tooling. Routes through the same intent stream as the SDK's typed\n   * events; downstream sinks see one canonical pipe.\n   *\n   * `name` should be snake_case past-tense (\"order_completed\",\n   * \"checkout_started\") — describes what happened, not what to do.\n   *\n   * @example\n   * ```ts\n   * dddk.track('order_completed', { order_id, value: 49.99, items: 3 });\n   * dddk.track('survey_dismissed');\n   * ```\n   */\n  track(name: string, props?: Record<string, unknown>): void {\n    if (!name || typeof name !== 'string') return;\n    this.emitIntent({\n      kind: 'custom_track',\n      name,\n      props: props ?? {},\n      timestamp: Date.now(),\n    });\n  }\n\n  // ─── highlight (frame any DOM element) ──────────────────────────\n\n  /**\n   * Frame an element with the same outline Dwell uses on long-press.\n   * Replaces any existing highlight (only one frame at a time).\n   *\n   * @returns true if the element was found and framed\n   */\n  highlightElement(\n    target: string | HTMLElement,\n    opts?: { autoDismiss?: number; scroll?: boolean },\n  ): boolean {\n    return this._highlight.highlightElement(target, opts);\n  }\n\n  /** Remove any active highlight frame. */\n  clearHighlight(): void {\n    this._highlight.clearHighlight();\n  }\n\n  /**\n   * Lazy-initialize the PanelRuntime. The runtime is a separate DOM overlay\n   * from the regular CommandPalette — it handles `PanelSkill` execution\n   * (top input + bottom panel + navigation stack).\n   * @internal\n   */\n  _ensurePanelRuntime(): PanelRuntime {\n    if (!this._panelRuntime) {\n      this._panelRuntime = new PanelRuntime({\n        host: {\n          llm: this._config.llm\n            ? async (prompt: string) => {\n                const llm = this._config.llm;\n                if (!llm) return '';\n                const r = await (llm as { complete?: (p: string) => Promise<string> }).complete?.(prompt);\n                return r ?? '';\n              }\n            : undefined,\n          navigate: (path: string) => this._navigate(path),\n          renderPiece: this._config.panelRenderPiece,\n        },\n      });\n    }\n    return this._panelRuntime;\n  }\n\n  /** Check whether a PanelSkill is currently active. */\n  isPanelOpen(): boolean {\n    return this._panelRuntime?.isOpen() ?? false;\n  }\n\n  /**\n   * Programmatically fire `voice_start` — same event the long-press gesture\n   * emits. Mobile FAB long-press, custom triggers (e.g. host's own header\n   * button bound via `MobileTrigger.bindTrigger`), or any other entry point\n   * can call this to enter voice mode without simulating keyboard events.\n   */\n  triggerVoiceStart(): void {\n    if (!this._voiceEnabled) return;\n    this._emitter.emit('voice_start', undefined);\n  }\n\n  /** Fire `voice_end` to match a prior `triggerVoiceStart`. */\n  triggerVoiceEnd(): void {\n    if (!this._voiceEnabled) return;\n    this._emitter.emit('voice_end', { text: '' });\n  }\n\n  /** Programmatically close any active panel skill (Esc equivalent for host). */\n  async closePanel(): Promise<void> {\n    if (this._panelRuntime) await this._panelRuntime.close();\n  }\n\n  /**\n   * Kick the webagent. `selection` defaults to whatever was captured at the\n   * last palette open — pass `{ selection: null }` to force no selection\n   * context, or pass an explicit `SelectionContext` to override.\n   */\n  startAgent(task: string, options: { selection?: SelectionContext | null } = {}): void {\n    this._lifecycle.startAgent(task, options);\n  }\n\n  /**\n   * Snapshot the current (or most-recent) agent run as a single JSON\n   * blob — session turns + every intent emitted during the run. Useful\n   * for shipping a complete query record to a dashboard / DB after the\n   * loop ends. Returns `null` if no agent has ever run in this session.\n   */\n  exportAgentRun(): ReturnType<IntentBuffer['exportAgentRun']> {\n    return this._intentBuffer.exportAgentRun(this._agentInstance?.getSession());\n  }\n\n  /** Resume a saved session — used by the host's onMount after a full\n   *  page reload. If there's no saved session or it's in a terminal\n   *  state, no-ops. Otherwise pumps the stream into the dddk UI as if\n   *  the loop had never been interrupted. */\n  resumeAgent(): void {\n    this._lifecycle.resumeAgent();\n  }\n\n  /** Tell the agent that its continuity window should close now (used\n   *  for `sessionScope: 'palette'` hosts when the palette closes). */\n  endAgentContinuity(): void {\n    this._agentInstance?.endContinuity();\n  }\n\n  /** Wipe any saved agent session — the next `runStream()` starts\n   *  fresh. Hosts call this after a full page reload to drop an\n   *  abandoned conversation from the previous load. */\n  clearAgentSession(): void {\n    this._agentInstance?.clearSession();\n  }\n\n  /** Stop a running agent and clear its on-screen UI. Safe to call\n   *  when the agent is idle (no-ops). Use this when the host wants to\n   *  cancel mid-task — e.g. the user clicked an in-app link / sidebar\n   *  entry, signalling they're moving on regardless of where the\n   *  agent thinks it is. */\n  stopAgent(): void {\n    this._lifecycle.handleUserStopAgent('close');\n  }\n\n  /**\n   * Fire the same \"accept\" gesture that single-tap Space fires on\n   * desktop — emits `gesture_accept`, advances script skills waiting\n   * on it, advances streaming pause hints, accepts confirm dialogs,\n   * etc. Use this from a mobile FAB tap or any host-built \"next\"\n   * button so touch users get the full Space-equivalent pipeline,\n   * not just `subtitle.invokeAccept()` (which alone misses script\n   * skills + intent analytics).\n   */\n  triggerAccept(): void {\n    this._lifecycle.triggerAccept();\n  }\n\n  /**\n   * Fire the same \"reject\" gesture that double-tap Space fires on\n   * desktop — emits `gesture_reject`, exits script skills, rejects\n   * confirms, or stops an in-flight agent. Use this from a mobile\n   * double-tap on the FAB / subtitle bar.\n   */\n  triggerReject(): void {\n    this._lifecycle.triggerReject();\n  }\n\n  /** Runtime toggle for voice (hold-space STT gesture). */\n  setVoiceEnabled(enabled: boolean): void {\n    this._voiceEnabled = enabled;\n  }\n\n  isVoiceEnabled(): boolean {\n    return this._voiceEnabled;\n  }\n\n  /**\n   * Runtime toggle for the DOM-grounded agent loop. When `false`,\n   * `startAgent()` no-ops with a subtitle hint, palette plain-text Enter\n   * does NOT fire the agent, and any in-flight run stops cleanly. Other\n   * subsystems that use the LLM router (inline AI, voice cleanup, …)\n   * keep working.\n   */\n  setAgentEnabled(enabled: boolean): void {\n    this._agentEnabled = enabled;\n    if (!enabled && this._agentInstance?.isRunning()) {\n      this._agentInstance.stop();\n    }\n  }\n\n  isAgentEnabled(): boolean {\n    return this._agentEnabled;\n  }\n\n  /**\n   * Active WebAgent. With multi-instance wiring (v0.2.0),\n   * this returns whichever agent the host put in `dddk.agents` and\n   * called `setActive(name)` on; falls back to the lazy-built\n   * singleton from `startAgent` for hosts that haven't adopted the\n   * registry. `null` when no agent is configured.\n   */\n  getAgent(): WebAgent | null {\n    return this.agents.getActive() ?? this._agentInstance;\n  }\n\n  /** Forward a user response to the agent (for ask_user / surface form submits). */\n  respondToAgent(answer: string | Record<string, unknown>): void {\n    this._agentInstance?.respond(answer);\n  }\n\n  /**\n   * Called by host after the user submits a preferences setup surface.\n   * Persists the values and resumes the skill that triggered it.\n   */\n  submitPreferences(values: Record<string, unknown>): void {\n    if (!this._pendingPrefs) return;\n    this._prefs.write(this._pendingPrefs.skillId, values);\n    this._pendingPrefs.resolve();\n  }\n\n  cancelPreferences(): void {\n    this._pendingPrefs?.reject();\n  }\n\n  /**\n   * Show a Surface and await the host's submission. Used by skill tools and\n   * any host code that wants the same \"emit → user fills → resolve\" pattern.\n   */\n  showSurfaceAndAwait(\n    surface: unknown,\n    placement: import('../skills/types').SurfacePlacement = 'modal',\n  ): Promise<Record<string, unknown> | null> {\n    return this._dispatcher.showSurfaceAndAwait(surface, placement);\n  }\n\n  /**\n   * Host calls this when the user submits the active Surface form. Routes\n   * to whichever subsystem opened the surface:\n   *   - If a ScriptSkill called `tools.surface(...)` → resolves that promise\n   *   - If webagent was awaiting a host interaction → resumes the agent loop\n   * (Both can be pending at once in theory — we resolve both for safety.)\n   */\n  submitSurface(data: Record<string, unknown>): void {\n    this._dispatcher.submitSurface(data);\n  }\n\n  /** Host calls this when the user cancels the Surface (Esc / backdrop click). */\n  cancelSurface(): void {\n    this._dispatcher.cancelSurface();\n  }\n\n  // ─── internal helpers consumed by sibling modules ───────────────\n\n  /** @internal */\n  _navigate(path: string): void {\n    if (this._config.onNavigate) this._config.onNavigate(path);\n    else if (typeof location !== 'undefined') location.assign(path);\n  }\n\n  /**\n   * Capture rich selection context from the current Window.Selection plus\n   * spotter's lock state. Best-effort — missing bits stay undefined.\n   * @internal\n   */\n  _captureSelection(text: string): SelectionContext {\n    const ctx: SelectionContext = { text };\n    if (typeof window === 'undefined') return ctx;\n    const sel = window.getSelection?.();\n    if (sel && sel.rangeCount > 0) {\n      const range = sel.getRangeAt(0);\n      const rect = range.getBoundingClientRect?.();\n      if (rect && (rect.width || rect.height)) {\n        ctx.bbox = { x: rect.x, y: rect.y, width: rect.width, height: rect.height };\n      }\n    }\n    return ctx;\n  }\n\n  /** @internal */\n  _t(key: string, fallback: string): string {\n    const dict = this._config.i18n?.[this._config.locale ?? 'en'];\n    return dict?.[key] ?? fallback;\n  }\n\n  /** @internal — used by AgentLifecycle.buildAgent to collect palette tools. */\n  _collectPaletteTools(): NonNullable<import('../agent').WebAgentConfig['customActions']> {\n    return this._lifecycle.collectPaletteTools();\n  }\n}\n","/**\r\n * AI evals — regression tests for agent prompts.\r\n *\r\n * When the host iterates a skill's PromptSkill or agent instructions it's\r\n * easy to break previously-working interactions. Evals freeze expected\r\n * behaviour so you catch regressions before users do. Mocks both the LLM\r\n * and host APIs; host wires the runner into their own CI.\r\n *\r\n * Usage:\r\n *   import { defineEval, runEvals, MockLLM } from '@perhapxin/dddk';\r\n *\r\n *   const evals = [\r\n *     defineEval({\r\n *       name: 'translate handles empty input',\r\n *       skill: translateSkill,\r\n *       userInput: '/translate',\r\n *       assertions: [{ kind: 'callsTool', tool: 'show_subtitle' }],\r\n *     }),\r\n *   ];\r\n *\r\n *   const report = await runEvals(evals, { llm: new MockLLM({ responses: [...] }) });\r\n *   if (report.failures > 0) process.exit(1);\r\n */\r\n\r\nimport type { Skill, PromptSkill } from './types';\r\n\r\nexport type EvalAssertion =\r\n  | { kind: 'includes'; substring: string }\r\n  | { kind: 'matches'; pattern: RegExp }\r\n  | { kind: 'callsTool'; tool: string }\r\n  | { kind: 'doesNotCallTool'; tool: string }\r\n  | { kind: 'meetsCriteria'; description: string; check: (trace: EvalTrace) => boolean | Promise<boolean> };\r\n\r\nexport interface EvalSpec {\r\n  name: string;\r\n  skill: Skill;\r\n  /** User input as typed in palette (e.g. '/translate en' or 'ask: hi') */\r\n  userInput: string;\r\n  /** Args / variables forwarded to PromptSkill / context. */\r\n  vars?: Record<string, string>;\r\n  /** Assertions — eval passes if ALL pass. */\r\n  assertions: EvalAssertion[];\r\n  /** Optional skip with reason. */\r\n  skip?: string;\r\n}\r\n\r\nexport function defineEval(spec: EvalSpec): EvalSpec {\r\n  return spec;\r\n}\r\n\r\n// ─── Eval trace (what the agent actually did during the run) ──────\r\n\r\nexport interface EvalTrace {\r\n  /** Final LLM-generated text response (concatenated assistant content). */\r\n  text: string;\r\n  /** Tool calls emitted by the LLM. */\r\n  toolCalls: Array<{ tool: string; args: Record<string, unknown> }>;\r\n  /** Subtitle messages shown. */\r\n  subtitles: string[];\r\n  /** Surfaces emitted by surface-skills (PieceSurface objects). */\r\n  surfaces: unknown[];\r\n  /** Errors thrown. */\r\n  errors: string[];\r\n  /** Raw LLM provider invocations (for debugging). */\r\n  llmCalls: number;\r\n}\r\n\r\n// ─── MockLLM — deterministic responses for testing ────────────────\r\n\r\nimport type { LLMProvider, CompleteOptions, CompleteResult, ToolCall } from '../agent/llm/types';\r\nimport { genId } from '../utils/id';\r\n\r\nexport interface MockLLMOptions {\r\n  /**\r\n   * Either:\r\n   *  - array of responses (returned in order, last one repeated)\r\n   *  - function called per request to compute response\r\n   */\r\n  responses:\r\n    | Array<Partial<CompleteResult> | string>\r\n    | ((opts: CompleteOptions, callIndex: number) => Partial<CompleteResult> | string);\r\n}\r\n\r\nexport class MockLLM implements LLMProvider {\r\n  readonly name = 'mock';\r\n  private cfg: MockLLMOptions;\r\n  private callCount = 0;\r\n\r\n  constructor(cfg: MockLLMOptions) {\r\n    this.cfg = cfg;\r\n  }\r\n\r\n  async complete(opts: CompleteOptions): Promise<CompleteResult> {\r\n    const idx = this.callCount++;\r\n    let resp: Partial<CompleteResult> | string;\r\n    if (typeof this.cfg.responses === 'function') {\r\n      resp = this.cfg.responses(opts, idx);\r\n    } else {\r\n      const arr = this.cfg.responses;\r\n      resp = arr[Math.min(idx, arr.length - 1)] ?? '';\r\n    }\r\n    if (typeof resp === 'string') {\r\n      return { content: resp, finishReason: 'stop' };\r\n    }\r\n    return {\r\n      content: resp.content ?? '',\r\n      toolCalls: resp.toolCalls,\r\n      usage: resp.usage,\r\n      finishReason: resp.finishReason ?? 'stop',\r\n    };\r\n  }\r\n}\r\n\r\n/** Convenience: build a CompleteResult that emits a single tool call. */\r\nexport function mockToolCall(tool: string, args: Record<string, unknown> = {}): Partial<CompleteResult> {\r\n  const toolCall: ToolCall = {\r\n    id: genId('mock'),\r\n    name: tool,\r\n    arguments: args,\r\n  };\r\n  return { content: '', toolCalls: [toolCall], finishReason: 'tool_calls' };\r\n}\r\n\r\n// ─── Runner ───────────────────────────────────────────────────────\r\n\r\nexport interface RunEvalsOptions {\r\n  llm: LLMProvider;\r\n  /** Host can wire its own tool mocks (palette commands etc.). Optional. */\r\n  toolMocks?: Record<string, (args: unknown) => unknown>;\r\n  /** Print to console as evals run. Default true. */\r\n  verbose?: boolean;\r\n}\r\n\r\nexport interface EvalReport {\r\n  total: number;\r\n  passed: number;\r\n  failed: number;\r\n  skipped: number;\r\n  failures: number;  // alias for failed (CI ergonomics)\r\n  results: EvalResult[];\r\n}\r\n\r\nexport interface EvalResult {\r\n  name: string;\r\n  skipped: boolean;\r\n  passed: boolean;\r\n  failures: string[];\r\n  trace?: EvalTrace;\r\n  durationMs: number;\r\n}\r\n\r\nexport async function runEvals(\r\n  evals: EvalSpec[],\r\n  opts: RunEvalsOptions\r\n): Promise<EvalReport> {\r\n  const results: EvalResult[] = [];\r\n  let passed = 0;\r\n  let failed = 0;\r\n  let skipped = 0;\r\n\r\n  for (const spec of evals) {\r\n    if (opts.verbose) console.log(`▶ ${spec.name}`);\r\n\r\n    if (spec.skip) {\r\n      if (opts.verbose) console.log(`  ⊘ skipped: ${spec.skip}`);\r\n      results.push({ name: spec.name, skipped: true, passed: false, failures: [], durationMs: 0 });\r\n      skipped++;\r\n      continue;\r\n    }\r\n\r\n    const start = Date.now();\r\n    const trace: EvalTrace = {\r\n      text: '',\r\n      toolCalls: [],\r\n      subtitles: [],\r\n      surfaces: [],\r\n      errors: [],\r\n      llmCalls: 0,\r\n    };\r\n\r\n    // Wrap the LLM to capture trace\r\n    const trackedLLM: LLMProvider = {\r\n      name: opts.llm.name,\r\n      complete: async (o) => {\r\n        trace.llmCalls++;\r\n        const r = await opts.llm.complete(o);\r\n        if (r.content) trace.text += r.content;\r\n        if (r.toolCalls) {\r\n          for (const tc of r.toolCalls) {\r\n            trace.toolCalls.push({ tool: tc.name, args: tc.arguments });\r\n          }\r\n        }\r\n        return r;\r\n      },\r\n    };\r\n\r\n    try {\r\n      await driveSkill(spec, trackedLLM, opts.toolMocks ?? {}, trace);\r\n    } catch (err) {\r\n      trace.errors.push((err as Error).message);\r\n    }\r\n\r\n    const failures = await evaluateAssertions(spec.assertions, trace);\r\n    const ok = failures.length === 0;\r\n    if (ok) passed++;\r\n    else failed++;\r\n\r\n    results.push({\r\n      name: spec.name,\r\n      skipped: false,\r\n      passed: ok,\r\n      failures,\r\n      trace,\r\n      durationMs: Date.now() - start,\r\n    });\r\n\r\n    if (opts.verbose) {\r\n      if (ok) console.log(`  ✓ passed (${results[results.length - 1]!.durationMs}ms)`);\r\n      else for (const f of failures) console.log(`  ✗ ${f}`);\r\n    }\r\n  }\r\n\r\n  return {\r\n    total: evals.length,\r\n    passed,\r\n    failed,\r\n    skipped,\r\n    failures: failed,\r\n    results,\r\n  };\r\n}\r\n\r\n// ─── private — drive a skill end-to-end with mocked LLM ──────────\r\n\r\nasync function driveSkill(\r\n  spec: EvalSpec,\r\n  llm: LLMProvider,\r\n  toolMocks: Record<string, (args: unknown) => unknown>,\r\n  trace: EvalTrace\r\n): Promise<void> {\r\n  const skill = spec.skill;\r\n\r\n  if (skill.type === 'script') {\r\n    // ScriptSkills don't call LLM directly; treat the step subtitles as outputs.\r\n    for (const step of skill.steps) {\r\n      if (step.subtitle) trace.subtitles.push(step.subtitle);\r\n    }\r\n  } else if (skill.type === 'prompt') {\r\n    // Resolve the prompt template with given vars, then a single LLM round.\r\n    const prompt = resolvePrompt(skill, spec.vars ?? {});\r\n    await llm.complete({\r\n      messages: [\r\n        { role: 'system', content: prompt },\r\n        { role: 'user', content: spec.userInput },\r\n      ],\r\n    });\r\n  } else if (skill.type === 'action') {\r\n    // Build a stub ActionSkillContext with track-and-mock surfaces.\r\n    await skill.handler(buildEvalActionContext(trace, toolMocks));\r\n  } else if (skill.type === 'surface') {\r\n    const surface = await skill.build(buildEvalActionContext(trace, toolMocks));\r\n    trace.surfaces.push(surface);\r\n  }\r\n}\r\n\r\nfunction resolvePrompt(skill: PromptSkill, vars: Record<string, string>): string {\r\n  const merged = { ...skill.variables, ...vars };\r\n  let p = skill.prompt;\r\n  for (const [k, v] of Object.entries(merged)) {\r\n    const escapedKey = k.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\r\n    p = p.replace(new RegExp(`\\\\{\\\\{\\\\s*${escapedKey}\\\\s*\\\\}\\\\}`, 'g'), v);\r\n  }\r\n  return p;\r\n}\r\n\r\nfunction buildEvalActionContext(\r\n  trace: EvalTrace,\r\n  toolMocks: Record<string, (args: unknown) => unknown>\r\n): import('./types').ActionSkillContext {\r\n  return {\r\n    getPreferences: () => ({}) as never,\r\n    palette: {\r\n      close: () => {},\r\n      replace: (items) => trace.toolCalls.push({ tool: 'palette.replace', args: { items } }),\r\n    },\r\n    subtitle: {\r\n      show: (opts) => trace.subtitles.push(opts.text),\r\n      hide: () => {},\r\n    },\r\n    storage: {\r\n      get: () => null,\r\n      set: () => {},\r\n    },\r\n    navigate: (path) => trace.toolCalls.push({ tool: 'navigate', args: { path } }),\r\n    agent: (task) => trace.toolCalls.push({ tool: 'agent', args: { task } }),\r\n    llm: async (prompt) => {\r\n      // Allow eval to mock specific tool calls\r\n      const mock = toolMocks['llm'];\r\n      return mock ? String(mock(prompt)) : '';\r\n    },\r\n  };\r\n}\r\n\r\nasync function evaluateAssertions(assertions: EvalAssertion[], trace: EvalTrace): Promise<string[]> {\r\n  const failures: string[] = [];\r\n  for (const a of assertions) {\r\n    switch (a.kind) {\r\n      case 'includes':\r\n        if (!trace.text.includes(a.substring) && !trace.subtitles.some((s) => s.includes(a.substring))) {\r\n          failures.push(`expected output to include \"${a.substring}\"`);\r\n        }\r\n        break;\r\n      case 'matches':\r\n        if (!a.pattern.test(trace.text) && !trace.subtitles.some((s) => a.pattern.test(s))) {\r\n          failures.push(`expected output to match ${a.pattern}`);\r\n        }\r\n        break;\r\n      case 'callsTool':\r\n        if (!trace.toolCalls.some((tc) => tc.tool === a.tool)) {\r\n          failures.push(`expected tool \"${a.tool}\" to be called (got: ${trace.toolCalls.map((t) => t.tool).join(',') || 'none'})`);\r\n        }\r\n        break;\r\n      case 'doesNotCallTool':\r\n        if (trace.toolCalls.some((tc) => tc.tool === a.tool)) {\r\n          failures.push(`expected tool \"${a.tool}\" NOT to be called`);\r\n        }\r\n        break;\r\n      case 'meetsCriteria': {\r\n        const ok = await a.check(trace);\r\n        if (!ok) failures.push(`criteria not met: ${a.description}`);\r\n        break;\r\n      }\r\n    }\r\n  }\r\n  if (trace.errors.length > 0) {\r\n    failures.push(`errors during run: ${trace.errors.join('; ')}`);\r\n  }\r\n  return failures;\r\n}\r\n","/**\n * Default HERO greeting template + config type.\n *\n * Auto-fires on a MobileTrigger's first mount (session-storage gated),\n * so every dddk install shows a coherent bilingual first-visit\n * greeting without the host writing any HTML. Hosts customise three\n * axes without touching internals:\n *\n *   1. Turn it off — `heroGreeting: false`.\n *   2. Swap text — per-locale record; falls back to English if a locale\n *      is missing.\n *   3. Swap styling — every visual is a CSS variable declared in\n *      `tokens.css`. Override on `:root`.\n *\n * Full escape hatch: pass `bodyHtml` (string or `(locale) => string`)\n * to replace the whole content HTML. Everything else on the config is\n * ignored in that case.\n *\n * The default template renders:\n *   - Title line (\"Hi! I'm your AI assistant here\")\n *   - Two action rows:\n *       👆 Tap me → open the palette\n *       🎤 Hold me → tell me what you need\n *   - Keyboard hint (desktop only): Ctrl+K + Space\n */\n\n/**\n * One entry in the action-row list of the default template. `icon` is\n * an emoji (or empty for no icon column); `body` is the row text —\n * either a plain string or a per-locale record.\n */\nexport interface HeroGreetingRow {\n  icon?: string;\n  body: string | Partial<Record<string, string>>;\n}\n\n/**\n * Full HERO greeting configuration surface.\n *\n * All fields are optional. Passing an empty object `{}` uses every\n * default. Passing `false` on the parent `heroGreeting` field disables\n * the auto-show entirely.\n */\nexport interface HeroGreetingConfig {\n  /**\n   * Auto-fire the greeting on the MobileTrigger's first mount when the\n   * user hasn't seen it this session. Default `true`. Set `false` to\n   * keep the config (for programmatic firing via\n   * `mobile.showHeroGreetingWithDefaults()`) but skip the auto-fire.\n   */\n  autoShow?: boolean;\n\n  /**\n   * How long the greeting stays visible before auto-dismiss (ms).\n   * Default `20000` (20 seconds) — long enough to read three lines of\n   * guidance, short enough not to sit on top of content.\n   */\n  autoDismissMs?: number;\n\n  /**\n   * sessionStorage key used to mark the greeting as \"seen\" so it\n   * doesn't fire again in the same tab session. Default\n   * `'dddk_hero_greeting_seen_v1'`. Bump the suffix if you change the\n   * greeting content and want every returning visitor to see it once\n   * more.\n   */\n  storageKey?: string;\n\n  /**\n   * Delay before the greeting fires on first mount (ms). Default\n   * `1200`. Gives the page a moment to render + settle so the greeting\n   * doesn't land during layout thrash.\n   */\n  delayMs?: number;\n\n  /**\n   * Title line at the top of the greeting. Either a plain string or a\n   * per-locale record. Default bilingual placeholder that reads as\n   * \"Hi, I'm the AI assistant here\" — not brand-specific so it doesn't\n   * feel out of place on any site.\n   *\n   *   { en: \"Hi! I'm your AI assistant.\", 'zh-TW': \"嗨！我是這裡的 AI 助理。\" }\n   */\n  title?: string | Partial<Record<string, string>>;\n\n  /**\n   * Action rows. Default two rows explaining the two primary\n   * gestures: tap-to-open-palette, hold-to-talk. Pass your own array\n   * to add / remove / reword rows.\n   */\n  rows?: HeroGreetingRow[];\n\n  /**\n   * Keyboard hint line at the bottom (desktop only — hidden on touch).\n   * Default bilingual note about Ctrl+K + Space. Set `false` to hide\n   * it even on desktop.\n   */\n  kbdHint?: string | Partial<Record<string, string>> | false;\n\n  /**\n   * Screen-reader label — plain-text version of the greeting for\n   * assistive tech (the visible HTML has emoji + `<kbd>` markup that\n   * doesn't read well). Default auto-generated from title + rows.\n   */\n  ariaLabel?: string | Partial<Record<string, string>>;\n\n  /**\n   * Full escape hatch — pass raw HTML (or a locale-aware function that\n   * returns it) to replace the entire body. When set, every other\n   * field on this config except `autoDismissMs` / `storageKey` /\n   * `delayMs` / `autoShow` is ignored.\n   */\n  bodyHtml?: string | ((locale: string) => string);\n}\n\n/**\n * Resolve a locale-record value to a single string. Prefers the exact\n * locale, falls back to `'en'`, then the first defined value. Returns\n * `undefined` if the input is `undefined` (caller decides the\n * fallback).\n */\nfunction pickLocale<T extends string>(\n  v: T | Partial<Record<string, T>> | undefined,\n  locale: string,\n): T | undefined {\n  if (v === undefined) return undefined;\n  if (typeof v === 'string') return v;\n  return v[locale] ?? v['en'] ?? Object.values(v)[0];\n}\n\n/**\n * Strip HTML tags from a string, useful for building a plain-text\n * aria-label from a snippet that includes `<b>` / `<kbd>`.\n */\nfunction stripHtml(s: string): string {\n  return s.replace(/<[^>]+>/g, '').replace(/\\s+/g, ' ').trim();\n}\n\nconst DEFAULT_ROWS_ZH: HeroGreetingRow[] = [\n  { icon: '👆', body: { 'zh-TW': '<b>點我</b> → 打開指令面板', en: '<b>Tap</b> me → open the palette' } },\n  { icon: '🎤', body: { 'zh-TW': '<b>按住我</b> → 告訴我你的問題', en: '<b>Hold</b> me → tell me what you need' } },\n];\n\nconst DEFAULT_TITLE: Record<string, string> = {\n  'zh-TW': '嗨！我是這裡的 AI 助理',\n  en: \"Hi! I'm your AI assistant here\",\n};\n\nconst DEFAULT_KBD_HINT: Record<string, string> = {\n  'zh-TW': '鍵盤也行：<kbd>Ctrl</kbd>+<kbd>K</kbd> 開面板 · 按住 <kbd>Space</kbd> 說話',\n  en: 'Or keyboard: <kbd>Ctrl</kbd>+<kbd>K</kbd> for the palette · hold <kbd>Space</kbd> to talk',\n};\n\n/**\n * Compute the bodyHtml + ariaLabel to pass into\n * `MobileTrigger.showHeroGreeting()`. Respects every override on\n * `cfg`, falls back to the built-in bilingual template.\n *\n * All the `style=\"...\"` chunks reference CSS custom properties so\n * hosts can retune sizes / weights / colours without patching the\n * inline HTML — see `mascot.md` for the token list.\n */\nexport function renderHeroGreetingBody(\n  cfg: HeroGreetingConfig,\n  locale: string,\n  ctx: { isTouch: boolean } = { isTouch: false },\n): { bodyHtml: string; ariaLabel: string } {\n  // Full escape hatch — host owns the whole HTML.\n  if (cfg.bodyHtml !== undefined) {\n    const html =\n      typeof cfg.bodyHtml === 'function' ? cfg.bodyHtml(locale) : cfg.bodyHtml;\n    const aria = pickLocale(cfg.ariaLabel, locale) ?? stripHtml(html) ?? 'Welcome';\n    return { bodyHtml: html, ariaLabel: aria };\n  }\n\n  const title = pickLocale(cfg.title, locale) ?? pickLocale(DEFAULT_TITLE, locale)!;\n  const rows = cfg.rows ?? DEFAULT_ROWS_ZH;\n  const kbdHint = ctx.isTouch\n    ? '' // no keyboard on touch — hint is nonsense\n    : cfg.kbdHint === false\n      ? ''\n      : (pickLocale(cfg.kbdHint, locale)\n        ?? pickLocale(DEFAULT_KBD_HINT, locale)\n        ?? '');\n\n  // Style chunks read from CSS variables declared in tokens.css. Hosts\n  // override on `:root` to retune. Fallback values in `var(..., …)`\n  // match what the FAB currently ships with.\n  const titleStyle =\n    'font-size:var(--dddk-fab-hero-title-size,17px);'\n    + 'font-weight:var(--dddk-fab-hero-title-weight,700)';\n  const rowStyle =\n    'display:flex;align-items:center;'\n    + 'gap:var(--dddk-fab-hero-row-gap,10px);'\n    + 'margin-top:var(--dddk-fab-hero-row-margin,8px);'\n    + 'font-size:var(--dddk-fab-hero-row-size,15px)';\n  const iconStyle =\n    'display:inline-flex;align-items:center;justify-content:center;'\n    + 'width:var(--dddk-fab-hero-icon-size,22px);'\n    + 'flex-shrink:0;font-size:16px;line-height:1';\n  const kbdStyle =\n    'margin-top:var(--dddk-fab-hero-kbd-margin,10px);'\n    + 'font-size:var(--dddk-fab-hero-kbd-size,12.5px);'\n    + 'opacity:var(--dddk-fab-hero-kbd-opacity,0.72)';\n\n  const rowsHtml = rows\n    .map((r) => {\n      const body = pickLocale(r.body, locale) ?? '';\n      const iconCell = r.icon\n        ? `<span style=\"${iconStyle}\">${r.icon}</span>`\n        : '';\n      return `<div style=\"${rowStyle}\">${iconCell}<span>${body}</span></div>`;\n    })\n    .join('');\n\n  const bodyHtml = `<div style=\"${titleStyle}\">${title}</div>${rowsHtml}${\n    kbdHint ? `<div style=\"${kbdStyle}\">${kbdHint}</div>` : ''\n  }`;\n\n  // Auto aria-label — join title + row plain-text bodies.\n  const rowsPlain = rows.map((r) => stripHtml(pickLocale(r.body, locale) ?? '')).join('. ');\n  const aria =\n    pickLocale(cfg.ariaLabel, locale)\n    ?? `${stripHtml(title)}. ${rowsPlain}`.trim();\n\n  return { bodyHtml, ariaLabel: aria };\n}\n","/**\r\n * MobileTrigger — touch invocation for dddk on phones / tablets.\r\n *\r\n * Gesture: **rapid up-down swipe** — the user wiggles a finger up and down\r\n * several times in quick succession (≥3 direction reversals within ~700ms).\r\n * This is chosen because:\r\n *   - Normal scroll is one direction at a time → no false positives\r\n *   - Doesn't collide with any OS-reserved gesture (iOS back, Android nav,\r\n *     pull-to-refresh, etc.)\r\n *   - Discoverable by hint or onboarding (\"shake your finger up and down\")\r\n *\r\n * On trigger, two semi-transparent chrome bars slide in:\r\n *\r\n *   ┌──────────────────────────────────────────┐\r\n *   │ 🔍 Palette                            ✕ │  ← top bar\r\n *   ├──────────────────────────────────────────┤\r\n *   │                                          │\r\n *   │   (original page content — still         │\r\n *   │    scrollable; **tapping any element     │\r\n *   │    triggers dwell-style**        │\r\n *   │    instead of the element's own click)   │\r\n *   │                                          │\r\n *   ├──────────────────────────────────────────┤\r\n *   │              ●  (center button)          │  ← bottom bar\r\n *   └──────────────────────────────────────────┘\r\n *\r\n * Top bar:\r\n *   - Tap \"🔍 Palette\" → opens command palette\r\n *   - Tap \"✕\"          → closes the chrome, page returns to normal\r\n *\r\n * Middle (the page):\r\n *   - Scrolling: works as before\r\n *   - Tapping an element: intercepted → fires `palette_open` with the\r\n *     element's selector so Dwell / a host skill can annotate\r\n *\r\n * Bottom bar — circular center button (replaces Space):\r\n *   - Long press (> 200ms)  → fires `voice_start`\r\n *   - Single tap            → fires `gesture_accept`\r\n *   - Double tap (within 350ms) → fires `gesture_reject`\r\n *\r\n * @example\r\n * ```ts\r\n * import { MobileTrigger } from '@perhapxin/dddk';\r\n *\r\n * const mt = new MobileTrigger();\r\n * mt.attachTo(dddk);\r\n * ```\r\n */\r\n\r\nimport type { DotDotDuck } from '../orchestrator';\r\nimport { injectScopedStyle } from '../utils/dom';\r\nimport { inferSelector } from '../utils/selector';\r\nimport { renderHeroGreetingBody, type HeroGreetingConfig, type HeroGreetingRow } from './mobile-hero-greeting';\r\nexport type { HeroGreetingConfig, HeroGreetingRow };\r\n\r\n/**\r\n * Floating action button (FAB) — the default mobile entry point.\r\n *\r\n * Replaces nothing; runs alongside the swipe gesture so users have two ways\r\n * in. Highly customizable: icon, label, position, shape, color, full CSS\r\n * override. Hosts can also call `bindTrigger(myButton)` to use their OWN\r\n * existing header / nav element as the trigger, then set `fab: false` to\r\n * suppress the default FAB.\r\n */\r\nexport interface MobileFABConfig {\r\n  /** Show the default FAB? Default true on touch devices. */\r\n  enabled?: boolean;\r\n  /**\r\n   * The icon shown inside the FAB. Accepts:\r\n   *   - emoji / text string ('🔍', '✨')\r\n   *   - raw HTML string ('<svg>...</svg>')\r\n   *   - an HTMLElement (will be appended into the button)\r\n   * Default: a 24px sparkle SVG.\r\n   */\r\n  icon?: string | HTMLElement;\r\n  /** Optional visible text under/next to the icon. Default none. */\r\n  text?: string;\r\n  /** ARIA label. Default 'Open command palette'. */\r\n  ariaLabel?: string;\r\n  /** Position. Default 'bottom-right'. */\r\n  position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\r\n  /** Offset from the edges in px. Default { x: 20, y: 24 }. */\r\n  offset?: { x?: number; y?: number };\r\n  /** Diameter in px (square shape uses this as width/height). Default 56. */\r\n  size?: number;\r\n  /** Shape. Default 'circle'. 'square' uses --dddk-radius. 'pill' = rounded rect. */\r\n  shape?: 'circle' | 'square' | 'pill';\r\n  /**\r\n   * Inline CSS override — applied AFTER all defaults. Use this to fully\r\n   * replace background, gradient, border, shadow, etc.\r\n   */\r\n  style?: Partial<CSSStyleDeclaration>;\r\n  /** Extra className(s) to append; lets hosts target with their own CSS. */\r\n  className?: string;\r\n  /**\r\n   * What the FAB does on tap. Default: open palette.\r\n   * Receive the DotDotDuck instance so host can do anything.\r\n   */\r\n  onTap?: (dddk: DotDotDuck) => void;\r\n  /**\r\n   * What the FAB does on long-press (>200ms by default).\r\n   * Default: fires the same voice-start event the center button fires.\r\n   * Set to `null` to disable long-press behavior entirely.\r\n   */\r\n  onLongPress?: ((dddk: DotDotDuck) => void) | null;\r\n  /**\r\n   * Map of face slug → image URL. When set, the FAB renders the\r\n   * `neutral` face by default and `setFace(slug)` swaps between them.\r\n   * Overrides `icon` when present. Typical use: point at deployed\r\n   * face assets so the FAB becomes an expressive duck-head avatar.\r\n   *\r\n   *   faces: {\r\n   *     neutral: '/duck/neutral.png',\r\n   *     thinking: '/duck/thinking.png',\r\n   *     listening: '/duck/listening.png',\r\n   *     done: '/duck/done.png',\r\n   *     error: '/duck/error.png',\r\n   *     smile: '/duck/smile.png',\r\n   *     wink: '/duck/wink.png',\r\n   *   }\r\n   *\r\n   * Missing slugs are ignored — `setFace('foo')` on an unknown slug\r\n   * is a no-op instead of clearing the image.\r\n   */\r\n  faces?: Record<string, string>;\r\n  /**\r\n   * Also mount the FAB on desktop viewports. Default `false` — the\r\n   * legacy behavior only shows it on mobile / touch. Set to `true`\r\n   * when the FAB is the primary presence for the SDK (mascot mode).\r\n   */\r\n  alwaysVisible?: boolean;\r\n}\r\n\r\nexport interface MobileTriggerConfig {\r\n  /** Min direction reversals in the swipe window to trigger. Default 3. */\r\n  reversalsToTrigger?: number;\r\n  /** Time window (ms) the reversals must happen within. Default 700. */\r\n  swipeWindowMs?: number;\r\n  /** Min Y delta per reversal (px). Default 30. Filters jitter. */\r\n  minSwipeDelta?: number;\r\n  /**\r\n   * Long-press threshold for voice (ms). Default 500 — matches\r\n   * Apple/Google convention for \"hold vs tap\". Was 200 in early\r\n   * versions but real fingers linger 250-350ms on a normal tap,\r\n   * which incorrectly triggered voice-start.\r\n   */\r\n  longPressMs?: number;\r\n  /** Double-tap window (ms). Default 350. */\r\n  doubleTapMs?: number;\r\n  /** Force enable on non-touch devices (for testing). Default false. */\r\n  forceEnable?: boolean;\r\n  /**\r\n   * When chrome is open, tapping page elements routes through Dwell (host\r\n   * wires the listener). Default `false` — chrome shows but taps work\r\n   * normally. Flip via `setDwellOnTap()` at runtime.\r\n   */\r\n  dwellOnTap?: boolean;\r\n  /**\r\n   * Floating action button — default mobile entry point.\r\n   * Pass `false` to disable (host uses `bindTrigger()` with their own UI).\r\n   * Pass an object to customize.\r\n   */\r\n  fab?: MobileFABConfig | false;\r\n\r\n  /**\r\n   * First-visit HERO greeting. Auto-fires on first `attachTo()` if the\r\n   * user hasn't seen it this session (sessionStorage-gated). Pass:\r\n   *   - `false` — disable entirely.\r\n   *   - `{}` — use every SDK default (bilingual title + tap-me / hold-me\r\n   *     action rows + keyboard hint on desktop).\r\n   *   - `{ title, rows, kbdHint, autoDismissMs, delayMs, storageKey, bodyHtml }`\r\n   *     — override any axis; unspecified fields fall back to defaults.\r\n   *\r\n   * Styling — every visual is a CSS variable declared in `tokens.css`\r\n   * (`--dddk-fab-hero-title-size`, `--dddk-fab-hero-row-gap`, ... etc).\r\n   * Override on `:root` instead of touching the config.\r\n   *\r\n   * See `docs/v0.2.2/dddk/mascot.md` for the full contract.\r\n   */\r\n  heroGreeting?: HeroGreetingConfig | false;\r\n}\r\n\r\nimport { UI_ATTR } from '../utils/dom';\r\nconst STYLE_ID = 'dddk-mobile-trigger-style';\r\n\r\ninterface SwipeSample {\r\n  y: number;\r\n  t: number;\r\n  dir: 'up' | 'down' | null;\r\n}\r\n\r\n/** Semantic states the mascot FAB can be in; drives face + CSS animation. */\r\nexport type FabState =\r\n  | 'idle'\r\n  | 'thinking'\r\n  | 'listening'\r\n  | 'voice-hold'\r\n  | 'done'\r\n  | 'error';\r\n\r\nconst STATE_TO_FACE: Record<FabState, string> = {\r\n  'idle': 'neutral',\r\n  'thinking': 'thinking',\r\n  'listening': 'listening',\r\n  'voice-hold': 'listening',\r\n  'done': 'done',\r\n  'error': 'error',\r\n};\r\n\r\nexport class MobileTrigger {\r\n  private cfg: Omit<Required<MobileTriggerConfig>, 'fab'> & { fab: MobileFABConfig | false };\r\n  private dddk: DotDotDuck | null = null;\r\n  private topBar: HTMLDivElement | null = null;\r\n  private bottomBar: HTMLDivElement | null = null;\r\n  private fabEl: HTMLButtonElement | null = null;\r\n  private fabImg: HTMLImageElement | null = null;\r\n  private greetingEl: HTMLDivElement | null = null;\r\n  private greetingDismiss: (() => void) | null = null;\r\n  private currentFace: string = 'neutral';\r\n  private currentState: FabState = 'idle';\r\n  private visible = false;\r\n  private samples: SwipeSample[] = [];\r\n  private longPressTimer: ReturnType<typeof setTimeout> | null = null;\r\n  private lastTapAt = 0;\r\n  private singleTapTimer: ReturnType<typeof setTimeout> | null = null;\r\n  private cleanups: Array<() => void> = [];\r\n\r\n  private dwellOnTap: boolean;\r\n\r\n  constructor(config: MobileTriggerConfig = {}) {\r\n    this.cfg = {\r\n      reversalsToTrigger: config.reversalsToTrigger ?? 2,\r\n      swipeWindowMs: config.swipeWindowMs ?? 900,\r\n      minSwipeDelta: config.minSwipeDelta ?? 18,\r\n      longPressMs: config.longPressMs ?? 500,\r\n      doubleTapMs: config.doubleTapMs ?? 350,\r\n      forceEnable: config.forceEnable ?? false,\r\n      dwellOnTap: config.dwellOnTap ?? false,\r\n      fab: config.fab ?? {},\r\n      // Default: auto-fire the built-in bilingual greeting on first\r\n      // visit. `false` disables it entirely; passing an object\r\n      // overrides just the fields you care about.\r\n      heroGreeting: config.heroGreeting ?? {},\r\n    };\r\n    this.dwellOnTap = this.cfg.dwellOnTap;\r\n  }\r\n\r\n  setDwellOnTap(enabled: boolean): void {\r\n    this.dwellOnTap = enabled;\r\n  }\r\n\r\n  isDwellOnTap(): boolean {\r\n    return this.dwellOnTap;\r\n  }\r\n\r\n  attachTo(dddk: DotDotDuck): void {\r\n    if (typeof document === 'undefined') return;\r\n\r\n    // Important: we ALWAYS attach + listen for breakpoint changes, even\r\n    // when the initial viewport is desktop. Otherwise:\r\n    //   1. Page loads on desktop → attachTo bails out\r\n    //   2. User opens DevTools, switches to mobile emulation → no listener\r\n    //      to react, FAB stays absent forever\r\n    //   3. User reports \"the FAB disappeared\"\r\n    // We still gate the actual FAB MOUNT on touch/mobile/forceEnable, but\r\n    // the matchMedia listener is unconditional so any later transition\r\n    // into mobile mode lights up the FAB.\r\n    this.dddk = dddk;\r\n    ensureStyles();\r\n\r\n    const touch = isTouchDevice();\r\n    const mobile = isMobileViewport();\r\n    const force = !!this.cfg.forceEnable;\r\n    const fabCfg = this.cfg.fab === false ? null : this.cfg.fab;\r\n    const alwaysVisible = !!fabCfg?.alwaysVisible;\r\n    // `alwaysVisible: true` — new mascot mode. The FAB is the primary\r\n    // presence for the SDK, so we mount it on every viewport, including\r\n    // desktop with a real mouse. Legacy behavior (touch/mobile only)\r\n    // still applies when alwaysVisible is false or unset.\r\n    const shouldMountNow = alwaysVisible || force || touch || mobile;\r\n\r\n    if (touch || force) {\r\n      this.bindSwipeDetector();\r\n    }\r\n\r\n    if (\r\n      shouldMountNow &&\r\n      this.cfg.fab !== false &&\r\n      (this.cfg.fab.enabled ?? true)\r\n    ) {\r\n      this.mountFab();\r\n    }\r\n\r\n    // Always-on breakpoint listener — handles desktop→mobile transitions\r\n    // (DevTools emulation, window resize, orientation change). Skipped\r\n    // when alwaysVisible is on because the FAB never dismounts.\r\n    if (!alwaysVisible) {\r\n      const mq = window.matchMedia('(max-width: 768px)');\r\n      const onChange = () => {\r\n        const shouldShow = mq.matches || isTouchDevice() || this.cfg.forceEnable;\r\n        if (shouldShow && !this.fabEl && this.cfg.fab !== false && (this.cfg.fab.enabled ?? true)) {\r\n          this.mountFab();\r\n        } else if (!shouldShow && this.fabEl) {\r\n          this.fabEl.remove();\r\n          this.fabEl = null;\r\n          this.fabImg = null;\r\n        }\r\n      };\r\n      if (mq.addEventListener) mq.addEventListener('change', onChange);\r\n      else (mq as MediaQueryList).addListener?.(onChange);\r\n      this.cleanups.push(() => {\r\n        if (mq.removeEventListener) mq.removeEventListener('change', onChange);\r\n        else (mq as MediaQueryList).removeListener?.(onChange);\r\n      });\r\n    }\r\n\r\n    // Fire the first-visit HERO greeting (if enabled + not seen this\r\n    // session). Deferred + session-storage-gated inside the helper.\r\n    this.scheduleFirstVisitGreeting();\r\n  }\r\n\r\n  /**\r\n   * Auto-fire the built-in HERO greeting on first attach if the visitor\r\n   * hasn't seen it this session. Reads `this.cfg.heroGreeting`:\r\n   *\r\n   *   - `false`             → skip entirely\r\n   *   - `undefined` / `{}`  → use every SDK default\r\n   *   - `{ autoShow: false }` → keep the config for later programmatic\r\n   *     firing via `showHeroGreetingWithDefaults()`, but skip auto-fire\r\n   *   - anything else — override just the fields you care about\r\n   *\r\n   * Session-storage-gated so returning visitors aren't nagged. Skips\r\n   * silently on SSR / storage-blocked contexts.\r\n   */\r\n  private scheduleFirstVisitGreeting(): void {\r\n    const cfg = this.cfg.heroGreeting;\r\n    if (cfg === false) return;\r\n    const config: HeroGreetingConfig = typeof cfg === 'object' && cfg !== null ? cfg : {};\r\n    if (config.autoShow === false) return;\r\n\r\n    const storageKey = config.storageKey ?? 'dddk_hero_greeting_seen_v1';\r\n    try {\r\n      if (typeof window !== 'undefined' && window.sessionStorage?.getItem(storageKey)) return;\r\n    } catch { /* storage blocked (private browsing / CSP) — treat as first-visit */ }\r\n\r\n    const delayMs = config.delayMs ?? 1200;\r\n    setTimeout(() => {\r\n      if (!this.fabEl) return;\r\n      void this.showHeroGreetingWithDefaults(config);\r\n      try {\r\n        if (typeof window !== 'undefined') window.sessionStorage?.setItem(storageKey, '1');\r\n      } catch { /* storage blocked — greeting will fire on every visit, acceptable */ }\r\n    }, delayMs);\r\n  }\r\n\r\n  /**\r\n   * Show the greeting using the SDK's built-in bilingual template.\r\n   * Called by the auto-fire path, but also public — hosts can call it\r\n   * on demand (e.g. from a \"Replay tour\" palette entry). Passing\r\n   * `overrides` lets you swap just the fields you care about without\r\n   * touching the trigger's config.\r\n   */\r\n  showHeroGreetingWithDefaults(overrides: HeroGreetingConfig = {}): Promise<void> {\r\n    const config: HeroGreetingConfig = {\r\n      ...(typeof this.cfg.heroGreeting === 'object' && this.cfg.heroGreeting !== null ? this.cfg.heroGreeting : {}),\r\n      ...overrides,\r\n    };\r\n    const locale = this.readLocale();\r\n    const isTouch =\r\n      typeof window !== 'undefined'\r\n      && window.matchMedia?.('(hover: none) and (pointer: coarse)').matches;\r\n    const { bodyHtml, ariaLabel } = renderHeroGreetingBody(config, locale, { isTouch });\r\n    return this.showHeroGreeting(ariaLabel, {\r\n      bodyHtml,\r\n      ariaLabel,\r\n      autoDismissMs: config.autoDismissMs ?? 20000,\r\n    });\r\n  }\r\n\r\n  /**\r\n   * Read the current locale from the attached DotDotDuck instance,\r\n   * falling back to `document.documentElement.lang` or `'en'`.\r\n   */\r\n  private readLocale(): string {\r\n    if (this.dddk) {\r\n      const loc = (this.dddk as unknown as { _config?: { locale?: string } })._config?.locale;\r\n      if (loc) return loc;\r\n    }\r\n    if (typeof document !== 'undefined') {\r\n      const lang = document.documentElement.lang;\r\n      if (lang) return lang;\r\n    }\r\n    return 'en';\r\n  }\r\n\r\n  /**\r\n   * Bind ANY host element as a palette trigger. Use this when you want your\r\n   * existing header button / hamburger menu / nav icon to also open dddk.\r\n   * Returns a cleanup function.\r\n   *\r\n   *   const off = mt.bindTrigger(document.querySelector('#my-fab')!);\r\n   *   // later: off();\r\n   */\r\n  bindTrigger(\r\n    element: HTMLElement,\r\n    opts: {\r\n      onTap?: (dddk: DotDotDuck) => void;\r\n      onLongPress?: ((dddk: DotDotDuck) => void) | null;\r\n    } = {},\r\n  ): () => void {\r\n    if (!this.dddk) {\r\n      // Defer until attached.\r\n      this.cleanups.push(() => {});\r\n      return () => {};\r\n    }\r\n    const dddk = this.dddk;\r\n    const onTap = opts.onTap ?? ((d) => d.palette.toggle());\r\n    const onLongPress = opts.onLongPress === undefined\r\n      ? (d: DotDotDuck) => d.triggerVoiceStart()\r\n      : opts.onLongPress;\r\n\r\n    let timer: ReturnType<typeof setTimeout> | null = null;\r\n    let longFired = false;\r\n\r\n    const press = () => {\r\n      longFired = false;\r\n      if (onLongPress) {\r\n        timer = setTimeout(() => {\r\n          timer = null;\r\n          longFired = true;\r\n          onLongPress(dddk);\r\n        }, this.cfg.longPressMs);\r\n      }\r\n    };\r\n    const release = () => {\r\n      if (timer) {\r\n        clearTimeout(timer);\r\n        timer = null;\r\n      }\r\n      if (!longFired) onTap(dddk);\r\n      else if (onLongPress) dddk.triggerVoiceEnd();\r\n    };\r\n    const cancel = () => {\r\n      if (timer) {\r\n        clearTimeout(timer);\r\n        timer = null;\r\n      }\r\n    };\r\n\r\n    const onTouchStart = (e: TouchEvent) => { e.preventDefault(); press(); };\r\n    const onTouchEnd = (e: TouchEvent) => { e.preventDefault(); release(); };\r\n\r\n    element.addEventListener('touchstart', onTouchStart, { passive: false });\r\n    element.addEventListener('touchend', onTouchEnd, { passive: false });\r\n    element.addEventListener('touchcancel', cancel);\r\n    element.addEventListener('mousedown', press);\r\n    element.addEventListener('mouseup', release);\r\n    element.addEventListener('mouseleave', cancel);\r\n\r\n    const off = () => {\r\n      element.removeEventListener('touchstart', onTouchStart);\r\n      element.removeEventListener('touchend', onTouchEnd);\r\n      element.removeEventListener('touchcancel', cancel);\r\n      element.removeEventListener('mousedown', press);\r\n      element.removeEventListener('mouseup', release);\r\n      element.removeEventListener('mouseleave', cancel);\r\n    };\r\n    this.cleanups.push(off);\r\n    return off;\r\n  }\r\n\r\n  show(): void {\r\n    if (!this.dddk) return;\r\n    if (!this.topBar) this.mountChrome();\r\n    this.visible = true;\r\n    this.topBar?.setAttribute('data-visible', '');\r\n    this.bottomBar?.setAttribute('data-visible', '');\r\n  }\r\n\r\n  hide(): void {\r\n    this.visible = false;\r\n    this.topBar?.removeAttribute('data-visible');\r\n    this.bottomBar?.removeAttribute('data-visible');\r\n  }\r\n\r\n  toggle(): void {\r\n    this.visible ? this.hide() : this.show();\r\n  }\r\n\r\n  destroy(): void {\r\n    for (const c of this.cleanups) c();\r\n    this.cleanups = [];\r\n    this.topBar?.remove();\r\n    this.bottomBar?.remove();\r\n    this.fabEl?.remove();\r\n    this.topBar = this.bottomBar = null;\r\n    this.fabEl = null;\r\n  }\r\n\r\n  // ─── FAB (floating action button) ───────────────────────────────\r\n\r\n  private mountFab(): void {\r\n    if (!this.dddk || this.fabEl) return;\r\n    const fabCfg: MobileFABConfig = this.cfg.fab === false ? {} : this.cfg.fab;\r\n    const btn = document.createElement('button');\r\n    btn.type = 'button';\r\n    btn.setAttribute(UI_ATTR, 'mobile-fab');\r\n    btn.setAttribute('aria-label', fabCfg.ariaLabel ?? 'Open command palette');\r\n    if (fabCfg.className) btn.className = fabCfg.className;\r\n\r\n    // Position\r\n    const pos = fabCfg.position ?? 'bottom-right';\r\n    const ox = fabCfg.offset?.x ?? 20;\r\n    const oy = fabCfg.offset?.y ?? 24;\r\n    if (pos.includes('top'))    btn.style.top = `calc(env(safe-area-inset-top, 0px) + ${oy}px)`;\r\n    if (pos.includes('bottom')) btn.style.bottom = `calc(env(safe-area-inset-bottom, 0px) + ${oy}px)`;\r\n    if (pos.includes('left'))   btn.style.left = `${ox}px`;\r\n    if (pos.includes('right'))  btn.style.right = `${ox}px`;\r\n\r\n    // Size + shape\r\n    const size = fabCfg.size ?? 56;\r\n    if (fabCfg.shape === 'pill') {\r\n      btn.style.minWidth = `${size}px`;\r\n      btn.style.height = `${size}px`;\r\n      btn.style.borderRadius = `${size / 2}px`;\r\n      btn.style.padding = '0 20px';\r\n    } else {\r\n      btn.style.width = `${size}px`;\r\n      btn.style.height = `${size}px`;\r\n      btn.style.borderRadius = fabCfg.shape === 'square' ? 'var(--dddk-radius, 12px)' : '50%';\r\n    }\r\n\r\n    // Icon content\r\n    const inner = document.createElement('span');\r\n    inner.style.display = 'inline-flex';\r\n    inner.style.alignItems = 'center';\r\n    inner.style.justifyContent = 'center';\r\n    inner.style.width = '100%';\r\n    inner.style.height = '100%';\r\n    inner.style.gap = '6px';\r\n    inner.style.pointerEvents = 'none';\r\n\r\n    // Face mode — swap between multiple duck-face images at runtime.\r\n    // Takes precedence over `icon` when configured; supports live\r\n    // swap via setFace(). The <img> fills the button (background is\r\n    // transparent so only the yellow duck circle shows).\r\n    const faces = fabCfg.faces;\r\n    if (faces && faces.neutral) {\r\n      const img = document.createElement('img');\r\n      img.src = faces.neutral;\r\n      img.alt = '';\r\n      img.setAttribute('aria-hidden', 'true');\r\n      img.style.width = '100%';\r\n      img.style.height = '100%';\r\n      img.style.objectFit = 'contain';\r\n      img.style.display = 'block';\r\n      // Instant swap on setFace — no fade so state indicators feel snappy.\r\n      inner.appendChild(img);\r\n      this.fabImg = img;\r\n      // Face-mode buttons are transparent background — the duck head\r\n      // is the whole visual, we don't want a colored disc under it.\r\n      btn.style.background = 'transparent';\r\n      btn.style.boxShadow = 'none';\r\n      btn.setAttribute('data-face', 'neutral');\r\n      btn.setAttribute('data-state', 'idle');\r\n      // One-shot pop-in on mount so the FAB isn't just there — it\r\n      // arrives. `data-enter=\"fresh\"` triggers the scale-bounce\r\n      // keyframe; we clear it on animationend so the idle bob resumes\r\n      // cleanly instead of both animations racing.\r\n      btn.setAttribute('data-enter', 'fresh');\r\n      btn.addEventListener('animationend', function onEnter(e) {\r\n        if ((e as AnimationEvent).animationName === 'dddk-fab-enter') {\r\n          btn.removeAttribute('data-enter');\r\n          btn.removeEventListener('animationend', onEnter as EventListener);\r\n        }\r\n      });\r\n      // (Eye tracking overlay attempt reverted — sprite already has\r\n      // eyes drawn in, so adding two more pupils overlaid on top\r\n      // produced a fly-eye look. Doing this properly needs a\r\n      // separately-baked base sprite with empty eye sockets. Deferred\r\n      // to whenever we regenerate the neutral face asset with that\r\n      // constraint.)\r\n    } else if (fabCfg.icon instanceof HTMLElement) {\r\n      inner.appendChild(fabCfg.icon);\r\n    } else if (typeof fabCfg.icon === 'string') {\r\n      // Allow either raw SVG/HTML or short text/emoji.\r\n      if (fabCfg.icon.trim().startsWith('<')) inner.innerHTML = fabCfg.icon;\r\n      else inner.textContent = fabCfg.icon;\r\n    } else {\r\n      inner.innerHTML = DEFAULT_FAB_SVG;\r\n    }\r\n    if (fabCfg.text) {\r\n      const t = document.createElement('span');\r\n      t.textContent = fabCfg.text;\r\n      t.style.fontSize = '13px';\r\n      t.style.fontWeight = '600';\r\n      inner.appendChild(t);\r\n    }\r\n    btn.appendChild(inner);\r\n\r\n    // Host-supplied style overrides (LAST so they always win).\r\n    if (fabCfg.style) Object.assign(btn.style, fabCfg.style);\r\n\r\n    // Behavior — use the existing bindTrigger machinery.\r\n    document.body.appendChild(btn);\r\n    this.fabEl = btn;\r\n    this.bindTrigger(btn, { onTap: fabCfg.onTap, onLongPress: fabCfg.onLongPress });\r\n  }\r\n\r\n  /** Hide / show the default FAB at runtime. */\r\n  setFabVisible(visible: boolean): void {\r\n    if (this.fabEl) this.fabEl.style.display = visible ? '' : 'none';\r\n  }\r\n\r\n  /** Return the default FAB element (so hosts can decorate it further). */\r\n  getFabElement(): HTMLButtonElement | null {\r\n    return this.fabEl;\r\n  }\r\n\r\n  // ─── mascot face + state ────────────────────────────────────────\r\n\r\n  /**\r\n   * Swap the FAB face to the given slug. No-op when the FAB isn't in\r\n   * face mode (no `faces` config) or the slug is unknown — the current\r\n   * face stays. Returns true when an actual swap happened.\r\n   */\r\n  setFace(slug: string): boolean {\r\n    const cfg = this.cfg.fab === false ? null : this.cfg.fab;\r\n    const url = cfg?.faces?.[slug];\r\n    if (!url || !this.fabImg || !this.fabEl) return false;\r\n    if (this.currentFace === slug) return true;\r\n    this.fabImg.src = url;\r\n    this.currentFace = slug;\r\n    this.fabEl.setAttribute('data-face', slug);\r\n    return true;\r\n  }\r\n\r\n  /** Current face slug (or 'neutral' if face mode is off). */\r\n  getFace(): string { return this.currentFace; }\r\n\r\n  /**\r\n   * Set the semantic state — swaps the face AND toggles the CSS\r\n   * animation class on the FAB. Every state change also fires a\r\n   * one-shot ripple burst (water ring emitted from the FAB centre)\r\n   * so the transition reads as physical, not a bare CSS class swap.\r\n   *\r\n   *   idle       — gentle bob loop (default)\r\n   *   thinking   — slow rotate + thinking face\r\n   *   listening  — subtle pulse + listening face\r\n   *   voice-hold — balloon inflate (long-press feedback)\r\n   *   done       — quick pop + done face\r\n   *   error      — small shake + error face\r\n   */\r\n  setState(state: FabState): void {\r\n    if (!this.fabEl) return;\r\n    const prev = this.currentState;\r\n    this.currentState = state;\r\n    this.fabEl.setAttribute('data-state', state);\r\n    this.setFace(STATE_TO_FACE[state]);\r\n    if (prev !== state) this.emitRipple();\r\n  }\r\n\r\n  /** One-shot ripple burst from the FAB centre. CSS-driven — we just\r\n   *  bump `data-ripple` on the button so the pseudo-element animation\r\n   *  replays. Auto-clears after the animation duration. */\r\n  private emitRipple(): void {\r\n    if (!this.fabEl) return;\r\n    const btn = this.fabEl;\r\n    // Replay-replay trick: remove attr, force reflow, re-add.\r\n    btn.removeAttribute('data-ripple');\r\n    void btn.offsetWidth;\r\n    btn.setAttribute('data-ripple', '');\r\n    setTimeout(() => btn.removeAttribute('data-ripple'), 900);\r\n  }\r\n\r\n  // (Eye tracking `setupEyeTracking` method removed — see note in\r\n  // mountFab. Kept the ripple burst + glance choreography which don't\r\n  // require sprite rework.)\r\n\r\n  /** Current mascot state. */\r\n  getState(): FabState { return this.currentState; }\r\n\r\n  // ─── greeting speech bubble ─────────────────────────────────────\r\n\r\n  /**\r\n   * Render a speech bubble next to the FAB with a text greeting. The\r\n   * bubble is anchored to the FAB's edge and stays until the user\r\n   * clicks anywhere (default) or the optional autoDismiss timeout\r\n   * elapses.\r\n   *\r\n   * Also briefly plays a wave animation on the FAB (face = smile,\r\n   * scale bounce) so the greeting reads as an active hello, not a\r\n   * passive tooltip.\r\n   *\r\n   * Resolves once the user dismisses the greeting. If the FAB isn't\r\n   * mounted, resolves immediately.\r\n   */\r\n  /**\r\n   * \"Big duck reveal\" greeting for first-visit / brand moments. The\r\n   * small FAB circle briefly recedes and a large side-view rubber-duck\r\n   * sprite grows out of the same corner, taking over ~30% of the\r\n   * viewport. A speech bubble anchors to its left with the greeting\r\n   * text. Click anywhere → duck shrinks back into the FAB circle,\r\n   * which fades back in.\r\n   *\r\n   * `heroSrc` — image URL for the big sprite; defaults to reading\r\n   *   `--dddk-swim-url` from :root (fallback: `--dddk-avatar-url`).\r\n   *   Skip this arg when the CSS variable is already wired.\r\n   */\r\n  showHeroGreeting(\r\n    text: string,\r\n    opts: { autoDismissMs?: number; heroSrc?: string; ariaLabel?: string; bodyHtml?: string } = {},\r\n  ): Promise<void> {\r\n    // Redesigned again: the FAB circle STRETCHES horizontally into a\r\n    // yellow-translucent capsule/pill. The duck face stays on the\r\n    // right (where the FAB was); the greeting text fills the space\r\n    // that opens up on its left. No separate bubble element — the\r\n    // FAB button IS the greeting surface. Everything themeable via\r\n    // CSS variables (see `--dddk-fab-hero-*` in the docs).\r\n    void opts.heroSrc;\r\n    if (!this.fabEl || typeof document === 'undefined') return Promise.resolve();\r\n    this.hideGreeting();\r\n\r\n    const fab = this.fabEl;\r\n    const prevFace = this.currentFace;\r\n    const prevState = this.currentState;\r\n\r\n    // Inject a text panel inside the FAB — sits absolutely-positioned\r\n    // covering the pill's non-face half. Uses aria-live so screen\r\n    // readers announce it.\r\n    const content = document.createElement('div');\r\n    content.setAttribute(UI_ATTR, 'fab-hero-content');\r\n    content.setAttribute('role', 'status');\r\n    content.setAttribute('aria-live', 'polite');\r\n    if (opts.ariaLabel) content.setAttribute('aria-label', opts.ariaLabel);\r\n    if (opts.bodyHtml) {\r\n      content.innerHTML = opts.bodyHtml;\r\n    } else {\r\n      content.textContent = text;\r\n    }\r\n    fab.appendChild(content);\r\n    this.greetingEl = content;\r\n\r\n    // Toggle the hero attribute — all shape / colour / motion is CSS.\r\n    // Reset any lingering transform + pause the bob so the width\r\n    // transition owns the animation.\r\n    fab.style.animation = 'none';\r\n    fab.style.transform = 'none';\r\n    void fab.offsetWidth;\r\n    fab.setAttribute('data-hero-active', '');\r\n    // Prefer the side-left (logo pose) face so the duck's bill points\r\n    // AT the text on its left — reads as \"the duck is talking\".\r\n    // Falls back to smile if the host hasn't wired the slug.\r\n    if (!this.setFace('side-left')) {\r\n      this.setFace('smile');\r\n    }\r\n\r\n    return new Promise<void>((resolve) => {\r\n      const dismiss = () => {\r\n        // Reverse: capsule shrinks back to circle. Content fades then\r\n        // the pill contracts to circle. See CSS on [data-hero-active]\r\n        // + [data-hero-dismissing].\r\n        fab.setAttribute('data-hero-dismissing', '');\r\n        fab.removeAttribute('data-hero-active');\r\n        this.setFace(prevFace);\r\n        this.setState(prevState);\r\n        setTimeout(() => {\r\n          fab.style.animation = '';\r\n          fab.style.transform = '';\r\n          fab.removeAttribute('data-hero-dismissing');\r\n          content.remove();\r\n          if (this.greetingEl === content) this.greetingEl = null;\r\n          resolve();\r\n        }, 520);\r\n      };\r\n      this.greetingDismiss = dismiss;\r\n\r\n      // Clicking the DUCK FACE (right end of the pill) fires the\r\n      // host's FAB onTap AND dismisses — reads as \"the mascot invites\r\n      // you to open the palette\". Clicking anywhere else on the pill\r\n      // (text, whitespace) or off-pill dismisses without opening.\r\n      const onPageClick = (e: Event) => {\r\n        const t = e.target as Node | null;\r\n        const clickedFab = t && fab.contains(t) && !content.contains(t);\r\n        document.removeEventListener('click', onPageClick, true);\r\n        document.removeEventListener('touchstart', onPageClick, true);\r\n        if (clickedFab) {\r\n          try {\r\n            const cfg = this.cfg.fab === false ? null : this.cfg.fab;\r\n            const dddk = this.dddk;\r\n            if (dddk) {\r\n              if (cfg?.onTap) cfg.onTap(dddk);\r\n              else dddk.palette.toggle();\r\n            }\r\n          } catch { /* swallow — dismiss anyway */ }\r\n        }\r\n        dismiss();\r\n      };\r\n      // 400ms delay skips the entrance-event flurry (framework focus /\r\n      // autofill dispatches) that used to auto-dismiss the greeting\r\n      // before it was fully visible.\r\n      setTimeout(() => {\r\n        document.addEventListener('click', onPageClick, true);\r\n        document.addEventListener('touchstart', onPageClick, true);\r\n      }, 400);\r\n\r\n      if (opts.autoDismissMs && opts.autoDismissMs > 0) {\r\n        setTimeout(() => {\r\n          document.removeEventListener('click', onPageClick, true);\r\n          document.removeEventListener('touchstart', onPageClick, true);\r\n          dismiss();\r\n        }, opts.autoDismissMs);\r\n      }\r\n    });\r\n  }\r\n\r\n  showGreeting(\r\n    text: string,\r\n    opts: { autoDismissMs?: number; faceSlug?: string; ariaLabel?: string } = {},\r\n  ): Promise<void> {\r\n    if (!this.fabEl || typeof document === 'undefined') return Promise.resolve();\r\n    // Squash any prior greeting first.\r\n    this.hideGreeting();\r\n\r\n    const bubble = document.createElement('div');\r\n    bubble.setAttribute(UI_ATTR, 'mobile-fab-greeting');\r\n    bubble.setAttribute('role', 'status');\r\n    bubble.setAttribute('aria-live', 'polite');\r\n    if (opts.ariaLabel) bubble.setAttribute('aria-label', opts.ariaLabel);\r\n    bubble.textContent = text;\r\n    document.body.appendChild(bubble);\r\n    this.greetingEl = bubble;\r\n\r\n    // Position the bubble relative to the FAB. FAB position is fixed;\r\n    // we compute an anchor point on the FAB's INNER edge (the edge\r\n    // facing the page content) so the bubble tail points at the duck.\r\n    const positionBubble = () => {\r\n      if (!this.fabEl || !this.greetingEl) return;\r\n      const rect = this.fabEl.getBoundingClientRect();\r\n      const vw = window.innerWidth;\r\n      const vh = window.innerHeight;\r\n      const onRight = rect.left > vw / 2;\r\n      const onBottom = rect.top > vh / 2;\r\n      const gap = 12;\r\n      // Horizontal anchor: bubble to the side of the FAB that faces the\r\n      // center of the page. If the FAB sits on the right half, bubble\r\n      // goes to its LEFT; on the left half, bubble goes RIGHT.\r\n      if (onRight) {\r\n        this.greetingEl.style.right = `${vw - rect.left + gap}px`;\r\n        this.greetingEl.style.left = 'auto';\r\n        this.greetingEl.setAttribute('data-side', 'left');\r\n      } else {\r\n        this.greetingEl.style.left = `${rect.right + gap}px`;\r\n        this.greetingEl.style.right = 'auto';\r\n        this.greetingEl.setAttribute('data-side', 'right');\r\n      }\r\n      // Vertical anchor: aligned with the top of the FAB or slightly\r\n      // above so the tail reads as \"coming from the mascot's mouth\".\r\n      if (onBottom) {\r\n        this.greetingEl.style.bottom = `${vh - rect.top - 12}px`;\r\n        this.greetingEl.style.top = 'auto';\r\n      } else {\r\n        this.greetingEl.style.top = `${rect.top - 12}px`;\r\n        this.greetingEl.style.bottom = 'auto';\r\n      }\r\n    };\r\n    positionBubble();\r\n    const onResize = () => positionBubble();\r\n    window.addEventListener('resize', onResize);\r\n    window.addEventListener('scroll', onResize, true);\r\n\r\n    // Give the FAB a moment of expressive greeting — wave face + a\r\n    // little scale bounce. Both revert on dismiss.\r\n    const wasFace = this.currentFace;\r\n    const wasState = this.currentState;\r\n    this.setFace(opts.faceSlug ?? 'smile');\r\n    this.fabEl.setAttribute('data-greeting', '');\r\n\r\n    // Reveal after next frame so CSS transition on data-visible works.\r\n    requestAnimationFrame(() => bubble.setAttribute('data-visible', ''));\r\n\r\n    return new Promise<void>((resolve) => {\r\n      const dismiss = () => {\r\n        this.hideGreeting();\r\n        // Revert face/state to what they were before the greeting.\r\n        this.setFace(wasFace);\r\n        this.setState(wasState);\r\n        window.removeEventListener('resize', onResize);\r\n        window.removeEventListener('scroll', onResize, true);\r\n        resolve();\r\n      };\r\n      this.greetingDismiss = dismiss;\r\n\r\n      // Anywhere-click dismisses the greeting. Capture-phase so it\r\n      // wins against page handlers; skip clicks on the FAB itself so\r\n      // the FAB's own tap handler still runs.\r\n      const onClickAnywhere = (e: Event) => {\r\n        const t = e.target as Node | null;\r\n        if (t && this.fabEl?.contains(t)) return;\r\n        if (t && bubble.contains(t)) return;\r\n        document.removeEventListener('click', onClickAnywhere, true);\r\n        document.removeEventListener('touchstart', onClickAnywhere, true);\r\n        dismiss();\r\n      };\r\n      // Defer registration so the click that opened the greeting\r\n      // doesn't immediately dismiss it.\r\n      requestAnimationFrame(() => {\r\n        document.addEventListener('click', onClickAnywhere, true);\r\n        document.addEventListener('touchstart', onClickAnywhere, true);\r\n      });\r\n\r\n      if (opts.autoDismissMs && opts.autoDismissMs > 0) {\r\n        setTimeout(() => {\r\n          document.removeEventListener('click', onClickAnywhere, true);\r\n          document.removeEventListener('touchstart', onClickAnywhere, true);\r\n          dismiss();\r\n        }, opts.autoDismissMs);\r\n      }\r\n    });\r\n  }\r\n\r\n  /** Force-dismiss any greeting bubble currently on screen. */\r\n  hideGreeting(): void {\r\n    if (this.greetingEl) {\r\n      this.greetingEl.remove();\r\n      this.greetingEl = null;\r\n    }\r\n    if (this.fabEl) this.fabEl.removeAttribute('data-greeting');\r\n    // NOTE: does not resolve the outstanding showGreeting() promise\r\n    // if called externally — greetingDismiss is only cleared when\r\n    // dismiss() runs from inside showGreeting.\r\n    this.greetingDismiss = null;\r\n  }\r\n\r\n  /** One-shot celebration animation — bounces + shows `done` face,\r\n   *  then returns to previous state after ~1.2s. Useful after the\r\n   *  agent completes a positive action. */\r\n  celebrate(): void {\r\n    if (!this.fabEl) return;\r\n    const prev = this.currentState;\r\n    this.setState('done');\r\n    setTimeout(() => {\r\n      if (this.currentState === 'done') this.setState(prev === 'done' ? 'idle' : prev);\r\n    }, 1200);\r\n  }\r\n\r\n  /**\r\n   * Choreography: tilt the FAB TOWARD a target rect for ~700ms then\r\n   * settle back. Reads as \"the duck notices something happened over\r\n   * there\" — used when the subtitle bar opens, when a proactive\r\n   * prompt materializes, or when a distant piece of UI catches the\r\n   * user's attention.\r\n   *\r\n   * The tilt is a 12° head lean toward the target's centre; the CSS\r\n   * animation composes with the idle bob so the head reads as\r\n   * momentarily looking, not teleporting. Passing `null` cancels.\r\n   */\r\n  glanceAt(target: { x: number; y: number } | DOMRect | null): void {\r\n    if (!this.fabEl) return;\r\n    if (!target) {\r\n      this.fabEl.removeAttribute('data-glance');\r\n      this.fabEl.style.removeProperty('--dddk-fab-glance-angle');\r\n      return;\r\n    }\r\n    const rect = this.fabEl.getBoundingClientRect();\r\n    const cx = rect.left + rect.width / 2;\r\n    const cy = rect.top + rect.height / 2;\r\n    const hasXY = 'x' in target && 'y' in target;\r\n    const px = hasXY ? (target as { x: number }).x : (target as DOMRect).left + (target as DOMRect).width / 2;\r\n    const py = hasXY ? (target as { y: number }).y : (target as DOMRect).top + (target as DOMRect).height / 2;\r\n    const dx = px - cx;\r\n    const dy = py - cy;\r\n    // Only the horizontal component maps to head tilt; vertical is\r\n    // small enough to ignore. Cap at ±12° so the tilt reads without\r\n    // looking cartoonish.\r\n    const angleDeg = Math.max(-12, Math.min(12, (dx / 200) * 12));\r\n    void dy;\r\n    this.fabEl.style.setProperty('--dddk-fab-glance-angle', `${angleDeg.toFixed(1)}deg`);\r\n    this.fabEl.setAttribute('data-glance', '');\r\n    setTimeout(() => { this.fabEl?.removeAttribute('data-glance'); }, 800);\r\n  }\r\n\r\n  // ─── chrome construction ───────────────────────────────────────\r\n\r\n  private mountChrome(): void {\r\n    const top = document.createElement('div');\r\n    top.setAttribute(UI_ATTR, 'mobile-top');\r\n    top.innerHTML = `\r\n      <button type=\"button\" class=\"mt-palette\" aria-label=\"Open command palette\">\r\n        <span aria-hidden>🔍</span>\r\n        <span class=\"mt-text\">Palette</span>\r\n      </button>\r\n      <button type=\"button\" class=\"mt-close\" aria-label=\"Close mobile chrome\">✕</button>\r\n    `;\r\n    top.querySelector<HTMLButtonElement>('.mt-palette')!.onclick = () => {\r\n      this.dddk?.palette.toggle();\r\n    };\r\n    top.querySelector<HTMLButtonElement>('.mt-close')!.onclick = () => this.hide();\r\n    document.body.appendChild(top);\r\n    this.topBar = top;\r\n\r\n    const bottom = document.createElement('div');\r\n    bottom.setAttribute(UI_ATTR, 'mobile-bottom');\r\n    bottom.innerHTML = `<button type=\"button\" class=\"mt-center\" aria-label=\"Voice / accept / reject\"></button>`;\r\n    const center = bottom.querySelector<HTMLButtonElement>('.mt-center')!;\r\n    this.bindCenterButton(center);\r\n    document.body.appendChild(bottom);\r\n    this.bottomBar = bottom;\r\n\r\n    // Click-through interception: when chrome visible AND user opted in,\r\n    // taps on page elements fire palette_open with the tapped element's\r\n    // selector. Default OFF — most users want the page to stay normal.\r\n    // Toggled via `setDwellOnTap(true)` at runtime.\r\n    const onPageClick = (e: MouseEvent | TouchEvent) => {\r\n      if (!this.visible) return;\r\n      if (!this.dwellOnTap) return; // page taps work normally\r\n      const target = e.target as HTMLElement | null;\r\n      if (!target) return;\r\n      // Skip our own chrome.\r\n      if (target.closest(`[${UI_ATTR}=\"mobile-top\"]`) || target.closest(`[${UI_ATTR}=\"mobile-bottom\"]`)) return;\r\n      e.preventDefault();\r\n      e.stopPropagation();\r\n      const selector = inferSelector(target) || null;\r\n      this.dddk?.palette.toggle(selector ?? target.textContent ?? '');\r\n    };\r\n    document.addEventListener('click', onPageClick, true);\r\n    this.cleanups.push(() => document.removeEventListener('click', onPageClick, true));\r\n  }\r\n\r\n  /**\r\n   * Center button mimics desktop Space gesture:\r\n   *   - single tap         → accept\r\n   *   - double tap (< 350) → reject\r\n   *   - long press (200ms) → voice_start\r\n   */\r\n  private bindCenterButton(btn: HTMLButtonElement): void {\r\n    const dddk = this.dddk;\r\n    if (!dddk) return;\r\n\r\n    const press = () => {\r\n      this.longPressTimer = setTimeout(() => {\r\n        this.longPressTimer = null;\r\n        document.dispatchEvent(new CustomEvent('dddk:mobile-voice-start'));\r\n      }, this.cfg.longPressMs);\r\n    };\r\n\r\n    const release = () => {\r\n      if (this.longPressTimer) {\r\n        clearTimeout(this.longPressTimer);\r\n        this.longPressTimer = null;\r\n        // Wasn't long-press → it's a tap. Distinguish single vs double.\r\n        const now = Date.now();\r\n        if (now - this.lastTapAt < this.cfg.doubleTapMs) {\r\n          // Double tap\r\n          if (this.singleTapTimer) {\r\n            clearTimeout(this.singleTapTimer);\r\n            this.singleTapTimer = null;\r\n          }\r\n          this.lastTapAt = 0;\r\n          document.dispatchEvent(new CustomEvent('dddk:mobile-reject'));\r\n        } else {\r\n          // Maybe single — wait the double window\r\n          this.lastTapAt = now;\r\n          this.singleTapTimer = setTimeout(() => {\r\n            this.singleTapTimer = null;\r\n            document.dispatchEvent(new CustomEvent('dddk:mobile-accept'));\r\n          }, this.cfg.doubleTapMs);\r\n        }\r\n      } else {\r\n        // Long-press already fired voice_start. Voice end signal.\r\n        document.dispatchEvent(new CustomEvent('dddk:mobile-voice-end'));\r\n      }\r\n    };\r\n\r\n    btn.addEventListener('touchstart', (e) => { e.preventDefault(); press(); }, { passive: false });\r\n    btn.addEventListener('touchend',   (e) => { e.preventDefault(); release(); }, { passive: false });\r\n    btn.addEventListener('mousedown',  press);\r\n    btn.addEventListener('mouseup',    release);\r\n    btn.addEventListener('mouseleave', () => {\r\n      if (this.longPressTimer) {\r\n        clearTimeout(this.longPressTimer);\r\n        this.longPressTimer = null;\r\n      }\r\n    });\r\n  }\r\n\r\n  // ─── swipe detector — rapid up/down reversals ───────────────────\r\n\r\n  private bindSwipeDetector(): void {\r\n    const onTouchStart = (e: TouchEvent) => {\r\n      if (e.touches.length !== 1) return;\r\n      const t = e.touches[0]!;\r\n      this.samples = [{ y: t.clientY, t: Date.now(), dir: null }];\r\n    };\r\n\r\n    const onTouchMove = (e: TouchEvent) => {\r\n      if (e.touches.length !== 1) return;\r\n      const t = e.touches[0]!;\r\n      const now = Date.now();\r\n      const last = this.samples[this.samples.length - 1];\r\n      if (!last) return;\r\n      const dy = t.clientY - last.y;\r\n      if (Math.abs(dy) < this.cfg.minSwipeDelta) return;\r\n      const dir: 'up' | 'down' = dy < 0 ? 'up' : 'down';\r\n      this.samples.push({ y: t.clientY, t: now, dir });\r\n      this.trimSamples(now);\r\n      if (this.countReversals() >= this.cfg.reversalsToTrigger) {\r\n        this.samples = [];\r\n        this.toggle();\r\n      }\r\n    };\r\n\r\n    const onTouchEnd = () => {\r\n      this.samples = [];\r\n    };\r\n\r\n    document.addEventListener('touchstart', onTouchStart, { passive: true });\r\n    document.addEventListener('touchmove',  onTouchMove,  { passive: true });\r\n    document.addEventListener('touchend',   onTouchEnd,   { passive: true });\r\n\r\n    this.cleanups.push(() => document.removeEventListener('touchstart', onTouchStart));\r\n    this.cleanups.push(() => document.removeEventListener('touchmove',  onTouchMove));\r\n    this.cleanups.push(() => document.removeEventListener('touchend',   onTouchEnd));\r\n  }\r\n\r\n  private trimSamples(now: number): void {\r\n    const cutoff = now - this.cfg.swipeWindowMs;\r\n    this.samples = this.samples.filter((s) => s.t >= cutoff);\r\n  }\r\n\r\n  /** Count direction reversals (up→down or down→up) in current sample buffer. */\r\n  private countReversals(): number {\r\n    let reversals = 0;\r\n    let prev: 'up' | 'down' | null = null;\r\n    for (const s of this.samples) {\r\n      if (s.dir && prev && s.dir !== prev) reversals += 1;\r\n      if (s.dir) prev = s.dir;\r\n    }\r\n    return reversals;\r\n  }\r\n}\r\n\r\n// ─── helpers ────────────────────────────────────────────────────────\r\n\r\nfunction isTouchDevice(): boolean {\r\n  if (typeof window === 'undefined') return false;\r\n  return 'ontouchstart' in window || (navigator.maxTouchPoints ?? 0) > 0;\r\n}\r\n\r\n/**\r\n * Narrow viewport detection — mobile / tablet portrait. Independent of touch\r\n * capability so DevTools \"responsive mode\" on a desktop browser triggers it.\r\n */\r\nfunction isMobileViewport(): boolean {\r\n  if (typeof window === 'undefined') return false;\r\n  return window.matchMedia('(max-width: 768px)').matches;\r\n}\r\n\r\nconst DEFAULT_FAB_SVG = `\r\n<svg viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"none\" stroke=\"currentColor\"\r\n  stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n  <path d=\"m12 3-1.9 5.8a2 2 0 0 1-1.3 1.3L3 12l5.8 1.9a2 2 0 0 1 1.3 1.3L12 21l1.9-5.8a2 2 0 0 1 1.3-1.3L21 12l-5.8-1.9a2 2 0 0 1-1.3-1.3Z\"/>\r\n  <path d=\"M5 3v4M19 17v4M3 5h4M17 19h4\"/>\r\n</svg>\r\n`.trim();\r\n\r\nfunction ensureStyles(): void {\r\n  injectScopedStyle(STYLE_ID, `\r\n    /* Top semi-transparent bar */\r\n    [${UI_ATTR}=\"mobile-top\"] {\r\n      position: fixed; top: 0; left: 0; right: 0;\r\n      display: flex; align-items: center; justify-content: space-between;\r\n      padding: env(safe-area-inset-top, 8px) 16px 8px 16px;\r\n      background: var(--dddk-mobile-bar, rgba(255,255,255,0.78));\r\n      backdrop-filter: blur(12px);\r\n      -webkit-backdrop-filter: blur(12px);\r\n      border-bottom: 1px solid var(--dddk-border, rgba(0,0,0,0.08));\r\n      z-index: var(--dddk-z-bar, 9700);\r\n      transform: translateY(-110%);\r\n      transition: transform 0.25s cubic-bezier(0.2,0.8,0.2,1);\r\n    }\r\n    [${UI_ATTR}=\"mobile-top\"][data-visible] { transform: translateY(0); }\r\n\r\n    [${UI_ATTR}=\"mobile-top\"] button {\r\n      background: transparent; border: 0; cursor: pointer;\r\n      font: inherit; color: var(--dddk-text, #18181b);\r\n      padding: 8px 12px; border-radius: 8px;\r\n      display: inline-flex; align-items: center; gap: 6px;\r\n    }\r\n    [${UI_ATTR}=\"mobile-top\"] button:active {\r\n      background: var(--dddk-accent-soft, rgba(139,115,85,0.12));\r\n    }\r\n    [${UI_ATTR}=\"mobile-top\"] .mt-text { font-size: 13px; font-weight: 600; }\r\n    [${UI_ATTR}=\"mobile-top\"] .mt-close { font-size: 18px; line-height: 1; padding: 8px 14px; }\r\n\r\n    /* Bottom semi-transparent bar with circular center button */\r\n    [${UI_ATTR}=\"mobile-bottom\"] {\r\n      position: fixed; left: 0; right: 0; bottom: 0;\r\n      display: flex; align-items: center; justify-content: center;\r\n      padding: 12px 16px calc(env(safe-area-inset-bottom, 0px) + 12px) 16px;\r\n      background: var(--dddk-mobile-bar, rgba(255,255,255,0.78));\r\n      backdrop-filter: blur(12px);\r\n      -webkit-backdrop-filter: blur(12px);\r\n      border-top: 1px solid var(--dddk-border, rgba(0,0,0,0.08));\r\n      z-index: var(--dddk-z-bar, 9700);\r\n      transform: translateY(110%);\r\n      transition: transform 0.25s cubic-bezier(0.2,0.8,0.2,1);\r\n    }\r\n    [${UI_ATTR}=\"mobile-bottom\"][data-visible] { transform: translateY(0); }\r\n\r\n    [${UI_ATTR}=\"mobile-bottom\"] .mt-center {\r\n      width: 64px; height: 64px; border-radius: 50%;\r\n      background: var(--dddk-accent, #ec4899);\r\n      border: 0; cursor: pointer;\r\n      box-shadow: 0 6px 20px rgba(0,0,0,0.18);\r\n      transition: transform 0.1s, box-shadow 0.15s;\r\n    }\r\n    [${UI_ATTR}=\"mobile-bottom\"] .mt-center:active {\r\n      transform: scale(0.92);\r\n      box-shadow: 0 2px 8px rgba(0,0,0,0.2);\r\n    }\r\n\r\n    /* Floating Action Button (FAB) — default mobile entry point.\r\n       Hosts can fully override via MobileFABConfig.style or by passing\r\n       className and writing their own CSS.\r\n\r\n       z-index = 10000 — ABOVE every other dddk surface (palette 9700,\r\n       subtitle 9950, cursor 9990). The FAB is the user's only way to\r\n       accept/reject the agent on mobile (replaces Space gesture), so\r\n       any surface that hides it strands the user with no input path.\r\n       Stays on top even when palette / confirm modal is open. */\r\n    [${UI_ATTR}=\"mobile-fab\"] {\r\n      position: fixed;\r\n      z-index: 10000;\r\n      background: var(--dddk-accent, #ec4899);\r\n      color: var(--dddk-text-on-accent, #fff);\r\n      border: 0;\r\n      cursor: pointer;\r\n      box-shadow: var(--dddk-shadow-md, 0 6px 20px rgba(0,0,0,0.18));\r\n      display: inline-flex;\r\n      align-items: center;\r\n      justify-content: center;\r\n      font: inherit;\r\n      transition: transform 0.1s ease-out, box-shadow 0.15s ease-out;\r\n      -webkit-tap-highlight-color: transparent;\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"]:active {\r\n      transform: scale(0.94);\r\n      box-shadow: var(--dddk-shadow-sm, 0 2px 8px rgba(0,0,0,0.2));\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"]:focus-visible {\r\n      outline: 2px solid var(--dddk-accent, #ec4899);\r\n      outline-offset: 3px;\r\n    }\r\n\r\n    /* ── mascot mode — face-image FAB ─────────────────────────────\r\n       When alwaysVisible + faces are configured, the FAB shows a\r\n       transparent duck-head PNG on every viewport. Face-mode buttons\r\n       carry a data-face attribute (set by setFace) and a data-state\r\n       attribute (set by setState). Both drive the CSS below.\r\n\r\n       The desktop-hide media query is intentionally scoped to\r\n       :not([data-face]) so face-mode FABs stay visible everywhere.\r\n       Legacy (icon-only) FABs still hide on real desktop. */\r\n    @media (min-width: 769px) and (hover: hover) and (pointer: fine) {\r\n      [${UI_ATTR}=\"mobile-fab\"]:not([data-face]) {\r\n        display: none;\r\n      }\r\n    }\r\n\r\n    /* Face-mode FAB — the yellow duck head is the whole visual.\r\n       Zero button chrome so the transparent PNG reads as a floating\r\n       character, not a button. Focus outline still works for a11y.\r\n       data-enter=\"fresh\" plays a one-shot pop-in scale animation on\r\n       first mount (host sets it via a class or opt-in flag). */\r\n    [${UI_ATTR}=\"mobile-fab\"][data-face] {\r\n      background: transparent;\r\n      box-shadow: none;\r\n      padding: 0;\r\n      overflow: visible; /* so bob/celebrate + ripple bursts aren't clipped */\r\n    }\r\n\r\n    /* Pupils — two overlays that ride the neutral face's eye sockets\r\n       and follow the cursor via JS-set transform. Coordinates are\r\n       percentage-based on the 512×512 face artwork so the pupils sit\r\n       correctly regardless of button size. Only visible when the face\r\n       IS neutral (other faces have their own eyes baked in). */\r\n    [${UI_ATTR}=\"fab-pupil\"] {\r\n      position: absolute;\r\n      width: 12%;\r\n      height: 12%;\r\n      border-radius: 50%;\r\n      background: #10182f;\r\n      /* Pupils are inside the yellow head silhouette (~15% inset from\r\n         edge). Left pupil ~28% from left, right ~60%. Vertical ~34%. */\r\n      top: 34%;\r\n      pointer-events: none;\r\n      transition: opacity 0.24s ease-out;\r\n      /* Small highlight — a tiny white dot on the upper-left of the\r\n         pupil. Uses radial-gradient so it moves with the pupil. */\r\n      background:\r\n        radial-gradient(circle at 32% 30%, #ffffff 0 14%, transparent 15%),\r\n        #10182f;\r\n    }\r\n    [${UI_ATTR}=\"fab-pupil\"][data-side=\"left\"]  { left: 28%; }\r\n    [${UI_ATTR}=\"fab-pupil\"][data-side=\"right\"] { left: 60%; }\r\n    /* Hide pupils when the face isn't neutral — the other faces have\r\n       their own emotional eye art we don't want to double-print. */\r\n    [${UI_ATTR}=\"mobile-fab\"][data-face]:not([data-face=\"neutral\"]) [${UI_ATTR}=\"fab-pupil\"] {\r\n      opacity: 0;\r\n    }\r\n\r\n    /* Ripple burst — replays on every setState. Emits a warm-yellow\r\n       water ring outward from the FAB centre so the state change\r\n       reads as a physical impulse, not a silent class swap. */\r\n    [${UI_ATTR}=\"mobile-fab\"][data-face] > .dddk-fab-ripple {\r\n      /* placeholder for a proper JS-injected ripple; the CSS below\r\n         handles the CSS-only version via data-ripple. */\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"][data-face][data-ripple]::before {\r\n      /* Overrides the scroll-ripple ::before that also uses this\r\n         selector — replays the burst regardless of scroll state. */\r\n      content: '';\r\n      position: absolute;\r\n      inset: 0;\r\n      border-radius: 50%;\r\n      animation: dddk-fab-state-ripple 900ms cubic-bezier(0.16, 1, 0.3, 1) forwards;\r\n      pointer-events: none;\r\n    }\r\n    @keyframes dddk-fab-state-ripple {\r\n      0%   { box-shadow:\r\n              0 0 0 0  rgba(255,220,80,0.75),\r\n              0 0 0 0  rgba(255,220,80,0.55);\r\n            }\r\n      100% { box-shadow:\r\n              0 0 0 30px rgba(255,220,80,0),\r\n              0 0 0 18px rgba(255,220,80,0);\r\n            }\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"][data-face][data-enter=\"fresh\"] {\r\n      animation: dddk-fab-enter 950ms cubic-bezier(0.16, 1, 0.3, 1) both;\r\n    }\r\n    /* Entrance choreography (Disney's twelve principles applied):\r\n         · anticipation — drop below start position + squash\r\n         · action     — spring up past target (overshoot)\r\n         · follow-through — settle back with damped oscillation\r\n       Not just \"scale 0 → 1 with a bounce\". Real feel-alive motion. */\r\n    @keyframes dddk-fab-enter {\r\n      0%   { transform: translateY(30px) scale(0.4, 0.55); opacity: 0; }\r\n      20%  { transform: translateY(18px) scale(0.7, 0.65); opacity: 0.6; }\r\n      45%  { transform: translateY(-12px) scale(1.14, 0.94); opacity: 1; }\r\n      65%  { transform: translateY(4px)  scale(0.94, 1.08); opacity: 1; }\r\n      82%  { transform: translateY(-2px) scale(1.03, 0.98); }\r\n      100% { transform: translateY(0)    scale(1); }\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"][data-face]:active {\r\n      transform: scale(0.92);\r\n    }\r\n\r\n    /* Glance-at choreography: on setState-triggered attention (host\r\n       calls glanceAt(rect)), the head briefly leans horizontally\r\n       toward the target. Overrides idle bob for ~800ms; smooth\r\n       cubic-bezier so the tilt feels like a natural head turn. */\r\n    @keyframes dddk-fab-glance {\r\n      0%   { transform: rotate(0); }\r\n      40%  { transform: rotate(var(--dddk-fab-glance-angle, 0deg)); }\r\n      100% { transform: rotate(0); }\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"][data-face][data-glance] {\r\n      animation: dddk-fab-glance 800ms cubic-bezier(0.4, 0, 0.2, 1) !important;\r\n    }\r\n\r\n    /* Idle bob — physics-inspired float on water: up-down coupled\r\n       with a small rotation swing so the head reads as bobbing on\r\n       a wave rather than an elevator ride. Non-integer duration\r\n       decouples the phase from other on-screen loops. */\r\n    @keyframes dddk-fab-bob {\r\n      0%   { transform: translateY(0)    rotate(-1.2deg); }\r\n      25%  { transform: translateY(-3px) rotate(0deg); }\r\n      50%  { transform: translateY(-4px) rotate(1.4deg); }\r\n      75%  { transform: translateY(-2px) rotate(0.4deg); }\r\n      100% { transform: translateY(0)    rotate(-1.2deg); }\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"][data-state=\"idle\"] {\r\n      animation: dddk-fab-bob 3.4s ease-in-out infinite;\r\n    }\r\n\r\n    /* Thinking — the duck no longer spins (rotating a face read as\r\n       vertigo). Instead a **conic-gradient progress arc** orbits the\r\n       FAB, giving a proper \"cooking\" feel while the face stays\r\n       upright. Face already switches to the thinking expression via\r\n       setState. */\r\n    [${UI_ATTR}=\"mobile-fab\"][data-state=\"thinking\"] {\r\n      animation: dddk-fab-listen 1.8s ease-in-out infinite;\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"][data-state=\"thinking\"]::after {\r\n      content: '';\r\n      position: absolute;\r\n      inset: -6px;\r\n      border-radius: 50%;\r\n      /* Circular sweeping arc: a bright yellow wedge orbits the FAB.\r\n         The wedge is drawn via conic-gradient, then masked into a ring\r\n         via inset shadow / border trick. */\r\n      background: conic-gradient(\r\n        from 0deg,\r\n        rgba(255,220,80,0.9) 0deg,\r\n        rgba(255,220,80,0.9) 60deg,\r\n        transparent 100deg,\r\n        transparent 360deg\r\n      );\r\n      -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3.5px), #000 calc(100% - 3px));\r\n              mask: radial-gradient(farthest-side, transparent calc(100% - 3.5px), #000 calc(100% - 3px));\r\n      animation: dddk-fab-orbit 1.4s linear infinite;\r\n      pointer-events: none;\r\n    }\r\n    @keyframes dddk-fab-orbit {\r\n      to { transform: rotate(360deg); }\r\n    }\r\n    /* Legacy spin keyframe retained (used by preview page CSS mirror). */\r\n    @keyframes dddk-fab-spin {\r\n      to { transform: rotate(360deg); }\r\n    }\r\n\r\n    /* Listening — SONAR animation. Two rings emanate outward from\r\n       the FAB edge with staggered timing, plus a warm yellow ambient\r\n       glow. Reads as \"radar actively listening\" — voice is one of\r\n       the most-used interactions and deserves a distinct state, not\r\n       another subtle bob. */\r\n    @keyframes dddk-fab-listen {\r\n      0%, 100% { transform: scale(1); }\r\n      50%      { transform: scale(1.06); }\r\n    }\r\n    @keyframes dddk-fab-sonar {\r\n      0%   { transform: scale(1);   opacity: 0.75; }\r\n      60%  { opacity: 0.35; }\r\n      100% { transform: scale(2.35); opacity: 0; }\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"][data-state=\"listening\"] {\r\n      animation: dddk-fab-listen 1.6s ease-in-out infinite;\r\n      filter: drop-shadow(0 0 20px rgba(255,220,80,0.7));\r\n    }\r\n    /* Two-ring sonar via ::before + ::after. Both loop 1.6s but with\r\n       an 800ms stagger so a new ring emerges just as the previous\r\n       one is halfway out — reads as continuous emanation. */\r\n    [${UI_ATTR}=\"mobile-fab\"][data-state=\"listening\"]::before {\r\n      content: '';\r\n      position: absolute;\r\n      inset: -2px;\r\n      border-radius: 50%;\r\n      border: 2.5px solid rgba(255,220,80,0.85);\r\n      pointer-events: none;\r\n      animation: dddk-fab-sonar 1.6s ease-out infinite;\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"][data-state=\"listening\"]::after {\r\n      content: '';\r\n      position: absolute;\r\n      inset: -2px;\r\n      border-radius: 50%;\r\n      border: 2.5px solid rgba(255,220,80,0.85);\r\n      pointer-events: none;\r\n      opacity: 0;\r\n      transform: scale(1);\r\n      animation: dddk-fab-sonar 1.6s ease-out infinite;\r\n      animation-delay: 0.8s;\r\n    }\r\n\r\n    /* Voice-hold — balloon breathe. The FAB rhythmically inflates and\r\n       deflates while held, reads as \"breathing pressure\" rather than\r\n       a one-shot inflate. Loops until state changes back to idle. The\r\n       warm halo tints the glow yellow-orange (duck accent) instead of\r\n       pink so recording doesn't feel like an error. */\r\n    @keyframes dddk-fab-balloon {\r\n      0%, 100% { transform: scale(1); }\r\n      50%      { transform: scale(1.32); }\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"][data-state=\"voice-hold\"] {\r\n      animation: dddk-fab-balloon 1.4s ease-in-out infinite;\r\n      filter: drop-shadow(0 0 22px rgba(255,190,60,0.55));\r\n    }\r\n\r\n    /* Done — quick pop bounce, then holds (setState will clear). */\r\n    @keyframes dddk-fab-pop {\r\n      0%   { transform: scale(1); }\r\n      40%  { transform: scale(1.18); }\r\n      70%  { transform: scale(0.94); }\r\n      100% { transform: scale(1); }\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"][data-state=\"done\"] {\r\n      animation: dddk-fab-pop 0.7s ease-out;\r\n    }\r\n\r\n    /* Error — small horizontal shake. */\r\n    @keyframes dddk-fab-shake {\r\n      0%, 100% { transform: translateX(0); }\r\n      20%      { transform: translateX(-4px); }\r\n      40%      { transform: translateX(4px); }\r\n      60%      { transform: translateX(-3px); }\r\n      80%      { transform: translateX(3px); }\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"][data-state=\"error\"] {\r\n      animation: dddk-fab-shake 0.5s ease-in-out;\r\n    }\r\n\r\n    /* Scroll ripple — a warm-yellow water ring pulses outward from\r\n       the FAB whenever the page scrolls, as if the duck is bobbing\r\n       on ripples from the scroll motion. Host toggles data-scrolling\r\n       on/off around scroll events; the pseudo animation replays each\r\n       toggle so rapid scrolling reads as continuous ripples. */\r\n    [${UI_ATTR}=\"mobile-fab\"][data-face]::before {\r\n      content: '';\r\n      position: absolute;\r\n      inset: 0;\r\n      border-radius: 50%;\r\n      box-shadow: 0 0 0 0 rgba(255,220,80,0);\r\n      pointer-events: none;\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"][data-face][data-scrolling]::before {\r\n      animation: dddk-fab-scroll-ripple 620ms ease-out;\r\n    }\r\n    @keyframes dddk-fab-scroll-ripple {\r\n      0%   { box-shadow: 0 0 0 0    rgba(255,220,80,0.55); }\r\n      100% { box-shadow: 0 0 0 22px rgba(255,220,80,0);    }\r\n    }\r\n\r\n    /* Hover pulse ring — non-blocking pseudo halo that expands on\r\n       cursor hover, giving desktop users an affordance without\r\n       decorating the FAB itself. */\r\n    [${UI_ATTR}=\"mobile-fab\"][data-face]::after {\r\n      content: '';\r\n      position: absolute;\r\n      inset: -6px;\r\n      border-radius: 50%;\r\n      border: 2px solid rgba(255,220,80,0.55);\r\n      opacity: 0;\r\n      pointer-events: none;\r\n      transition: opacity 0.2s ease-out, transform 0.35s ease-out;\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"][data-face]:hover::after {\r\n      opacity: 1;\r\n      transform: scale(1.08);\r\n    }\r\n\r\n    /* ── HERO greeting (capsule/pill) ─────────────────────────────\r\n       The FAB circle STRETCHES horizontally into a translucent\r\n       yellow capsule. The duck face stays on the right (its original\r\n       corner); the greeting text fills the leftward space that opens\r\n       up. Reads as \"the FAB itself is speaking\" — no separate bubble\r\n       to fight with layout.\r\n\r\n       All shape / colour / motion is CSS-variable-controlled so hosts\r\n       can retheme without touching the SDK:\r\n         --dddk-fab-hero-width          capsule expanded width (default 460px)\r\n         --dddk-fab-hero-height         capsule height (default 88px)\r\n         --dddk-fab-hero-radius         capsule end radius (default 44px)\r\n         --dddk-fab-hero-bg             capsule fill (default warm-yellow gradient)\r\n         --dddk-fab-hero-fg             text colour inside (default #1a2a4a)\r\n         --dddk-fab-hero-padding        content padding (default 14px 90px 14px 22px)\r\n         --dddk-fab-hero-shadow         drop shadow around capsule\r\n         --dddk-fab-hero-transition-ms  morph timing (default 520ms)\r\n         --dddk-fab-hero-easing         morph easing (default spring-out) */\r\n    [${UI_ATTR}=\"mobile-fab\"][data-hero-active] {\r\n      width: var(--dddk-fab-hero-width, min(460px, calc(100vw - 40px))) !important;\r\n      height: var(--dddk-fab-hero-height, 88px) !important;\r\n      border-radius: var(--dddk-fab-hero-radius, 44px) !important;\r\n      background: var(--dddk-fab-hero-bg,\r\n        linear-gradient(135deg,\r\n          rgba(255,244,196,0.98) 0%,\r\n          rgba(255,232,150,0.95) 60%,\r\n          rgba(255,220,100,0.92) 100%\r\n        )\r\n      ) !important;\r\n      box-shadow: var(--dddk-fab-hero-shadow, 0 12px 32px rgba(255,180,40,0.35), 0 4px 12px rgba(0,0,0,0.08)) !important;\r\n      overflow: hidden !important;\r\n      transform: none !important;\r\n      animation: none !important;\r\n      transition:\r\n        width  var(--dddk-fab-hero-transition-ms, 520ms) var(--dddk-fab-hero-easing, cubic-bezier(0.34, 1.4, 0.64, 1)),\r\n        height var(--dddk-fab-hero-transition-ms, 520ms) var(--dddk-fab-hero-easing, cubic-bezier(0.34, 1.4, 0.64, 1)),\r\n        border-radius var(--dddk-fab-hero-transition-ms, 520ms) var(--dddk-fab-hero-easing, cubic-bezier(0.34, 1.4, 0.64, 1)),\r\n        background 320ms ease-out,\r\n        box-shadow 320ms ease-out !important;\r\n      backdrop-filter: blur(8px) saturate(1.1);\r\n      -webkit-backdrop-filter: blur(8px) saturate(1.1);\r\n    }\r\n    /* Duck face inside the pill — anchored to the right edge (its\r\n       original corner). Sized down from full-FAB to leave room for\r\n       the text. */\r\n    [${UI_ATTR}=\"mobile-fab\"][data-hero-active] > span {\r\n      position: absolute !important;\r\n      right: var(--dddk-fab-hero-face-inset, 10px);\r\n      top: 50%;\r\n      transform: translateY(-50%);\r\n      width: var(--dddk-fab-hero-face-size, 68px) !important;\r\n      height: var(--dddk-fab-hero-face-size, 68px) !important;\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"][data-hero-active] > span > img {\r\n      width: 100% !important;\r\n      height: 100% !important;\r\n      object-fit: contain;\r\n    }\r\n    /* Greeting text panel — fills the pill's non-face half. */\r\n    [${UI_ATTR}=\"fab-hero-content\"] {\r\n      position: absolute;\r\n      inset: 0;\r\n      padding: var(--dddk-fab-hero-padding, 12px 90px 12px 22px);\r\n      color: var(--dddk-fab-hero-fg, #1a2a4a);\r\n      font: var(--dddk-fab-hero-font, 600 14px/1.45\r\n        var(--dddk-font, -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"PingFang TC\", sans-serif));\r\n      letter-spacing: 0.005em;\r\n      text-align: left;\r\n      opacity: 0;\r\n      transform: translateX(-8px);\r\n      pointer-events: none;\r\n      display: flex;\r\n      flex-direction: column;\r\n      justify-content: center;\r\n      gap: var(--dddk-fab-hero-gap, 4px);\r\n      overflow: hidden;\r\n      transition:\r\n        opacity 260ms ease-out var(--dddk-fab-hero-content-delay, 220ms),\r\n        transform 320ms ease-out var(--dddk-fab-hero-content-delay, 220ms);\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"][data-hero-active] [${UI_ATTR}=\"fab-hero-content\"] {\r\n      opacity: 1;\r\n      transform: translateX(0);\r\n    }\r\n    /* Content-provided keycap-style badges (used by hosts inlining\r\n       Ctrl / K / Space etc.). */\r\n    [${UI_ATTR}=\"fab-hero-content\"] kbd {\r\n      display: inline-block;\r\n      padding: 1px 6px;\r\n      margin: 0 1px;\r\n      background: rgba(255,255,255,0.85);\r\n      color: var(--dddk-fab-hero-fg, #1a2a4a);\r\n      border: 1px solid rgba(20,30,60,0.15);\r\n      border-radius: 4px;\r\n      box-shadow: 0 1px 0 rgba(20,30,60,0.1);\r\n      font: 600 12px ui-monospace, \"SFMono-Regular\", Menlo, monospace;\r\n    }\r\n\r\n    /* Dismiss: pill contracts back to circle. Content fades first,\r\n       then the width/height/radius run back to the FAB defaults. */\r\n    [${UI_ATTR}=\"mobile-fab\"][data-hero-dismissing] {\r\n      transition:\r\n        width  var(--dddk-fab-hero-transition-ms, 520ms) cubic-bezier(0.5, 0, 0.2, 1),\r\n        height var(--dddk-fab-hero-transition-ms, 520ms) cubic-bezier(0.5, 0, 0.2, 1),\r\n        border-radius var(--dddk-fab-hero-transition-ms, 520ms) cubic-bezier(0.5, 0, 0.2, 1),\r\n        background 320ms ease-out,\r\n        box-shadow 320ms ease-out !important;\r\n      overflow: hidden !important;\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab\"][data-hero-dismissing] [${UI_ATTR}=\"fab-hero-content\"] {\r\n      opacity: 0;\r\n      transition: opacity 160ms ease-out;\r\n    }\r\n\r\n    /* ── HERO greeting (legacy separate-sprite) ───────────────────\r\n       Old design left in place for hosts wiring their own hero\r\n       elements; unused by the current showHeroGreeting.  Kept to\r\n       avoid breaking third-party CSS overrides. */\r\n    [${UI_ATTR}=\"fab-hero\"] {\r\n      position: fixed;\r\n      width: min(30vw, 240px);\r\n      height: min(30vw, 240px);\r\n      /* Duck sits IN FRONT of the bubble — semantically the character\r\n         is the foreground, the text label is a soft caption behind it. */\r\n      z-index: 10003;\r\n      pointer-events: none;\r\n      opacity: 0;\r\n      transform-origin: bottom right;\r\n      transform: scale(0.15) translate(60%, 60%);\r\n      transition:\r\n        opacity 320ms ease-out,\r\n        transform 720ms cubic-bezier(0.16, 1.2, 0.3, 1);\r\n    }\r\n    [${UI_ATTR}=\"fab-hero\"][data-corner*=\"left\"]  { transform-origin: bottom left;  transform: scale(0.15) translate(-60%, 60%); }\r\n    [${UI_ATTR}=\"fab-hero\"][data-corner*=\"top\"]   { transform-origin: top right;    transform: scale(0.15) translate(60%, -60%); }\r\n    [${UI_ATTR}=\"fab-hero\"][data-corner*=\"top\"][data-corner*=\"left\"] { transform-origin: top left; transform: scale(0.15) translate(-60%, -60%); }\r\n    [${UI_ATTR}=\"fab-hero\"][data-visible] {\r\n      opacity: 1;\r\n      transform: scale(1) translate(0, 0);\r\n      animation: dddk-fab-hero-bob 3.6s ease-in-out infinite 720ms;\r\n    }\r\n    [${UI_ATTR}=\"fab-hero\"][data-dismissing] {\r\n      opacity: 0;\r\n      transform: scale(0.15) translate(60%, 60%);\r\n      transition:\r\n        opacity 240ms ease-in 60ms,\r\n        transform 420ms cubic-bezier(0.5, 0, 0.75, 0);\r\n    }\r\n    [${UI_ATTR}=\"fab-hero\"] img {\r\n      width: 100%;\r\n      height: 100%;\r\n      object-fit: contain;\r\n      display: block;\r\n      filter: drop-shadow(0 12px 24px rgba(30,60,120,0.18));\r\n    }\r\n    @keyframes dddk-fab-hero-bob {\r\n      /* Larger sprite = smaller rotation angle. What reads as a subtle\r\n         float on a 52px FAB reads as a drunken wobble at 240px.\r\n         Kept translation but toned rotation to a hair. */\r\n      0%   { transform: translateY(0)    rotate(-0.6deg); }\r\n      50%  { transform: translateY(-6px) rotate(0.6deg); }\r\n      100% { transform: translateY(0)    rotate(-0.6deg); }\r\n    }\r\n\r\n    /* HERO greeting text — deliberately NOT a rigid chat bubble. Text\r\n       floats over the page with a soft warm-yellow radial gradient\r\n       behind it (fades to transparent at edges) so it reads clearly\r\n       against any background without a hard box drawn around it. No\r\n       tail, no border. Feels like a caption or a hand-lettered sign\r\n       hovering near the mascot rather than a UI chat window. */\r\n    [${UI_ATTR}=\"fab-hero-bubble\"] {\r\n      position: fixed;\r\n      /* Behind the duck (10003). The bubble is a soft caption; the\r\n         duck is the character. Duck occlusion feels natural. */\r\n      z-index: 10001;\r\n      max-width: min(60vw, 380px);\r\n      padding: 22px 28px;\r\n      /* Dense warm-white centre so text sits on a fully opaque field —\r\n         no bleed-through from posters / images beneath. Only the outer\r\n         ~15% fades to transparent so the edge dissolves softly. */\r\n      background:\r\n        radial-gradient(\r\n          ellipse at center,\r\n          #fffaea 0%,\r\n          rgba(255,246,214,0.98) 55%,\r\n          rgba(255,240,200,0.9)  82%,\r\n          rgba(255,240,200,0)    100%\r\n        );\r\n      /* Blur whatever's behind so any bleed at the fade edge reads as\r\n         atmosphere, not competing content. */\r\n      backdrop-filter: blur(10px) saturate(1.15);\r\n      -webkit-backdrop-filter: blur(10px) saturate(1.15);\r\n      color: #18181b;\r\n      font: 600 16.5px/1.55 var(--dddk-font, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif);\r\n      letter-spacing: 0.005em;\r\n      text-shadow: 0 1px 0 rgba(255,255,255,0.6);\r\n      /* Soft warm glow — reads as light, not a chat box. */\r\n      filter: drop-shadow(0 10px 28px rgba(255,180,40,0.28));\r\n      opacity: 0;\r\n      transform: translateY(20px) scale(0.85);\r\n      transform-origin: bottom right;\r\n      transition:\r\n        opacity 300ms ease-out 280ms,\r\n        transform 620ms cubic-bezier(0.34, 1.6, 0.64, 1) 280ms;\r\n      pointer-events: auto;\r\n    }\r\n    /* kbd-style key inside the greeting text — makes \"Ctrl+K\" look\r\n       like an actual keycap so users read it as a keyboard shortcut. */\r\n    [${UI_ATTR}=\"fab-hero-bubble\"] kbd {\r\n      display: inline-block;\r\n      padding: 2px 8px;\r\n      margin: 0 2px;\r\n      background: #ffffff;\r\n      color: #1a2a4a;\r\n      border: 1px solid rgba(20,30,60,0.18);\r\n      border-radius: 5px;\r\n      box-shadow: 0 1px 0 rgba(20,30,60,0.18);\r\n      font: 600 13.5px ui-monospace, \"SFMono-Regular\", Menlo, monospace;\r\n      vertical-align: 2px;\r\n    }\r\n    [${UI_ATTR}=\"fab-hero-bubble\"][data-visible] {\r\n      opacity: 1;\r\n      transform: translateY(0) scale(1);\r\n    }\r\n    [${UI_ATTR}=\"fab-hero-bubble\"][data-side=\"left\"] { transform-origin: bottom right; }\r\n    [${UI_ATTR}=\"fab-hero-bubble\"][data-side=\"right\"] { transform-origin: bottom left; }\r\n\r\n    /* Greeting bubble — anchored beside the FAB, tail points at it. */\r\n    [${UI_ATTR}=\"mobile-fab-greeting\"] {\r\n      position: fixed;\r\n      z-index: 10001;\r\n      max-width: min(70vw, 340px);\r\n      padding: 12px 16px;\r\n      background: var(--dddk-surface, #ffffff);\r\n      color: var(--dddk-text, #18181b);\r\n      border: 1px solid var(--dddk-border, rgba(0,0,0,0.08));\r\n      border-radius: 16px;\r\n      box-shadow: 0 12px 32px rgba(0,0,0,0.14), 0 2px 6px rgba(0,0,0,0.06);\r\n      font: 14px/1.4 var(--dddk-font, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif);\r\n      opacity: 0;\r\n      transform: translateY(14px) scale(0.7);\r\n      /* Spring-mimicking cubic-bezier: overshoots at ~1.02× then\r\n         settles. Feels bouncy without a physics library. */\r\n      transition:\r\n        opacity 0.28s ease-out,\r\n        transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);\r\n      pointer-events: none;\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab-greeting\"][data-visible] {\r\n      opacity: 1;\r\n      transform: translateY(0) scale(1);\r\n    }\r\n    /* Bubble tail — small pointer toward the FAB. Direction set via\r\n       data-side (matches which side of the FAB we're anchored on). */\r\n    [${UI_ATTR}=\"mobile-fab-greeting\"][data-side=\"left\"] {\r\n      transform-origin: bottom right;\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab-greeting\"][data-side=\"left\"]::after {\r\n      content: '';\r\n      position: absolute;\r\n      right: -6px;\r\n      bottom: 18px;\r\n      width: 12px;\r\n      height: 12px;\r\n      background: var(--dddk-surface, #ffffff);\r\n      border-right: 1px solid var(--dddk-border, rgba(0,0,0,0.08));\r\n      border-bottom: 1px solid var(--dddk-border, rgba(0,0,0,0.08));\r\n      transform: rotate(-45deg);\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab-greeting\"][data-side=\"right\"] {\r\n      transform-origin: bottom left;\r\n    }\r\n    [${UI_ATTR}=\"mobile-fab-greeting\"][data-side=\"right\"]::after {\r\n      content: '';\r\n      position: absolute;\r\n      left: -6px;\r\n      bottom: 18px;\r\n      width: 12px;\r\n      height: 12px;\r\n      background: var(--dddk-surface, #ffffff);\r\n      border-left: 1px solid var(--dddk-border, rgba(0,0,0,0.08));\r\n      border-bottom: 1px solid var(--dddk-border, rgba(0,0,0,0.08));\r\n      transform: rotate(45deg);\r\n    }\r\n\r\n    /* Respect motion preferences — kill all decorative loops. */\r\n    @media (prefers-reduced-motion: reduce) {\r\n      [${UI_ATTR}=\"mobile-fab\"][data-state=\"idle\"],\r\n      [${UI_ATTR}=\"mobile-fab\"][data-state=\"thinking\"],\r\n      [${UI_ATTR}=\"mobile-fab\"][data-state=\"listening\"] {\r\n        animation: none;\r\n      }\r\n    }\r\n  `);\r\n}\r\n","/**\n * Runtime sprite-URL setup.\n *\n * Why this exists. The SDK ships seven PNGs in `dist/duck/` and\n * `tokens.css` declares `--dddk-avatar-url: url('./duck/neutral.png')`\n * etc. In a Vite / Webpack app that imports the SDK's `styles.css`,\n * those relative URLs get resolved + hashed at build time and\n * generally work. **But** three SDK subsystems (Dwell, palette\n * cursor, palette footer brand mark) inject their own `<style>`\n * blocks at runtime that reference the same `--dddk-*-url` variables\n * via `background-image: var(...)`. Chrome resolves `url()` inside\n * runtime-injected styles against the DOCUMENT URL — not the source\n * CSS file — so the SDK's relative `./duck/…` breaks on subdirectory\n * hosts and on any setup that isn't standard Vite production.\n *\n * The fix. At `DotDotDuck` construction time, compute the sprite URLs\n * from `new URL('./duck/x.png', import.meta.url)`. Bundlers (Vite,\n * Webpack, esbuild) recognise this pattern and process the referenced\n * PNGs as assets — copying to the bundler's output dir + rewriting\n * the string at build time — so hosts using standard bundlers get\n * URLs that always resolve without any explicit configuration. For\n * non-bundler setups (esm.sh, raw `<script type=\"module\">`) the URLs\n * resolve against the SDK JS's actual location, which is where the\n * PNGs also live.\n *\n * We set the resolved URLs on `document.documentElement.style` (inline\n * style, wins over CSS declarations without `!important`). Hosts\n * wanting to override for their own brand still use `autoInstall({\n * sprites: { avatar: '/my-brand/mascot.png' } })` — that override\n * beats the runtime default because we consult it before setting.\n */\n\nexport interface SpriteOverrides {\n  /** Subtitle bar / Dwell chip / FAB fallback (`--dddk-avatar-url`). */\n  avatar?: string;\n  /** Proactive swim indicator, subtitle swim relay (`--dddk-swim-url`). */\n  swim?: string;\n  /** HERO capsule big-reveal sprite (`--dddk-hero-url`). */\n  hero?: string;\n  /** Dwell frame corner mascot (`--dddk-chill-url`). */\n  chill?: string;\n  /** Dwell top-edge 8-frame spritesheet (`--dddk-swim-cycle-url`). */\n  swimCycle?: string;\n  /** Palette \"Powered by dotdotduck\" brand mark (`--dddk-brand-mark-url`). */\n  brandMark?: string;\n  /** WebAgent synthetic cursor pointer mode (`--dddk-cursor-url`). */\n  cursor?: string;\n}\n\n/** Vite/Webpack/esbuild recognise `new URL(literal, import.meta.url)`\n *  and process the referenced asset at build time. Keep each call as\n *  a plain literal — no template strings, no variables — so static\n *  analysis catches them. */\nfunction bundledSpriteUrls(): Record<keyof SpriteOverrides, string> {\n  return {\n    avatar:    new URL('./duck/neutral.png',      import.meta.url).href,\n    swim:      new URL('./duck/swim-side.png',    import.meta.url).href,\n    hero:      new URL('./duck/hero-greet.png',   import.meta.url).href,\n    chill:     new URL('./duck/chill-shades.png', import.meta.url).href,\n    swimCycle: new URL('./duck/swim-cycle.png',   import.meta.url).href,\n    brandMark: new URL('./duck/logo.png',         import.meta.url).href,\n    cursor:    new URL('./duck/cursor.png',       import.meta.url).href,\n  };\n}\n\nconst CSS_VAR_BY_KEY: Record<keyof SpriteOverrides, string> = {\n  avatar:    '--dddk-avatar-url',\n  swim:      '--dddk-swim-url',\n  hero:      '--dddk-hero-url',\n  chill:     '--dddk-chill-url',\n  swimCycle: '--dddk-swim-cycle-url',\n  brandMark: '--dddk-brand-mark-url',\n  cursor:    '--dddk-cursor-url',\n};\n\n/**\n * Set sprite URLs on `:root.style` inline. Called once at DotDotDuck\n * construction — cheap enough to redo (idempotent). Overrides win\n * per-key; unspecified keys fall back to the SDK-bundled sprite.\n */\nexport function initSpriteDefaults(overrides: SpriteOverrides = {}): void {\n  if (typeof document === 'undefined') return;\n  const bundled = bundledSpriteUrls();\n  const root = document.documentElement;\n  for (const key of Object.keys(CSS_VAR_BY_KEY) as (keyof SpriteOverrides)[]) {\n    const varName = CSS_VAR_BY_KEY[key];\n    const url = overrides[key] ?? bundled[key];\n    root.style.setProperty(varName, `url(${url})`);\n  }\n}\n","/**\n * One-line install for dotdotduck.\n *\n * Motivation. The `new DotDotDuck({...})` constructor accepts ~24\n * config knobs. Every field is optional and every subsystem silently\n * degrades if a dependency isn't wired — which is the correct library\n * behaviour, but it means a stranger dropping the package into a page\n * gets a palette (works) + no ducks (silent) + no agent (silent) + no\n * voice (silent) unless they read the docs.\n *\n * `autoInstall()` is the zero-config on-ramp. It:\n *   - Detects the browser locale (falls back to 'en').\n *   - Wires a demo LLM that produces a helpful \"connect an LLM\"\n *     response for any completion — so `startAgent()` doesn't silently\n *     no-op; the user sees \"wire config.llm to enable AI\".\n *   - Uses SDK-shipped duck sprites (the tokens.css defaults already\n *     ship these via `dist/duck/`) so the mascot appears without any\n *     `--dddk-*-url` wiring.\n *   - Registers built-in prompts on the process-wide registry so\n *     `dddk.prompts.list()` works immediately.\n *\n * When the host is ready for real integration they pass overrides on\n * top of the defaults:\n *\n *   const dddk = autoInstall({\n *     llm: myOpenAIProvider,          // switch off the demo stub\n *     siteName: 'Acme',\n *     agentName: 'Rex',\n *     paletteCommands: myCommands,\n *     brand: { voice: 'friendly' },\n *   });\n *\n * `autoInstall(overrides)` and `new DotDotDuck({ ...defaults, ...overrides })`\n * are functionally equivalent — the factory just picks the defaults.\n */\n\nimport { DotDotDuck } from './orchestrator';\nimport type { DotDotDuckConfig } from './orchestrator/types';\nimport { MockLLM } from './skills/evals';\nimport { registerBuiltinPrompts } from './prompts/defaults';\nimport type { LLMProvider } from './agent/llm/types';\nimport { MobileTrigger, type MobileTriggerConfig, type HeroGreetingConfig } from './triggers/mobile';\nimport { initSpriteDefaults, type SpriteOverrides } from './init-sprite-urls';\n\n/**\n * Options for `autoInstall()`. Every field is optional and passes\n * through to `DotDotDuckConfig` verbatim.\n */\nexport interface AutoInstallOptions extends Partial<DotDotDuckConfig> {\n  /**\n   * When true and no `llm` is provided, spin up a demo LLM that\n   * returns a canned \"wire an LLM\" response. Default: `true`. Set to\n   * `false` to keep the agent silently no-op (matches raw `new\n   * DotDotDuck({})` behaviour) — useful when the host will wire an\n   * LLM later at runtime.\n   */\n  demoLLM?: boolean;\n\n  /**\n   * MobileTrigger config. `autoInstall()` auto-attaches a MobileTrigger\n   * with `alwaysVisible: true` (desktop shows the FAB too) + the\n   * built-in bilingual HERO greeting on first visit. Pass:\n   *   - `false` — skip auto-attach entirely (host attaches their own,\n   *     or wants no FAB).\n   *   - `{}` — accept every default.\n   *   - Any subset of `MobileTriggerConfig` — override just the fields\n   *     you care about, unspecified fall back to the sensible default.\n   *\n   * The FAB config specifically defaults to `alwaysVisible: true` here\n   * (vs. `new MobileTrigger()` which stays off unless opted in) — the\n   * whole point of `autoInstall()` is \"you see the mascot without\n   * doing anything\".\n   */\n  mobile?: MobileTriggerConfig | false;\n\n  /**\n   * Sprite URL overrides. `autoInstall()` computes correct default\n   * URLs for the seven bundled duck sprites via `import.meta.url` +\n   * sets them on `:root.style`. Pass a per-key override to swap for\n   * your brand — the URL you pass wins over the SDK default.\n   *\n   *   autoInstall({\n   *     sprites: {\n   *       avatar:    '/my-brand/mascot.png',\n   *       swim:      '/my-brand/mascot-side.png',\n   *       // brand-mark left as SDK default → keeps the dotdotduck logo\n   *       // on the palette footer's \"Powered by\" strip.\n   *     },\n   *   });\n   */\n  sprites?: SpriteOverrides;\n\n  /**\n   * HERO greeting override. Convenience alias for\n   * `mobile.heroGreeting`. Whichever you pass wins; if you set both,\n   * `mobile.heroGreeting` takes precedence.\n   *\n   *   autoInstall({ heroGreeting: false });                   // disable\n   *   autoInstall({ heroGreeting: { title: 'Welcome!' } });   // override title\n   */\n  heroGreeting?: HeroGreetingConfig | false;\n}\n\n/**\n * Zero-config install. Returns a fully-constructed DotDotDuck with\n * sensible defaults. Pass overrides to fill in real host wiring.\n *\n * Idempotent w.r.t. singletons: prompt registry defaults are shared\n * across instances so a second `autoInstall()` call doesn't re-\n * register or duplicate them.\n */\nexport function autoInstall(overrides: AutoInstallOptions = {}): DotDotDuck {\n  // Ensure the built-in prompt registry is populated even if the host\n  // never touches a subsystem that would side-effect-register it.\n  registerBuiltinPrompts();\n\n  // Compute + inline-set sprite URLs on :root.style so Dwell / cursor\n  // / brand-mark work in every setup — bundler or not, subdirectory\n  // or root, standard site or embedded WebView.\n  initSpriteDefaults(overrides.sprites);\n\n  const { demoLLM: demoLLMFlag, mobile, sprites: _sprites, heroGreeting, ...rest } = overrides;\n\n  const shouldUseDemoLLM = demoLLMFlag !== false && !rest.llm;\n  const llm: LLMProvider | undefined = shouldUseDemoLLM\n    ? createDemoLLM()\n    : (rest.llm as LLMProvider | undefined);\n\n  const config: DotDotDuckConfig = {\n    locale: rest.locale ?? detectBrowserLocale(),\n    ...rest,\n    // Applied AFTER spread so the demo LLM only lands when the host\n    // didn't override — spreading `rest.llm: undefined` on top would\n    // clobber our fallback otherwise.\n    llm: llm as DotDotDuckConfig['llm'],\n  };\n\n  const dddk = new DotDotDuck(config);\n\n  // Auto-attach a MobileTrigger unless the host opted out. Default is\n  // `alwaysVisible: true` (desktop shows the FAB too) — matches\n  // autoInstall's \"you see the mascot without doing anything\" goal.\n  if (mobile !== false) {\n    const userMobile: MobileTriggerConfig = mobile ?? {};\n    const userFab = userMobile.fab === false ? false : (userMobile.fab ?? {});\n    const mergedMobileCfg: MobileTriggerConfig = {\n      ...userMobile,\n      fab: userFab === false ? false : { alwaysVisible: true, ...userFab },\n      // Convenience alias — top-level `heroGreeting` wins if the host\n      // passed it directly, but `mobile.heroGreeting` still overrides\n      // that (matches \"more specific wins\").\n      heroGreeting: userMobile.heroGreeting ?? heroGreeting ?? {},\n    };\n    const mt = new MobileTrigger(mergedMobileCfg);\n    mt.attachTo(dddk);\n  }\n\n  return dddk;\n}\n\n/**\n * Detect the browser locale. Currently returns 'zh-TW' for any\n * Chinese variant, else 'en'. Kept intentionally coarse — the SDK\n * ships user-facing i18n for these two, so returning a locale we\n * can't serve just triggers a silent fallback to English.\n *\n * Hosts wanting finer control pass `locale` in the overrides.\n */\nfunction detectBrowserLocale(): string {\n  if (typeof navigator === 'undefined') return 'en';\n  const raw = navigator.language || 'en';\n  if (raw.toLowerCase().startsWith('zh')) return 'zh-TW';\n  return 'en';\n}\n\n/**\n * Demo LLM factory — emits a friendly setup nudge for every request.\n * Uses MockLLM under the hood so the response contract stays consistent\n * with test-mode setups.\n *\n * The response text is intentionally short and English-only — a demo\n * user will paste it into the palette / agent surface and see it\n * appear verbatim, so it needs to read as \"the SDK is alive, plug in\n * an LLM to make it think\". Anything longer risks looking like a real\n * agent response.\n */\nfunction createDemoLLM(): MockLLM {\n  return new MockLLM({\n    responses: () =>\n      '[dotdotduck demo mode] Pass a real `llm` to `autoInstall({ llm })` (or `new DotDotDuck({ llm })`) to enable agent + inline-edit + voice cleanup + translate. See https://dddk.perhapxin.com for provider recipes.',\n  });\n}\n","/**\n * Dwell — semantic annotation on long-press.\n *\n * Trigger: the user presses (mouse-down on desktop, touch-start on touch\n * devices) on any element and **holds without moving** for `dwellMs`.\n * If the pointer leaves the original target element before the timer fires,\n * the gesture cancels and normal interaction (text selection, click, drag)\n * proceeds — same UX shape as the iOS context-menu long-press.\n *\n * When the timer fires:\n *   1. Element's reachable DOM (tag, attributes, inner text — bounded by\n *      `maxContextChars`) is sent to the `inline` LLM role.\n *   2. Returned `{label, actions}` JSON renders as a small popover next\n *      to the cursor.\n *   3. Esc dismisses the popover at any time.\n *\n * Security boundary: only the visible DOM of the long-pressed element\n * is sent — same shape as user copying & asking AI about a paragraph.\n *\n * Disabled by default? No — but `setEnabled(false)` turns it off without\n * detaching listeners, so hosts can offer a runtime toggle.\n *\n * @example\n * ```ts\n * const mp = new Dwell({ llm, dwellMs: 500 });\n * mp.attachTo(dddk);\n *\n * // host UI somewhere:\n * <button onClick={() => mp.setEnabled(!mp.isEnabled())}>\n *   Dwell: {mp.isEnabled() ? 'on' : 'off'}\n * </button>\n * ```\n */\n\nimport type { Subtitle } from '../../ui/subtitle';\nimport type { DotDotDuck } from '../../orchestrator';\nimport { resolveLLM, type LLMSource } from '../../agent/llm/router';\nimport { inferSelector } from '../../utils/selector';\nimport { safeJsonParse } from '../../utils/llm-parse';\nimport { ensureDwellStyles, POPOVER_ATTR } from './styles';\nimport { PROMPT_IDS, promptRegistry } from '../../prompts/registry';\nimport { registerBuiltinPrompts } from '../../prompts/defaults';\n\n// Register SDK-shipped prompt defaults on module load. Idempotent.\nregisterBuiltinPrompts();\n\n// Locale is threaded through the DotDotDuck orchestrator into per-\n// trigger config on `mount()`. Dwell doesn't own its own locale\n// field on the config type; when a host wants a non-EN Dwell prompt\n// they call `dddk.prompts.override('dwell-classify.system', 'ja', …)`\n// and set the current locale globally on the parent DotDotDuck. This\n// module reads that back at call time via the shared module-level\n// signal (set by the orchestrator's `setLocale`). Defaults to 'en'.\nlet DDDK_LOCALE = 'en';\nexport function setDwellLocale(locale: string): void {\n  DDDK_LOCALE = locale;\n}\n\nexport interface DwellConfig {\n  /** LLMProvider or LLMRouter — `inline` role used. Optional when\n   *  `annotateOnSelect: false` (the LLM popover isn't needed). */\n  llm?: LLMSource;\n  /** Hold time before selection fires. Default 700ms. */\n  dwellMs?: number;\n  /**\n   * After the long-press fires, also call the LLM and surface a popover with\n   * a label + suggested actions. Default `false` — Dwell becomes a pure\n   * \"pin an element\" gesture: the frame appears, the element is remembered\n   * for whatever happens next (`Ctrl+K` palette context, voice question\n   * against the element, etc.), and the LLM is not invoked.\n   *\n   * Set `true` if you want the legacy \"long-press → AI annotation\" UX.\n   */\n  annotateOnSelect?: boolean;\n  /** Called every time Dwell pins an element. Receives the element and a\n   *  best-effort CSS selector. Hosts use this to seed palette context. */\n  onSelect?: (el: HTMLElement, selector?: string) => void;\n  /** Called when the marked element is cleared (Esc, click outside, etc.). */\n  onClear?: () => void;\n  /** Max DOM characters sent to LLM. Default 800. */\n  maxContextChars?: number;\n  /** System prompt override. */\n  systemPrompt?: string;\n  /** Start enabled? Default true. */\n  enabled?: boolean;\n  /**\n   * Extra CSS selector for elements that should NOT trigger Dwell.\n   * Appended to a sensible default (`[data-no-dwell], input, textarea,\n   * select, [contenteditable], [draggable=\"true\"]`). Set `ignoreDefaults: true`\n   * to opt out of the defaults.\n   */\n  ignoreSelector?: string;\n  /** Skip the default ignoreSelector list. Default false. */\n  ignoreDefaults?: boolean;\n  /**\n   * Show the two decorative corner mascots (side-view swim duck riding\n   * the top edge + sunglasses \"chill\" duck at the frame corner) when a\n   * Dwell frame is active. Default `true` — a playful indicator that\n   * Dwell is engaged.\n   *\n   * Set `false` to render just the frame outline itself. Recommended\n   * for enterprise / business-app hosts where the mascots feel out of\n   * context against a serious UI (accounting, ERP, medical, legal).\n   * The frame outline + Escape-to-clear still work identically.\n   */\n  showCornerMascots?: boolean;\n  /**\n   * Require a modifier key to be held during the long-press. Useful on sites\n   * that already use plain long-press for their own buttons — set this to\n   * disambiguate. Default `null` (no modifier required).\n   */\n  triggerModifier?: 'alt' | 'shift' | 'meta' | 'ctrl' | null;\n  /**\n   * Run the long-press detector on touch devices? Default `false`. Mobile\n   * users typically interact via the MobileTrigger chrome instead; native\n   * long-press is also already used by the OS for text selection + context\n   * menus. Set `true` if you have a touch-only kiosk product where the OS\n   * long-press is fine to override.\n   */\n  enableOnTouch?: boolean;\n}\n\n// POPOVER_ATTR / POPOVER_STYLE_ID moved to ./dwell/styles.ts\n// Dwell classifier system prompt lives in `./prompt.ts` and is\n// registered on the SDK-wide `promptRegistry` so hosts can override\n// per-locale without patching this module. Resolve at call time via\n// `promptRegistry.render(PROMPT_IDS.DWELL_CLASSIFY, undefined, locale)`.\n\ninterface DwellResult {\n  label: string;\n  actions: string[];\n}\n\nconst DEFAULT_IGNORE = [\n  '[data-no-dwell]',\n  'input',\n  'textarea',\n  'select',\n  '[contenteditable]',\n  '[contenteditable=\"true\"]',\n  '[draggable=\"true\"]',\n].join(', ');\n\nexport class Dwell {\n  private cfg: Required<Omit<DwellConfig, 'systemPrompt' | 'ignoreSelector' | 'triggerModifier' | 'llm' | 'onSelect' | 'onClear'>> & {\n    llm?: LLMSource;\n    systemPrompt?: string;\n    ignoreSelector?: string;\n    triggerModifier?: 'alt' | 'shift' | 'meta' | 'ctrl' | null;\n    annotateOnSelect: boolean;\n    onSelect?: (el: HTMLElement, selector?: string) => void;\n    onClear?: () => void;\n  };\n  private effectiveIgnore: string;\n  private hasLLM: boolean = false;\n  private subtitle: Subtitle | null = null;\n\n  private enabled: boolean;\n  private dwellTimer: ReturnType<typeof setTimeout> | null = null;\n  private pressStartX = 0;\n  private pressStartY = 0;\n  private pressStartSelLen = 0;\n  private pressedTarget: HTMLElement | null = null;\n  private inFlight: AbortController | null = null;\n  private popover: HTMLDivElement | null = null;\n  private cleanups: Array<() => void> = [];\n\n  constructor(config: DwellConfig) {\n    this.cfg = {\n      llm: config.llm,\n      dwellMs: config.dwellMs ?? 500,\n      maxContextChars: config.maxContextChars ?? 800,\n      enabled: config.enabled ?? true,\n      ignoreDefaults: config.ignoreDefaults ?? false,\n      enableOnTouch: config.enableOnTouch ?? false,\n      systemPrompt: config.systemPrompt,\n      ignoreSelector: config.ignoreSelector,\n      triggerModifier: config.triggerModifier ?? null,\n      annotateOnSelect: config.annotateOnSelect ?? false,\n      onSelect: config.onSelect,\n      onClear: config.onClear,\n      // Default: show the playful corner mascots. Enterprise hosts pass\n      // `false` to render just the frame outline itself.\n      showCornerMascots: config.showCornerMascots ?? true,\n    };\n    this.enabled = this.cfg.enabled;\n    const parts: string[] = [];\n    if (!this.cfg.ignoreDefaults) parts.push(DEFAULT_IGNORE);\n    if (this.cfg.ignoreSelector) parts.push(this.cfg.ignoreSelector);\n    this.effectiveIgnore = parts.join(', ');\n    this.hasLLM = !!config.llm;\n  }\n\n  attachTo(dddk: DotDotDuck): void {\n    if (typeof document === 'undefined') return;\n    this.subtitle = dddk.subtitle;\n    ensureDwellStyles();\n    this.bindLongPress();\n    this.bindDismiss();\n  }\n\n  setEnabled(enabled: boolean): void {\n    this.enabled = enabled;\n    if (!enabled) {\n      this.cancel();\n      this.hidePopover();\n    }\n  }\n\n  isEnabled(): boolean {\n    return this.enabled;\n  }\n\n  destroy(): void {\n    this.cancel();\n    this.hidePopover();\n    this.popover?.remove();\n    this.popover = null;\n    for (const c of this.cleanups) c();\n    this.cleanups = [];\n  }\n\n  // ─── press lifecycle ────────────────────────────────────────────\n\n  private bindLongPress(): void {\n    const onDown = (x: number, y: number, target: EventTarget | null, modifiers: ModifierState) => {\n      if (!this.enabled) return;\n      if (!(target instanceof HTMLElement)) return;\n      if (this.effectiveIgnore && target.closest(this.effectiveIgnore)) return;\n      // Don't fire on our own UI (progress ring, popover).\n      if (target.closest(`[${POPOVER_ATTR}]`)) return;\n      // Modifier gate — when configured, the matching key must be held during press.\n      if (this.cfg.triggerModifier && !modifiers[this.cfg.triggerModifier]) return;\n\n      this.pressStartX = x;\n      this.pressStartY = y;\n      this.pressedTarget = target;\n      // Baseline selection length at press start. If the selection GROWS\n      // during the dwell window the user is mid-drag-to-select, not\n      // long-pressing — bail out so Dwell doesn't fight the browser's\n      // text-selection gesture.\n      this.pressStartSelLen = typeof window !== 'undefined'\n        ? (window.getSelection?.()?.toString().length ?? 0)\n        : 0;\n      this.dwellTimer = setTimeout(() => {\n        this.dwellTimer = null;\n        if (!this.pressedTarget) return;\n        const selLenNow = typeof window !== 'undefined'\n          ? (window.getSelection?.()?.toString().length ?? 0)\n          : 0;\n        // User started selecting text mid-press — defer to the browser.\n        if (selLenNow > this.pressStartSelLen) {\n          this.pressedTarget = null;\n          return;\n        }\n        this.markTarget(this.pressedTarget);\n        if (this.cfg.onSelect) {\n          this.cfg.onSelect(this.pressedTarget, inferSelector(this.pressedTarget) || undefined);\n        }\n        if (this.cfg.annotateOnSelect && this.hasLLM) {\n          this.annotate(this.pressedTarget);\n        }\n      }, this.cfg.dwellMs);\n    };\n\n    /**\n     * Cancellation rule: only if the cursor LEAVES the originally-pressed\n     * element (and isn't on a descendant). Free movement WITHIN the pressed\n     * element keeps the timer alive — natural for text reading, big buttons,\n     * card hovers etc. HTML5 drag and right-click still cancel separately.\n     */\n    const onMove = (_x: number, _y: number, target: EventTarget | null) => {\n      if (!this.dwellTimer) return;\n      if (!this.pressedTarget) return;\n      if (!(target instanceof HTMLElement)) return;\n      if (target === this.pressedTarget) return;\n      if (this.pressedTarget.contains(target)) return;\n      // Cursor moved off the pressed element → cancel.\n      this.cancel();\n    };\n\n    const onUp = () => {\n      // Released before timer fires → normal click, no annotation.\n      this.cancel();\n    };\n\n    // Mouse\n    const mouseDown = (e: MouseEvent) => {\n      if (e.button !== 0) return; // only primary button\n      // Scrollbar guard. Browser-rendered scrollbars sit OUTSIDE the\n      // document's `clientWidth` / `clientHeight` rect — clicks on them\n      // still arrive at `<html>` as the event target. Without this\n      // check, holding the scrollbar to scroll triggered Dwell and\n      // framed the entire <html> element.\n      const doc = document.documentElement;\n      if (\n        e.clientX > doc.clientWidth ||\n        e.clientY > doc.clientHeight\n      ) return;\n      onDown(e.clientX, e.clientY, e.target, modifiersFromEvent(e));\n    };\n    const mouseMove = (e: MouseEvent) => onMove(e.clientX, e.clientY, e.target);\n    const mouseUp = () => onUp();\n\n    // Right-click → cancel everything (press in flight + popover)\n    const contextMenu = (e: MouseEvent) => {\n      const inFlight = this.dwellTimer !== null;\n      const popoverOpen = this.popover && this.popover.style.display !== 'none';\n      if (inFlight || popoverOpen) {\n        e.preventDefault();\n        this.cancel();\n        this.hidePopover();\n      }\n    };\n\n    // HTML5 native drag-and-drop hijacks the cursor — cancel any in-flight press.\n    const dragStart = () => this.cancel();\n\n    document.addEventListener('mousedown',   mouseDown,  true);\n    document.addEventListener('mousemove',   mouseMove,  true);\n    document.addEventListener('mouseup',     mouseUp,    true);\n    document.addEventListener('contextmenu', contextMenu);\n    document.addEventListener('dragstart',   dragStart,  true);\n\n    // Touch — opt-in via enableOnTouch (default false). Mobile users normally\n    // interact through MobileTrigger's chrome instead.\n    let cleanTouch: (() => void) | null = null;\n    if (this.cfg.enableOnTouch) {\n      const touchStart = (e: TouchEvent) => {\n        const t = e.touches[0];\n        if (!t) return;\n        onDown(t.clientX, t.clientY, e.target, modifiersFromEvent(e));\n      };\n      const touchMove = (e: TouchEvent) => {\n        const t = e.touches[0];\n        if (t) {\n          const el = document.elementFromPoint(t.clientX, t.clientY);\n          onMove(t.clientX, t.clientY, el);\n        }\n      };\n      const touchEnd = () => onUp();\n      const touchCancel = () => this.cancel();\n\n      document.addEventListener('touchstart',  touchStart,  { passive: true, capture: true });\n      document.addEventListener('touchmove',   touchMove,   { passive: true, capture: true });\n      document.addEventListener('touchend',    touchEnd,    { passive: true, capture: true });\n      document.addEventListener('touchcancel', touchCancel, { passive: true, capture: true });\n      cleanTouch = () => {\n        document.removeEventListener('touchstart',  touchStart,  true);\n        document.removeEventListener('touchmove',   touchMove,   true);\n        document.removeEventListener('touchend',    touchEnd,    true);\n        document.removeEventListener('touchcancel', touchCancel, true);\n      };\n    }\n\n    this.cleanups.push(() => {\n      document.removeEventListener('mousedown',   mouseDown,   true);\n      document.removeEventListener('mousemove',   mouseMove,   true);\n      document.removeEventListener('mouseup',     mouseUp,     true);\n      document.removeEventListener('contextmenu', contextMenu);\n      document.removeEventListener('dragstart',   dragStart,   true);\n      if (cleanTouch) cleanTouch();\n    });\n  }\n\n  // ─── target frame ───────────────────────────────────────────────\n\n  private currentMarked: HTMLElement | null = null;\n  private swimOverlay: HTMLDivElement | null = null;\n  private chillOverlay: HTMLDivElement | null = null;\n  private swimRafId: number | null = null;\n\n  /**\n   * Add the selection-frame attribute to a target so host CSS can style it.\n   * Once marked, the frame stays until the user explicitly dismisses it —\n   * Esc, click anywhere outside the marked element / popover, or the\n   * popover's own close button. Mouse movement alone does NOT clear it,\n   * because the frame represents *selection state*, not a hover preview.\n   */\n  private markTarget(el: HTMLElement): void {\n    this.unmarkTarget();\n    el.setAttribute('data-dddk-dwell-target', '');\n    this.currentMarked = el;\n    this.startSwim(el);\n  }\n\n  private unmarkTarget(): void {\n    if (this.currentMarked) {\n      this.currentMarked.removeAttribute('data-dddk-dwell-target');\n      this.currentMarked = null;\n      this.cfg.onClear?.();\n    }\n    this.stopSwim();\n  }\n\n  /**\n   * Spawn a floating duck sprite above the marked element's top edge and\n   * animate it left → right → left in a loop. The overlay is a body-\n   * level fixed div so it never disturbs the target's own layout; a rAF\n   * loop keeps it synced with the target's rect through scrolls /\n   * layout shifts. Motion is CSS-driven; the JS only positions the\n   * container.\n   */\n  private startSwim(el: HTMLElement): void {\n    if (typeof document === 'undefined') return;\n    // Host opted out of the playful corner mascots (see DwellConfig\n    // .showCornerMascots) — leave the frame outline itself alone but\n    // skip the swim strip + chill mascot. Enterprise UIs choose this.\n    if (this.cfg.showCornerMascots === false) return;\n    // Kill any prior overlay first.\n    this.stopSwim();\n    // Only render when the host has wired a duck URL. Detect by reading\n    // the computed --dddk-avatar-url on :root. If unset (\"none\"), skip\n    // — hosts that don't want mascot decoration shouldn't get a floating\n    // sprite either.\n    const rootStyle = getComputedStyle(document.documentElement);\n    const url = (rootStyle.getPropertyValue('--dddk-avatar-url') || '').trim();\n    if (!url || url === 'none') return;\n\n    const overlay = document.createElement('div');\n    overlay.setAttribute(POPOVER_ATTR, 'dwell-swim');\n    const duck = document.createElement('div');\n    duck.setAttribute(POPOVER_ATTR, 'dwell-swim-duck');\n    overlay.appendChild(duck);\n    document.body.appendChild(overlay);\n    this.swimOverlay = overlay;\n\n    // Chill mascot in the bottom-right corner. Rendered only when\n    // --dddk-chill-url is wired on :root. Same rAF loop below keeps\n    // it glued to the target's bottom-right corner.\n    const chillUrl = (rootStyle.getPropertyValue('--dddk-chill-url') || '').trim();\n    if (chillUrl && chillUrl !== 'none') {\n      const chill = document.createElement('div');\n      chill.setAttribute(POPOVER_ATTR, 'dwell-chill');\n      document.body.appendChild(chill);\n      this.chillOverlay = chill;\n    }\n\n    // Constants matching the CSS:\n    //   CONTAINER_W: shell width (small — slides across the outline)\n    //   CONTAINER_H: shell height (room for sprite + eraser strip)\n    //   OUTLINE_OFFSET: matches --dddk-dwell-frame-offset default 3px\n    //   VELOCITY_PX_PER_SEC: how fast the duck actually swims. 22px/s\n    //     feels calm and lifelike; the user complained repeatedly that\n    //     the earlier 4.4s and 7s CSS-only versions were \"she-mah fast\"\n    //     because they were percentage-based (small element = fast).\n    //     This is now real pixels per second regardless of width.\n    //   MIN_DURATION / MAX_DURATION: clamp so tiny elements aren't\n    //     glacial and huge ones aren't marathons.\n    // Shell width = sprite (40) + a small symmetric gap each side\n    // (~4-5px) so the outline break extends a hair beyond the duck's\n    // silhouette on BOTH sides, matching user's \"前後都要一點白\" ask.\n    const CONTAINER_W = 50;\n    const CONTAINER_H = 38;\n    const OUTLINE_OFFSET = 7;\n    const VELOCITY_PX_PER_SEC = 22;\n    const MIN_DURATION = 6;\n    const MAX_DURATION = 26;\n    // Read the outline width so the eraser strip covers it exactly.\n    const targetStyle = getComputedStyle(el);\n    const outlineWidth = parseFloat(targetStyle.outlineWidth || '3') || 3;\n    // Eraser strip height = outline + a hair each side (avoids aliasing).\n    const eraserH = outlineWidth + 4;\n\n    const sync = () => {\n      if (!this.swimOverlay || !this.currentMarked || this.currentMarked !== el) {\n        this.swimRafId = null;\n        return;\n      }\n      if (!el.isConnected) {\n        this.stopSwim();\n        return;\n      }\n      const rect = el.getBoundingClientRect();\n      // Position the shell so its VERTICAL CENTRE lands ON the outline\n      // stroke (rect.top - outline-offset - outline-width/2). Reads as\n      // \"duck IS the break in the line\", not \"duck floats above line\".\n      const outlineCentreY = rect.top - OUTLINE_OFFSET - outlineWidth / 2;\n      overlay.style.left = `${rect.left}px`;\n      overlay.style.top = `${outlineCentreY - CONTAINER_H / 2}px`;\n      overlay.style.width = `${CONTAINER_W}px`;\n      overlay.style.height = `${CONTAINER_H}px`;\n      // Constant-velocity duration = 2 × width / v (full loop, both dirs).\n      const durationS = Math.max(\n        MIN_DURATION,\n        Math.min(MAX_DURATION, (2 * rect.width) / VELOCITY_PX_PER_SEC),\n      );\n      const range = Math.max(0, rect.width - CONTAINER_W);\n      overlay.style.setProperty('--dddk-swim-duration', `${durationS}s`);\n      overlay.style.setProperty('--dddk-swim-range', `${range}px`);\n      overlay.style.setProperty('--dddk-dwell-swim-eraser-height', `${eraserH}px`);\n      // Chill mascot — bottom-right corner of the frame, hanging just\n      // outside the outline (so it doesn't clip content inside).\n      if (this.chillOverlay) {\n        const chill = this.chillOverlay;\n        const CHILL_W = 42;\n        const CHILL_H = 34;\n        chill.style.left = `${rect.right - CHILL_W * 0.55}px`;\n        chill.style.top = `${rect.bottom - CHILL_H * 0.6}px`;\n      }\n      this.swimRafId = requestAnimationFrame(sync);\n    };\n    this.swimRafId = requestAnimationFrame(sync);\n  }\n\n  private stopSwim(): void {\n    if (this.swimRafId !== null) {\n      cancelAnimationFrame(this.swimRafId);\n      this.swimRafId = null;\n    }\n    if (this.chillOverlay) {\n      this.chillOverlay.remove();\n      this.chillOverlay = null;\n    }\n    if (this.swimOverlay) {\n      this.swimOverlay.remove();\n      this.swimOverlay = null;\n    }\n  }\n\n  /** Public: the currently-marked element, or `null` if nothing is selected.\n   *  Hosts call this on palette-open / voice-start to fetch the pinned\n   *  element as agent / LLM context. */\n  markedElement(): HTMLElement | null {\n    return this.currentMarked;\n  }\n\n  private bindDismiss(): void {\n    const onKey = (e: KeyboardEvent) => {\n      if (e.key === 'Escape') {\n        this.hidePopover();\n        this.unmarkTarget();\n      }\n    };\n    // Mutual exclusivity with text selection. The moment the user\n    // creates a non-empty range, Dwell yields — both showing a frame\n    // AND a highlighted text range at the same time is the bug the user\n    // hit. The palette / agent context derive a SINGLE pin at open time;\n    // clearing here keeps the visual in sync with that decision.\n    const onSelChange = () => {\n      if (!this.currentMarked) return;\n      const sel = typeof window !== 'undefined' ? window.getSelection?.() : null;\n      if (!sel || sel.isCollapsed) return;\n      const text = sel.toString();\n      if (!text || text.trim().length === 0) return;\n      // User has an active text selection → kill the dwell frame + pin.\n      this.hidePopover();\n      this.unmarkTarget();\n    };\n    // mousedown outside both the marked element and the popover → dismiss.\n    // Covers the \"popover hasn't rendered yet but frame is showing\" gap.\n    //\n    // IMPORTANT: this listener runs in the BUBBLE phase, AFTER bindLongPress's\n    // capture-phase mousedown has already started a fresh press timer. We must\n    // NOT call `this.cancel()` here unconditionally — that would clobber every\n    // new press timer and the long-press would never fire. Only dismiss when\n    // there is actually something visible to dismiss (mark or popover).\n    const onPageMouseDown = (e: MouseEvent) => {\n      const t = e.target;\n      if (!(t instanceof HTMLElement)) return;\n      const popoverOpen = this.popover !== null && this.popover.style.display !== 'none';\n      const hasMark = this.currentMarked !== null;\n      if (!popoverOpen && !hasMark) return; // nothing to dismiss — let the press proceed\n      if (this.popover && this.popover.contains(t)) return;\n      if (this.currentMarked && this.currentMarked.contains(t)) return;\n      // Click landed outside the marked element / popover — dismiss only the\n      // visible state. Do NOT call cancel(): the freshly-started press timer\n      // from bindLongPress is the user's NEW long-press, which should run.\n      this.hidePopover();\n      this.unmarkTarget();\n    };\n    document.addEventListener('keydown', onKey);\n    document.addEventListener('mousedown', onPageMouseDown);\n    document.addEventListener('selectionchange', onSelChange);\n    this.cleanups.push(() => {\n      document.removeEventListener('keydown', onKey);\n      document.removeEventListener('mousedown', onPageMouseDown);\n      document.removeEventListener('selectionchange', onSelChange);\n    });\n  }\n\n  /**\n   * Cancel an *in-flight* press. Only clears state that belongs to the\n   * pre-fire phase — does NOT remove the frame, because the frame represents\n   * \"this element is currently selected\" and must persist for the user even\n   * after they lift the mouse button. The frame is cleared by `hidePopover()`\n   * (Esc / outside click / dismiss button) or by `setEnabled(false)`.\n   */\n  private cancel(): void {\n    if (this.dwellTimer) {\n      clearTimeout(this.dwellTimer);\n      this.dwellTimer = null;\n    }\n    this.pressedTarget = null;\n    this.inFlight?.abort();\n    this.inFlight = null;\n  }\n\n  // ─── annotate + popover ─────────────────────────────────────────\n\n  private async annotate(el: HTMLElement): Promise<void> {\n    if (typeof document === 'undefined') return;\n    if (!this.hasLLM || !this.cfg.llm) return; // no LLM → cannot annotate (annotateOnSelect off path)\n    const text = extractContext(el, this.cfg.maxContextChars);\n    if (!text) return;\n\n    this.inFlight = new AbortController();\n    const target = el;\n    try {\n      const llm = resolveLLM(this.cfg.llm, 'inline');\n      const response = await llm.complete({\n        messages: [\n          { role: 'system', content: this.cfg.systemPrompt ?? promptRegistry.render(PROMPT_IDS.DWELL_CLASSIFY, undefined, DDDK_LOCALE ?? 'en') },\n          { role: 'user', content: `Selected text:\\n\"\"\"\\n${text}\\n\"\"\"\\n\\nInstruction: annotate this element` },\n        ],\n        signal: this.inFlight.signal,\n        thinking: 'off',\n        temperature: 0.2,\n      });\n      const raw = response.content;\n      if (!this.enabled) return;\n      const parsed = parseResult(raw);\n      // Even when parsing fails (LLM returned bad JSON), keep the frame —\n      // the user's \"selection\" gesture succeeded; the popover just can't\n      // populate. They dismiss it themselves via Esc / click elsewhere.\n      if (!parsed) return;\n      this.showPopover(target, parsed);\n    } catch (err) {\n      if ((err as Error).name !== 'AbortError') {\n        console.warn('[dwell] annotation failed:', err);\n      }\n      // Frame stays — see comment above.\n    } finally {\n      this.inFlight = null;\n    }\n  }\n\n  private showPopover(el: HTMLElement, result: DwellResult): void {\n    if (!this.popover) {\n      this.popover = document.createElement('div');\n      this.popover.setAttribute(POPOVER_ATTR, 'dwell');\n      document.body.appendChild(this.popover);\n    }\n    this.popover.innerHTML = '';\n\n    const head = document.createElement('div');\n    head.className = 'dwell-head';\n    const label = document.createElement('div');\n    label.className = 'dwell-label';\n    label.textContent = result.label;\n    const close = document.createElement('button');\n    close.type = 'button';\n    close.className = 'dwell-close';\n    close.setAttribute('aria-label', 'Dismiss');\n    close.textContent = '✕';\n    close.onclick = () => this.hidePopover();\n    head.appendChild(label);\n    head.appendChild(close);\n    this.popover.appendChild(head);\n\n    if (result.actions.length > 0) {\n      const actions = document.createElement('div');\n      actions.className = 'dwell-actions';\n      for (const action of result.actions.slice(0, 3)) {\n        const btn = document.createElement('button');\n        btn.type = 'button';\n        btn.textContent = action;\n        btn.onclick = () => {\n          this.subtitle?.show({ text: `→ ${action}`, type: 'info', autoHide: 1500 });\n          this.hidePopover();\n        };\n        actions.appendChild(btn);\n      }\n      this.popover.appendChild(actions);\n    }\n\n    const hint = document.createElement('div');\n    hint.className = 'dwell-hint';\n    hint.textContent = 'Esc to dismiss';\n    this.popover.appendChild(hint);\n\n    const rect = el.getBoundingClientRect();\n    this.popover.style.left = `${rect.left + window.scrollX}px`;\n    this.popover.style.top = `${rect.bottom + window.scrollY + 6}px`;\n    this.popover.style.display = 'block';\n  }\n\n  private hidePopover(): void {\n    this.unmarkTarget();\n    if (this.popover) this.popover.style.display = 'none';\n  }\n}\n\n// ─── helpers ────────────────────────────────────────────────────────\n\ninterface ModifierState {\n  alt: boolean;\n  shift: boolean;\n  meta: boolean;\n  ctrl: boolean;\n}\n\nfunction modifiersFromEvent(e: MouseEvent | TouchEvent): ModifierState {\n  return {\n    alt: e.altKey,\n    shift: e.shiftKey,\n    meta: e.metaKey,\n    ctrl: e.ctrlKey,\n  };\n}\n\n/**\n * Best-effort CSS selector for an element — id → unique class → tag.\n * Good enough to round-trip back to the same node for palette context\n * snapshots; not a full XPath.\n */\nfunction extractContext(el: HTMLElement, maxChars: number): string {\n  const tag = el.tagName.toLowerCase();\n  const attrs: string[] = [];\n  for (const a of ['id', 'class', 'aria-label', 'title', 'href', 'name', 'role']) {\n    const v = el.getAttribute(a);\n    if (v) attrs.push(`${a}=\"${v}\"`);\n  }\n  const innerText = (el.innerText ?? el.textContent ?? '').trim().slice(0, maxChars);\n  const opener = `<${tag}${attrs.length > 0 ? ' ' + attrs.join(' ') : ''}>`;\n  return `${opener}\\n${innerText}\\n</${tag}>`;\n}\n\nfunction parseResult(raw: string): DwellResult | null {\n  const obj = safeJsonParse<Partial<DwellResult>>(raw);\n  if (!obj || typeof obj.label !== 'string' || !Array.isArray(obj.actions)) return null;\n  return {\n    label: obj.label,\n    actions: obj.actions.filter((a): a is string => typeof a === 'string'),\n  };\n}\n\n","/**\n * ActionPanel — typed action system for palette items.\n *\n * Each palette result can carry multiple actions:\n *  - primary (⏎)         — the first action, runs on Enter\n *  - secondary (Ctrl+⏎)  — the second action\n *  - others (Ctrl+K)     — opens a sub-panel listing the rest\n *\n * Actions are typed so the palette renders the right icon and handles the\n * right side-effect (copy, open URL, navigate, run skill, …) without each\n * command author re-implementing them.\n */\n\nexport type PaletteAction =\n  | CopyAction\n  | InsertAction\n  | OpenUrlAction\n  | NavigateAction\n  | AgentTaskAction\n  | RenderSurfaceAction\n  | RunSkillAction\n  | CustomAction;\n\ninterface ActionShared {\n  /** Display title shown in the panel. */\n  title: string;\n  /** Optional icon (emoji or icon name). */\n  icon?: string;\n  /** Keyboard shortcut hint — display only, doesn't bind. */\n  shortcut?: string;\n  /** Mark as destructive — renders red, requires confirmation by default. */\n  destructive?: boolean;\n}\n\nexport interface CopyAction extends ActionShared {\n  kind: 'copy';\n  content: string;\n  /** True to redact from clipboard history hooks. Default false. */\n  concealed?: boolean;\n}\n\nexport interface InsertAction extends ActionShared {\n  kind: 'insert';\n  /** Text to insert into the active input / contenteditable on the page. */\n  text: string;\n}\n\nexport interface OpenUrlAction extends ActionShared {\n  kind: 'open-url';\n  url: string;\n  /** Open in same tab vs new (default 'new'). */\n  target?: 'self' | 'new';\n}\n\nexport interface NavigateAction extends ActionShared {\n  kind: 'navigate';\n  /** SPA path — host's `onNavigate` is invoked. */\n  path: string;\n}\n\nexport interface AgentTaskAction extends ActionShared {\n  kind: 'agent-task';\n  task: string;\n}\n\nexport interface RenderSurfaceAction extends ActionShared {\n  kind: 'render-surface';\n  surface: unknown; // PieceSurface\n  placement?: import('../skills/types').SurfacePlacement;\n}\n\nexport interface RunSkillAction extends ActionShared {\n  kind: 'run-skill';\n  skillId: string;\n  vars?: Record<string, string>;\n}\n\nexport interface CustomAction extends ActionShared {\n  kind: 'custom';\n  /** Arbitrary handler — escape hatch for things outside the typed kinds. */\n  onActivate: (ctx: ActionRunContext) => void | Promise<void>;\n}\n\nexport interface ActionRunContext {\n  navigate(path: string): void;\n  startAgent(task: string): void;\n  runSkill(skillId: string, vars?: Record<string, string>): void;\n  emitSurface(surface: unknown, placement?: import('../skills/types').SurfacePlacement): void;\n}\n\n// ─── runner ────────────────────────────────────────────────────────\n\nexport async function runAction(\n  action: PaletteAction,\n  ctx: ActionRunContext\n): Promise<void> {\n  switch (action.kind) {\n    case 'copy':\n      if (typeof navigator !== 'undefined' && navigator.clipboard) {\n        await navigator.clipboard.writeText(action.content);\n      }\n      break;\n    case 'insert': {\n      const el = document.activeElement as HTMLElement | null;\n      if (!el) break;\n      if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') {\n        const input = el as HTMLInputElement | HTMLTextAreaElement;\n        const start = input.selectionStart ?? input.value.length;\n        const end = input.selectionEnd ?? input.value.length;\n        input.value = input.value.slice(0, start) + action.text + input.value.slice(end);\n        input.dispatchEvent(new Event('input', { bubbles: true }));\n      } else if (el.isContentEditable) {\n        document.execCommand('insertText', false, action.text);\n      }\n      break;\n    }\n    case 'open-url':\n      if (typeof window !== 'undefined') {\n        window.open(action.url, action.target === 'self' ? '_self' : '_blank');\n      }\n      break;\n    case 'navigate':\n      ctx.navigate(action.path);\n      break;\n    case 'agent-task':\n      ctx.startAgent(action.task);\n      break;\n    case 'render-surface':\n      ctx.emitSurface(action.surface, action.placement);\n      break;\n    case 'run-skill':\n      ctx.runSkill(action.skillId, action.vars);\n      break;\n    case 'custom':\n      await action.onActivate(ctx);\n      break;\n  }\n}\n\nexport function defaultIconFor(kind: PaletteAction['kind']): string {\n  // Monochrome Unicode glyphs only — never multi-color emoji (per user UI\n  // memo). These map cleanly to the dddk icon style across both themes.\n  switch (kind) {\n    case 'copy': return '⎘';\n    case 'insert': return '↩︎';\n    case 'open-url': return '⇗';\n    case 'navigate': return '→';\n    case 'agent-task': return '✦';\n    case 'render-surface': return '⊟';\n    case 'run-skill': return '▸';\n    case 'custom': return '·';\n  }\n}\n","/**\n * LLM streaming — dual-form return (Promise + AsyncIterable).\n *\n *   const reply = llm.streamComplete(opts);\n *   for await (const chunk of reply) {\n *     ui.append(chunk.delta);\n *   }\n *   const full = await reply;          // same object resolves to CompleteResult\n *\n * The provider implementation creates a single object that is both\n * awaitable (returns CompleteResult) and async-iterable (yields StreamChunk\n * per delta), so each provider only writes its SSE parsing once.\n */\n\nimport type { CompleteResult, ToolCall } from './types';\n\nexport interface StreamChunk {\n  /** Incremental text delta since previous chunk. */\n  delta: string;\n  /** Snapshot of accumulated text so far. */\n  text: string;\n  /** Tool calls assembled so far. */\n  toolCalls?: ToolCall[];\n  /** True only on the very last chunk. */\n  done: boolean;\n  /** Reason for stop — present on the final chunk only. */\n  finishReason?: CompleteResult['finishReason'];\n  /**\n   * Incremental tool-call argument fragment. v0.2.0 — used by the\n   * streaming-envelope path so the cot loop can feed each piece into\n   * the envelope parser AS the LLM types it, instead of waiting for\n   * the full JSON to settle.\n   *\n   * `deltaText` is just the new chars added in this chunk.\n   * `accumulatedText` is the full args buffer so far (so consumers\n   * with no parser state can still inspect the snapshot).\n   *\n   * Only OpenAIProvider (and adapters that wrap it — Agnes / DeepSeek\n   * via OpenAI-compatible) currently emit this. Other providers may\n   * not, which is fine — the cot loop falls back to the JSON-parsed\n   * path when no streaming-envelope events arrive.\n   */\n  toolArgsDelta?: {\n    id: string;\n    name: string;\n    deltaText: string;\n    accumulatedText: string;\n  };\n  /**\n   * Set on the terminal chunk when streaming aborted with an error. The\n   * `await handle` form will reject with the same error; iterators receive\n   * the chunk so callers iterating without awaiting can still observe it.\n   */\n  error?: unknown;\n}\n\n/**\n * Combined awaitable + async-iterable handle.\n *   const r = streamComplete(...);\n *   for await (const c of r) {}\n *   const result = await r;\n */\nexport type StreamHandle = AsyncIterable<StreamChunk> & Promise<CompleteResult>;\n\ninterface BuildStreamOptions {\n  /**\n   * Produces a stream of deltas. Implementation is provider-specific (parses\n   * SSE, decodes Gemini chunks, whatever). Each yield is a string delta;\n   * pass `null` to signal completion with optional final result.\n   */\n  produce(): AsyncIterable<{\n    delta?: string;\n    toolCall?: ToolCall;\n    /** v0.2.0 streaming-envelope: per-fragment tool-args delta. */\n    toolArgsDelta?: { id: string; name: string; deltaText: string; accumulatedText: string };\n    finishReason?: CompleteResult['finishReason'];\n    usage?: CompleteResult['usage'];\n  }>;\n}\n\n/**\n * Build a StreamHandle from a provider's chunk producer.\n * Buffers a single iteration so the awaited Promise and the iterable share state.\n */\nexport function buildStream(opts: BuildStreamOptions): StreamHandle {\n  let text = '';\n  const toolCalls: ToolCall[] = [];\n  let finishReason: CompleteResult['finishReason'] | undefined;\n  let usage: CompleteResult['usage'] | undefined;\n  const buffered: StreamChunk[] = [];\n  let waiters: Array<(c: StreamChunk | null) => void> = [];\n  let done = false;\n  let pendingError: unknown;\n  // TTFT instrumentation. `startedAt` is sampled at buildStream() return,\n  // which is the moment the host issued the call. `firstDeltaAt` is the\n  // first non-empty text delta — TTFT = firstDeltaAt − startedAt.\n  const startedAt = Date.now();\n  let firstDeltaAt: number | undefined;\n  let endedAt = startedAt;\n\n  // Drive the producer in the background.\n  let producerErrored = false;\n  (async () => {\n    try {\n      for await (const evt of opts.produce()) {\n        if (evt.toolCall) {\n          // Merge / append tool call (could be partial fragments)\n          const existing = toolCalls.find((t) => t.id === evt.toolCall!.id);\n          if (existing) {\n            // accumulate arguments\n            existing.arguments = { ...existing.arguments, ...evt.toolCall.arguments };\n          } else {\n            toolCalls.push(evt.toolCall);\n          }\n        }\n        if (evt.delta !== undefined) {\n          if (evt.delta.length > 0 && firstDeltaAt === undefined) {\n            firstDeltaAt = Date.now();\n          }\n          text += evt.delta;\n        }\n        if (evt.usage) usage = evt.usage;\n        if (evt.finishReason) finishReason = evt.finishReason;\n        endedAt = Date.now();\n\n        const chunk: StreamChunk = {\n          delta: evt.delta ?? '',\n          text,\n          toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n          done: false,\n          // Pass through unmodified — consumer (cot loop) feeds this\n          // into the envelope parser when enableStreamingEnvelope is on.\n          ...(evt.toolArgsDelta ? { toolArgsDelta: evt.toolArgsDelta } : {}),\n        };\n        if (waiters.length > 0) {\n          const w = waiters.shift()!;\n          w(chunk);\n        } else {\n          buffered.push(chunk);\n        }\n      }\n    } catch (err) {\n      // Don't pretend success: emit a terminal chunk carrying the error so\n      // iterators see it, AND store the error so the awaited Promise form\n      // rejects.\n      producerErrored = true;\n      pendingError = err;\n      const errChunk: StreamChunk = {\n        delta: '',\n        text,\n        toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n        done: true,\n        // No finishReason — caller can branch on `error` field instead.\n        error: err,\n      };\n      if (waiters.length > 0) {\n        const w = waiters.shift()!;\n        w(errChunk);\n      } else {\n        buffered.push(errChunk);\n      }\n      // Wake any remaining waiters with end-of-stream\n      for (const w of waiters) w(null);\n      waiters = [];\n      done = true;\n    } finally {\n      if (!producerErrored) {\n        const final: StreamChunk = {\n          delta: '',\n          text,\n          toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n          done: true,\n          finishReason: finishReason ?? 'stop',\n        };\n        if (waiters.length > 0) {\n          const w = waiters.shift()!;\n          w(final);\n        } else {\n          buffered.push(final);\n        }\n        for (const w of waiters) w(null);\n        waiters = [];\n        done = true;\n      }\n    }\n  })();\n\n  // Build the iterator.\n  const iterator: AsyncIterator<StreamChunk> = {\n    next(): Promise<IteratorResult<StreamChunk>> {\n      if (buffered.length > 0) {\n        const c = buffered.shift()!;\n        return Promise.resolve({ value: c, done: c.done && !buffered.length });\n      }\n      if (done) {\n        return Promise.resolve({ value: undefined as never, done: true });\n      }\n      return new Promise<IteratorResult<StreamChunk>>((resolve) => {\n        waiters.push((c) => {\n          if (!c) resolve({ value: undefined as never, done: true });\n          else resolve({ value: c, done: c.done && !buffered.length });\n        });\n      });\n    },\n  };\n\n  // Awaitable resolution — drains iterator then resolves with CompleteResult.\n  const awaitable = (async (): Promise<CompleteResult> => {\n    for await (const _ of {\n      [Symbol.asyncIterator]() {\n        return iterator;\n      },\n    }) {\n      // drain\n    }\n    if (pendingError) throw pendingError;\n    return {\n      content: text,\n      toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n      usage,\n      finishReason: finishReason ?? 'stop',\n      streamMetrics: { startedAt, firstDeltaAt, endedAt },\n    };\n  })();\n\n  // The dual handle — looks like a Promise AND an AsyncIterable.\n  const handle = awaitable as StreamHandle;\n  (handle as unknown as { [Symbol.asyncIterator]: () => AsyncIterator<StreamChunk> })[\n    Symbol.asyncIterator\n  ] = () => iterator;\n  return handle;\n}\n\n/**\n * Provider interface extension — providers MAY implement streamComplete in\n * addition to the base complete(). Callers should feature-check.\n */\nexport interface StreamingProvider {\n  streamComplete?(opts: import('./types').CompleteOptions): StreamHandle;\n}\n","/**\n * Strip secrets (typically API keys) from a string before logging or\n * raising it as an Error message. Empty/null secrets are skipped — they\n * would otherwise replace the entire string with `[REDACTED]`.\n */\nexport function redactSecrets(s: string, secrets: Array<string | undefined | null>): string {\n  let out = s;\n  for (const sec of secrets) {\n    if (sec && sec.length > 0) {\n      out = out.split(sec).join('[REDACTED]');\n    }\n  }\n  return out;\n}\n","/**\n * OpenAI provider. Works with Azure OpenAI, OpenRouter, Cloudflare AI Gateway,\n * and any other OpenAI-compatible endpoint via `baseURL`.\n */\n\nimport type {\n  LLMProvider,\n  CompleteOptions,\n  CompleteResult,\n  LLMMessage,\n  ToolCall,\n} from './types';\nimport { buildStream, type StreamHandle, type StreamingProvider } from './stream';\nimport { redactSecrets } from '../../utils/redact';\n\nexport interface OpenAIProviderConfig {\n  apiKey: string;\n  model?: string;\n  baseURL?: string;\n  organization?: string;\n  /** Default request headers (e.g. for self-hosted reverse proxies). */\n  headers?: Record<string, string>;\n  /**\n   * Vendor-specific request body fields merged into every request. The\n   * OpenAI Chat Completions shape is a lingua franca — DeepSeek, Qwen,\n   * Together, OpenRouter, etc. all accept it but each adds proprietary\n   * knobs. Put them here:\n   *\n   *   new OpenAIProvider({\n   *     apiKey, baseURL: 'https://api.deepseek.com/v1',\n   *     extraBody: { thinking: { type: 'disabled' } },  // DeepSeek-specific\n   *   });\n   *\n   * Values here are spread shallow-merged into the body AFTER the\n   * built-in fields, so they can override `temperature` / `max_tokens` /\n   * etc. when needed.\n   */\n  extraBody?: Record<string, unknown>;\n}\n\nexport class OpenAIProvider implements LLMProvider, StreamingProvider {\n  readonly name = 'openai';\n\n  private apiKey: string;\n  private model: string;\n  private baseURL: string;\n  private headers: Record<string, string>;\n  private extraBody: Record<string, unknown>;\n\n  constructor(config: OpenAIProviderConfig) {\n    this.apiKey = config.apiKey;\n    this.model = config.model ?? 'gpt-5.4-mini';\n    this.baseURL = config.baseURL ?? 'https://api.openai.com/v1';\n    this.headers = {\n      'Content-Type': 'application/json',\n      Authorization: `Bearer ${this.apiKey}`,\n      ...(config.organization ? { 'OpenAI-Organization': config.organization } : {}),\n      ...(config.headers ?? {}),\n    };\n    this.extraBody = config.extraBody ?? {};\n  }\n\n  private buildBody(opts: CompleteOptions, stream: boolean): Record<string, unknown> {\n    const model = opts.model ?? this.model;\n    const body: Record<string, unknown> = {\n      model,\n      messages: opts.messages.map(toOpenAIMessage),\n    };\n\n    if (stream) body.stream = true;\n\n    // Two orthogonal model-family axes (see `usesMaxCompletionTokens`\n    // and `isReasoningModel` for the matchers):\n    //   1. `max_completion_tokens` vs `max_tokens` — all gpt-5+ models\n    //      including `-mini` / `-nano` require the new name.\n    //   2. Reasoning controls (`reasoning_effort`, no custom temperature) —\n    //      only true reasoning models (o-series, gpt-5+ non-mini). The\n    //      mini / nano variants still accept temperature.\n    // `opts.thinking` is also treated as opt-in to the reasoning shape.\n    const newParamShape = usesMaxCompletionTokens(model);\n    const reasoning = opts.thinking !== undefined || isReasoningModel(model);\n\n    if (newParamShape) {\n      if (opts.maxTokens !== undefined) body.max_completion_tokens = opts.maxTokens;\n    } else if (opts.maxTokens !== undefined) {\n      body.max_tokens = opts.maxTokens;\n    }\n\n    if (reasoning) {\n      const hasTools = (opts.tools?.length ?? 0) > 0;\n      const wantsReasoning = opts.thinking && opts.thinking !== 'off';\n      if (wantsReasoning && !hasTools) {\n        body.reasoning_effort = opts.thinking;\n      }\n    } else {\n      body.temperature = opts.temperature ?? 0.7;\n    }\n\n    if (opts.jsonMode) {\n      body.response_format = { type: 'json_object' };\n    }\n\n    if (opts.tools && opts.tools.length > 0) {\n      body.tools = opts.tools.map((t) => ({\n        type: 'function',\n        function: {\n          name: t.name,\n          description: t.description,\n          parameters: t.parameters,\n        },\n      }));\n      const choice = opts.toolChoice ?? 'auto';\n      if (choice === 'auto' || choice === 'required') {\n        body.tool_choice = choice;\n      } else if (typeof choice === 'object' && typeof choice.name === 'string') {\n        body.tool_choice = { type: 'function', function: { name: choice.name } };\n      }\n    }\n\n    // Vendor-specific knobs (DeepSeek `thinking`, etc.) layered last so\n    // they can override defaults when the host explicitly sets them.\n    return { ...body, ...this.extraBody };\n  }\n\n  async complete(opts: CompleteOptions): Promise<CompleteResult> {\n    const body = this.buildBody(opts, false);\n    const response = await fetch(`${this.baseURL}/chat/completions`, {\n      method: 'POST',\n      headers: this.headers,\n      body: JSON.stringify(body),\n      signal: opts.signal,\n    });\n\n    if (!response.ok) {\n      const errText = await response.text().catch(() => response.statusText);\n      throw new Error(\n        `OpenAI HTTP ${response.status}: ${redactSecrets(errText, [this.apiKey])}`,\n      );\n    }\n\n    const data = (await response.json()) as OpenAIChatResponse;\n    const choice = data.choices?.[0];\n    if (!choice) throw new Error('OpenAI: no choices returned');\n\n    const message = choice.message;\n    const toolCalls: ToolCall[] | undefined = message.tool_calls?.map((tc) => ({\n      id: tc.id,\n      name: tc.function.name,\n      arguments: safeParseJson(tc.function.arguments) ?? {},\n    }));\n\n    return {\n      content: message.content ?? '',\n      toolCalls,\n      usage: data.usage\n        ? {\n            promptTokens: data.usage.prompt_tokens,\n            completionTokens: data.usage.completion_tokens,\n          }\n        : undefined,\n      finishReason: (choice.finish_reason as CompleteResult['finishReason']) ?? 'stop',\n    };\n  }\n\n  /**\n   * Streaming via OpenAI's SSE `chat/completions?stream=true`. Each event is\n   * `data: { ... }` carrying either a text delta or a tool_call fragment.\n   * Tool calls stream piecewise — `index` slots; `id` / `function.name` arrive\n   * on the first fragment, `function.arguments` accumulates JSON characters\n   * across subsequent fragments.\n   */\n  streamComplete(opts: CompleteOptions): StreamHandle {\n    const body = this.buildBody(opts, true);\n    const baseURL = this.baseURL;\n    const headers = this.headers;\n    const apiKey = this.apiKey;\n\n    return buildStream({\n      produce: () => streamOpenAI({ url: `${baseURL}/chat/completions`, headers, body, signal: opts.signal, apiKey }),\n    });\n  }\n}\n\nasync function* streamOpenAI(args: {\n  url: string;\n  headers: Record<string, string>;\n  body: Record<string, unknown>;\n  signal?: AbortSignal;\n  apiKey: string;\n}): AsyncIterable<{\n  delta?: string;\n  toolCall?: ToolCall;\n  // v0.2.0 streaming-envelope fragment.\n  toolArgsDelta?: { id: string; name: string; deltaText: string; accumulatedText: string };\n  finishReason?: CompleteResult['finishReason'];\n  usage?: CompleteResult['usage'];\n}> {\n  const response = await fetch(args.url, {\n    method: 'POST',\n    headers: args.headers,\n    body: JSON.stringify(args.body),\n    signal: args.signal,\n  });\n\n  if (!response.ok) {\n    const errText = await response.text().catch(() => response.statusText);\n    throw new Error(`OpenAI HTTP ${response.status}: ${redactSecrets(errText, [args.apiKey])}`);\n  }\n  if (!response.body) {\n    throw new Error('OpenAI: no response body for stream');\n  }\n\n  // Track in-progress tool calls by streaming index. OpenAI emits each\n  // tool_call as a sequence of fragments — first one carries `id` and\n  // `function.name`, subsequent ones carry `function.arguments` deltas.\n  const inflight = new Map<number, { id: string; name: string; argsBuf: string; flushedAccum: boolean }>();\n  // Track which tool calls have been yielded already so we don't re-yield\n  // every fragment; we emit a single toolCall event when arguments parse\n  // cleanly (typically on the closing `}` or at finish_reason=tool_calls).\n  const yielded = new Set<number>();\n\n  const reader = response.body.getReader();\n  const decoder = new TextDecoder();\n  let buf = '';\n  let finishReason: CompleteResult['finishReason'] | undefined;\n  let usage: CompleteResult['usage'] | undefined;\n\n  while (true) {\n    let value: Uint8Array | undefined;\n    let done = false;\n    try {\n      const r = await reader.read();\n      value = r.value;\n      done = r.done;\n    } catch (err) {\n      // User aborted (subtitle ×, Esc, double-tap Space). The fetch's\n      // body stream throws AbortError mid-read — treat as a clean stop\n      // and return so the loop can wind down without an unhandled\n      // rejection bubbling to the console.\n      if ((err as Error).name === 'AbortError') return;\n      throw err;\n    }\n    if (done) break;\n    buf += decoder.decode(value, { stream: true });\n\n    // SSE events are separated by `\\n\\n`. Each event line starts with `data: `.\n    let sep: number;\n    while ((sep = buf.indexOf('\\n\\n')) !== -1) {\n      const event = buf.slice(0, sep);\n      buf = buf.slice(sep + 2);\n      if (!event.trim()) continue;\n\n      for (const line of event.split('\\n')) {\n        if (!line.startsWith('data:')) continue;\n        const payload = line.slice(5).trim();\n        if (payload === '[DONE]') continue;\n        let parsed: OpenAIStreamChunk;\n        try {\n          parsed = JSON.parse(payload) as OpenAIStreamChunk;\n        } catch {\n          continue;\n        }\n        if (parsed.usage) {\n          usage = {\n            promptTokens: parsed.usage.prompt_tokens,\n            completionTokens: parsed.usage.completion_tokens,\n          };\n        }\n        const choice = parsed.choices?.[0];\n        if (!choice) continue;\n        const delta = choice.delta ?? {};\n\n        if (typeof delta.content === 'string' && delta.content.length > 0) {\n          yield { delta: delta.content };\n        }\n\n        if (Array.isArray(delta.tool_calls)) {\n          for (const frag of delta.tool_calls) {\n            const idx = frag.index ?? 0;\n            let entry = inflight.get(idx);\n            if (!entry) {\n              entry = { id: frag.id ?? `call_${idx}_${Date.now()}`, name: frag.function?.name ?? '', argsBuf: '', flushedAccum: false };\n              inflight.set(idx, entry);\n            } else {\n              if (frag.id) entry.id = frag.id;\n              if (frag.function?.name) entry.name = frag.function.name;\n            }\n            const fragArgs = frag.function?.arguments;\n            if (fragArgs) entry.argsBuf += fragArgs;\n\n            // v0.2.0 streaming-envelope: yield deltas as soon as the\n            // tool name is known. OpenAI's SSE order is provider-\n            // dependent — sometimes name arrives BEFORE first args,\n            // sometimes the SAME chunk delivers `{\"`-style args while\n            // the name is still being sent in a later chunk. We can't\n            // yield without `name` (downstream filters on it), so on\n            // the FIRST chunk after name is known we flush the entire\n            // accumulated buffer in one shot (covers args-before-name\n            // ordering). Subsequent chunks yield each new fragment.\n            if (entry.name && !entry.flushedAccum) {\n              if (entry.argsBuf) {\n                yield {\n                  toolArgsDelta: {\n                    id: entry.id,\n                    name: entry.name,\n                    deltaText: entry.argsBuf,\n                    accumulatedText: entry.argsBuf,\n                  },\n                };\n              }\n              entry.flushedAccum = true;\n            } else if (entry.name && fragArgs) {\n              yield {\n                toolArgsDelta: {\n                  id: entry.id,\n                  name: entry.name,\n                  deltaText: fragArgs,\n                  accumulatedText: entry.argsBuf,\n                },\n              };\n            }\n\n            // Try parsing accumulated JSON. If it parses, the tool call is\n            // complete enough to dispatch — yield exactly once per index.\n            if (entry.name && !yielded.has(idx)) {\n              const parsedArgs = safeParseJson(entry.argsBuf);\n              if (parsedArgs !== null) {\n                yielded.add(idx);\n                yield { toolCall: { id: entry.id, name: entry.name, arguments: parsedArgs } };\n              }\n            }\n          }\n        }\n\n        if (choice.finish_reason) {\n          finishReason = choice.finish_reason as CompleteResult['finishReason'];\n          // Flush any tool calls that didn't get a clean JSON parse yet —\n          // emit with whatever we have (best effort, may be empty object).\n          for (const [idx, entry] of inflight) {\n            if (yielded.has(idx) || !entry.name) continue;\n            yielded.add(idx);\n            yield { toolCall: { id: entry.id, name: entry.name, arguments: safeParseJson(entry.argsBuf) ?? {} } };\n          }\n        }\n      }\n    }\n  }\n\n  if (finishReason || usage) {\n    yield { finishReason, usage };\n  }\n}\n\ninterface OpenAIStreamChunk {\n  choices?: Array<{\n    delta?: {\n      content?: string;\n      tool_calls?: Array<{\n        index?: number;\n        id?: string;\n        type?: 'function';\n        function?: { name?: string; arguments?: string };\n      }>;\n    };\n    finish_reason?: string | null;\n  }>;\n  usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };\n}\n\n// ─── helpers ────────────────────────────────────────────────────────\n\nfunction toOpenAIMessage(m: LLMMessage): Record<string, unknown> {\n  const out: Record<string, unknown> = { role: m.role };\n\n  if (typeof m.content === 'string') {\n    out.content = m.content;\n  } else {\n    out.content = m.content.map((part) =>\n      part.type === 'image'\n        ? { type: 'image_url', image_url: { url: part.image } }\n        : { type: 'text', text: part.text }\n    );\n  }\n\n  if (m.toolCallId) out.tool_call_id = m.toolCallId;\n  if (m.toolCalls) {\n    out.tool_calls = m.toolCalls.map((tc) => ({\n      id: tc.id,\n      type: 'function',\n      function: { name: tc.name, arguments: JSON.stringify(tc.arguments) },\n    }));\n  }\n  if (m.name) out.name = m.name;\n\n  return out;\n}\n\n/**\n * True for OpenAI true-reasoning models (o-series + gpt-5+ full, NOT mini/nano).\n * These reject custom temperature. The `-mini` / `-nano` variants behave like\n * conventional chat models on the temperature axis.\n */\nfunction isReasoningModel(model: string): boolean {\n  return /^(o[1-9](?!.*-mini|.*-nano)|gpt-[5-9](?!.*-mini|.*-nano)|gpt-1\\d(?!.*-mini|.*-nano))/i.test(\n    model,\n  );\n}\n\n/**\n * True for models that require `max_completion_tokens` instead of `max_tokens`.\n * Includes ALL gpt-5+ models (mini/nano too) and all o-series. Verified against\n * gpt-5.4-mini which returns 400 \"Unsupported parameter: 'max_tokens' is not\n * supported with this model\" on `max_tokens`.\n */\nfunction usesMaxCompletionTokens(model: string): boolean {\n  return /^(o[1-9]|gpt-[5-9]|gpt-1\\d)/i.test(model);\n}\n\nfunction safeParseJson(s: string): Record<string, unknown> | null {\n  try {\n    return JSON.parse(s);\n  } catch {\n    return null;\n  }\n}\n\ninterface OpenAIChatResponse {\n  choices: Array<{\n    message: {\n      role: string;\n      content: string | null;\n      tool_calls?: Array<{\n        id: string;\n        type: 'function';\n        function: { name: string; arguments: string };\n      }>;\n    };\n    finish_reason: string;\n  }>;\n  usage?: {\n    prompt_tokens: number;\n    completion_tokens: number;\n    total_tokens: number;\n  };\n}\n","/**\n * Conversion between our generic LLM shape and Gemini's wire shape.\n */\n\nimport type { LLMMessage, CompleteResult } from '../types';\n\nexport function toGeminiMessages(messages: LLMMessage[]): {\n  contents: Array<Record<string, unknown>>;\n  systemInstruction?: Record<string, unknown>;\n} {\n  const contents: Array<Record<string, unknown>> = [];\n  let systemText = '';\n\n  for (const m of messages) {\n    if (m.role === 'system') {\n      systemText += (typeof m.content === 'string' ? m.content : '') + '\\n';\n      continue;\n    }\n\n    const role = m.role === 'assistant' ? 'model' : 'user';\n\n    if (m.toolCalls && m.toolCalls.length > 0) {\n      const parts: Array<Record<string, unknown>> = [];\n      // Preserve any assistant text accompanying the tool calls — some models\n      // emit a thought / preamble alongside the call.\n      if (typeof m.content === 'string' && m.content.length > 0) {\n        parts.push({ text: m.content });\n      }\n      for (const tc of m.toolCalls) {\n        parts.push({ functionCall: { name: tc.name, args: tc.arguments } });\n      }\n      contents.push({ role: 'model', parts });\n      continue;\n    }\n\n    if (m.role === 'tool') {\n      // Gemini's functionResponse.name pairs with the call's name (Gemini\n      // doesn't track tool_call_ids the way OpenAI does). Prefer toolCallId\n      // when supplied so router-shaped messages still round-trip.\n      contents.push({\n        role: 'user',\n        parts: [\n          {\n            functionResponse: {\n              name: m.toolCallId ?? m.name ?? 'unknown',\n              response: { content: typeof m.content === 'string' ? m.content : '' },\n            },\n          },\n        ],\n      });\n      continue;\n    }\n\n    const parts =\n      typeof m.content === 'string'\n        ? [{ text: m.content }]\n        : m.content.map((p) =>\n            p.type === 'text'\n              ? { text: p.text }\n              : { inlineData: { mimeType: 'image/png', data: stripDataPrefix(p.image) } },\n          );\n    contents.push({ role, parts });\n  }\n\n  return {\n    contents,\n    systemInstruction: systemText.trim()\n      ? { parts: [{ text: systemText.trim() }] }\n      : undefined,\n  };\n}\n\nfunction stripDataPrefix(s: string): string {\n  const idx = s.indexOf('base64,');\n  return idx >= 0 ? s.slice(idx + 7) : s;\n}\n\nexport function mapFinishReason(r?: string): CompleteResult['finishReason'] {\n  switch (r) {\n    case 'STOP':\n      return 'stop';\n    case 'MAX_TOKENS':\n      return 'length';\n    case 'SAFETY':\n      return 'content_filter';\n    default:\n      return 'stop';\n  }\n}\n","/**\n * Gemini SSE stream parser. Used by GoogleProvider.streamComplete.\n */\n\nimport type { CompleteOptions } from '../types';\nimport { toGeminiMessages, mapFinishReason } from './transform';\nimport { redactSecrets } from '../../../utils/redact';\n\nexport const THINKING_BUDGET: Record<NonNullable<CompleteOptions['thinking']>, number> = {\n  off: 0,\n  minimal: 64,\n  low: 512,\n  medium: 1024,\n  high: 4096,\n};\n\n/**\n * Per-family thinkingConfig builder — per official 2026-05 Google docs:\n *   https://ai.google.dev/gemini-api/docs/thinking\n *\n *   - Gemini 3.x / Gemma 4 → `thinkingLevel`: \"minimal\"|\"low\"|\"medium\"|\"high\"\n *   - Gemini 2.5           → `thinkingBudget`: int (0–32768, -1=dynamic)\n *\n * Sending the wrong field returns HTTP 400 (\"Thinking budget is not\n * supported for this model\").\n *\n * On Gemma 4, `includeThoughts: false` is silently ignored — the only\n * effective lever is `thinkingLevel`, and a response-side filter strips\n * `thought:true` parts as defense.\n *\n * When the caller doesn't pass `opts.thinking` we omit `thinkingConfig`\n * entirely; the model uses its dynamic default. Short / JSON tasks\n * should pass `thinking: 'off'` to avoid `maxOutputTokens` truncation.\n *\n * Returns `null` when nothing should be sent.\n */\nconst GEMMA_THINKING_LEVEL: Record<NonNullable<CompleteOptions['thinking']>, string> = {\n  off: 'minimal',\n  minimal: 'minimal',\n  low: 'low',\n  medium: 'medium',\n  high: 'high',\n};\n\nexport function buildThinkingConfig(\n  model: string,\n  thinking: CompleteOptions['thinking'] | undefined,\n): Record<string, unknown> | null {\n  if (!thinking) return null;\n  const m = model.toLowerCase();\n  // Gemini 3.x and Gemma 4 take thinkingLevel. Other Gemini families (2.5)\n  // take thinkingBudget. We can't reliably detect \"Gemini 3.x\" by prefix\n  // because the line includes pro/flash/flash-lite preview variants, so\n  // default to thinkingBudget unless we know it's a thinkingLevel family.\n  if (m.startsWith('gemma-') || /^gemini-3(\\.|-|$)/.test(m)) {\n    return { thinkingLevel: GEMMA_THINKING_LEVEL[thinking] };\n  }\n  return { thinkingBudget: THINKING_BUDGET[thinking] };\n}\n\nexport async function* streamGemini(args: {\n  apiKey: string;\n  model: string;\n  baseURL: string;\n  opts: CompleteOptions;\n}) {\n  // Key goes in a header, not the URL.\n  const url = `${args.baseURL}/models/${args.model}:streamGenerateContent?alt=sse`;\n\n  const { contents, systemInstruction } = toGeminiMessages(args.opts.messages);\n  const generationConfig: Record<string, unknown> = {\n    temperature: args.opts.temperature ?? 0.7,\n    maxOutputTokens: args.opts.maxTokens,\n  };\n  // Thinking config — see buildThinkingConfig docstring for the per-family\n  // field mapping. No auto-default: caller controls the level.\n  const thinkingPayload = buildThinkingConfig(args.model, args.opts.thinking);\n  if (thinkingPayload) generationConfig.thinkingConfig = thinkingPayload;\n  if (args.opts.jsonMode) {\n    generationConfig.responseMimeType = 'application/json';\n  }\n  const body: Record<string, unknown> = {\n    contents,\n    generationConfig,\n  };\n  if (systemInstruction) body.systemInstruction = systemInstruction;\n  if (args.opts.tools && args.opts.tools.length > 0) {\n    body.tools = [\n      {\n        functionDeclarations: args.opts.tools.map((t) => ({\n          name: t.name,\n          description: t.description,\n          parameters: t.parameters,\n        })),\n      },\n    ];\n    const choice = args.opts.toolChoice;\n    if (choice === 'required') {\n      body.tool_config = { function_calling_config: { mode: 'ANY' } };\n    } else if (typeof choice === 'object' && typeof choice.name === 'string') {\n      body.tool_config = {\n        function_calling_config: { mode: 'ANY', allowed_function_names: [choice.name] },\n      };\n    }\n  }\n\n  const response = await fetch(url, {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n      'x-goog-api-key': args.apiKey,\n    },\n    body: JSON.stringify(body),\n    signal: args.opts.signal,\n  });\n\n  if (!response.ok || !response.body) {\n    const txt = await response.text().catch(() => response.statusText);\n    throw new Error(\n      `Gemini stream HTTP ${response.status}: ${redactSecrets(txt, [args.apiKey])}`,\n    );\n  }\n\n  const reader = response.body.getReader();\n  const decoder = new TextDecoder();\n  let buf = '';\n\n  while (true) {\n    let done = false;\n    let value: Uint8Array | undefined;\n    try {\n      const r = await reader.read();\n      done = r.done;\n      value = r.value;\n    } catch (err) {\n      // User aborted the stream — surface as a clean exit so the loop\n      // can wind down without an unhandled rejection.\n      if ((err as Error).name === 'AbortError') return;\n      throw err;\n    }\n    if (done) break;\n    buf += decoder.decode(value, { stream: true });\n    const lines = buf.split('\\n');\n    buf = lines.pop() ?? '';\n\n    for (const rawLine of lines) {\n      const line = rawLine.trim();\n      if (!line || !line.startsWith('data:')) continue;\n      const data = line.slice(5).trim();\n      if (!data) continue;\n\n      let parsed: {\n        candidates?: Array<{\n          content?: {\n            parts: Array<{\n              text?: string;\n              thought?: boolean;\n              functionCall?: { name: string; args?: unknown };\n            }>;\n          };\n          finishReason?: string;\n        }>;\n        usageMetadata?: {\n          promptTokenCount: number;\n          candidatesTokenCount: number;\n          totalTokenCount: number;\n        };\n      };\n      try {\n        parsed = JSON.parse(data);\n      } catch {\n        continue;\n      }\n\n      const cand = parsed.candidates?.[0];\n      if (!cand) continue;\n\n      for (const part of cand.content?.parts ?? []) {\n        // Skip Gemma 4 thought parts — they pollute the streaming buffer\n        // and corrupt JSON output for downstream consumers (immersive\n        // translate, structured tool calling, etc.).\n        if (part.thought === true) continue;\n        if (part.text) {\n          yield { delta: part.text };\n        }\n        if (part.functionCall) {\n          yield {\n            toolCall: {\n              id: `gem_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,\n              name: part.functionCall.name,\n              arguments: (part.functionCall.args ?? {}) as Record<string, unknown>,\n            },\n          };\n        }\n      }\n      if (cand.finishReason) {\n        yield {\n          finishReason: mapFinishReason(cand.finishReason),\n          usage: parsed.usageMetadata\n            ? {\n                promptTokens: parsed.usageMetadata.promptTokenCount,\n                completionTokens: parsed.usageMetadata.candidatesTokenCount,\n              }\n            : undefined,\n        };\n      }\n    }\n  }\n}\n","/**\n * Google provider — talks to Google AI Studio (`generativelanguage.googleapis.com`).\n * Supports both Gemini (gemini-3.1-pro-preview, gemini-2.5-pro, ...) and\n * Gemma (gemma-4-31b-it, ...) — the endpoint shape is the same; only the\n * model id differs. Translates messages / tools to / from OpenAI-shape internally.\n */\n\nimport type {\n  LLMProvider,\n  CompleteOptions,\n  CompleteResult,\n  ToolCall,\n} from '../types';\nimport { buildStream, type StreamHandle, type StreamingProvider } from '../stream';\nimport { redactSecrets } from '../../../utils/redact';\nimport { toGeminiMessages, mapFinishReason } from './transform';\nimport { streamGemini, buildThinkingConfig } from './stream';\n\nexport interface GoogleProviderConfig {\n  apiKey: string;\n  model?: string;\n  baseURL?: string;\n}\n\nexport class GoogleProvider implements LLMProvider, StreamingProvider {\n  readonly name = 'google';\n\n  private apiKey: string;\n  private model: string;\n  private baseURL: string;\n\n  constructor(config: GoogleProviderConfig) {\n    this.apiKey = config.apiKey;\n    this.model = config.model ?? 'gemini-3.1-pro-preview';\n    this.baseURL = config.baseURL ?? 'https://generativelanguage.googleapis.com/v1beta';\n  }\n\n  async complete(opts: CompleteOptions): Promise<CompleteResult> {\n    const model = opts.model ?? this.model;\n    // Pass the key in a header instead of the URL query string — query\n    // strings leak into proxy access logs, browser history, and referrer\n    // headers on subsequent navigations.\n    const url = `${this.baseURL}/models/${model}:generateContent`;\n\n    const { contents, systemInstruction } = toGeminiMessages(opts.messages);\n\n    const generationConfig: Record<string, unknown> = {\n      temperature: opts.temperature ?? 0.7,\n      maxOutputTokens: opts.maxTokens,\n    };\n    // Thinking config — see buildThinkingConfig for the per-family field\n    // mapping (thinkingLevel vs. thinkingBudget) and which models reject\n    // which field. When opts.thinking is undefined we deliberately do not\n    // inject a default — the caller is responsible for choosing the right\n    // level for their workload (translation / voice cleanup → 'off';\n    // agent loop → omit to use the model's dynamic default).\n    const thinkingPayload = buildThinkingConfig(model, opts.thinking);\n    if (thinkingPayload) generationConfig.thinkingConfig = thinkingPayload;\n    if (opts.jsonMode) {\n      generationConfig.responseMimeType = 'application/json';\n    }\n    const body: Record<string, unknown> = {\n      contents,\n      generationConfig,\n    };\n\n    if (systemInstruction) body.systemInstruction = systemInstruction;\n\n    if (opts.tools && opts.tools.length > 0) {\n      body.tools = [\n        {\n          functionDeclarations: opts.tools.map((t) => ({\n            name: t.name,\n            description: t.description,\n            parameters: t.parameters,\n          })),\n        },\n      ];\n      // Gemini's tool_choice equivalent is `tool_config.function_calling_config`.\n      // mode: 'AUTO' (default) | 'ANY' (must call any tool) | 'NONE' (no tools)\n      // ANY with allowed_function_names = ['agent_turn'] forces the named tool.\n      const choice = opts.toolChoice;\n      if (choice === 'required') {\n        body.tool_config = { function_calling_config: { mode: 'ANY' } };\n      } else if (typeof choice === 'object' && typeof choice.name === 'string') {\n        body.tool_config = {\n          function_calling_config: { mode: 'ANY', allowed_function_names: [choice.name] },\n        };\n      }\n    }\n\n    // generativelanguage.googleapis.com occasionally returns transient\n    // 500/502/503 INTERNAL errors. Retry up to three times with\n    // exponential backoff (700 / 1500 / 2800 ms) plus jitter so we\n    // survive brief upstream blips without surfacing them as agent\n    // failures. 429 is handled at the proxy layer with its own\n    // pool/cooldown, so we don't retry on it here.\n    const fetchOnce = () => fetch(url, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        'x-goog-api-key': this.apiKey,\n      },\n      body: JSON.stringify(body),\n      signal: opts.signal,\n    });\n    const backoffs = [700, 1500, 2800];\n    let response = await fetchOnce();\n    for (const base of backoffs) {\n      if (response.ok) break;\n      if (response.status < 500 || response.status >= 600) break;\n      // Drain failed body so the connection can be reused.\n      try { await response.text(); } catch { /* noop */ }\n      const jitter = Math.random() * 250;\n      await new Promise((r) => setTimeout(r, base + jitter));\n      response = await fetchOnce();\n    }\n\n    if (!response.ok) {\n      const errText = await response.text().catch(() => response.statusText);\n      throw new Error(\n        `Gemini HTTP ${response.status}: ${redactSecrets(errText, [this.apiKey])}`,\n      );\n    }\n\n    const data = (await response.json()) as GeminiResponse;\n    const candidate = data.candidates?.[0];\n    if (!candidate) throw new Error('Gemini: no candidates returned');\n\n    let content = '';\n    const toolCalls: ToolCall[] = [];\n\n    for (const part of candidate.content?.parts ?? []) {\n      // Gemma 4 emits reasoning as `{ text, thought: true }` parts even\n      // at thinkingLevel=MINIMAL. Drop them so the model's chain-of-thought\n      // never leaks into translated/JSON output.\n      if (part.thought === true) continue;\n      if (part.text) content += part.text;\n      if (part.functionCall) {\n        toolCalls.push({\n          id: `call_${toolCalls.length}_${Date.now()}`,\n          name: part.functionCall.name,\n          arguments: (part.functionCall.args ?? {}) as Record<string, unknown>,\n        });\n      }\n    }\n\n    return {\n      content,\n      toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n      usage: data.usageMetadata\n        ? {\n            promptTokens: data.usageMetadata.promptTokenCount,\n            completionTokens: data.usageMetadata.candidatesTokenCount,\n          }\n        : undefined,\n      finishReason: mapFinishReason(candidate.finishReason),\n    };\n  }\n\n  /**\n   * Streaming via Gemini's :streamGenerateContent endpoint (alt=sse).\n   */\n  streamComplete(opts: CompleteOptions): StreamHandle {\n    const apiKey = this.apiKey;\n    const model = opts.model ?? this.model;\n    const baseURL = this.baseURL;\n\n    return buildStream({\n      produce: () => streamGemini({ apiKey, model, baseURL, opts }),\n    });\n  }\n}\n\ninterface GeminiResponse {\n  candidates?: Array<{\n    content?: {\n      parts: Array<{\n        text?: string;\n        thought?: boolean;\n        functionCall?: { name: string; args?: unknown };\n      }>;\n    };\n    finishReason?: string;\n  }>;\n  usageMetadata?: {\n    promptTokenCount: number;\n    candidatesTokenCount: number;\n    totalTokenCount: number;\n  };\n}\n","/**\n * ProxyProvider — calls the host's own backend instead of OpenAI/Gemini directly.\n *\n * **THE production-safe pattern for BYOK + browser apps.** The user's API key\n * never touches client code: client → your /api/llm endpoint → OpenAI.\n *\n * Your backend implements `/api/llm/complete` (or whatever path), reads the\n * key from `process.env`, and forwards the request. This file is the client\n * half — it sends OpenAI-shaped `CompleteOptions`, expects the standardized\n * `CompleteResult` shape back.\n *\n * See ../../docs/09-security.md for full discussion + a Node.js reference\n * implementation.\n */\n\nimport type {\n  LLMProvider,\n  CompleteOptions,\n  CompleteResult,\n  LLMMessage,\n  ToolCall,\n} from './types';\nimport { buildStream, type StreamHandle, type StreamingProvider } from './stream';\nimport { redactSecrets } from '../../utils/redact';\n\nexport interface ProxyProviderConfig {\n  /** Endpoint that returns CompleteResult-shaped JSON. */\n  endpoint: string;\n\n  /** Method override (default 'POST'). */\n  method?: 'POST' | 'PUT';\n\n  /** Extra headers — pass auth tokens etc. */\n  headers?: Record<string, string>;\n\n  /**\n   * Optional credentials override. Set 'include' if your endpoint is\n   * cross-origin and relies on cookies.\n   */\n  credentials?: RequestCredentials;\n\n  /**\n   * Optional request body transformer — if your backend expects a different\n   * shape than the default `{ messages, tools, ... }`.\n   */\n  buildBody?: (opts: CompleteOptions) => unknown;\n\n  /**\n   * Optional response transformer — if your backend returns a different\n   * shape than `CompleteResult`. Map it here.\n   */\n  parseResult?: (raw: unknown) => CompleteResult;\n\n  /**\n   * Logical model name to advertise — purely informational, controls the\n   * `name` field. Default 'proxy'.\n   */\n  name?: string;\n\n  /**\n   * Per-request timeout in milliseconds. The proxy aborts the fetch and\n   * throws if no response arrives in this window. Default 30_000 (30s).\n   * Pass `0` (or any non-positive value) to disable.\n   */\n  timeoutMs?: number;\n}\n\nconst DEFAULT_PROXY_TIMEOUT_MS = 30_000;\n\nexport class ProxyProvider implements LLMProvider, StreamingProvider {\n  readonly name: string;\n  private config: ProxyProviderConfig;\n\n  constructor(config: ProxyProviderConfig) {\n    this.config = config;\n    this.name = config.name ?? 'proxy';\n  }\n\n  async complete(opts: CompleteOptions): Promise<CompleteResult> {\n    const body = this.config.buildBody\n      ? this.config.buildBody(opts)\n      : defaultBody(opts);\n\n    // Compose abort signal: combine the caller's signal with our timeout\n    // signal so either source can cancel.\n    const timeoutMs = this.config.timeoutMs ?? DEFAULT_PROXY_TIMEOUT_MS;\n    const timeoutCtrl = new AbortController();\n    let timeoutHandle: ReturnType<typeof setTimeout> | null = null;\n    if (timeoutMs > 0) {\n      timeoutHandle = setTimeout(() => timeoutCtrl.abort(new Error('proxy timeout')), timeoutMs);\n    }\n    const onCallerAbort = () => timeoutCtrl.abort(opts.signal!.reason);\n    if (opts.signal) {\n      if (opts.signal.aborted) timeoutCtrl.abort(opts.signal.reason);\n      else opts.signal.addEventListener('abort', onCallerAbort, { once: true });\n    }\n\n    try {\n      const response = await fetch(this.config.endpoint, {\n        method: this.config.method ?? 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n          ...(this.config.headers ?? {}),\n        },\n        credentials: this.config.credentials,\n        body: JSON.stringify(body),\n        signal: timeoutCtrl.signal,\n      });\n\n      if (!response.ok) {\n        const text = await response.text().catch(() => response.statusText);\n        throw new Error(`Proxy HTTP ${response.status}: ${text}`);\n      }\n\n      const raw = (await response.json()) as unknown;\n      return this.config.parseResult ? this.config.parseResult(raw) : defaultParse(raw);\n    } finally {\n      if (timeoutHandle !== null) clearTimeout(timeoutHandle);\n      if (opts.signal) opts.signal.removeEventListener('abort', onCallerAbort);\n    }\n  }\n\n  /**\n   * Streaming via the same endpoint. Default body shape (OpenAI-compatible)\n   * is `{ messages, tools, ..., stream: true }`; the proxy is expected to\n   * forward the SSE body verbatim. Hosts using a non-OpenAI wire shape\n   * should override `buildBody` to inject their own streaming flag and\n   * implement an OpenAI-style SSE on the backend (or use a separate\n   * provider class).\n   */\n  streamComplete(opts: CompleteOptions): StreamHandle {\n    const body = this.config.buildBody\n      ? this.config.buildBody({ ...opts })\n      : { ...defaultBody(opts), stream: true };\n\n    const endpoint = this.config.endpoint;\n    const headers = {\n      'Content-Type': 'application/json',\n      ...(this.config.headers ?? {}),\n    };\n    const method = this.config.method ?? 'POST';\n    const credentials = this.config.credentials;\n\n    return buildStream({\n      produce: () => streamProxy({ endpoint, method, headers, body, credentials, signal: opts.signal }),\n    });\n  }\n}\n\nasync function* streamProxy(args: {\n  endpoint: string;\n  method: 'POST' | 'PUT';\n  headers: Record<string, string>;\n  body: unknown;\n  credentials?: RequestCredentials;\n  signal?: AbortSignal;\n}): AsyncIterable<{ delta?: string; toolCall?: ToolCall; finishReason?: CompleteResult['finishReason']; usage?: CompleteResult['usage'] }> {\n  const response = await fetch(args.endpoint, {\n    method: args.method,\n    headers: args.headers,\n    credentials: args.credentials,\n    body: JSON.stringify(args.body),\n    signal: args.signal,\n  });\n  if (!response.ok) {\n    const text = await response.text().catch(() => response.statusText);\n    throw new Error(`Proxy HTTP ${response.status}: ${redactSecrets(text, [])}`);\n  }\n  if (!response.body) {\n    throw new Error('Proxy: no response body for stream');\n  }\n\n  // Assume OpenAI-compatible SSE. Hosts that need a different wire shape\n  // should implement their own streaming provider.\n  const inflight = new Map<number, { id: string; name: string; argsBuf: string }>();\n  const yielded = new Set<number>();\n  const reader = response.body.getReader();\n  const decoder = new TextDecoder();\n  let buf = '';\n  let finishReason: CompleteResult['finishReason'] | undefined;\n\n  while (true) {\n    let value: Uint8Array | undefined;\n    let done = false;\n    try {\n      const r = await reader.read();\n      value = r.value;\n      done = r.done;\n    } catch (err) {\n      // User-initiated abort — exit silently rather than bubbling an\n      // AbortError up to the unhandled-rejection handler.\n      if ((err as Error).name === 'AbortError') return;\n      throw err;\n    }\n    if (done) break;\n    buf += decoder.decode(value, { stream: true });\n    let sep: number;\n    while ((sep = buf.indexOf('\\n\\n')) !== -1) {\n      const event = buf.slice(0, sep);\n      buf = buf.slice(sep + 2);\n      if (!event.trim()) continue;\n      for (const line of event.split('\\n')) {\n        if (!line.startsWith('data:')) continue;\n        const payload = line.slice(5).trim();\n        if (payload === '[DONE]') continue;\n        let parsed: ProxyStreamChunk;\n        try { parsed = JSON.parse(payload) as ProxyStreamChunk; } catch { continue; }\n        const choice = parsed.choices?.[0];\n        if (!choice) continue;\n        const delta = choice.delta ?? {};\n        if (typeof delta.content === 'string' && delta.content.length > 0) {\n          yield { delta: delta.content };\n        }\n        if (Array.isArray(delta.tool_calls)) {\n          for (const frag of delta.tool_calls) {\n            const idx = frag.index ?? 0;\n            let entry = inflight.get(idx);\n            if (!entry) {\n              entry = { id: frag.id ?? `call_${idx}_${Date.now()}`, name: frag.function?.name ?? '', argsBuf: '' };\n              inflight.set(idx, entry);\n            } else {\n              if (frag.id) entry.id = frag.id;\n              if (frag.function?.name) entry.name = frag.function.name;\n            }\n            if (frag.function?.arguments) entry.argsBuf += frag.function.arguments;\n            if (entry.name && !yielded.has(idx)) {\n              const parsedArgs = safeParseJson(entry.argsBuf);\n              if (parsedArgs !== null) {\n                yielded.add(idx);\n                yield { toolCall: { id: entry.id, name: entry.name, arguments: parsedArgs } };\n              }\n            }\n          }\n        }\n        if (choice.finish_reason) {\n          finishReason = choice.finish_reason as CompleteResult['finishReason'];\n          for (const [idx, entry] of inflight) {\n            if (yielded.has(idx) || !entry.name) continue;\n            yielded.add(idx);\n            yield { toolCall: { id: entry.id, name: entry.name, arguments: safeParseJson(entry.argsBuf) ?? {} } };\n          }\n        }\n      }\n    }\n  }\n  if (finishReason) yield { finishReason };\n}\n\nfunction safeParseJson(s: string): Record<string, unknown> | null {\n  if (!s) return {};\n  try { return JSON.parse(s) as Record<string, unknown>; } catch { return null; }\n}\n\ninterface ProxyStreamChunk {\n  choices?: Array<{\n    delta?: {\n      content?: string;\n      tool_calls?: Array<{\n        index?: number;\n        id?: string;\n        function?: { name?: string; arguments?: string };\n      }>;\n    };\n    finish_reason?: string | null;\n  }>;\n}\n\n// ─── default wire shapes ────────────────────────────────────────────\n\nfunction defaultBody(opts: CompleteOptions): Record<string, unknown> {\n  return {\n    messages: opts.messages,\n    tools: opts.tools,\n    toolChoice: opts.toolChoice,\n    temperature: opts.temperature,\n    maxTokens: opts.maxTokens,\n    model: opts.model,\n    // Forward jsonMode so the backend can set `response_format:{type:'json_object'}`.\n    // The webagent's cotMode (`agent_turn` structured envelope) relies on this —\n    // without it weaker models free-form and emit an \"invalid agent_turn envelope\".\n    jsonMode: opts.jsonMode,\n  };\n}\n\nfunction defaultParse(raw: unknown): CompleteResult {\n  if (raw && typeof raw === 'object') {\n    const r = raw as Record<string, unknown>;\n    return {\n      content: typeof r.content === 'string' ? r.content : '',\n      toolCalls: Array.isArray(r.toolCalls) ? (r.toolCalls as ToolCall[]) : undefined,\n      usage: r.usage as CompleteResult['usage'],\n      finishReason: (r.finishReason as CompleteResult['finishReason']) ?? 'stop',\n    };\n  }\n  return { content: '', finishReason: 'stop' };\n}\n","/**\n * Adapter registry — module-level map from id → adapter.\n *\n * IMPORTANT: This module does NOT auto-register the built-in adapters.\n * Per the tsup tree-shake constraint (see project memory\n * `feedback_sdk_seed_tree_shake.md`), side-effect imports are dropped\n * from the bundle, so the host MUST call `seedDefaultAdapters()`\n * explicitly at boot to get the OpenAI/Google/Proxy adapters available.\n *\n * The registry is per-process (module singleton). All `createProvider`\n * / `getAdapter` calls see the same map. Re-registering an id silently\n * replaces the previous adapter — useful when an app wants to swap the\n * default OpenAI adapter for one that hits an internal proxy.\n */\n\nimport type { LLMProvider } from '../types';\nimport type { LLMAdapter, AdapterConfig } from './types';\n\nconst registry = new Map<string, LLMAdapter>();\n\n/** Register or replace an adapter by id. */\nexport function registerAdapter(adapter: LLMAdapter): void {\n  registry.set(adapter.id, adapter);\n}\n\n/** Get an adapter by id, or undefined if not registered. */\nexport function getAdapter(id: string): LLMAdapter | undefined {\n  return registry.get(id);\n}\n\n/** All currently-registered adapters (insertion order). */\nexport function listAdapters(): LLMAdapter[] {\n  return [...registry.values()];\n}\n\n/** Remove an adapter from the registry. Returns whether it existed. */\nexport function unregisterAdapter(id: string): boolean {\n  return registry.delete(id);\n}\n\n/**\n * Build a provider from either:\n *   1. A `\"<adapter>:<model>\"` spec string (`\"openai:gpt-5.4-mini\"`)\n *      — looks up the adapter, calls `.create({ model })` against it.\n *      Caller can pass extra `{ apiKey, baseURL, ... }` via the second arg.\n *   2. A config object with an explicit `adapter` field.\n *\n * Throws if no adapter is registered for the given id. We throw instead\n * of returning null because a missing adapter is almost always a boot-\n * order bug (forgot `seedDefaultAdapters()`) and a loud failure\n * surfaces it faster than a silent `null`.\n */\nexport function createProvider(\n  spec: string | (AdapterConfig & { adapter: string }),\n  extra?: AdapterConfig,\n): LLMProvider {\n  if (typeof spec === 'string') {\n    const idx = spec.indexOf(':');\n    if (idx < 0) throw new Error(`LLM spec must be \"<adapter>:<model>\", got \"${spec}\"`);\n    const adapterId = spec.slice(0, idx).trim();\n    const model = spec.slice(idx + 1).trim();\n    return createProvider({ ...(extra ?? {}), adapter: adapterId, model });\n  }\n  const { adapter: adapterId, ...config } = spec;\n  const adapter = registry.get(adapterId);\n  if (!adapter) {\n    throw new Error(\n      `No LLM adapter registered for \"${adapterId}\". Did you call seedDefaultAdapters()?`,\n    );\n  }\n  return adapter.create(config);\n}\n","/**\n * OpenAI adapter — wraps `OpenAIProvider`.\n *\n * `matchesModel` returns true for OpenAI's first-party model families\n * (`gpt-*`, `o1`/`o3`/..., `text-*`). Routers that detect by model id\n * use this as the dispatch test.\n *\n * Vendor quirks (see `notes/llm-adapter-guide.md` § 3 for full table):\n *   - gpt-5+ (incl. `-mini`/`-nano`) require `max_completion_tokens`,\n *     NOT `max_tokens`.\n *   - True reasoning models (o-series, gpt-5+ full non-mini) reject\n *     custom `temperature`.\n *   - `-mini` / `-nano` accept both temperature AND `max_completion_tokens`.\n * These are all handled inside `OpenAIProvider.complete()`.\n */\n\nimport { OpenAIProvider, type OpenAIProviderConfig } from '../openai';\nimport type { LLMAdapter, AdapterConfig } from './types';\n\nexport const openaiAdapter: LLMAdapter = {\n  id: 'openai',\n  matchesModel(modelId: string): boolean {\n    return /^(gpt-|o[1-9]|text-)/i.test(modelId);\n  },\n  create(config: AdapterConfig) {\n    const cfg: OpenAIProviderConfig = {\n      apiKey: String(config.apiKey ?? ''),\n      model: config.model as string | undefined,\n      baseURL: config.baseURL as string | undefined,\n      organization: config.organization as string | undefined,\n      headers: config.headers as Record<string, string> | undefined,\n      extraBody: config.extraBody as Record<string, unknown> | undefined,\n    };\n    return new OpenAIProvider(cfg);\n  },\n};\n","/**\n * Google adapter — wraps `GoogleProvider`, covering both Gemini and Gemma\n * model families (both go through `generativelanguage.googleapis.com`).\n * `matchesModel` recognises `gemini-*` and `gemma-*` model ids.\n *\n * Model-family quirks are normalised inside `GoogleProvider.complete()`\n * via `buildThinkingConfig` — Gemini 3.x / Gemma 4 use `thinkingLevel`,\n * Gemini 2.5 uses `thinkingBudget`, and `part.thought === true` parts\n * are stripped from responses so reasoning never leaks.\n */\n\nimport { GoogleProvider, type GoogleProviderConfig } from '../google';\nimport type { LLMAdapter, AdapterConfig } from './types';\n\nexport const googleAdapter: LLMAdapter = {\n  id: 'google',\n  matchesModel(modelId: string): boolean {\n    return /^(gemini-|gemma-)/i.test(modelId);\n  },\n  create(config: AdapterConfig) {\n    const cfg: GoogleProviderConfig = {\n      apiKey: String(config.apiKey ?? ''),\n      model: config.model as string | undefined,\n      baseURL: config.baseURL as string | undefined,\n    };\n    return new GoogleProvider(cfg);\n  },\n};\n","/**\n * Proxy adapter — wraps `ProxyProvider`. The production-safe pattern for\n * BYOK in browser apps: client → your /api/llm endpoint → vendor. The\n * adapter is registered under id `'proxy'`; `matchesModel` is omitted\n * because proxy routes don't carry a model-id naming convention.\n *\n * Config keys:\n *   - `endpoint`     (string, required) — backend URL\n *   - `method`       ('POST' | 'PUT')\n *   - `headers`      (Record<string,string>)\n *   - `credentials`  (RequestCredentials)\n *   - `buildBody`    ((opts) => unknown)\n *   - `parseResult`  ((raw) => CompleteResult)\n *   - `timeoutMs`    (number)\n *   - `name`         (string)\n *\n * See `ProxyProviderConfig` for the full surface.\n */\n\nimport { ProxyProvider, type ProxyProviderConfig } from '../proxy';\nimport type { LLMAdapter, AdapterConfig } from './types';\n\nexport const proxyAdapter: LLMAdapter = {\n  id: 'proxy',\n  create(config: AdapterConfig) {\n    if (typeof config.endpoint !== 'string' || !config.endpoint) {\n      throw new Error('proxy adapter requires `endpoint` (string)');\n    }\n    const cfg: ProxyProviderConfig = {\n      endpoint: config.endpoint,\n      method: config.method as ProxyProviderConfig['method'],\n      headers: config.headers as Record<string, string> | undefined,\n      credentials: config.credentials as RequestCredentials | undefined,\n      buildBody: config.buildBody as ProxyProviderConfig['buildBody'],\n      parseResult: config.parseResult as ProxyProviderConfig['parseResult'],\n      name: config.name as string | undefined,\n      timeoutMs: config.timeoutMs as number | undefined,\n    };\n    return new ProxyProvider(cfg);\n  },\n};\n","/**\n * Agnes AI adapter — wraps `OpenAIProvider` against Agnes AI's\n * OpenAI-compatible gateway.\n *\n * Agnes AI (https://agnes-ai.com) exposes a vLLM-backed, OpenAI-compatible\n * API at `https://apihub.agnes-ai.com/v1`: standard `/chat/completions`\n * (blocking + SSE streaming), `/models`, `/images/generations`, Bearer\n * auth. Responses carry extra `provider_specific_fields` keys which the\n * OpenAI parser ignores, and may omit the `data: [DONE]` SSE sentinel\n * (the empty-`choices` usage chunk marks the end) — both handled by\n * `OpenAIProvider`'s tolerant stream reader.\n *\n * The free tier is capped at ~20 RPM on a shared key, so the canonical\n * deployment proxies through a backend (dddk-frontend `/api/llm/agnes/v1`)\n * that injects the real key and throttles — same `proxied-via-worker`\n * dummy-key pattern as the other vendors. Direct use (passing a real\n * `apiKey`) works too for local testing.\n *\n * Verified live 2026-06-23 via curl: base URL, bearer auth, model list\n * (`agnes-2.0-flash` for chat), blocking + streaming all confirmed.\n */\n\nimport { OpenAIProvider, type OpenAIProviderConfig } from '../openai';\nimport type { LLMAdapter, AdapterConfig } from './types';\n\n/** Agnes AI default gateway (OpenAI-compatible). */\nexport const AGNES_BASE_URL = 'https://apihub.agnes-ai.com/v1';\n/** Default chat/coding/tool-calling model. */\nexport const AGNES_DEFAULT_MODEL = 'agnes-2.0-flash';\n\nexport const agnesAdapter: LLMAdapter = {\n  id: 'agnes',\n  matchesModel(modelId: string): boolean {\n    return /^agnes-/i.test(modelId);\n  },\n  create(config: AdapterConfig) {\n    const cfg: OpenAIProviderConfig = {\n      apiKey: String(config.apiKey ?? ''),\n      model: (config.model as string | undefined) ?? AGNES_DEFAULT_MODEL,\n      baseURL: (config.baseURL as string | undefined) ?? AGNES_BASE_URL,\n      headers: config.headers as Record<string, string> | undefined,\n      extraBody: config.extraBody as Record<string, unknown> | undefined,\n    };\n    return new OpenAIProvider(cfg);\n  },\n};\n","/**\n * LLM Adapter system — public entry point.\n *\n * Typical boot:\n *\n *   import { seedDefaultAdapters, createProvider } from '@perhapxin/dddk';\n *   seedDefaultAdapters();\n *   const provider = createProvider('google:gemma-4-26b-a4b-it', {\n *     apiKey: env.GOOGLE_API_KEY,\n *   });\n *\n * Custom adapter (e.g. self-hosted vLLM exposing an OpenAI-compatible\n * endpoint at a private URL):\n *\n *   import { registerAdapter, type LLMAdapter } from '@perhapxin/dddk';\n *   registerAdapter({\n *     id: 'company-vllm',\n *     matchesModel: (m) => m.startsWith('vllm/'),\n *     create: (c) => new OpenAIProvider({\n *       apiKey: c.apiKey ?? '',\n *       baseURL: 'https://llm.internal.acme.com/v1',\n *       model: c.model,\n *     }),\n *   });\n *\n * `seedDefaultAdapters()` must be called explicitly — bundlers tree-shake\n * pure side-effect imports.\n */\n\nimport { registerAdapter } from './registry';\nimport { openaiAdapter } from './openai';\nimport { googleAdapter } from './google';\nimport { proxyAdapter } from './proxy';\nimport { agnesAdapter } from './agnes';\n\nexport { openaiAdapter, googleAdapter, proxyAdapter, agnesAdapter };\nexport {\n  registerAdapter,\n  getAdapter,\n  listAdapters,\n  unregisterAdapter,\n  createProvider,\n} from './registry';\nexport type { LLMAdapter, AdapterConfig } from './types';\n\n/**\n * Register the built-in adapters (`openai`, `google`, `proxy`, `agnes`).\n * Idempotent: safe to call multiple times. Returns the list of registered\n * adapter ids for diagnostic logging.\n */\nexport function seedDefaultAdapters(): string[] {\n  registerAdapter(openaiAdapter);\n  registerAdapter(googleAdapter);\n  registerAdapter(proxyAdapter);\n  registerAdapter(agnesAdapter);\n  return [openaiAdapter.id, googleAdapter.id, proxyAdapter.id, agnesAdapter.id];\n}\n","/**\n * multi-step transaction skill pattern.\n *\n * Some product flows aren't a one-shot agent task. They're transactions:\n * step 1 needs to land BEFORE step 2 runs (e.g. create draft → add line\n * items → submit), and if step 3 fails the host wants to roll back what\n * steps 1+2 did.\n *\n * Existing `ScriptSkill.steps` runs forward only. This module adds a\n * `TransactionStep` extension where each step can:\n *   - declare an `assert` predicate that gates progress to the next step\n *     (returns false → step is treated as failed)\n *   - declare a `compensate` rollback handler — on later failure, the\n *     runner replays compensators of completed steps in REVERSE order\n *\n * Use:\n *\n *   import { runTransaction } from '@perhapxin/dddk';\n *\n *   const outcome = await runTransaction({\n *     tools,                       // SkillTools from a Script skill\n *     steps: [\n *       {\n *         name: 'create_draft',\n *         action: async (t) => t.navigate('/orders/new'),\n *         assert: () => location.pathname.startsWith('/orders/new'),\n *         compensate: async (t) => t.navigate('/orders'),\n *       },\n *       {\n *         name: 'add_line',\n *         action: async (t) => t.navigate('/orders/new/line'),\n *         assert: () => document.querySelector('.line-row') != null,\n *         compensate: async () => { console.info('cleanup line-add'); },\n *       },\n *     ],\n *   });\n *\n *   if (!outcome.ok) {\n *     console.warn('transaction failed:', outcome.failedStep, outcome.error);\n *     // outcome.compensated lists the names of compensators that ran.\n *   }\n *\n * Compensators are best-effort: a throwing compensator is logged and\n * the runner continues to the next one, so a partial rollback is\n * better than no rollback.\n */\n\nimport type { SkillTools } from './types';\n\nexport interface TransactionStep {\n  name: string;\n  action: (tools: SkillTools) => void | Promise<void>;\n  /** Optional gate — return true to advance, false to treat the step as\n   *  failed. Default = true (no gate). Synchronous only for now. */\n  assert?: () => boolean;\n  /** Rollback handler. Runs in reverse order on later failure. */\n  compensate?: (tools: SkillTools) => void | Promise<void>;\n  /** Delay (ms) after the action before evaluating `assert`. Default 80. */\n  settleMs?: number;\n}\n\nexport interface TransactionOpts {\n  tools: SkillTools;\n  steps: TransactionStep[];\n  /** Optional signal — if aborted, the runner halts AND replays\n   *  compensators for completed steps. */\n  signal?: AbortSignal;\n}\n\nexport interface TransactionOutcome {\n  ok: boolean;\n  /** Names of steps whose action completed (and assert passed). */\n  completed: string[];\n  /** Set when ok=false: the step that failed. */\n  failedStep: string | null;\n  /** Set when ok=false: error or reason. */\n  error: string | null;\n  /** Names of compensators that ran during rollback (reverse order). */\n  compensated: string[];\n}\n\nexport async function runTransaction(opts: TransactionOpts): Promise<TransactionOutcome> {\n  const { tools, steps, signal } = opts;\n  const completed: TransactionStep[] = [];\n\n  for (const step of steps) {\n    if (signal?.aborted) {\n      const compensated = await rollback(completed, tools);\n      return { ok: false, completed: completed.map((s) => s.name), failedStep: step.name, error: 'aborted', compensated };\n    }\n    try {\n      await step.action(tools);\n    } catch (e) {\n      const compensated = await rollback(completed, tools);\n      return {\n        ok: false,\n        completed: completed.map((s) => s.name),\n        failedStep: step.name,\n        error: e instanceof Error ? e.message : String(e),\n        compensated,\n      };\n    }\n    if (step.settleMs !== 0) {\n      await new Promise((r) => setTimeout(r, step.settleMs ?? 80));\n    }\n    if (step.assert) {\n      let passed: boolean;\n      try { passed = step.assert(); } catch { passed = false; }\n      if (!passed) {\n        const compensated = await rollback(completed, tools);\n        return {\n          ok: false,\n          completed: completed.map((s) => s.name),\n          failedStep: step.name,\n          error: 'assert failed',\n          compensated,\n        };\n      }\n    }\n    completed.push(step);\n  }\n  return {\n    ok: true,\n    completed: completed.map((s) => s.name),\n    failedStep: null,\n    error: null,\n    compensated: [],\n  };\n}\n\nasync function rollback(completed: TransactionStep[], tools: SkillTools): Promise<string[]> {\n  const ran: string[] = [];\n  for (let i = completed.length - 1; i >= 0; i--) {\n    const step = completed[i]!;\n    if (!step.compensate) continue;\n    try {\n      await step.compensate(tools);\n      ran.push(step.name);\n    } catch {\n      // Compensator threw — keep going so a partial rollback still\n      // happens. The caller sees this step missing from `compensated`.\n    }\n  }\n  return ran;\n}\n","/**\n * Dock state tracker — persists \"minimized\" and \"closed\" state for surfaces\n * rendered with `placement: 'dock'`. dddk doesn't ship the dock widget itself\n * (hosts implement their own UI); this tracker provides the persistence layer\n * so user state survives reloads.\n *\n * Usage in a host renderer:\n *\n *   const dock = createDockState({ id: 'task_progress' });\n *   dock.onChange(({ minimized, closed }) => updateUI({ minimized, closed }));\n *\n *   minimizeBtn.onclick = () => dock.minimize();\n *   closeBtn.onclick    = () => dock.close();\n *   restoreBtn.onclick  = () => dock.restore();\n */\n\nexport type DockStateValue = {\n  minimized: boolean;\n  closed: boolean;\n};\n\nexport interface DockState {\n  id: string;\n  read(): DockStateValue;\n  minimize(): void;\n  restore(): void;\n  close(): void;\n  reopen(): void;\n  onChange(handler: (value: DockStateValue) => void): () => void;\n}\n\nexport interface DockStateOpts {\n  id: string;\n  /** Where to persist state. Defaults to localStorage. Set to 'memory' to skip persistence. */\n  storage?: 'localstorage' | 'memory';\n}\n\nconst STORAGE_PREFIX = 'dddk:dock:';\n\nexport function createDockState(opts: DockStateOpts): DockState {\n  const { id } = opts;\n  const useStorage = (opts.storage ?? 'localstorage') === 'localstorage' && typeof localStorage !== 'undefined';\n  const storageKey = STORAGE_PREFIX + id;\n  const listeners = new Set<(v: DockStateValue) => void>();\n\n  let value: DockStateValue = { minimized: false, closed: false };\n  if (useStorage) {\n    try {\n      const raw = localStorage.getItem(storageKey);\n      if (raw) value = JSON.parse(raw);\n    } catch {\n      /* ignore */\n    }\n  }\n\n  function emit(): void {\n    if (useStorage) {\n      try {\n        localStorage.setItem(storageKey, JSON.stringify(value));\n      } catch {\n        /* quota / private mode — ignore */\n      }\n    }\n    listeners.forEach((fn) => fn({ ...value }));\n  }\n\n  return {\n    id,\n    read: () => ({ ...value }),\n    minimize() {\n      value = { minimized: true, closed: false };\n      emit();\n    },\n    restore() {\n      value = { minimized: false, closed: false };\n      emit();\n    },\n    close() {\n      value = { minimized: false, closed: true };\n      emit();\n    },\n    reopen() {\n      value = { minimized: false, closed: false };\n      emit();\n    },\n    onChange(handler) {\n      listeners.add(handler);\n      handler({ ...value });\n      return () => listeners.delete(handler);\n    },\n  };\n}\n","/**\r\n * ImmersiveTranslate — page-wide bilingual rendering.\r\n *\r\n * UX (common pattern for inline page-translation tooling):\r\n *   1. Host calls `translate.enable('zh-TW')` (usually from a palette command).\r\n *   2. Module walks the visible DOM, collects translatable text BLOCKS (one\r\n *      per block-level element — paragraph, heading, list item, etc.).\r\n *   3. Blocks are BATCHED into LLM calls (default 30 blocks per call, ~5k\r\n *      chars per call cap) — so a 200-paragraph article costs ~7 API calls,\r\n *      not 200.\r\n *   4. For each translated block, we append a styled inline element AFTER\r\n *      the original (NOT replacing). Default wrapper is `<font class=\r\n *      \"dddk-imm-translate\">` — a deliberate use of the legacy <font> tag\r\n *      because it survives most rich-text editors and PDF viewers without\r\n *      being styled away by host CSS, which is the conventional choice for\r\n *      this kind of inline-translation overlay.\r\n *   5. Cache by content hash so re-enabling the same language is instant.\r\n *\r\n * Limitations:\r\n *   - PDFs: HTML viewers (pdf.js / Chrome built-in) render selectable text\r\n *     in an overlay — this module will translate that overlay if it's part\r\n *     of the DOM; native PDF viewers (the browser plugin) are out of reach.\r\n *   - docx: native .docx files served as downloads are not in the DOM.\r\n *     If your host renders docx as HTML (e.g. via mammoth.js), it works.\r\n *     If you embed Office Online viewer, the iframe is cross-origin → out\r\n *     of reach.\r\n *   - Both PDF and docx have to be HTML in the page for this module to\r\n *     touch them. The output convention (`<font class=\"dddk-imm-translate\">`)\r\n *     was chosen so downstream PDF / docx renderers that DO accept inline\r\n *     HTML preserve the bilingual layout.\r\n */\r\n\r\nimport { resolveLLM, type LLMSource } from '../../agent/llm/router';\r\nimport type { DotDotDuck } from '../../orchestrator';\r\nimport { stripCodeFence } from '../../utils/llm-parse';\r\nimport { injectScopedStyle } from '../../utils/dom';\r\n\r\nconst TRANSLATED_ATTR = 'data-dddk-imm-translated';\r\nconst WRAPPER_TAG = 'font';                         // see file header\r\nconst WRAPPER_CLASS = 'dddk-imm-translate';\r\nconst STYLE_ID = 'dddk-imm-translate-style';\r\n\r\nexport interface ImmersiveTranslateConfig {\r\n  llm: LLMSource;\r\n  /** Max DOM blocks per LLM call. Default 30. */\r\n  batchSize?: number;\r\n  /** Max combined chars per LLM call. Default 4500. Batches break here too. */\r\n  batchCharCap?: number;\r\n  /** CSS selectors whose contents should NOT be translated. */\r\n  ignoreSelector?: string;\r\n  /** Root element to walk. Default `document.body`. */\r\n  root?: HTMLElement;\r\n  /** Optional persisted cache. Falls back to in-memory Map. */\r\n  cache?: { get(key: string): string | null; set(key: string, val: string): void };\r\n}\r\n\r\nconst DEFAULT_IGNORE = [\r\n  '[data-dddk-ui]',\r\n  '[data-dddk-no-translate]',\r\n  'script', 'style', 'noscript', 'svg', 'code', 'pre', 'kbd',\r\n  '.dddk-imm-translate',\r\n];\r\n\r\n// Translatable block tags. `div` is included because many design systems\r\n// (Tailwind UI, custom card components, SvelteKit pages, etc.) use bare\r\n// `<div>` for card titles / bodies / sections instead of semantic `<p>` /\r\n// `<h*>` — without `div` we silently skip those texts. The walker's\r\n// \"skip if contains a block child\" rule (see `collectBlocks`) prevents\r\n// double-translation of div-wrapped paragraphs, since the outer div is\r\n// SKIPped (descend) when its children are also blocks.\r\nconst BLOCK_TAGS = new Set([\r\n  'p', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote',\r\n  'figcaption', 'td', 'th', 'dt', 'dd', 'summary', 'caption',\r\n  'div',\r\n]);\r\n\r\n// System prompt lives in `./prompt.ts` and is registered on the SDK's\r\n// central prompt registry. Callsites below resolve via the registry so\r\n// hosts can override per-locale without patching this file.\r\nimport { PROMPT_IDS, promptRegistry } from '../../prompts/registry';\r\nimport { registerBuiltinPrompts } from '../../prompts/defaults';\r\n\r\n// Ensure defaults are registered on module load. Idempotent — safe to\r\n// call from multiple entry points.\r\nregisterBuiltinPrompts();\r\n\r\nexport class ImmersiveTranslate {\r\n  private cfg: Required<Pick<ImmersiveTranslateConfig, 'batchSize' | 'batchCharCap' | 'root'>>\r\n    & Pick<ImmersiveTranslateConfig, 'llm' | 'ignoreSelector' | 'cache'>;\r\n  private effectiveIgnore: string;\r\n  private memCache = new Map<string, string>();\r\n  private currentLang: string | null = null;\r\n  private dddk: DotDotDuck | null = null;\r\n  /** Teardown for the SPA route-change listener installed in `attachTo`. */\r\n  private routeChangeTeardown: (() => void) | null = null;\r\n\r\n  constructor(config: ImmersiveTranslateConfig) {\r\n    this.cfg = {\r\n      llm: config.llm,\r\n      // Smaller batches than the original 30 / 4500. With Promise.all\r\n      // fan-out, latency is bounded by the slowest single call —\r\n      // generating 4500 chars of translation takes ~5s on a mid model,\r\n      // generating 1200 chars takes ~1.5s. The total work is the same,\r\n      // so more, smaller batches → much faster wall-clock on parallel\r\n      // hardware. Hosts that hit rate limits can override upward.\r\n      batchSize: config.batchSize ?? 8,\r\n      batchCharCap: config.batchCharCap ?? 1200,\r\n      root: config.root ?? (typeof document !== 'undefined' ? document.body : (null as unknown as HTMLElement)),\r\n      ignoreSelector: config.ignoreSelector,\r\n      cache: config.cache,\r\n    };\r\n    const parts = [...DEFAULT_IGNORE];\r\n    if (config.ignoreSelector) parts.push(config.ignoreSelector);\r\n    this.effectiveIgnore = parts.join(', ');\r\n  }\r\n\r\n  attachTo(dddk: DotDotDuck): void {\r\n    this.dddk = dddk;\r\n    ensureStyles();\r\n    this.installRouteChangeCleanup();\r\n  }\r\n\r\n  /**\r\n   * Wipe injected translation nodes on any SPA route change.\r\n   *\r\n   * Without this, a host SPA (SvelteKit / Next / Vue Router) swaps its\r\n   * page slot but our `<font.dddk-imm-translate>` siblings stay attached\r\n   * to the still-mounted parent nodes — they bleed into the next page,\r\n   * making it look like two pages are stacked. We catch:\r\n   *   - `popstate` (back / forward),\r\n   *   - patched `history.pushState` / `replaceState` (programmatic nav).\r\n   *\r\n   * Idempotent — re-installing replaces the previous teardown so a host\r\n   * calling `attachTo` twice doesn't accumulate listeners.\r\n   */\r\n  private installRouteChangeCleanup(): void {\r\n    if (typeof window === 'undefined' || typeof history === 'undefined') return;\r\n    this.routeChangeTeardown?.();\r\n\r\n    let lastPath = window.location.pathname + window.location.search;\r\n    const checkAndClear = (): void => {\r\n      const now = window.location.pathname + window.location.search;\r\n      if (now === lastPath) return;\r\n      lastPath = now;\r\n      if (this.currentLang) this.disable();\r\n    };\r\n\r\n    // Patch pushState / replaceState to dispatch a custom event we can\r\n    // listen to. SvelteKit / Next / Vue Router all funnel SPA nav through\r\n    // these; popstate alone doesn't catch programmatic navigation.\r\n    const origPush = history.pushState;\r\n    const origReplace = history.replaceState;\r\n    const ROUTE_EVENT = 'dddk:imm-translate-route-change';\r\n    history.pushState = function patchedPush(...args) {\r\n      const r = origPush.apply(this, args);\r\n      window.dispatchEvent(new Event(ROUTE_EVENT));\r\n      return r;\r\n    };\r\n    history.replaceState = function patchedReplace(...args) {\r\n      const r = origReplace.apply(this, args);\r\n      window.dispatchEvent(new Event(ROUTE_EVENT));\r\n      return r;\r\n    };\r\n\r\n    window.addEventListener('popstate', checkAndClear);\r\n    window.addEventListener(ROUTE_EVENT, checkAndClear);\r\n\r\n    this.routeChangeTeardown = () => {\r\n      window.removeEventListener('popstate', checkAndClear);\r\n      window.removeEventListener(ROUTE_EVENT, checkAndClear);\r\n      history.pushState = origPush;\r\n      history.replaceState = origReplace;\r\n    };\r\n  }\r\n\r\n  isEnabled(): boolean { return this.currentLang !== null; }\r\n  language(): string | null { return this.currentLang; }\r\n\r\n  /** Run a full translation pass. If the language differs from the previous\r\n   *  enable, the page is cleared and re-translated. */\r\n  async enable(targetLang: string, label?: string): Promise<void> {\r\n    if (this.currentLang === targetLang) return;\r\n    if (this.currentLang) this.disable();\r\n    this.currentLang = targetLang;\r\n    ensureStyles();\r\n\r\n    const blocks = this.collectBlocks();\r\n    if (blocks.length === 0) return;\r\n\r\n    // Persistent processing indicator so the bottom of the screen\r\n    // shows \"translating…\" the entire time the LLM calls are in flight,\r\n    // not just for the brief moment between `subtitle.show` re-renders.\r\n    // Without this the user sees a flash of progress text then nothing\r\n    // while the slowest batch finishes, and assumes the feature hung.\r\n    const indicatorLabel = `Translating → ${label ?? targetLang}`;\r\n    this.dddk?.subtitle.showIndicator('processing', indicatorLabel);\r\n    this.dddk?.subtitle.show({\r\n      text: `Translating → ${label ?? targetLang} (${blocks.length} blocks)`,\r\n      type: 'info',\r\n    });\r\n\r\n    // Batch the blocks honouring both block-count and char-cap, then\r\n    // fire every batch IN PARALLEL. Sequential awaits used to walk a\r\n    // 27-block page through one batch at a time; with parallel fan-out\r\n    // a typical doc page completes in roughly the slowest single batch's\r\n    // latency. Each batch independently checks the cache + mounts results\r\n    // so a slow / failing batch doesn't block the others.\r\n    const batches = this.buildBatches(blocks);\r\n    let done = 0;\r\n    const updateProgress = (): void => {\r\n      this.dddk?.subtitle.show({\r\n        text: `Translating ${done}/${blocks.length} → ${label ?? targetLang}`,\r\n        type: 'info',\r\n      });\r\n      this.dddk?.subtitle.showIndicator('processing', `${indicatorLabel} (${done}/${blocks.length})`);\r\n    };\r\n\r\n    await Promise.all(batches.map(async (batch) => {\r\n      const inputs = batch.map((b) => b.html);\r\n      const cached: (string | null)[] = inputs.map((html) => this.cacheGet(html, targetLang));\r\n      const need = inputs.map((html, i) => (cached[i] == null ? html : null));\r\n      const needIdxs = need.map((v, i) => (v != null ? i : -1)).filter((i) => i >= 0);\r\n      let translations: string[] = [];\r\n      if (needIdxs.length > 0) {\r\n        const toSend = needIdxs.map((i) => inputs[i]!);\r\n        try {\r\n          translations = await this.translateBatch(toSend, targetLang);\r\n        } catch (err) {\r\n          console.warn('[immersive-translate] batch failed, skipping:', err);\r\n          translations = toSend.map(() => '');\r\n        }\r\n      }\r\n      const finalOutputs: string[] = cached.map((c) => c ?? '');\r\n      let tIdx = 0;\r\n      for (const i of needIdxs) {\r\n        finalOutputs[i] = translations[tIdx] ?? '';\r\n        if (finalOutputs[i]) this.cacheSet(inputs[i]!, targetLang, finalOutputs[i]!);\r\n        tIdx++;\r\n      }\r\n      for (let i = 0; i < batch.length; i++) {\r\n        const out = finalOutputs[i];\r\n        if (out && out !== inputs[i]) {\r\n          this.appendTranslation(batch[i]!.el, out);\r\n        } else {\r\n          batch[i]!.el.removeAttribute(TRANSLATED_ATTR);\r\n        }\r\n      }\r\n      done += batch.length;\r\n      updateProgress();\r\n    }));\r\n\r\n    this.dddk?.subtitle.hideIndicator();\r\n    this.dddk?.subtitle.show({\r\n      text: `Translation complete (${blocks.length} blocks)`,\r\n      type: 'info',\r\n      autoHide: 2000,\r\n    });\r\n  }\r\n\r\n  /** Strip all injected translation nodes; revert page to original state. */\r\n  disable(): void {\r\n    if (!this.currentLang) return;\r\n    this.cfg.root.querySelectorAll(`.${WRAPPER_CLASS}`).forEach((el) => el.remove());\r\n    this.cfg.root.querySelectorAll(`[${TRANSLATED_ATTR}]`).forEach((el) => el.removeAttribute(TRANSLATED_ATTR));\r\n    this.currentLang = null;\r\n  }\r\n\r\n  toggle(targetLang: string, label?: string): Promise<void> | void {\r\n    if (this.isEnabled()) { this.disable(); return; }\r\n    return this.enable(targetLang, label);\r\n  }\r\n\r\n  // ─── internals ───────────────────────────────────────────────\r\n\r\n  private collectBlocks(): Array<{ el: HTMLElement; html: string }> {\r\n    const out: Array<{ el: HTMLElement; html: string }> = [];\r\n    const walker = document.createTreeWalker(this.cfg.root, NodeFilter.SHOW_ELEMENT, {\r\n      acceptNode: (node) => {\r\n        if (!(node instanceof HTMLElement)) return NodeFilter.FILTER_REJECT;\r\n        if (this.effectiveIgnore && node.closest(this.effectiveIgnore)) return NodeFilter.FILTER_REJECT;\r\n        if (!BLOCK_TAGS.has(node.tagName.toLowerCase())) return NodeFilter.FILTER_SKIP;\r\n        if (node.hasAttribute(TRANSLATED_ATTR)) return NodeFilter.FILTER_REJECT;\r\n        const text = (node.textContent ?? '').trim();\r\n        if (text.length < 2) return NodeFilter.FILTER_REJECT;\r\n        // Skip if it contains a block child (we'd double-translate).\r\n        for (const child of Array.from(node.children)) {\r\n          if (BLOCK_TAGS.has(child.tagName.toLowerCase())) return NodeFilter.FILTER_SKIP;\r\n        }\r\n        return NodeFilter.FILTER_ACCEPT;\r\n      },\r\n    });\r\n    let n: Node | null;\r\n    while ((n = walker.nextNode())) {\r\n      const el = n as HTMLElement;\r\n      el.setAttribute(TRANSLATED_ATTR, 'pending');\r\n      // Use innerHTML so inline tags (<a>, <strong>, …) survive — the prompt\r\n      // tells the LLM to preserve them.\r\n      out.push({ el, html: (el.innerHTML ?? '').trim() });\r\n    }\r\n    return out;\r\n  }\r\n\r\n  private buildBatches(blocks: Array<{ el: HTMLElement; html: string }>):\r\n    Array<Array<{ el: HTMLElement; html: string }>> {\r\n    const out: Array<Array<{ el: HTMLElement; html: string }>> = [];\r\n    let cur: Array<{ el: HTMLElement; html: string }> = [];\r\n    let curChars = 0;\r\n    for (const b of blocks) {\r\n      if (cur.length >= this.cfg.batchSize || curChars + b.html.length > this.cfg.batchCharCap) {\r\n        if (cur.length > 0) out.push(cur);\r\n        cur = [];\r\n        curChars = 0;\r\n      }\r\n      cur.push(b);\r\n      curChars += b.html.length;\r\n    }\r\n    if (cur.length > 0) out.push(cur);\r\n    return out;\r\n  }\r\n\r\n  private async translateBatch(blocks: string[], targetLang: string): Promise<string[]> {\r\n    const llm = resolveLLM(this.cfg.llm, 'inline');\r\n    const user = `Target language: ${targetLang}\\n\\nSource (JSON array of ${blocks.length} strings):\\n${JSON.stringify(blocks)}`;\r\n    const res = await llm.complete({\r\n      messages: [\r\n        { role: 'system', content: promptRegistry.render(PROMPT_IDS.TRANSLATE, undefined, this.currentLang ?? 'en') },\r\n        { role: 'user', content: user },\r\n      ],\r\n      // Translation doesn't need reasoning — disable thinking for speed +\r\n      // to keep the model from leaking analysis into the JSON output.\r\n      thinking: 'off',\r\n      jsonMode: true,\r\n      temperature: 0.2,\r\n      maxTokens: Math.min(4000, blocks.reduce((s, b) => s + b.length, 0) * 3 + 500),\r\n    });\r\n    const raw = res.content.trim();\r\n    // Strip leading/trailing markdown fences if the model leaked them.\r\n    const cleaned = stripCodeFence(raw);\r\n    try {\r\n      const parsed = JSON.parse(cleaned);\r\n      const arr = extractTranslationsArray(parsed);\r\n      if (!arr) throw new Error('no translations array found in response');\r\n      if (arr.length !== blocks.length) throw new Error(`length mismatch ${arr.length} vs ${blocks.length}`);\r\n      return arr.map((s: unknown) => String(s));\r\n    } catch (err) {\r\n      console.warn('[immersive-translate] JSON parse failed:', err, 'raw:', raw);\r\n      return blocks.map(() => '');\r\n    }\r\n  }\r\n\r\n  private appendTranslation(el: HTMLElement, html: string): void {\r\n    el.setAttribute(TRANSLATED_ATTR, 'done');\r\n    // Insert as a <font class=\"dddk-imm-translate\"> after the original\r\n    // content inside the same block — survives most rich-text + Office /\r\n    // PDF HTML pipelines.\r\n    const wrap = document.createElement(WRAPPER_TAG);\r\n    wrap.className = WRAPPER_CLASS;\r\n    wrap.innerHTML = html;\r\n    // Force a line break before so original + translation are visually separable.\r\n    const br = document.createElement('br');\r\n    br.className = WRAPPER_CLASS;\r\n    el.appendChild(br);\r\n    el.appendChild(wrap);\r\n  }\r\n\r\n  private cacheKey(source: string, lang: string): string {\r\n    return `imm:${lang}:${fnv1a(source)}`;\r\n  }\r\n  private cacheGet(source: string, lang: string): string | null {\r\n    const k = this.cacheKey(source, lang);\r\n    return (this.cfg.cache?.get(k)) ?? this.memCache.get(k) ?? null;\r\n  }\r\n  private cacheSet(source: string, lang: string, value: string): void {\r\n    const k = this.cacheKey(source, lang);\r\n    this.memCache.set(k, value);\r\n    this.cfg.cache?.set(k, value);\r\n  }\r\n}\r\n\r\nfunction ensureStyles(): void {\r\n  injectScopedStyle(STYLE_ID, `\r\n    .${WRAPPER_CLASS} {\r\n      color: var(--dddk-text-muted, #6b6b6b);\r\n      font-family: inherit;\r\n      display: inline;\r\n      opacity: 0.95;\r\n    }\r\n    br.${WRAPPER_CLASS} { display: block; margin-top: 4px; }\r\n  `);\r\n}\r\n\r\n/**\r\n * Tolerantly extract the translations array from an LLM JSON response.\r\n *\r\n * `jsonMode: true` (OpenAI's `response_format: json_object`) forces a\r\n * top-level object, so the model can't return a bare array. We ask for\r\n * `{\"translations\": [...]}` but accept several common drift shapes:\r\n *   - `[...]` — model ignored jsonMode (rare).\r\n *   - `{\"translations\": [...]}` — the requested shape.\r\n *   - `{\"<langCode>\": [...]}` — model keyed by the target lang (`{\"ja\": [...]}`).\r\n *   - `{\"result\": [...]}` / `{\"data\": [...]}` — generic fallback keys.\r\n *   - Any object with exactly one array-valued property — use that array.\r\n */\r\nfunction extractTranslationsArray(parsed: unknown): unknown[] | null {\r\n  if (Array.isArray(parsed)) return parsed;\r\n  if (!parsed || typeof parsed !== 'object') return null;\r\n  const obj = parsed as Record<string, unknown>;\r\n  if (Array.isArray(obj.translations)) return obj.translations;\r\n  const arrayValues = Object.values(obj).filter((v) => Array.isArray(v)) as unknown[][];\r\n  if (arrayValues.length === 1) return arrayValues[0]!;\r\n  return null;\r\n}\r\n\r\n/** Tiny non-crypto hash for the translation cache key. 32-bit FNV-1a. */\r\nfunction fnv1a(s: string): string {\r\n  let h = 0x811c9dc5;\r\n  for (let i = 0; i < s.length; i++) {\r\n    h ^= s.charCodeAt(i);\r\n    h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;\r\n  }\r\n  return h.toString(36);\r\n}\r\n","/**\r\n * Voice — Speech-to-Text.\r\n *\r\n * Primary path: Web Speech API via `webkitSpeechRecognition` (Chrome, Edge,\r\n * Android Chrome, iOS / macOS Safari). All of these use the same underlying\r\n * vendor STT (Google on Chrome/Android, Microsoft on Edge, Apple on Safari).\r\n *\r\n * Cross-platform quirks the code handles:\r\n *   - Android Chrome / iOS Safari sometimes auto-end the recognition before\r\n *     the user releases the hold gesture. With `autoRestartOnEnd: true`\r\n *     (default), the recognition is restarted while the user is still\r\n *     holding, keeping `finalText` accumulating across mini-sessions.\r\n *   - `continuous: true` is the default (hold-to-talk UX). On some Android\r\n *     builds the flag is ignored but auto-restart compensates.\r\n *\r\n * Fallback path: host-supplied `transcribe(audioBlob)` function.\r\n *   - `transcribeMode: 'always'` — skip Web Speech entirely; record via\r\n *     MediaRecorder and hand the audio Blob to the host's STT.\r\n *   - `transcribeMode: 'fallback'` — use Web Speech if available, fall back\r\n *     to MediaRecorder + host transcribe when Web Speech is unavailable\r\n *     (e.g. Firefox / Samsung Internet).\r\n *\r\n * The SDK does NOT ship any STT model. Hosts wire their own (OpenAI Whisper,\r\n * Gemini audio, Azure Speech, on-prem Whisper.cpp, whatever).\r\n *\r\n * If neither path is available, `isSupported()` returns false and `start()`\r\n * emits an explicit error so the host UI can say \"browser doesn't support\r\n * voice input\".\r\n */\r\n\r\nimport { resolveLLM, type LLMSource } from '../../agent/llm/router';\r\nimport { PROMPT_IDS, promptRegistry } from '../../prompts/registry';\r\nimport { registerBuiltinPrompts } from '../../prompts/defaults';\r\n\r\n// Register SDK-shipped prompt defaults on module load. Idempotent.\r\nregisterBuiltinPrompts();\r\n\r\nexport type AudioTranscriber = (\r\n  audio: Blob,\r\n  opts: { language: string; mimeType: string }\r\n) => Promise<string>;\r\n\r\nexport interface VoiceConfig {\r\n  language?: string;\r\n  continuous?: boolean;\r\n  interimResults?: boolean;\r\n  /** Run an LLM pass to remove fillers / fix punctuation. Default true if llm provided. */\r\n  cleanupWithLLM?: boolean;\r\n  /** Pass an LLMProvider or LLMRouter — the `voiceCleanup` role is used. */\r\n  llm?: LLMSource;\r\n  /** Override cleanup system prompt. */\r\n  cleanupPrompt?: string;\r\n\r\n  /**\r\n   * Host-supplied STT. Receives the recorded audio Blob and the detected\r\n   * language, returns the transcript. The SDK records audio via\r\n   * MediaRecorder and hands the result to this function — no model bundled.\r\n   *\r\n   * Hook this up if you want a fallback (or replacement) for the browser's\r\n   * built-in Web Speech API. Common implementations:\r\n   *   - OpenAI Whisper API\r\n   *   - Gemini audio input (multimodal)\r\n   *   - Azure Speech, Deepgram, etc.\r\n   *   - Self-hosted Whisper.cpp via your own API\r\n   */\r\n  transcribe?: AudioTranscriber;\r\n\r\n  /**\r\n   * How to use the host transcriber relative to Web Speech.\r\n   *   - `fallback` (default if `transcribe` provided) — use Web Speech if\r\n   *     available, fall back to MediaRecorder + transcribe when not\r\n   *   - `always` — never use Web Speech; always go MediaRecorder + transcribe\r\n   */\r\n  transcribeMode?: 'fallback' | 'always';\r\n\r\n  /**\r\n   * Auto-restart recognition when it ends prematurely while the user is\r\n   * still holding the gesture. Critical for Android Chrome / iOS Safari\r\n   * which auto-stop on silence pauses even with `continuous: true`.\r\n   * Default true.\r\n   */\r\n  autoRestartOnEnd?: boolean;\r\n}\r\n\r\ntype Listener<T = unknown> = (payload: T) => void;\r\n\r\ntype Platform = 'desktop-chrome' | 'desktop-edge' | 'desktop-safari' | 'android-chrome' | 'ios-safari' | 'unknown';\r\n\r\nfunction detectPlatform(): Platform {\r\n  if (typeof navigator === 'undefined') return 'unknown';\r\n  const ua = navigator.userAgent;\r\n  if (/Android/i.test(ua)) return 'android-chrome';\r\n  if (/iPhone|iPad|iPod/i.test(ua)) return 'ios-safari';\r\n  if (/Edg\\//.test(ua)) return 'desktop-edge';\r\n  if (/Chrome\\//.test(ua)) return 'desktop-chrome';\r\n  if (/Safari\\//.test(ua)) return 'desktop-safari';\r\n  return 'unknown';\r\n}\r\n\r\nfunction getMediaRecorderMime(): string {\r\n  if (typeof MediaRecorder === 'undefined') return '';\r\n  const candidates = ['audio/webm;codecs=opus', 'audio/webm', 'audio/mp4', 'audio/ogg;codecs=opus'];\r\n  for (const m of candidates) if (MediaRecorder.isTypeSupported(m)) return m;\r\n  return '';\r\n}\r\n\r\nexport class Voice {\r\n  private config: Required<Pick<VoiceConfig, 'language' | 'continuous' | 'interimResults' | 'autoRestartOnEnd'>> &\r\n    VoiceConfig;\r\n  private recognition: SpeechRecognition | null = null;\r\n  /** Warm-up recognition spawned by warmUp(). Held so a real voice\r\n   *  gesture can abort it before spawning its own — Web Speech rejects\r\n   *  a second concurrent start() with InvalidStateError, and the\r\n   *  symptom is identical to \"voice didn't start\" (silent failure). */\r\n  private warmupRecognition: SpeechRecognition | null = null;\r\n  private listeners: Map<string, Set<Listener>> = new Map();\r\n  private finalText = '';\r\n  private interimText = '';\r\n  private webSpeechSupported: boolean;\r\n  private mediaRecorderSupported: boolean;\r\n  private platform: Platform;\r\n\r\n  // State for managing the active session\r\n  private userStopped = false;\r\n  private mediaRecorder: MediaRecorder | null = null;\r\n  private mediaStream: MediaStream | null = null;\r\n  private mediaChunks: Blob[] = [];\r\n  private usingTranscribe = false;\r\n\r\n  constructor(config: VoiceConfig = {}) {\r\n    const merged: VoiceConfig = { ...config };\r\n    if (merged.language === undefined) {\r\n      merged.language = (typeof navigator !== 'undefined' && navigator.language) || 'en-US';\r\n    }\r\n    if (merged.continuous === undefined) merged.continuous = true;\r\n    if (merged.interimResults === undefined) merged.interimResults = true;\r\n    if (merged.autoRestartOnEnd === undefined) merged.autoRestartOnEnd = true;\r\n    this.config = merged as typeof this.config;\r\n\r\n    this.platform = detectPlatform();\r\n    this.webSpeechSupported =\r\n      typeof window !== 'undefined' &&\r\n      ((window as unknown as { SpeechRecognition?: unknown }).SpeechRecognition !== undefined ||\r\n        (window as unknown as { webkitSpeechRecognition?: unknown }).webkitSpeechRecognition !==\r\n          undefined);\r\n    this.mediaRecorderSupported =\r\n      typeof window !== 'undefined' && typeof MediaRecorder !== 'undefined' && getMediaRecorderMime() !== '';\r\n  }\r\n\r\n  /**\r\n   * True if ANY STT path is usable (Web Speech OR host transcribe + MediaRecorder).\r\n   * Host should check this before showing the voice button at all.\r\n   */\r\n  isSupported(): boolean {\r\n    if (this.config.transcribeMode === 'always') {\r\n      return this.mediaRecorderSupported && !!this.config.transcribe;\r\n    }\r\n    if (this.webSpeechSupported) return true;\r\n    if (this.config.transcribe && this.mediaRecorderSupported) return true;\r\n    return false;\r\n  }\r\n\r\n  /** Detected platform string. Useful for diagnostics. */\r\n  getPlatform(): Platform {\r\n    return this.platform;\r\n  }\r\n\r\n  on(event: 'start' | 'interim' | 'final' | 'end' | 'error', handler: Listener): void {\r\n    if (!this.listeners.has(event)) this.listeners.set(event, new Set());\r\n    this.listeners.get(event)!.add(handler);\r\n  }\r\n\r\n  off(event: string, handler: Listener): void {\r\n    this.listeners.get(event)?.delete(handler);\r\n  }\r\n\r\n  private emit(event: string, payload?: unknown): void {\r\n    this.listeners.get(event)?.forEach((h) => {\r\n      try {\r\n        h(payload);\r\n      } catch (err) {\r\n        console.error('[voice] listener error:', err);\r\n      }\r\n    });\r\n  }\r\n\r\n  start(): void {\r\n    this.userStopped = false;\r\n    this.finalText = '';\r\n    this.interimText = '';\r\n    this.mediaChunks = [];\r\n    // Tear down any in-flight warmup recognition. Web Speech rejects a\r\n    // second concurrent start() with InvalidStateError — symptom in the\r\n    // wild is \"voice gesture seems to do nothing\". This happens when\r\n    // the user's FIRST page interaction (the gesture that fired\r\n    // warmUp) is immediately followed by a real voice gesture before\r\n    // the warmup recognition's onstart→abort cycle completes.\r\n    this.abortWarmup();\r\n\r\n    // Decide which path:\r\n    //   1. transcribeMode==='always' AND transcribe provided → MediaRecorder\r\n    //   2. Web Speech available → use it (with auto-restart on Android/iOS)\r\n    //   3. transcribe provided as fallback → MediaRecorder\r\n    //   4. nothing → emit error\r\n    if (this.config.transcribeMode === 'always' && this.config.transcribe) {\r\n      this.usingTranscribe = true;\r\n      this.startMediaRecorder();\r\n      return;\r\n    }\r\n    if (this.webSpeechSupported) {\r\n      this.usingTranscribe = false;\r\n      this.startWebSpeech();\r\n      return;\r\n    }\r\n    if (this.config.transcribe && this.mediaRecorderSupported) {\r\n      this.usingTranscribe = true;\r\n      this.startMediaRecorder();\r\n      return;\r\n    }\r\n    this.emit('error', {\r\n      code: 'not-supported',\r\n      message: 'browser does not support speech recognition',\r\n    });\r\n    this.emit('final', '');\r\n  }\r\n\r\n  async stop(): Promise<string> {\r\n    this.userStopped = true;\r\n\r\n    if (this.usingTranscribe) {\r\n      return await this.stopMediaRecorder();\r\n    }\r\n\r\n    if (this.recognition) {\r\n      try {\r\n        this.recognition.stop();\r\n      } catch {\r\n        /* ignore */\r\n      }\r\n      // Wait for the engine to settle — Chrome can take 800-1500ms to promote\r\n      // the tail audio into a final result after stop().\r\n      await new Promise<void>((resolve) => {\r\n        const handler = () => {\r\n          this.off('end', handler);\r\n          resolve();\r\n        };\r\n        this.on('end', handler);\r\n        setTimeout(() => resolve(), 3000);\r\n      });\r\n    }\r\n\r\n    return await this.finalize(this.finalText + ' ' + this.interimText);\r\n  }\r\n\r\n  abort(): void {\r\n    this.userStopped = true;\r\n    this.recognition?.abort();\r\n    this.recognition = null;\r\n    if (this.mediaRecorder && this.mediaRecorder.state !== 'inactive') {\r\n      try { this.mediaRecorder.stop(); } catch { /* ignore */ }\r\n    }\r\n    this.releaseMicStream();\r\n  }\r\n\r\n  destroy(): void {\r\n    this.abort();\r\n    this.listeners.clear();\r\n  }\r\n\r\n  /** True once a full warmUp() (device + engine) has completed. Prevents\r\n   *  redundant warmups on every incidental gesture. */\r\n  private warmedUp = false;\r\n\r\n  /**\r\n   * Pre-warm the entire STT pipeline so the FIRST real voice gesture\r\n   * isn't eaten by browser cold-start latency. Three things get warm:\r\n   *\r\n   *   1. **Microphone permission**. If state is `prompt` we trigger\r\n   *      the browser's permission UI here, NOT on the user's first\r\n   *      Space-hold — so the gesture's critical path stays clean.\r\n   *   2. **Audio device handle**. We open + immediately close a\r\n   *      `getUserMedia` stream. The OS-level open is the slowest part\r\n   *      of `getUserMedia` once permission is granted (300-800ms cold,\r\n   *      <50ms warm) — touching it here pre-pays the cost.\r\n   *   3. **SpeechRecognition / Google STT TLS handshake**. We spawn a\r\n   *      `SpeechRecognition`, call `start()`, and abort it. Even a\r\n   *      no-speech run establishes the persistent connection to Google's\r\n   *      STT endpoint that the next real run reuses.\r\n   *\r\n   * Two call points work well:\r\n   *   - On `onMount` if permission is already `granted` (returning\r\n   *     visitor) — no gesture required, totally silent.\r\n   *   - On the first user gesture (`pointerdown` / `keydown`) for the\r\n   *     `prompt` case — triggers the permission UI off the critical\r\n   *     path.\r\n   *\r\n   * Idempotent. Subsequent calls after a successful warmup are no-ops.\r\n   * Pass `{ force: true }` to re-warm e.g. after a long idle period.\r\n   */\r\n  async warmUp(\r\n    opts: { force?: boolean; warmEngine?: boolean } = {},\r\n  ): Promise<'granted' | 'prompt' | 'denied' | 'unavailable'> {\r\n    if (typeof navigator === 'undefined' || !navigator.mediaDevices?.getUserMedia) {\r\n      return 'unavailable';\r\n    }\r\n    if (this.warmedUp && !opts.force) return 'granted';\r\n\r\n    // 1) Permission state. Skip the prompt path on denied — calling\r\n    //    getUserMedia again on a denied origin just re-fails.\r\n    if (navigator.permissions?.query) {\r\n      try {\r\n        const status = await navigator.permissions.query({ name: 'microphone' as PermissionName });\r\n        if (status.state === 'denied') return 'denied';\r\n      } catch {\r\n        /* Some engines (Firefox, embedded webviews) don't expose\r\n           `microphone` in the Permissions API. Fall through to the\r\n           getUserMedia probe — slightly more invasive but works\r\n           everywhere. */\r\n      }\r\n    }\r\n\r\n    // 2) Open the audio device. Triggers the permission UI on first\r\n    //    visit; cheap once granted (OS just hands back a handle).\r\n    let stream: MediaStream;\r\n    try {\r\n      stream = await navigator.mediaDevices.getUserMedia({ audio: true });\r\n    } catch (err) {\r\n      return (err as { name?: string })?.name === 'NotAllowedError' ? 'denied' : 'prompt';\r\n    }\r\n    // Release immediately — Web Speech will open its own stream when a\r\n    // real gesture fires. Keeping ours open here would leave the mic\r\n    // icon lit in the tab bar and look creepy.\r\n    stream.getTracks().forEach((t) => t.stop());\r\n\r\n    // We deliberately do NOT pre-spawn a SpeechRecognition here. The\r\n    // first real `start()` will do its own TLS handshake to Google's\r\n    // STT endpoint — that 200-500ms ramp-up lands well inside the\r\n    // user's first long-press hold (typically 1-2s). Spawning a\r\n    // recognition for warmup risks colliding with the real one (Web\r\n    // Speech rejects concurrent `start()` with InvalidStateError)\r\n    // and the symptom is identical to \"voice did nothing\" — exactly\r\n    // the bug we were trying to prevent.\r\n    void opts.warmEngine; // accepted-but-ignored for API stability\r\n\r\n    this.warmedUp = true;\r\n    return 'granted';\r\n  }\r\n\r\n  /** Abort any in-flight warmup recognition. Defensive no-op now that\r\n   *  warmUp() doesn't spawn one, but kept on the class so call-sites\r\n   *  (e.g. start()) don't need to know whether engine warmup happened. */\r\n  private abortWarmup(): void {\r\n    if (!this.warmupRecognition) return;\r\n    try { this.warmupRecognition.abort(); } catch { /* ignore */ }\r\n    this.warmupRecognition = null;\r\n  }\r\n\r\n  // ─── Web Speech path ─────────────────────────────────────────────\r\n\r\n  private startWebSpeech(): void {\r\n    const Recognition =\r\n      (window as unknown as { SpeechRecognition?: typeof SpeechRecognition }).SpeechRecognition ??\r\n      (window as unknown as { webkitSpeechRecognition?: typeof SpeechRecognition })\r\n        .webkitSpeechRecognition;\r\n    if (!Recognition) {\r\n      this.emit('error', { code: 'not-supported', message: 'webkitSpeechRecognition missing' });\r\n      this.emit('final', '');\r\n      return;\r\n    }\r\n    // Pre-prompt for mic via getUserMedia, then immediately close the\r\n    // stream. Web Speech's implicit permission ask is flakier than\r\n    // getUserMedia — Edge/Chrome sometimes fire a fast `network` error\r\n    // when the mic permission was never asked. Explicit ask makes the\r\n    // permission state clear before recognition starts.\r\n    if (typeof navigator !== 'undefined' && navigator.mediaDevices?.getUserMedia) {\r\n      navigator.mediaDevices\r\n        .getUserMedia({ audio: true })\r\n        .then((stream) => {\r\n          // Release immediately — Web Speech will open its own stream.\r\n          stream.getTracks().forEach((t) => t.stop());\r\n          this.spawnRecognition(Recognition);\r\n        })\r\n        .catch((err) => {\r\n          const code = (err as { name?: string })?.name === 'NotAllowedError'\r\n            ? 'not-allowed' : 'audio-capture';\r\n          this.emit('error', { code, message: 'microphone permission needed' });\r\n          this.emit('final', '');\r\n        });\r\n      return;\r\n    }\r\n    this.spawnRecognition(Recognition);\r\n  }\r\n\r\n  private spawnRecognition(Ctor: typeof SpeechRecognition): void {\r\n    const rec = new Ctor();\r\n    rec.lang = this.config.language;\r\n    rec.continuous = this.config.continuous;\r\n    rec.interimResults = this.config.interimResults;\r\n\r\n    rec.onstart = () => this.emit('start');\r\n\r\n    rec.onresult = (event: SpeechRecognitionEvent) => {\r\n      let interim = '';\r\n      let final = '';\r\n      for (let i = event.resultIndex; i < event.results.length; i++) {\r\n        const result = event.results[i];\r\n        if (!result) continue;\r\n        const alt = result[0];\r\n        if (!alt) continue;\r\n        if (result.isFinal) final += alt.transcript;\r\n        else interim += alt.transcript;\r\n      }\r\n      if (final) {\r\n        this.finalText += final;\r\n        this.interimText = '';\r\n        this.emit('interim', this.finalText + interim);\r\n      } else if (interim) {\r\n        this.interimText = interim;\r\n        this.emit('interim', this.finalText + interim);\r\n      }\r\n    };\r\n\r\n    rec.onerror = (e: Event) => {\r\n      const errCode = (e as unknown as { error?: string }).error;\r\n      const errMessage = (e as unknown as { message?: string }).message;\r\n      const friendly =\r\n        errCode === 'not-allowed'    ? 'microphone permission denied' :\r\n        errCode === 'no-speech'      ? 'no speech detected' :\r\n        errCode === 'audio-capture'  ? 'audio capture failed (mic hardware?)' :\r\n        errCode === 'network'        ? 'speech recognition network error' :\r\n        errCode === 'aborted'        ? 'recognition aborted' :\r\n        errCode === 'not-supported'  ? 'language not supported' :\r\n        errCode ?? 'unknown speech recognition error';\r\n      // Raw diagnostics surface — the friendly string above is what reaches\r\n      // the user-facing subtitle, but for debugging \"voice fails on first\r\n      // try\" we need the actual SpeechRecognitionErrorEvent fields so the\r\n      // developer can see whether it's permission state, network, or the\r\n      // engine itself bailing. Inspect `window.__dddkDebug.lastVoiceError`\r\n      // for the captured snapshot.\r\n      console.warn('[dddk voice] STT error', {\r\n        code: errCode,\r\n        message: errMessage,\r\n        friendly,\r\n        raw: e,\r\n        recognitionLang: rec.lang,\r\n        userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined,\r\n        timestamp: new Date().toISOString(),\r\n      });\r\n      if (typeof window !== 'undefined') {\r\n        const w = window as unknown as { __dddkDebug?: { lastVoiceError?: unknown; lastVoiceErrorAt?: string } };\r\n        w.__dddkDebug = w.__dddkDebug ?? {};\r\n        w.__dddkDebug.lastVoiceError = {\r\n          code: errCode,\r\n          message: errMessage,\r\n          friendly,\r\n          raw: { type: e.type, timeStamp: e.timeStamp },\r\n        };\r\n        w.__dddkDebug.lastVoiceErrorAt = new Date().toISOString();\r\n      }\r\n      this.emit('error', { code: errCode, message: friendly, raw: e });\r\n      // Stop the auto-restart loop on fatal errors. `network` is included\r\n      // because Web Speech sends audio to Google's STT servers — if that\r\n      // network path is blocked (firewall / VPN / no internet), restarting\r\n      // just hits the same wall in a loop and spams the user with the\r\n      // same error subtitle. Treat the first network failure as fatal\r\n      // for THIS gesture; the user can try again later.\r\n      if (\r\n        errCode === 'not-allowed' ||\r\n        errCode === 'audio-capture' ||\r\n        errCode === 'not-supported' ||\r\n        errCode === 'network'\r\n      ) {\r\n        this.userStopped = true;\r\n      }\r\n    };\r\n\r\n    rec.onend = () => {\r\n      this.recognition = null;\r\n      // Auto-restart: if the user is still holding the gesture (no manual\r\n      // stop() yet), the engine likely auto-ended due to a silence pause\r\n      // (Android Chrome / iOS Safari are the main culprits). Spawn a fresh\r\n      // recognition and keep accumulating into the same finalText.\r\n      if (!this.userStopped && this.config.autoRestartOnEnd) {\r\n        try {\r\n          this.spawnRecognition(Ctor);\r\n          return;\r\n        } catch (err) {\r\n          this.emit('error', err instanceof Error ? err : new Error(String(err)));\r\n        }\r\n      }\r\n      this.emit('end');\r\n    };\r\n\r\n    this.recognition = rec;\r\n    try {\r\n      rec.start();\r\n    } catch (err) {\r\n      this.recognition = null;\r\n      this.emit('error', err instanceof Error ? err : new Error(String(err)));\r\n      this.emit('final', '');\r\n    }\r\n  }\r\n\r\n  // ─── MediaRecorder + host transcribe path ────────────────────────\r\n\r\n  private async startMediaRecorder(): Promise<void> {\r\n    if (!this.config.transcribe) {\r\n      this.emit('error', { code: 'not-supported', message: 'no host transcribe provided' });\r\n      this.emit('final', '');\r\n      return;\r\n    }\r\n    if (!this.mediaRecorderSupported) {\r\n      this.emit('error', { code: 'not-supported', message: 'MediaRecorder unavailable' });\r\n      this.emit('final', '');\r\n      return;\r\n    }\r\n\r\n    try {\r\n      this.mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });\r\n    } catch (err) {\r\n      const errCode = (err as { name?: string })?.name;\r\n      this.emit('error', {\r\n        code: errCode === 'NotAllowedError' ? 'not-allowed' : 'audio-capture',\r\n        message: errCode === 'NotAllowedError'\r\n          ? 'microphone permission denied'\r\n          : 'failed to access microphone',\r\n        raw: err,\r\n      });\r\n      this.emit('final', '');\r\n      return;\r\n    }\r\n\r\n    const mime = getMediaRecorderMime();\r\n    try {\r\n      this.mediaRecorder = new MediaRecorder(this.mediaStream, { mimeType: mime });\r\n    } catch (err) {\r\n      this.emit('error', err instanceof Error ? err : new Error(String(err)));\r\n      this.releaseMicStream();\r\n      this.emit('final', '');\r\n      return;\r\n    }\r\n\r\n    this.mediaRecorder.ondataavailable = (e) => {\r\n      if (e.data && e.data.size > 0) this.mediaChunks.push(e.data);\r\n    };\r\n\r\n    this.mediaRecorder.onstart = () => this.emit('start');\r\n    this.mediaRecorder.onerror = (e) => {\r\n      this.emit('error', e);\r\n    };\r\n\r\n    try {\r\n      this.mediaRecorder.start();\r\n    } catch (err) {\r\n      this.emit('error', err instanceof Error ? err : new Error(String(err)));\r\n      this.releaseMicStream();\r\n      this.emit('final', '');\r\n    }\r\n  }\r\n\r\n  private async stopMediaRecorder(): Promise<string> {\r\n    if (!this.mediaRecorder || this.mediaRecorder.state === 'inactive') {\r\n      this.emit('end');\r\n      return await this.finalize('');\r\n    }\r\n    const mime = this.mediaRecorder.mimeType || getMediaRecorderMime();\r\n    await new Promise<void>((resolve) => {\r\n      this.mediaRecorder!.onstop = () => resolve();\r\n      try {\r\n        this.mediaRecorder!.stop();\r\n      } catch {\r\n        resolve();\r\n      }\r\n    });\r\n    this.emit('end');\r\n    this.releaseMicStream();\r\n\r\n    if (this.mediaChunks.length === 0) return await this.finalize('');\r\n    const blob = new Blob(this.mediaChunks, { type: mime });\r\n\r\n    try {\r\n      const text = await this.config.transcribe!(blob, {\r\n        language: this.config.language,\r\n        mimeType: mime,\r\n      });\r\n      return await this.finalize(text);\r\n    } catch (err) {\r\n      this.emit('error', {\r\n        code: 'transcribe-failed',\r\n        message: 'host transcribe function threw',\r\n        raw: err,\r\n      });\r\n      return await this.finalize('');\r\n    }\r\n  }\r\n\r\n  private releaseMicStream(): void {\r\n    if (this.mediaStream) {\r\n      this.mediaStream.getTracks().forEach((t) => t.stop());\r\n      this.mediaStream = null;\r\n    }\r\n    this.mediaRecorder = null;\r\n  }\r\n\r\n  // ─── Shared finalization ─────────────────────────────────────────\r\n\r\n  private async finalize(rawText: string): Promise<string> {\r\n    const raw = rawText.trim();\r\n    if (!raw) {\r\n      this.emit('final', '');\r\n      return '';\r\n    }\r\n    if (this.config.cleanupWithLLM !== false && this.config.llm) {\r\n      try {\r\n        const cleaned = await this.cleanup(raw);\r\n        this.emit('final', cleaned);\r\n        return cleaned;\r\n      } catch (err) {\r\n        console.warn('[voice] LLM cleanup failed, returning raw:', err);\r\n      }\r\n    }\r\n    this.emit('final', raw);\r\n    return raw;\r\n  }\r\n\r\n  private async cleanup(raw: string): Promise<string> {\r\n    // Pick the cleanup prompt by configured language. We branch on the\r\n    // language prefix so `zh-TW`, `zh-CN`, `zh` etc. all match the\r\n    // Chinese cleanup; everything else (en, ja, etc.) falls back to the\r\n    // English-language cleanup. Host override via `cleanupPrompt`\r\n    // bypasses this branch entirely (advanced use case — translating to\r\n    // a specific tone, domain glossary, etc.).\r\n    // Single universal English prompt. Reply language is determined by\r\n    // the INPUT transcript, not by a per-language branch — so this works\r\n    // for any number of languages (en, zh, ja, ko, es, ar, …) without\r\n    // the SDK shipping 20+ prompt variants.\r\n    //\r\n    // Language hint: if `config.language` is set (a BCP-47 tag from STT\r\n    // config like 'zh-TW' / 'en-US'), we pass it to the LLM as a soft\r\n    // hint. The LLM is told to trust the actual transcript over the hint\r\n    // when they disagree, so a Japanese user on a zh-TW-configured site\r\n    // still gets a Japanese cleanup. Override the entire prompt by\r\n    // setting `config.cleanupPrompt` — your prompt must handle language\r\n    // detection itself.\r\n    const langHint = this.config.language\r\n      ? `\\n\\nLanguage hint from STT config: ${this.config.language}. Trust the actual transcript content over this hint if they disagree.`\r\n      : '';\r\n    // Prefer the config-level override, then the SDK-registered default\r\n    // (per-locale-overridable via `dddk.prompts.override('voice-cleanup.system', locale, …)`),\r\n    // then append the language hint. Locale is the STT language when set,\r\n    // else 'en' — matches the previous inline behaviour.\r\n    const basePrompt =\r\n      this.config.cleanupPrompt\r\n      ?? promptRegistry.render(PROMPT_IDS.VOICE_CLEANUP, undefined, this.config.language ?? 'en');\r\n    const system = `${basePrompt}${langHint}`;\r\n    const llm = resolveLLM(this.config.llm!, 'utility');\r\n    const response = await llm.complete({\r\n      messages: [\r\n        { role: 'system', content: system },\r\n        { role: 'user', content: raw },\r\n      ],\r\n      // Literal text fix — no chain-of-thought needed. Critical on Gemma 4\r\n      // which otherwise burns ~700 thought tokens before any answer and\r\n      // truncates with MAX_TOKENS.\r\n      thinking: 'off',\r\n      temperature: 0.2,\r\n      maxTokens: 500,\r\n    });\r\n    return response.content.trim() || raw;\r\n  }\r\n}\r\n","/**\n * TTS — Text-to-Speech.\n * Default provider: Web Speech (free, browser-native).\n * Optional cloud providers: OpenAI tts-1, Gemini TTS — need API key.\n */\n\nexport type TTSProvider = 'web-speech' | 'openai' | 'gemini';\n\nexport interface TTSConfig {\n  provider?: TTSProvider;\n  voice?: string;\n  rate?: number;   // 0.5 ~ 2.0\n  pitch?: number;  // 0 ~ 2\n  volume?: number; // 0 ~ 1\n  language?: string;\n\n  // cloud provider auth (only used when provider is 'openai' / 'gemini')\n  apiKey?: string;\n  model?: string;\n}\n\ntype Listener = (payload?: unknown) => void;\n\nexport class TTS {\n  private config: TTSConfig;\n  private listeners: Map<string, Set<Listener>> = new Map();\n  private currentUtterance: SpeechSynthesisUtterance | null = null;\n  private currentAudio: HTMLAudioElement | null = null;\n  private currentAbort: AbortController | null = null;\n\n  constructor(config: TTSConfig = {}) {\n    this.config = {\n      provider: 'web-speech',\n      rate: 1.0,\n      pitch: 1.0,\n      volume: 1.0,\n      ...config,\n    };\n  }\n\n  isSupported(): boolean {\n    if (this.config.provider === 'web-speech') {\n      return typeof speechSynthesis !== 'undefined';\n    }\n    return typeof fetch !== 'undefined';\n  }\n\n  on(event: 'start' | 'end' | 'error', handler: Listener): void {\n    if (!this.listeners.has(event)) this.listeners.set(event, new Set());\n    this.listeners.get(event)!.add(handler);\n  }\n  off(event: string, handler: Listener): void {\n    this.listeners.get(event)?.delete(handler);\n  }\n  private emit(event: string, payload?: unknown): void {\n    this.listeners.get(event)?.forEach((h) => h(payload));\n  }\n\n  async speak(text: string): Promise<void> {\n    if (!text.trim()) return;\n    this.stop();\n\n    if (this.config.provider === 'web-speech') {\n      return this.speakWebSpeech(text);\n    } else if (this.config.provider === 'openai') {\n      return this.speakOpenAI(text);\n    } else if (this.config.provider === 'gemini') {\n      return this.speakGemini(text);\n    }\n  }\n\n  stop(): void {\n    if (this.currentUtterance) {\n      speechSynthesis.cancel();\n      this.currentUtterance = null;\n    }\n    if (this.currentAudio) {\n      this.currentAudio.pause();\n      URL.revokeObjectURL(this.currentAudio.src);\n      this.currentAudio = null;\n    }\n    this.currentAbort?.abort();\n    this.currentAbort = null;\n  }\n\n  destroy(): void {\n    this.stop();\n    this.listeners.clear();\n  }\n\n  // ─── providers ──────────────────────────────────────────────────\n\n  private speakWebSpeech(text: string): Promise<void> {\n    return new Promise((resolve, reject) => {\n      const u = new SpeechSynthesisUtterance(text);\n      u.lang = this.config.language ?? (typeof navigator !== 'undefined' ? navigator.language : 'en-US');\n      u.rate = this.config.rate!;\n      u.pitch = this.config.pitch!;\n      u.volume = this.config.volume!;\n\n      if (this.config.voice) {\n        const v = speechSynthesis.getVoices().find((vv) => vv.name === this.config.voice);\n        if (v) u.voice = v;\n      }\n\n      u.onstart = () => this.emit('start');\n      u.onend = () => {\n        this.emit('end');\n        this.currentUtterance = null;\n        resolve();\n      };\n      u.onerror = (e) => {\n        this.emit('error', e);\n        this.currentUtterance = null;\n        reject(e);\n      };\n\n      this.currentUtterance = u;\n      speechSynthesis.speak(u);\n    });\n  }\n\n  private async speakOpenAI(text: string): Promise<void> {\n    if (!this.config.apiKey) throw new Error('OpenAI TTS requires apiKey');\n    this.currentAbort = new AbortController();\n    this.emit('start');\n\n    const response = await fetch('https://api.openai.com/v1/audio/speech', {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        Authorization: `Bearer ${this.config.apiKey}`,\n      },\n      body: JSON.stringify({\n        model: this.config.model ?? 'tts-1',\n        input: text,\n        voice: this.config.voice ?? 'alloy',\n        speed: this.config.rate,\n      }),\n      signal: this.currentAbort.signal,\n    });\n    if (!response.ok) throw new Error(`OpenAI TTS HTTP ${response.status}`);\n\n    const blob = await response.blob();\n    return this.playBlob(blob);\n  }\n\n  /**\n   * @experimental Google has not yet shipped a stable public TTS endpoint at\n   * the time this code was written. The `gemini-2.0-flash-tts` model id below\n   * is a placeholder pointing at the streaming-content API in audio-response\n   * mode; the actual TTS surface may differ when Google ships it. Expect this\n   * to require updates when Gemini TTS becomes GA. Use Web Speech or OpenAI\n   * TTS for production.\n   */\n  private async speakGemini(text: string): Promise<void> {\n    if (!this.config.apiKey) throw new Error('Gemini TTS requires apiKey');\n    console.warn(\n      '[webagent/TTS] Gemini TTS is experimental — the model id and endpoint shape may change. ' +\n        'See JSDoc on speakGemini.',\n    );\n    // Gemini TTS endpoint (subject to API evolution). For now we use the streaming\n    // model that supports audio output via PCM base64 payloads.\n    this.currentAbort = new AbortController();\n    this.emit('start');\n\n    const model = this.config.model ?? 'gemini-2.0-flash-tts';\n    const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${encodeURIComponent(this.config.apiKey)}`;\n\n    const response = await fetch(url, {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json' },\n      body: JSON.stringify({\n        contents: [{ role: 'user', parts: [{ text }] }],\n        generationConfig: { responseMimeType: 'audio/wav' },\n      }),\n      signal: this.currentAbort.signal,\n    });\n    if (!response.ok) throw new Error(`Gemini TTS HTTP ${response.status}`);\n\n    const data = (await response.json()) as {\n      candidates?: Array<{ content?: { parts?: Array<{ inlineData?: { data: string; mimeType: string } }> } }>;\n    };\n    const part = data.candidates?.[0]?.content?.parts?.[0]?.inlineData;\n    if (!part) throw new Error('Gemini TTS returned no audio');\n\n    const bin = atob(part.data);\n    const bytes = Uint8Array.from(bin, (c) => c.charCodeAt(0));\n    const blob = new Blob([bytes], { type: part.mimeType || 'audio/wav' });\n    return this.playBlob(blob);\n  }\n\n  private playBlob(blob: Blob): Promise<void> {\n    return new Promise((resolve, reject) => {\n      const url = URL.createObjectURL(blob);\n      const audio = new Audio(url);\n      this.currentAudio = audio;\n      audio.onended = () => {\n        URL.revokeObjectURL(url);\n        this.currentAudio = null;\n        this.emit('end');\n        resolve();\n      };\n      audio.onerror = (e) => {\n        URL.revokeObjectURL(url);\n        this.currentAudio = null;\n        this.emit('error', e);\n        reject(e);\n      };\n      audio.play().catch(reject);\n    });\n  }\n}\n","/**\n * Voice module — wraps the bundled Voice (STT) + TTS into one dddk-friendly module.\n */\n\nimport { Voice, type VoiceConfig, type AudioTranscriber } from './voice';\nimport { TTS, type TTSConfig } from './tts';\nimport type { LLMSource } from '../../agent/llm/router';\nimport type { Subtitle } from '../../ui/subtitle';\nimport { sdkString } from '../../utils/sdk-i18n';\n\nexport type { AudioTranscriber } from './voice';\n\nexport interface VoiceModuleConfig {\n  /** STT (Speech-to-Text) — defaults to Web Speech API. */\n  stt?: VoiceConfig;\n  /** TTS (Text-to-Speech) — defaults to Web Speech API. */\n  tts?: TTSConfig;\n  /** LLMProvider or LLMRouter — `voiceCleanup` role is used for transcript cleanup. */\n  llm?: LLMSource;\n  /** Auto-speak agent subtitles. Default false. */\n  autoSpeakSubtitles?: boolean;\n  /**\n   * Upper bound for a single voice capture. Default 30s — if STT never fires\n   * `final` (e.g. permission silently denied, engine hung), the awaiting\n   * caller resolves with empty string after this many ms instead of waiting\n   * forever.\n   */\n  captureTimeoutMs?: number;\n  /**\n   * UI label shown in the subtitle indicator while listening. When\n   * omitted, falls back to the SDK i18n stub keyed by `locale`\n   * (`'Listening'` / `'聽取中'`).\n   */\n  listeningLabel?: string;\n  /**\n   * UI label shown when the browser doesn't support STT. When omitted,\n   * falls back to the SDK i18n stub keyed by `locale`.\n   */\n  unsupportedLabel?: string;\n  /**\n   * Locale tag used to pick SDK i18n fallbacks for `listeningLabel` /\n   * `unsupportedLabel` when the host doesn't supply explicit overrides.\n   * Defaults to `'en'`. Hosts can call `setLocale(...)` at runtime to\n   * switch (e.g. when the user toggles UI language).\n   *\n   * @since v0.2.0\n   */\n  locale?: string;\n  /**\n   * Default `true`. When enabled, `captureOnce` returns `null` for any\n   * capture that resolves to whitespace-only text — empty utterance,\n   * timeout, browser-unsupported, denied permission. Hosts can then write\n   * a single `if (!text) return;` guard instead of repeating `.trim()`\n   * checks everywhere. Set `false` if you want the raw transcript\n   * (including empty / whitespace-only) at the host boundary.\n   */\n  skipEmptyTranscript?: boolean;\n}\n\nexport class VoiceModule {\n  readonly stt: Voice;\n  readonly tts: TTS;\n  private autoSpeakSubtitles: boolean;\n  private captureTimeoutMs: number;\n  private listeningLabelOverride: string | undefined;\n  private unsupportedLabelOverride: string | undefined;\n  private locale: string;\n  private skipEmptyTranscript: boolean;\n\n  constructor(config: VoiceModuleConfig = {}) {\n    this.stt = new Voice({\n      ...config.stt,\n      llm: config.stt?.llm ?? config.llm,\n    });\n    this.tts = new TTS(config.tts ?? {});\n    this.autoSpeakSubtitles = config.autoSpeakSubtitles ?? false;\n    this.captureTimeoutMs = config.captureTimeoutMs ?? 30_000;\n    this.locale = config.locale ?? 'en';\n    this.listeningLabelOverride = config.listeningLabel;\n    this.unsupportedLabelOverride = config.unsupportedLabel;\n    this.skipEmptyTranscript = config.skipEmptyTranscript ?? true;\n  }\n\n  /** Resolved listening label — host override if set, else SDK i18n fallback. */\n  private get listeningLabel(): string {\n    return this.listeningLabelOverride ?? sdkString(this.locale, 'voice.listening');\n  }\n\n  /** Resolved unsupported label — host override if set, else SDK i18n fallback. */\n  private get unsupportedLabel(): string {\n    return this.unsupportedLabelOverride ?? sdkString(this.locale, 'voice.unsupported');\n  }\n\n  /**\n   * Switch the locale used for the SDK i18n fallback labels at runtime.\n   * Hosts call this when the user toggles UI language. Has no effect on\n   * labels the host has explicitly overridden via constructor config.\n   *\n   * @since v0.2.0\n   */\n  setLocale(locale: string): void {\n    this.locale = locale;\n  }\n\n  /**\n   * Capture one utterance, return the trimmed transcript.\n   *\n   * Default behaviour (`skipEmptyTranscript: true`): empty / whitespace\n   * / timeout / unsupported all resolve to `null`. Hosts write a single\n   * `if (!text) return;` guard instead of repeating `.trim()` checks\n   * and accidentally feeding empty queries to the webagent.\n   *\n   * Disable with `skipEmptyTranscript: false` to receive the raw\n   * transcript at the host boundary (empty string for nothing captured).\n   */\n  async captureOnce(subtitle?: Subtitle): Promise<string | null> {\n    if (!this.stt.isSupported()) {\n      subtitle?.show({\n        text: this.unsupportedLabel,\n        type: 'info',\n        autoHide: 2000,\n      });\n      return this.skipEmptyTranscript ? null : '';\n    }\n\n    return new Promise((resolve) => {\n      let settled = false;\n      let timer: ReturnType<typeof setTimeout> | null = null;\n      const cleanup = () => {\n        this.stt.off('final', handler);\n        this.stt.off('start', onStart);\n        if (timer != null) clearTimeout(timer);\n        subtitle?.hideIndicator();\n      };\n      // Normalise the resolved value against the skipEmptyTranscript flag.\n      // raw → null when empty (and skipping), trimmed string otherwise.\n      const finish = (raw: string): void => {\n        const trimmed = raw.trim();\n        if (this.skipEmptyTranscript) {\n          resolve(trimmed.length === 0 ? null : trimmed);\n        } else {\n          resolve(raw);\n        }\n      };\n      const handler = (text: unknown) => {\n        if (settled) return;\n        settled = true;\n        cleanup();\n        finish(String(text ?? ''));\n      };\n      // The STT engine fires `start` when the mic is actually captured —\n      // that's AFTER the permission grant + browser-side warmup. We\n      // delay the \"Listening\" indicator until that moment so the first-\n      // use case (user holds the button, browser is prompting for mic\n      // permission) doesn't show a label promising audio capture before\n      // any audio is actually being captured. Until then we show the\n      // generic processing indicator so the bar isn't empty during the\n      // ~hundreds-of-ms preparing window.\n      const onStart = (): void => {\n        if (settled) return;\n        subtitle?.showIndicator('listening', this.listeningLabel);\n      };\n      this.stt.on('start', onStart);\n      this.stt.on('final', handler);\n      // Failsafe: some STT engines (or denied permissions) never fire 'final'.\n      // Caller-configurable upper bound so the indicator doesn't hang forever.\n      timer = setTimeout(() => {\n        if (settled) return;\n        settled = true;\n        cleanup();\n        try { this.stt.stop(); } catch { /* ignore */ }\n        finish('');\n      }, this.captureTimeoutMs);\n      subtitle?.showIndicator('processing');\n      this.stt.start();\n    });\n  }\n\n  /**\n   * Pre-warm the mic permission. Forwards to the underlying `Voice.warmUp()` —\n   * see that doc for why. Resolves with the permission state.\n   */\n  warmUp(): Promise<'granted' | 'prompt' | 'denied' | 'unavailable'> {\n    return this.stt.warmUp();\n  }\n\n  async speakSubtitle(text: string): Promise<void> {\n    if (!this.autoSpeakSubtitles) return;\n    if (!this.tts.isSupported()) return;\n    await this.tts.speak(text);\n  }\n\n  setAutoSpeak(enabled: boolean): void {\n    this.autoSpeakSubtitles = enabled;\n    if (!enabled) this.tts.stop();\n  }\n\n  destroy(): void {\n    this.stt.destroy();\n    this.tts.destroy();\n  }\n}\n","/**\n * Theme toggle — switch between light / dark / system. Registers a palette command.\n */\n\nimport type { CommandPalette, PaletteItem } from '../triggers/command-palette';\nimport type { StorageAdapter } from '../types';\nimport { sdkString } from '../utils/sdk-i18n';\n\nexport type ThemeValue = 'light' | 'dark' | 'system';\n\nexport interface ThemeToggleConfig {\n  storage?: StorageAdapter;\n  /** Attribute to set on <html>. Default 'data-theme'. */\n  attribute?: string;\n  /** Storage key. Default 'dddk.theme'. */\n  storageKey?: string;\n  /** Locale used for the palette command names — `en` / `zh-TW` ship\n   *  bundled, anything else falls back to English. Default `en`. */\n  locale?: string;\n  /** Callback when theme changes. */\n  onChange?: (theme: ThemeValue) => void;\n}\n\nexport class ThemeToggleModule {\n  private cfg: Required<Pick<ThemeToggleConfig, 'attribute' | 'storageKey'>> & ThemeToggleConfig;\n  private mediaQuery?: MediaQueryList;\n\n  constructor(config: ThemeToggleConfig = {}) {\n    this.cfg = {\n      attribute: 'data-theme',\n      storageKey: 'dddk.theme',\n      ...config,\n    };\n  }\n\n  apply(theme?: ThemeValue): ThemeValue {\n    const target = theme ?? this.read();\n    const effective = target === 'system' ? this.systemPreference() : target;\n\n    if (typeof document !== 'undefined') {\n      document.documentElement.setAttribute(this.cfg.attribute, effective);\n    }\n    this.cfg.storage?.set(this.cfg.storageKey, target);\n    this.cfg.onChange?.(target);\n\n    if (target === 'system') this.bindSystemListener();\n    else this.unbindSystemListener();\n\n    return target;\n  }\n\n  read(): ThemeValue {\n    const stored = this.cfg.storage?.get(this.cfg.storageKey);\n    return (stored as ThemeValue | null | undefined) ?? 'system';\n  }\n\n  toggle(): ThemeValue {\n    const cur = this.read();\n    const next: ThemeValue = cur === 'light' ? 'dark' : cur === 'dark' ? 'system' : 'light';\n    return this.apply(next);\n  }\n\n  private systemPreference(): 'light' | 'dark' {\n    if (typeof window === 'undefined' || !window.matchMedia) return 'light';\n    return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n  }\n\n  private bindSystemListener(): void {\n    if (typeof window === 'undefined' || !window.matchMedia || this.mediaQuery) return;\n    this.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n    this.mediaQuery.addEventListener('change', this.onSystemChange);\n  }\n\n  private unbindSystemListener(): void {\n    if (this.mediaQuery) {\n      this.mediaQuery.removeEventListener('change', this.onSystemChange);\n      this.mediaQuery = undefined;\n    }\n  }\n\n  private onSystemChange = () => {\n    if (this.read() === 'system') this.apply('system');\n  };\n\n  paletteCommands(): PaletteItem[] {\n    const loc = this.cfg.locale;\n    return [\n      {\n        id: 'theme-light',\n        name: sdkString(loc, 'palette.theme.light'),\n        section: 'Appearance',\n        icon: '○',\n        handler: (p) => {\n          this.apply('light');\n          p.close();\n        },\n      },\n      {\n        id: 'theme-dark',\n        name: sdkString(loc, 'palette.theme.dark'),\n        section: 'Appearance',\n        icon: '●',\n        handler: (p) => {\n          this.apply('dark');\n          p.close();\n        },\n      },\n      {\n        id: 'theme-system',\n        name: sdkString(loc, 'palette.theme.system'),\n        section: 'Appearance',\n        icon: '◐',\n        handler: (p) => {\n          this.apply('system');\n          p.close();\n        },\n      },\n    ];\n  }\n\n  registerOn(palette: CommandPalette): void {\n    for (const cmd of this.paletteCommands()) palette.addItem(cmd);\n  }\n}\n","/**\n * Language switcher — exposes palette commands to switch site / dddk locale.\n */\n\nimport type { CommandPalette, PaletteItem } from '../triggers/command-palette';\nimport type { StorageAdapter } from '../types';\nimport { sdkString } from '../utils/sdk-i18n';\n\nexport interface LanguageSwitcherConfig {\n  available: Array<{ code: string; label: string }>;\n  current?: string;\n  storage?: StorageAdapter;\n  storageKey?: string;\n  /** Locale for the \"✓ Active\" marker label on the currently-selected\n   *  language. `en` / `zh-TW` ship bundled, anything else falls back\n   *  to English. Default `en`. */\n  locale?: string;\n  /** Called when user picks a language. Host applies to its i18n layer. */\n  onChange: (code: string) => void;\n}\n\nexport class LanguageSwitcherModule {\n  private cfg: LanguageSwitcherConfig & { storageKey: string };\n  private current: string;\n\n  constructor(config: LanguageSwitcherConfig) {\n    this.cfg = { storageKey: 'dddk.language', ...config };\n    const stored = this.cfg.storage?.get(this.cfg.storageKey);\n    this.current =\n      stored ??\n      config.current ??\n      (typeof navigator !== 'undefined' ? navigator.language : 'en');\n  }\n\n  getCurrent(): string {\n    return this.current;\n  }\n\n  switch(code: string): void {\n    if (this.current === code) return;\n    this.current = code;\n    this.cfg.storage?.set(this.cfg.storageKey, code);\n    this.cfg.onChange(code);\n  }\n\n  paletteCommands(): PaletteItem[] {\n    return this.cfg.available.map((lang) => ({\n      id: `lang-${lang.code}`,\n      name: lang.label,\n      description: lang.code === this.current ? sdkString(this.cfg.locale, 'palette.language.current') : undefined,\n      section: 'Language',\n      icon: '文',\n      handler: (p) => {\n        this.switch(lang.code);\n        p.close();\n      },\n    }));\n  }\n\n  registerOn(palette: CommandPalette): void {\n    for (const cmd of this.paletteCommands()) palette.addItem(cmd);\n  }\n}\n","/**\r\n * FormAssist — detect forms on the page, offer \"AI fill\" near them.\r\n *\r\n * Workflow:\r\n *  1. Module observes the DOM for <form> + ARIA forms (role=form)\r\n *  2. Adds a small floating \"AI fill\" button near each form (toggleable)\r\n *  3. User clicks → orchestrator starts agent task \"fill the form at <selector>\r\n *     based on: <context>\". Webagent's fill_input action handles the rest.\r\n *\r\n * Pure DOM module — no host data. Agent only sees what's in the page DOM\r\n * (which is what the user can see too) — so security boundary holds.\r\n */\r\n\r\nimport type { Subtitle } from '../ui/subtitle';\r\nimport { inferSelector } from '../utils/selector';\r\nimport { injectScopedStyle } from '../utils/dom';\r\nimport { sdkString } from '../utils/sdk-i18n';\r\n\r\nexport interface FormAssistConfig {\r\n  /** Selector for forms to assist with. Default 'form'. */\r\n  formSelector?: string;\r\n  /** Skip forms matching this selector (e.g. login forms). */\r\n  skipSelector?: string;\r\n  /**\r\n   * Called when user clicks the \"AI fill\" button. Host typically dispatches\r\n   * this to `dddk.startAgent(...)` with a task that uses webagent's\r\n   * `fill_input` action.\r\n   */\r\n  onAssist: (info: FormAssistInfo) => void;\r\n  /** Show the button automatically when forms appear. Default true. */\r\n  autoShow?: boolean;\r\n  /** Locale for the \"AI fill\" button label + tooltip. `en` / `zh-TW`\r\n   *  ship bundled; anything else falls back to English. */\r\n  locale?: string;\r\n  /** Override the button label entirely (skips the locale lookup). */\r\n  buttonLabel?: string;\r\n}\r\n\r\nexport interface FormAssistInfo {\r\n  form: HTMLFormElement;\r\n  selector: string;\r\n  fields: Array<{ name: string; label: string; type: string; required: boolean }>;\r\n}\r\n\r\nimport { UI_ATTR } from '../utils/dom';\r\nconst STYLE_ID = 'dddk-form-assist-style';\r\n\r\nexport class FormAssistModule {\r\n  private cfg: Required<Pick<FormAssistConfig, 'formSelector' | 'autoShow'>> & FormAssistConfig;\r\n  private observed = new WeakSet<HTMLFormElement>();\r\n  private buttons = new WeakMap<HTMLFormElement, HTMLButtonElement>();\r\n  private observer: MutationObserver | null = null;\r\n\r\n  constructor(config: FormAssistConfig) {\r\n    this.cfg = {\r\n      formSelector: 'form',\r\n      autoShow: true,\r\n      ...config,\r\n    };\r\n  }\r\n\r\n  start(subtitle?: Subtitle): void {\r\n    if (typeof document === 'undefined') return;\r\n    ensureStyles();\r\n    this.scan(subtitle);\r\n    if (this.cfg.autoShow) {\r\n      this.observer = new MutationObserver(() => this.scan(subtitle));\r\n      this.observer.observe(document.body, { childList: true, subtree: true });\r\n    }\r\n  }\r\n\r\n  stop(): void {\r\n    this.observer?.disconnect();\r\n    this.observer = null;\r\n    document.querySelectorAll(`[${UI_ATTR}=\"form-assist-btn\"]`).forEach((el) => el.remove());\r\n  }\r\n\r\n  /** Manually attach a button to one form. */\r\n  attachTo(form: HTMLFormElement, subtitle?: Subtitle): void {\r\n    if (this.observed.has(form)) return;\r\n    if (this.cfg.skipSelector && form.matches(this.cfg.skipSelector)) return;\r\n\r\n    this.observed.add(form);\r\n    const btn = document.createElement('button');\r\n    btn.type = 'button';\r\n    btn.setAttribute(UI_ATTR, 'form-assist-btn');\r\n    btn.textContent = this.cfg.buttonLabel ?? sdkString(this.cfg.locale, 'form.assist.fill');\r\n    btn.title = this.cfg.buttonLabel ?? sdkString(this.cfg.locale, 'form.assist.fill');\r\n    btn.onclick = (e) => {\r\n      e.preventDefault();\r\n      e.stopPropagation();\r\n      const info = inspectForm(form);\r\n      subtitle?.show({\r\n        text: sdkString(this.cfg.locale, 'form.assist.scanning', { count: info.fields.length }),\r\n        type: 'info',\r\n        autoHide: 1500,\r\n      });\r\n      this.cfg.onAssist(info);\r\n    };\r\n    // place inside form, top-right corner. `position: static` is the default\r\n    // computed value, and `||` won't overwrite it (it's a truthy string), so\r\n    // we have to consult getComputedStyle to know whether we need to bump it\r\n    // to `relative` for our absolute-positioned button to anchor correctly.\r\n    if (typeof window !== 'undefined' && getComputedStyle(form).position === 'static') {\r\n      form.style.position = 'relative';\r\n    }\r\n    form.appendChild(btn);\r\n    this.buttons.set(form, btn);\r\n  }\r\n\r\n  /** Manually detach. */\r\n  detachFrom(form: HTMLFormElement): void {\r\n    const btn = this.buttons.get(form);\r\n    btn?.remove();\r\n    this.buttons.delete(form);\r\n    this.observed.delete(form);\r\n  }\r\n\r\n  // ─── private ──────────────────────────────────────────────────────\r\n\r\n  private scan(subtitle?: Subtitle): void {\r\n    const forms = document.querySelectorAll<HTMLFormElement>(this.cfg.formSelector);\r\n    forms.forEach((f) => this.attachTo(f, subtitle));\r\n  }\r\n}\r\n\r\n// ─── helpers ──────────────────────────────────────────────────────\r\n\r\nexport function inspectForm(form: HTMLFormElement): FormAssistInfo {\r\n  const fields: FormAssistInfo['fields'] = [];\r\n  const inputs = form.querySelectorAll<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>(\r\n    'input, select, textarea'\r\n  );\r\n  inputs.forEach((el) => {\r\n    if (el.type === 'hidden' || el.type === 'submit' || el.type === 'button') return;\r\n    const label = findLabel(el);\r\n    fields.push({\r\n      name: el.name || el.id || label || '(unnamed)',\r\n      label,\r\n      type: el.type || el.tagName.toLowerCase(),\r\n      required: el.required,\r\n    });\r\n  });\r\n  return {\r\n    form,\r\n    selector: inferSelector(form),\r\n    fields,\r\n  };\r\n}\r\n\r\nfunction findLabel(el: HTMLElement): string {\r\n  const id = el.id;\r\n  if (id) {\r\n    const lbl = document.querySelector<HTMLLabelElement>(`label[for=\"${CSS.escape(id)}\"]`);\r\n    if (lbl) return lbl.textContent?.trim() ?? '';\r\n  }\r\n  const wrap = el.closest('label');\r\n  if (wrap) {\r\n    // strip the input's own text content\r\n    const clone = wrap.cloneNode(true) as HTMLLabelElement;\r\n    clone.querySelectorAll('input, select, textarea').forEach((x) => x.remove());\r\n    return clone.textContent?.trim() ?? '';\r\n  }\r\n  return el.getAttribute('aria-label') ?? (el as HTMLInputElement).placeholder ?? '';\r\n}\r\n\r\n\r\nfunction ensureStyles(): void {\r\n  injectScopedStyle(STYLE_ID, `\r\n    [${UI_ATTR}=\"form-assist-btn\"] {\r\n      position: absolute; top: 8px; right: 8px;\r\n      background: var(--dddk-accent, #3b82f6);\r\n      color: #fff; border: 0; border-radius: 6px;\r\n      padding: 4px 10px; font-size: 12px; cursor: pointer;\r\n      box-shadow: var(--dddk-shadow-sm, 0 1px 3px rgba(0,0,0,0.1));\r\n      z-index: 10;\r\n    }\r\n    [${UI_ATTR}=\"form-assist-btn\"]:hover {\r\n      background: var(--dddk-accent-hover, #2563eb);\r\n    }\r\n  `);\r\n}\r\n","/**\n * Onboarding — auto-run a ScriptSkill the first time a user visits.\n *\n * Wraps the registry pattern with:\n *   - persistent \"seen\" flag (so it doesn't run again unless reset)\n *   - manual \"restart tour\" command\n *   - optional URL-based gating (only run on specific pages)\n */\n\nimport type { ScriptSkill } from '../../skills/types';\nimport type { CommandPalette, PaletteItem } from '../../triggers/command-palette';\nimport type { StorageAdapter } from '../../types';\nimport { sdkString } from '../../utils/sdk-i18n';\n\nexport interface OnboardingConfig {\n  /** The tour to run. */\n  skill: ScriptSkill;\n  /** Storage for the \"seen\" flag. */\n  storage: StorageAdapter;\n  /** Storage key. Default 'dddk.onboarding.seen.<skill.id>'. */\n  storageKey?: string;\n  /**\n   * Only auto-run if the current pathname matches.\n   * String → exact match; RegExp → tested; Array → any of.\n   * Default: any page.\n   */\n  runOnPath?: string | RegExp | Array<string | RegExp>;\n  /** Run after this delay (let host render first). Default 500ms. */\n  startDelayMs?: number;\n  /** Locale for the \"Replay tour\" palette command name. `en` / `zh-TW`\n   *  ship bundled. Default `en`. */\n  locale?: string;\n}\n\nexport class OnboardingModule {\n  private cfg: OnboardingConfig;\n  private storageKey: string;\n\n  constructor(config: OnboardingConfig) {\n    this.cfg = config;\n    this.storageKey = config.storageKey ?? `dddk.onboarding.seen.${config.skill.id}`;\n  }\n\n  /**\n   * Call once after `dddk.mount()`. Auto-runs the skill if (a) not seen\n   * before, and (b) current path matches `runOnPath`.\n   */\n  maybeRun(runSkill: (id: string) => Promise<void> | void): void {\n    if (typeof window === 'undefined') return;\n    if (this.hasSeen()) return;\n    if (!this.matchesPath()) return;\n\n    const delay = this.cfg.startDelayMs ?? 500;\n    setTimeout(() => {\n      Promise.resolve(runSkill(this.cfg.skill.id))\n        .then(() => this.markSeen())\n        .catch((err) => console.error('[Onboarding] skill error:', err));\n    }, delay);\n  }\n\n  /** Mark the tour as seen — won't auto-run again. */\n  markSeen(): void {\n    this.cfg.storage.set(this.storageKey, '1');\n  }\n\n  /** Reset so the tour will run again next visit. */\n  reset(): void {\n    this.cfg.storage.remove(this.storageKey);\n  }\n\n  hasSeen(): boolean {\n    const v = this.cfg.storage.get(this.storageKey);\n    return v != null && v.length > 0;\n  }\n\n  /** Palette commands: re-run + reset. */\n  paletteCommands(runSkill: (id: string) => Promise<void> | void): PaletteItem[] {\n    return [\n      {\n        id: `${this.cfg.skill.id}-restart`,\n        name: sdkString(this.cfg.locale, 'palette.onboarding.replay'),\n        description: this.cfg.skill.name,\n        icon: '▶',\n        section: 'Help',\n        handler: (p) => {\n          p.close();\n          this.reset();\n          runSkill(this.cfg.skill.id);\n        },\n      },\n    ];\n  }\n\n  registerOn(palette: CommandPalette, runSkill: (id: string) => Promise<void> | void): void {\n    for (const cmd of this.paletteCommands(runSkill)) palette.addItem(cmd);\n  }\n\n  // ─── private ──────────────────────────────────────────────────────\n\n  private matchesPath(): boolean {\n    const spec = this.cfg.runOnPath;\n    if (!spec) return true;\n    const path = location.pathname;\n    const tests = Array.isArray(spec) ? spec : [spec];\n    return tests.some((t) =>\n      typeof t === 'string' ? t === path : (t as RegExp).test(path)\n    );\n  }\n}\n","/**\n * Platform detection — read the user's OS to surface the right modifier-key\n * label (⌘ on Mac, Ctrl elsewhere). Behaviour is platform-agnostic everywhere\n * else in dddk: key handling already accepts both Ctrl and Meta. This module\n * exists solely so UI labels can match the user's actual keyboard.\n *\n * SSR-safe — returns `false` / Ctrl-flavoured labels when `navigator` is\n * undefined, so static-render frameworks (SvelteKit / Next.js) don't blow up\n * during server pre-render. Hosts that need to swap on hydration should call\n * the helper inside `onMount` / `useEffect`.\n */\n\n/** Best-effort Mac detection. */\nexport function isMac(): boolean {\n  if (typeof navigator === 'undefined') return false;\n  // Modern UA-Client-Hints API (Chromium 90+) — preferred because\n  // `navigator.platform` has been deprecated for years and may be frozen to\n  // a generic value by privacy modes.\n  const uaPlatform = (navigator as unknown as {\n    userAgentData?: { platform?: string };\n  }).userAgentData?.platform;\n  if (typeof uaPlatform === 'string') return uaPlatform === 'macOS';\n  // Legacy fallback. Includes iOS — touch devices with a hardware keyboard\n  // (iPad Magic Keyboard etc.) also use ⌘, so treating them as Mac is\n  // correct for the modifier-key label.\n  return /Mac|iPhone|iPad|iPod/.test(navigator.platform || '');\n}\n\n/**\n * Display label for the palette-open shortcut. `⌘K` on Mac/iOS, `Ctrl+K`\n * everywhere else. The underlying keybinding accepts both (Ctrl OR Meta) on\n * every platform — this is purely a hint string.\n */\nexport function paletteShortcutLabel(): string {\n  return isMac() ? '⌘K' : 'Ctrl+K';\n}\n\n/** Same shape but with a leading `+`-style join (`⌘+K` / `Ctrl+K`). */\nexport function paletteShortcutLabelPlus(): string {\n  return isMac() ? '⌘+K' : 'Ctrl+K';\n}\n","/**\n * Cache — synchronous key/value store with LRU eviction.\n *\n * Why sync (not async)? Because the canonical use case is:\n *   const cached = cache.get('user-42');  // render immediately\n *   if (cached) showResult(JSON.parse(cached));\n *   fetchUser(42).then(u => cache.set('user-42', JSON.stringify(u)));  // refresh\n *\n * `useState` / `useMemo` flow needs the value RIGHT NOW, not a microtask later.\n *\n * Storage tiers (configurable):\n *   - 'memory'  — in-process Map. Lost on page reload.\n *   - 'session' — sessionStorage backup. Survives reload, dies on tab close.\n *   - 'local'   — localStorage backup. Survives tab close, dies on clear.\n *\n * The in-memory layer is always present. Lower tier (if set) is read on first\n * touch and written on every set.\n */\n\nexport type CacheTier = 'memory' | 'session' | 'local';\n\nexport interface CacheOptions {\n  /** Logical namespace — prefixes storage keys to avoid collision. */\n  namespace?: string;\n  /** Max entries in memory. Older entries evicted (LRU). Default 1000. */\n  capacity?: number;\n  /** Backing store. Default 'memory' only. */\n  tier?: CacheTier;\n  /** Time-to-live in ms. Default Infinity. Applies to all entries. */\n  ttl?: number;\n}\n\ninterface Entry {\n  value: string;\n  expiresAt: number;\n}\n\ntype Listener = (key: string, value: string | null) => void;\n\nexport class Cache {\n  private mem = new Map<string, Entry>();\n  private listeners = new Set<Listener>();\n  private namespace: string;\n  private capacity: number;\n  private tier: CacheTier;\n  private ttl: number;\n  private backing?: Storage;\n\n  constructor(opts: CacheOptions = {}) {\n    this.namespace = opts.namespace ?? 'dddk';\n    this.capacity = opts.capacity ?? 1000;\n    this.tier = opts.tier ?? 'memory';\n    this.ttl = opts.ttl ?? Infinity;\n    this.backing = this.resolveBacking(this.tier);\n  }\n\n  // ─── public sync API ──────────────────────────────────────────────\n\n  get(key: string): string | null {\n    const k = this.fullKey(key);\n\n    // memory first\n    const mem = this.mem.get(k);\n    if (mem) {\n      if (mem.expiresAt < Date.now()) {\n        this.delete(key);\n        return null;\n      }\n      // touch (move to most-recent end of insertion order)\n      this.mem.delete(k);\n      this.mem.set(k, mem);\n      return mem.value;\n    }\n\n    // fall back to backing\n    if (this.backing) {\n      const raw = this.backing.getItem(k);\n      if (raw == null) return null;\n      try {\n        const parsed = JSON.parse(raw) as Entry;\n        if (parsed.expiresAt < Date.now()) {\n          this.backing.removeItem(k);\n          return null;\n        }\n        this.mem.set(k, parsed);\n        this.evictIfOverflow();\n        return parsed.value;\n      } catch {\n        return null;\n      }\n    }\n\n    return null;\n  }\n\n  set(key: string, value: string): void {\n    const k = this.fullKey(key);\n    const entry: Entry = {\n      value,\n      expiresAt: this.ttl === Infinity ? Number.MAX_SAFE_INTEGER : Date.now() + this.ttl,\n    };\n    // Refresh insertion order\n    this.mem.delete(k);\n    this.mem.set(k, entry);\n    this.evictIfOverflow();\n\n    if (this.backing) {\n      try {\n        this.backing.setItem(k, JSON.stringify(entry));\n      } catch {\n        // Quota — silently ignore. Memory still has it.\n      }\n    }\n\n    this.notify(key, value);\n  }\n\n  has(key: string): boolean {\n    return this.get(key) !== null;\n  }\n\n  delete(key: string): void {\n    const k = this.fullKey(key);\n    this.mem.delete(k);\n    if (this.backing) {\n      try {\n        this.backing.removeItem(k);\n      } catch {\n        // ignore\n      }\n    }\n    this.notify(key, null);\n  }\n\n  clear(): void {\n    const memKeys = Array.from(this.mem.keys());\n    this.mem.clear();\n    // We also have to wipe backing keys that were already evicted from mem\n    // (mem is bounded by `capacity`; backing isn't). Scan ALL keys in the\n    // backing store for our namespace prefix and remove them.\n    const backingKeys = new Set<string>(memKeys);\n    if (this.backing) {\n      const prefix = `${this.namespace}:`;\n      try {\n        for (let i = 0; i < this.backing.length; i++) {\n          const k = this.backing.key(i);\n          if (k && k.startsWith(prefix)) backingKeys.add(k);\n        }\n      } catch {\n        // ignore: some Storage impls throw on length access in private mode\n      }\n      for (const k of backingKeys) {\n        try {\n          this.backing.removeItem(k);\n        } catch {\n          // ignore\n        }\n      }\n    }\n    for (const k of backingKeys) this.notify(this.stripNamespace(k), null);\n  }\n\n  size(): number {\n    return this.mem.size;\n  }\n\n  /** Subscribe to changes. Returns unsubscribe. */\n  subscribe(handler: Listener): () => void {\n    this.listeners.add(handler);\n    return () => this.listeners.delete(handler);\n  }\n\n  // ─── private ──────────────────────────────────────────────────────\n\n  private fullKey(key: string): string {\n    return `${this.namespace}:${key}`;\n  }\n\n  private stripNamespace(fullKey: string): string {\n    const prefix = `${this.namespace}:`;\n    return fullKey.startsWith(prefix) ? fullKey.slice(prefix.length) : fullKey;\n  }\n\n  private resolveBacking(tier: CacheTier): Storage | undefined {\n    if (typeof window === 'undefined') return undefined;\n    if (tier === 'session') return window.sessionStorage;\n    if (tier === 'local') return window.localStorage;\n    return undefined;\n  }\n\n  private evictIfOverflow(): void {\n    while (this.mem.size > this.capacity) {\n      const oldest = this.mem.keys().next().value;\n      if (oldest === undefined) break;\n      this.mem.delete(oldest);\n      if (this.backing) {\n        try {\n          this.backing.removeItem(oldest);\n        } catch {\n          // ignore\n        }\n      }\n    }\n  }\n\n  private notify(key: string, value: string | null): void {\n    for (const h of this.listeners) {\n      try {\n        h(key, value);\n      } catch (err) {\n        console.error('[Cache] listener error:', err);\n      }\n    }\n  }\n}\n","/**\n * HeatRank — frequency × recency scoring for palette items, recent files,\n * snippet suggestions, etc.\n *\n * Algorithm: each \"visit\" adds a unit boost that decays exponentially over\n * `halfLifeMs`. Total score = sum of decayed visit weights.\n *   score(now) = Σ (0.5 ^ ((now - visitedAt) / halfLifeMs))\n *\n * Sorted descending → most-recently-and-frequently-used items float to top.\n *\n * Storage is opaque — caller passes a `read/write` adapter. Default uses\n * an in-process Map (lost on reload). For persistence, wire to the dddk Cache.\n */\n\nexport interface HeatRankAdapter {\n  read(scope: string): Record<string, number[]>;\n  write(scope: string, data: Record<string, number[]>): void;\n}\n\nexport interface HeatRankOptions {\n  /** Identifier scoping ranks (e.g. 'palette', 'recent-files'). */\n  scope?: string;\n  /** Time in ms for visit weight to halve. Default 7 days. */\n  halfLifeMs?: number;\n  /** Cap on visits kept per item — prevents unbounded growth. Default 20. */\n  maxVisitsPerItem?: number;\n  /** Adapter for persistence. Defaults to in-memory. */\n  adapter?: HeatRankAdapter;\n}\n\nconst DEFAULT_HALF_LIFE = 7 * 24 * 60 * 60 * 1000; // 7 days\n\nexport class HeatRank {\n  private scope: string;\n  private halfLifeMs: number;\n  private maxVisitsPerItem: number;\n  private adapter: HeatRankAdapter;\n\n  constructor(opts: HeatRankOptions = {}) {\n    this.scope = opts.scope ?? 'default';\n    this.halfLifeMs = opts.halfLifeMs ?? DEFAULT_HALF_LIFE;\n    this.maxVisitsPerItem = opts.maxVisitsPerItem ?? 20;\n    this.adapter = opts.adapter ?? makeMemoryAdapter();\n  }\n\n  /** Record a usage event for the given id. */\n  visit(id: string): void {\n    const all = this.adapter.read(this.scope);\n    const arr = all[id] ?? [];\n    arr.push(Date.now());\n    if (arr.length > this.maxVisitsPerItem) {\n      arr.splice(0, arr.length - this.maxVisitsPerItem);\n    }\n    all[id] = arr;\n    this.adapter.write(this.scope, all);\n  }\n\n  /** Current score for one id. */\n  score(id: string, now: number = Date.now()): number {\n    const all = this.adapter.read(this.scope);\n    const visits = all[id];\n    if (!visits || visits.length === 0) return 0;\n    let sum = 0;\n    for (const t of visits) {\n      const age = now - t;\n      if (age < 0) sum += 1;\n      else sum += Math.pow(0.5, age / this.halfLifeMs);\n    }\n    return sum;\n  }\n\n  /** Sort items in descending score. Items not yet visited go last (via fallbackCompare). */\n  sort<T>(\n    items: T[],\n    idOf: (item: T) => string,\n    fallbackCompare?: (a: T, b: T) => number\n  ): T[] {\n    const now = Date.now();\n    return [...items].sort((a, b) => {\n      const sa = this.score(idOf(a), now);\n      const sb = this.score(idOf(b), now);\n      if (sa === sb) return fallbackCompare ? fallbackCompare(a, b) : 0;\n      return sb - sa;\n    });\n  }\n\n  /** Drop scoring data for one item. */\n  forget(id: string): void {\n    const all = this.adapter.read(this.scope);\n    delete all[id];\n    this.adapter.write(this.scope, all);\n  }\n\n  /** Drop all scoring data in this scope. */\n  reset(): void {\n    this.adapter.write(this.scope, {});\n  }\n}\n\n// ─── adapters ──────────────────────────────────────────────────────\n\nfunction makeMemoryAdapter(): HeatRankAdapter {\n  const store: Record<string, Record<string, number[]>> = {};\n  return {\n    read: (scope) => store[scope] ?? {},\n    write: (scope, data) => {\n      store[scope] = data;\n    },\n  };\n}\n\n/** Persistence adapter backed by dddk Cache (or any sync K/V). */\nexport function makeCacheAdapter(cache: {\n  get(key: string): string | null;\n  set(key: string, value: string): void;\n}): HeatRankAdapter {\n  return {\n    read(scope) {\n      const raw = cache.get(`heatrank:${scope}`);\n      if (!raw) return {};\n      try {\n        return JSON.parse(raw) as Record<string, number[]>;\n      } catch {\n        return {};\n      }\n    },\n    write(scope, data) {\n      cache.set(`heatrank:${scope}`, JSON.stringify(data));\n    },\n  };\n}\n","/**\n * Unified ingest event schema .\n *\n * Every event flowing through the SDK conforms to this shape: intent\n * events (existing `IntentEvent` union), raw browser telemetry (clicks,\n * scrolls, hovers, focus — 7.2), and host-defined custom events via\n * `dddk.track(...)` (7.3). Downstream sinks (7.5) consume from one\n * canonical stream.\n *\n * Schema versioning rules:\n *\n *   - `schemaVersion` is bumped on every breaking change.\n *   - Within a minor SDK version, schema changes are ADDITIVE only —\n *     new optional fields, new event kinds. Existing consumers keep\n *     working without code changes.\n *   - Removing or renaming a field bumps the schema major.\n *   - The string in `EVENT_SCHEMA_VERSION` is the canonical version\n *     identifier; downstream pipelines should pin to a specific\n *     version and migrate explicitly.\n */\n\nexport const EVENT_SCHEMA_VERSION = '1.0.0';\n\n/**\n * Top-level event categories. Each category has retention + routing\n * behavior. Downstream sinks can route per category.\n */\nexport type EventCategory =\n  | 'intent'      // typed high-level events (palette, voice, agent, etc.)\n  | 'interaction' // raw browser telemetry (clicks, scrolls, hovers, focus)\n  | 'lifecycle'   // session/page/visitor lifecycle events\n  | 'audit'       // audit-category events (10.x) — stronger durability\n  | 'experiment'  // A/B variant exposure + outcomes\n  | 'custom';     // host-defined via `dddk.track(...)`\n\nexport interface BaseEvent {\n  /** Stable id assigned at emit time. */\n  id: string;\n  /** Schema version this event was emitted against. */\n  schemaVersion: string;\n  /** Category routes downstream sink behavior. */\n  category: EventCategory;\n  /** Type discriminator within the category. */\n  kind: string;\n  /** Unix epoch ms at emit time on the client. */\n  timestamp: number;\n  /** Multi-tenant scope, omitted in single-tenant / extension modes. */\n  orgId?: string;\n  visitorId?: string;\n  sessionId?: string;\n  /** Per-agent-run linkage, when applicable. */\n  runId?: string;\n  /** Page context at emit time. */\n  page?: {\n    path: string;\n    locale?: string;\n    title?: string;\n  };\n  /** Browser / device snapshot — populated by the SDK once per session. */\n  device?: {\n    ua?: string;\n    deviceType?: 'desktop' | 'mobile' | 'tablet' | 'tv' | 'other';\n    locale?: string;\n  };\n  /** Category-specific shape lives in `props`. */\n  props?: Record<string, unknown>;\n}\n\n// ─── interaction props (7.2 raw telemetry) ────────────────────────────\n\nexport interface ClickEventProps {\n  selector?: string;\n  /** Stable hash id from the DOM dump if available, otherwise undefined. */\n  domId?: string;\n  tag?: string;\n  text?: string;\n  elementRole?: string;\n  href?: string;\n  buttonName?: string;\n  modifierKeys?: string[];\n}\n\nexport interface ScrollEventProps {\n  /** 0-1 depth ratio of the page that's been scrolled past. */\n  maxDepth: number;\n  /** Direction sample over the last window. */\n  direction?: 'up' | 'down';\n  /** Optional per-element scroll if attached to a scrollable region. */\n  containerSelector?: string;\n}\n\nexport interface HoverEventProps {\n  selector?: string;\n  domId?: string;\n  tag?: string;\n  /** How long the mouse hovered before firing the event (ms). */\n  dwellMs: number;\n}\n\nexport interface FocusEventProps {\n  selector?: string;\n  domId?: string;\n  fieldType?: string;\n  fieldName?: string;\n  /** Time-on-field (ms) — populated on blur events. */\n  durationMs?: number;\n  validity?: 'valid' | 'invalid' | 'pending';\n}\n\nexport interface RoutingEventProps {\n  from: string;\n  to: string;\n  trigger?: 'link' | 'spa' | 'back' | 'forward' | 'reload' | 'agent';\n}\n\nexport interface PerformanceEventProps {\n  /** Largest Contentful Paint (ms). */\n  lcp?: number;\n  /** Interaction to Next Paint (ms). */\n  inp?: number;\n  /** Cumulative Layout Shift. */\n  cls?: number;\n  /** Time to First Byte (ms). */\n  ttfb?: number;\n}\n\n// ─── lifecycle ─────────────────────────────────────────────────────────\n\nexport interface SessionStartProps {\n  /** True if `visitorId` was just created (first-ever visit). */\n  newVisitor: boolean;\n  referrer?: string;\n  utm?: { source?: string; medium?: string; campaign?: string; content?: string; term?: string };\n}\n\nexport interface PageViewProps {\n  path: string;\n  /** Previous path on SPA nav, undefined on first page view. */\n  prevPath?: string;\n}\n\n// ─── custom ────────────────────────────────────────────────────────────\n\nexport type CustomEventProps = Record<string, unknown>;\n\n// ─── helpers ───────────────────────────────────────────────────────────\n\n/**\n * Construct a well-formed event with the current schema version + a\n * fresh id. Callers may override any field by spreading.\n */\nexport function makeEvent<P extends Record<string, unknown> = Record<string, unknown>>(\n  category: EventCategory,\n  kind: string,\n  partial: Partial<Omit<BaseEvent, 'category' | 'kind' | 'schemaVersion'>> & { props?: P } = {},\n): BaseEvent {\n  return {\n    id: partial.id ?? newEventId(),\n    schemaVersion: EVENT_SCHEMA_VERSION,\n    category,\n    kind,\n    timestamp: partial.timestamp ?? Date.now(),\n    orgId: partial.orgId,\n    visitorId: partial.visitorId,\n    sessionId: partial.sessionId,\n    runId: partial.runId,\n    page: partial.page,\n    device: partial.device,\n    props: partial.props,\n  };\n}\n\nfunction newEventId(): string {\n  if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n    return crypto.randomUUID();\n  }\n  // RFC4122-ish fallback\n  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n    const r = (Math.random() * 16) | 0;\n    const v = c === 'x' ? r : (r & 0x3) | 0x8;\n    return v.toString(16);\n  });\n}\n","/**\n * Transport layer — batching, retry, ordering — for the unified ingest\n * stream. \n *\n * Pluggable sink: anything implementing `EventSink` works. The\n * transport handles the bits that every sink would otherwise reinvent:\n *\n *   - Batching: events queue in memory, flush every N ms or M events\n *   - Retry with exponential backoff, capped at 5 attempts\n *   - Sequence ordering: events carry a monotonic seq per session\n *   - Page-unload flush via Beacon API\n *   - Optional gzip body when supported\n */\n\nimport type { BaseEvent } from './schema';\n\nexport interface EventSink {\n  send(batch: BaseEvent[]): Promise<void>;\n  /** Flush any sink-internal buffers. Optional. */\n  flush?(): Promise<void>;\n  /** Tear down. Optional. */\n  dispose?(): Promise<void>;\n}\n\nexport interface TransportOptions {\n  sink: EventSink;\n  /** Auto-flush interval in ms. Default 5000. */\n  flushIntervalMs?: number;\n  /** Max batch size before forcing a flush. Default 20. */\n  flushBatchSize?: number;\n  /** Max retry attempts per batch. Default 5. */\n  maxRetries?: number;\n  /** Hard cap on the in-memory queue. Default 1000. Overflow drops oldest. */\n  queueCap?: number;\n  /** Optional clock override for tests. */\n  now?: () => number;\n}\n\nexport class Transport {\n  private readonly sink: EventSink;\n  private readonly flushIntervalMs: number;\n  private readonly flushBatchSize: number;\n  private readonly maxRetries: number;\n  private readonly queueCap: number;\n  private queue: BaseEvent[] = [];\n  private flushTimer: ReturnType<typeof setInterval> | null = null;\n  private inflight = 0;\n  private disposed = false;\n  private seqBySession: Map<string, number> = new Map();\n  private beaconHandler: ((e: Event) => void) | null = null;\n\n  constructor(opts: TransportOptions) {\n    this.sink = opts.sink;\n    this.flushIntervalMs = opts.flushIntervalMs ?? 5000;\n    this.flushBatchSize = opts.flushBatchSize ?? 20;\n    this.maxRetries = opts.maxRetries ?? 5;\n    this.queueCap = opts.queueCap ?? 1000;\n\n    if (typeof window !== 'undefined') {\n      this.flushTimer = setInterval(() => void this.flush(), this.flushIntervalMs);\n      this.beaconHandler = () => void this.flushBeacon();\n      window.addEventListener('pagehide', this.beaconHandler);\n      window.addEventListener('beforeunload', this.beaconHandler);\n    }\n  }\n\n  /**\n   * Queue an event. Returns immediately. Auto-flushes when batch size\n   * is reached.\n   */\n  enqueue(event: BaseEvent): void {\n    if (this.disposed) return;\n    const stamped = this.stampSequence(event);\n    this.queue.push(stamped);\n    if (this.queue.length > this.queueCap) {\n      // Drop oldest to bound memory. Loud in dev, silent in prod.\n      this.queue.splice(0, this.queue.length - this.queueCap);\n    }\n    if (this.queue.length >= this.flushBatchSize) {\n      void this.flush();\n    }\n  }\n\n  /** Force a flush of any queued events. */\n  async flush(): Promise<void> {\n    if (this.queue.length === 0) return;\n    const batch = this.queue.splice(0, this.queue.length);\n    this.inflight += 1;\n    try {\n      await this.sendWithRetry(batch, 0);\n    } finally {\n      this.inflight -= 1;\n    }\n  }\n\n  /**\n   * Best-effort beacon-style flush — fire-and-forget on page unload.\n   * Falls back to a regular flush if the sink doesn't implement a\n   * beacon path.\n   */\n  flushBeacon(): void {\n    if (this.queue.length === 0) return;\n    const batch = this.queue.splice(0, this.queue.length);\n    // Best effort — most sinks won't have a real beacon path; fire\n    // a normal send and hope it lands before the page goes away.\n    void this.sink.send(batch).catch(() => {\n      /* swallow — page is going away */\n    });\n  }\n\n  async dispose(): Promise<void> {\n    this.disposed = true;\n    if (this.flushTimer !== null) {\n      clearInterval(this.flushTimer);\n      this.flushTimer = null;\n    }\n    if (typeof window !== 'undefined' && this.beaconHandler) {\n      window.removeEventListener('pagehide', this.beaconHandler);\n      window.removeEventListener('beforeunload', this.beaconHandler);\n      this.beaconHandler = null;\n    }\n    await this.flush();\n    if (this.sink.dispose) await this.sink.dispose();\n  }\n\n  private async sendWithRetry(batch: BaseEvent[], attempt: number): Promise<void> {\n    try {\n      await this.sink.send(batch);\n    } catch (err) {\n      if (attempt >= this.maxRetries) {\n        // Give up — push back to the queue head for IndexedDB persistence\n        // on next page load. Best-effort; if storage isn't wired the\n        // events are lost.\n        this.queue.unshift(...batch);\n        if (typeof console !== 'undefined') {\n          console.warn('[dddk-ingest] sink send failed after retries:', err);\n        }\n        return;\n      }\n      const delay = 400 * Math.pow(2, attempt);\n      await sleep(delay);\n      await this.sendWithRetry(batch, attempt + 1);\n    }\n  }\n\n  private stampSequence(event: BaseEvent): BaseEvent {\n    const sessionKey = event.sessionId ?? 'global';\n    const next = (this.seqBySession.get(sessionKey) ?? 0) + 1;\n    this.seqBySession.set(sessionKey, next);\n    return {\n      ...event,\n      props: { ...(event.props ?? {}), _seq: next },\n    };\n  }\n}\n\nfunction sleep(ms: number): Promise<void> {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n// ─── Reference sinks ──────────────────────────────────────────────────\n\n/**\n * POST batches as JSON to a host-configured endpoint. The most common\n * sink — used by hosts who route through their own backend.\n */\nexport class HttpSink implements EventSink {\n  constructor(\n    private readonly endpoint: string,\n    private readonly headers: Record<string, string> = {},\n  ) {}\n\n  async send(batch: BaseEvent[]): Promise<void> {\n    const res = await fetch(this.endpoint, {\n      method: 'POST',\n      headers: { 'content-type': 'application/json', ...this.headers },\n      body: JSON.stringify({ events: batch }),\n      // Don't keep the page alive past unload — beacon path handles unload.\n      keepalive: false,\n    });\n    if (!res.ok) {\n      throw new Error(`HttpSink: ${res.status} ${res.statusText}`);\n    }\n  }\n}\n\n/**\n * `console.log` sink for development — prints batches without sending.\n */\nexport class DebugSink implements EventSink {\n  async send(batch: BaseEvent[]): Promise<void> {\n    if (typeof console !== 'undefined') {\n      console.info(`[dddk-ingest] ${batch.length} events`, batch);\n    }\n  }\n}\n\n/**\n * Fan-out wrapper — sends every batch to all wrapped sinks in parallel.\n * Failures in any one sink don't break the others.\n */\nexport class MultiSink implements EventSink {\n  constructor(private readonly sinks: EventSink[]) {}\n\n  async send(batch: BaseEvent[]): Promise<void> {\n    const results = await Promise.allSettled(this.sinks.map((s) => s.send(batch)));\n    const failed = results.filter((r) => r.status === 'rejected');\n    if (failed.length === this.sinks.length) {\n      throw new Error(`MultiSink: all ${this.sinks.length} sinks failed`);\n    }\n  }\n\n  async flush(): Promise<void> {\n    await Promise.allSettled(this.sinks.map((s) => s.flush?.()));\n  }\n\n  async dispose(): Promise<void> {\n    await Promise.allSettled(this.sinks.map((s) => s.dispose?.()));\n  }\n}\n","/**\n * Local event store — persistent, queryable, capped.\n *\n * Hosts who install dddk usually want intent data SOMEWHERE: their\n * own backend, dddk-console, a BI warehouse. EventStore is the\n * \"self-hosted by default\" answer — the SDK keeps a rolling local\n * copy of every event in the end-user's browser (IndexedDB), capped\n * to a sensible default that the host can lift, query, and export to\n * CSV / NDJSON / SQL whenever they want.\n *\n * Storage is per-end-user (IndexedDB is origin-scoped) — not a\n * central DB. There is no per-store quota *we* enforce beyond the\n * browser's; the cap below is a politeness setting so the SDK\n * doesn't silently consume gigabytes of a visitor's quota.\n *\n * Cap policy:\n *   - Default 50,000 events OR 30 days, whichever fires first.\n *   - `onFull: 'ring'` (default) deletes the oldest events to make\n *     room. The data is lost — by design, ring buffers don't keep\n *     history.\n *   - `onFull: 'drop-new'` rejects incoming events instead. Useful\n *     when the host wants to keep early-session events (e.g. for\n *     RL training) and tolerate gaps later.\n *   - `onFull: { notifyHost }` hands the decision to the host. The\n *     callback can drain to backend, clear locally, raise the cap,\n *     or whatever — return value is ignored, just side-effects.\n *\n * Set `cap: { maxEvents: Infinity, maxDays: Infinity }` to disable\n * the cap entirely.\n */\n\nimport type { BaseEvent, EventCategory } from '../ingest/schema';\nimport type { EventSink } from '../ingest/transport';\n\nconst STORE = 'events';\nconst IDX_TS = 'by_timestamp';\nconst IDX_CAT_KIND = 'by_category_kind';\nconst IDX_SESSION = 'by_session';\nconst IDX_VISITOR = 'by_visitor';\nconst IDX_RUN = 'by_run';\n\nconst DEFAULT_DB_NAME = 'dddk-events';\nconst DEFAULT_MAX_EVENTS = 50_000;\nconst DEFAULT_MAX_DAYS = 30;\n\nexport interface Cap {\n  /** Max events to retain. `Infinity` disables the count cap. */\n  maxEvents: number;\n  /** Max retention in days. `Infinity` disables the age cap. */\n  maxDays: number;\n}\n\nexport interface CapInfo {\n  /** Cap values currently in effect. */\n  cap: Cap;\n  /** Current store size at the moment the cap triggered. */\n  current: { events: number; oldestTs: number | null };\n  /** The event we were about to write when the cap hit. */\n  pendingEvent: BaseEvent;\n}\n\n/**\n * Host callback for the `notify-host` policy. The store does NOT auto-\n * evict before calling — the host gets to decide. After the callback\n * resolves, the store does NOT retry the failing write; if the host\n * wants the event kept, they must explicitly do so (e.g. by calling\n * `store.clear()` first to make room, then re-emit). This is the\n * \"loud\" mode — chosen by hosts that hate silent data loss.\n */\nexport type NotifyHostHandler = (info: CapInfo) => void | Promise<void>;\n\nexport type OnFullPolicy =\n  | 'ring'\n  | 'drop-new'\n  | { notifyHost: NotifyHostHandler };\n\nexport interface EventStoreOpts {\n  /** IndexedDB database name. Default `'dddk-events'`. Hosts wiring\n   *  multiple isolated stores (e.g. one per tenant inside the same\n   *  browser) should pass distinct names. */\n  dbName?: string;\n  /** Retention cap. Both bounds are optional and default to 50k / 30d.\n   *  `Infinity` on either disables that bound. */\n  cap?: Partial<Cap>;\n  /** Behavior when the cap is exceeded. Default `'ring'`. */\n  onFull?: OnFullPolicy;\n}\n\nexport interface EventQuery {\n  /** Filter by category. Single value or array (OR). */\n  category?: EventCategory | EventCategory[];\n  /** Filter by kind. Single value or array (OR). */\n  kind?: string | string[];\n  /** Timestamp lower bound (inclusive, ms-epoch). */\n  from?: number;\n  /** Timestamp upper bound (inclusive, ms-epoch). */\n  to?: number;\n  /** Per-id filters. */\n  sessionId?: string;\n  visitorId?: string;\n  runId?: string;\n  /** Pagination. */\n  limit?: number;\n  offset?: number;\n  /** Sort by timestamp. Default `'desc'` (newest first). */\n  order?: 'asc' | 'desc';\n}\n\n/**\n * One opened EventStore wraps an IndexedDB connection. Hosts open it\n * once and reuse the instance for the page's lifetime. Closing is\n * optional — IndexedDB closes on tab unload automatically — but\n * `close()` exists for hot-reload / test cleanup.\n */\nexport class EventStore {\n  private db: IDBDatabase;\n  private cap: Cap;\n  private onFull: OnFullPolicy;\n  private writeInFlight: Promise<void> = Promise.resolve();\n\n  private constructor(db: IDBDatabase, cap: Cap, onFull: OnFullPolicy) {\n    this.db = db;\n    this.cap = cap;\n    this.onFull = onFull;\n  }\n\n  /**\n   * Open (creating if needed) the underlying IndexedDB database.\n   * Throws if IndexedDB is unavailable (SSR / Node / locked-down\n   * iframes). Hosts evaluating dddk in those environments should\n   * skip EventStore wiring.\n   */\n  static async open(opts: EventStoreOpts = {}): Promise<EventStore> {\n    if (typeof indexedDB === 'undefined') {\n      throw new Error('EventStore.open: IndexedDB unavailable in this environment');\n    }\n    const dbName = opts.dbName ?? DEFAULT_DB_NAME;\n    const cap: Cap = {\n      maxEvents: opts.cap?.maxEvents ?? DEFAULT_MAX_EVENTS,\n      maxDays:   opts.cap?.maxDays   ?? DEFAULT_MAX_DAYS,\n    };\n    const onFull: OnFullPolicy = opts.onFull ?? 'ring';\n\n    const db = await openDb(dbName);\n    return new EventStore(db, cap, onFull);\n  }\n\n  /**\n   * Persist one event. Cap policy fires here. Resolves to:\n   *   `{ stored: true }`              — written\n   *   `{ stored: false, reason: 'full' }`         — cap rejected (drop-new)\n   *   `{ stored: false, reason: 'host-rejected' }` — host's notify callback ran,\n   *                                                 store didn't auto-evict\n   */\n  write(event: BaseEvent): Promise<{ stored: boolean; reason?: 'full' | 'host-rejected' }> {\n    // Serialize writes so cap math is correct under concurrent emits.\n    const prev = this.writeInFlight;\n    let resolveOuter!: (v: { stored: boolean; reason?: 'full' | 'host-rejected' }) => void;\n    const next = new Promise<void>((res) => {\n      prev.finally(async () => {\n        try {\n          const result = await this.doWrite(event);\n          resolveOuter(result);\n        } catch (err) {\n          resolveOuter({ stored: false, reason: 'full' });\n          // Surface the underlying error to the console — silent\n          // IndexedDB failures are the classic \"events vanished\" trap.\n          // eslint-disable-next-line no-console\n          console.error('[dddk EventStore] write failed:', err);\n        } finally {\n          res();\n        }\n      });\n    });\n    this.writeInFlight = next;\n    return new Promise((res) => { resolveOuter = res; });\n  }\n\n  private async doWrite(event: BaseEvent): Promise<{ stored: boolean; reason?: 'full' | 'host-rejected' }> {\n    // Age cap: evict events older than the cutoff before doing any\n    // capacity math. Cheap — uses the timestamp index.\n    if (Number.isFinite(this.cap.maxDays)) {\n      const cutoff = Date.now() - this.cap.maxDays * 86_400_000;\n      await this.evictOlderThan(cutoff);\n    }\n\n    // Count cap: would adding this event push us over?\n    if (Number.isFinite(this.cap.maxEvents)) {\n      const current = await this.countAll();\n      if (current + 1 > this.cap.maxEvents) {\n        const oldestTs = await this.oldestTimestamp();\n        const info: CapInfo = {\n          cap: this.cap,\n          current: { events: current, oldestTs },\n          pendingEvent: event,\n        };\n        const decision = await this.handleFull(info);\n        if (decision === 'reject') {\n          return { stored: false, reason: 'host-rejected' };\n        }\n        if (decision === 'drop') {\n          return { stored: false, reason: 'full' };\n        }\n        // 'ring' — evict oldest until we have room for the new event.\n        const need = current + 1 - this.cap.maxEvents;\n        await this.evictOldestN(need);\n      }\n    }\n\n    await this.put(event);\n    return { stored: true };\n  }\n\n  private async handleFull(info: CapInfo): Promise<'ring' | 'drop' | 'reject'> {\n    if (this.onFull === 'ring')     return 'ring';\n    if (this.onFull === 'drop-new') return 'drop';\n    try {\n      await this.onFull.notifyHost(info);\n    } catch (err) {\n      // eslint-disable-next-line no-console\n      console.error('[dddk EventStore] notifyHost threw:', err);\n    }\n    return 'reject';\n  }\n\n  /**\n   * Query events. Filters that have a matching IDB index are applied\n   * server-side; the rest run as in-memory filters on the retrieved\n   * subset. For 50k-cap stores even a full scan is sub-50ms.\n   */\n  async query(q: EventQuery = {}): Promise<BaseEvent[]> {\n    const order = q.order ?? 'desc';\n    const tx = this.db.transaction(STORE, 'readonly');\n    const store = tx.objectStore(STORE);\n\n    // Pick the most selective index available.\n    let source: IDBIndex | IDBObjectStore;\n    let range: IDBKeyRange | null = null;\n    if (q.sessionId) {\n      source = store.index(IDX_SESSION);\n      range = IDBKeyRange.only(q.sessionId);\n    } else if (q.visitorId) {\n      source = store.index(IDX_VISITOR);\n      range = IDBKeyRange.only(q.visitorId);\n    } else if (q.runId) {\n      source = store.index(IDX_RUN);\n      range = IDBKeyRange.only(q.runId);\n    } else {\n      source = store.index(IDX_TS);\n      const lo = q.from;\n      const hi = q.to;\n      if (lo !== undefined && hi !== undefined)      range = IDBKeyRange.bound(lo, hi);\n      else if (lo !== undefined)                     range = IDBKeyRange.lowerBound(lo);\n      else if (hi !== undefined)                     range = IDBKeyRange.upperBound(hi);\n    }\n\n    const categories = q.category ? toSet(q.category) : null;\n    const kinds      = q.kind     ? toSet(q.kind)     : null;\n    const fromTs = q.from;\n    const toTs   = q.to;\n\n    const direction: IDBCursorDirection = order === 'asc' ? 'next' : 'prev';\n    const collected: BaseEvent[] = [];\n    const skip = q.offset ?? 0;\n    const limit = q.limit ?? Infinity;\n    let skipped = 0;\n\n    await new Promise<void>((resolve, reject) => {\n      const req = source.openCursor(range ?? undefined, direction);\n      req.onsuccess = () => {\n        const cur = req.result;\n        if (!cur || collected.length >= limit) { resolve(); return; }\n        const ev = cur.value as BaseEvent;\n        // In-memory filters not covered by the chosen index.\n        if (categories && !categories.has(ev.category))                              { cur.continue(); return; }\n        if (kinds && !kinds.has(ev.kind))                                             { cur.continue(); return; }\n        if (fromTs !== undefined && ev.timestamp < fromTs)                            { cur.continue(); return; }\n        if (toTs   !== undefined && ev.timestamp > toTs)                              { cur.continue(); return; }\n        if (skipped < skip) { skipped++; cur.continue(); return; }\n        collected.push(ev);\n        cur.continue();\n      };\n      req.onerror = () => reject(req.error);\n    });\n\n    return collected;\n  }\n\n  /** Total count of matching events. Filter shape mirrors `query`. */\n  async count(q: Pick<EventQuery, 'category' | 'kind' | 'from' | 'to' | 'sessionId' | 'visitorId' | 'runId'> = {}): Promise<number> {\n    // Falls back to the same logic as query but counts instead of collecting.\n    const evs = await this.query({ ...q, limit: Infinity, offset: 0 });\n    return evs.length;\n  }\n\n  /** Aggregate stats. Cheap — uses the timestamp index. */\n  async size(): Promise<{ events: number; oldestTs: number | null; newestTs: number | null }> {\n    const events = await this.countAll();\n    if (events === 0) return { events: 0, oldestTs: null, newestTs: null };\n    const [oldestTs, newestTs] = await Promise.all([\n      this.oldestTimestamp(),\n      this.newestTimestamp(),\n    ]);\n    return { events, oldestTs, newestTs };\n  }\n\n  /** Delete every event. Cap settings stay. */\n  async clear(): Promise<void> {\n    await this.tx('readwrite', (store) => promisify(store.clear()));\n  }\n\n  /**\n   * Delete a subset. Returns the count of deleted events. Useful for\n   * \"after I've shipped these to the backend, drop them locally\".\n   */\n  async drop(opts: { olderThanMs?: number; keepLast?: number; matching?: Pick<EventQuery, 'category' | 'kind'> }): Promise<number> {\n    let deleted = 0;\n    if (opts.olderThanMs !== undefined) {\n      const cutoff = Date.now() - opts.olderThanMs;\n      deleted += await this.evictOlderThan(cutoff);\n    }\n    if (opts.keepLast !== undefined) {\n      const total = await this.countAll();\n      if (total > opts.keepLast) {\n        deleted += await this.evictOldestN(total - opts.keepLast);\n      }\n    }\n    if (opts.matching) {\n      const matches = await this.query({ ...opts.matching, limit: Infinity, order: 'asc' });\n      for (const ev of matches) {\n        await this.tx('readwrite', (store) => promisify(store.delete(ev.id)));\n        deleted++;\n      }\n    }\n    return deleted;\n  }\n\n  /**\n   * Return an `EventSink` view of this store so it can plug straight\n   * into `Transport`:\n   *\n   * ```ts\n   * const transport = new Transport({\n   *   sinks: [new HttpSink(...), eventStore.sink()],\n   * });\n   * ```\n   *\n   * Errors at write time are swallowed (logged) — the transport's\n   * other sinks shouldn't fail just because the local store hit a\n   * quota or was rejected by `onFull: 'drop-new'`.\n   */\n  sink(): EventSink {\n    return {\n      send: async (batch: BaseEvent[]) => {\n        for (const ev of batch) {\n          await this.write(ev);\n        }\n      },\n    };\n  }\n\n  /** Close the IDB connection. Optional; called automatically on tab unload. */\n  close(): void {\n    this.db.close();\n  }\n\n  // ─── internals ──────────────────────────────────────────────\n\n  private async tx<T>(mode: IDBTransactionMode, fn: (store: IDBObjectStore) => Promise<T>): Promise<T> {\n    const tx = this.db.transaction(STORE, mode);\n    const store = tx.objectStore(STORE);\n    // `req.success` resolves when an op succeeded but BEFORE the tx\n    // is committed. Subsequent reads on a fresh tx race against the\n    // commit. Wait for `tx.oncomplete` so writes are durable before\n    // the helper returns.\n    const result = await fn(store);\n    await new Promise<void>((resolve, reject) => {\n      tx.oncomplete = () => resolve();\n      tx.onerror = () => reject(tx.error);\n      tx.onabort = () => reject(tx.error ?? new Error('IDB tx aborted'));\n    });\n    return result;\n  }\n\n  private async put(event: BaseEvent): Promise<void> {\n    await this.tx('readwrite', (store) => promisify(store.put(event)));\n  }\n\n  private async countAll(): Promise<number> {\n    return this.tx('readonly', (store) => promisify(store.count()));\n  }\n\n  private async oldestTimestamp(): Promise<number | null> {\n    return this.tx('readonly', async (store) => {\n      const idx = store.index(IDX_TS);\n      const cur = await openCursor(idx, null, 'next');\n      return cur ? (cur.value as BaseEvent).timestamp : null;\n    });\n  }\n\n  private async newestTimestamp(): Promise<number | null> {\n    return this.tx('readonly', async (store) => {\n      const idx = store.index(IDX_TS);\n      const cur = await openCursor(idx, null, 'prev');\n      return cur ? (cur.value as BaseEvent).timestamp : null;\n    });\n  }\n\n  private async evictOlderThan(cutoff: number): Promise<number> {\n    let evicted = 0;\n    await this.tx('readwrite', async (store) => {\n      const idx = store.index(IDX_TS);\n      const range = IDBKeyRange.upperBound(cutoff, true);\n      await iterateCursor(idx, range, 'next', (cur) => {\n        cur.delete();\n        evicted++;\n      });\n    });\n    return evicted;\n  }\n\n  private async evictOldestN(n: number): Promise<number> {\n    if (n <= 0) return 0;\n    let evicted = 0;\n    await this.tx('readwrite', async (store) => {\n      const idx = store.index(IDX_TS);\n      await iterateCursor(idx, null, 'next', (cur) => {\n        if (evicted >= n) return 'stop';\n        cur.delete();\n        evicted++;\n        return undefined;\n      });\n    });\n    return evicted;\n  }\n}\n\n// ─── IDB helpers ──────────────────────────────────────────────\n\nfunction openDb(name: string): Promise<IDBDatabase> {\n  return new Promise((resolve, reject) => {\n    const req = indexedDB.open(name, 1);\n    req.onupgradeneeded = () => {\n      const db = req.result;\n      if (db.objectStoreNames.contains(STORE)) return;\n      const store = db.createObjectStore(STORE, { keyPath: 'id' });\n      store.createIndex(IDX_TS,       'timestamp');\n      store.createIndex(IDX_CAT_KIND, ['category', 'kind']);\n      store.createIndex(IDX_SESSION,  'sessionId');\n      store.createIndex(IDX_VISITOR,  'visitorId');\n      store.createIndex(IDX_RUN,      'runId');\n    };\n    req.onsuccess = () => resolve(req.result);\n    req.onerror = () => reject(req.error);\n  });\n}\n\nfunction promisify<T>(req: IDBRequest<T>): Promise<T> {\n  return new Promise((resolve, reject) => {\n    req.onsuccess = () => resolve(req.result);\n    req.onerror = () => reject(req.error);\n  });\n}\n\nfunction openCursor(\n  source: IDBIndex | IDBObjectStore,\n  range: IDBKeyRange | null,\n  direction: IDBCursorDirection,\n): Promise<IDBCursorWithValue | null> {\n  return new Promise((resolve, reject) => {\n    const req = source.openCursor(range ?? undefined, direction);\n    req.onsuccess = () => resolve(req.result);\n    req.onerror = () => reject(req.error);\n  });\n}\n\nfunction iterateCursor(\n  source: IDBIndex | IDBObjectStore,\n  range: IDBKeyRange | null,\n  direction: IDBCursorDirection,\n  onEach: (cur: IDBCursorWithValue) => 'stop' | void,\n): Promise<void> {\n  return new Promise((resolve, reject) => {\n    const req = source.openCursor(range ?? undefined, direction);\n    req.onsuccess = () => {\n      const cur = req.result;\n      if (!cur) { resolve(); return; }\n      const sig = onEach(cur);\n      if (sig === 'stop') { resolve(); return; }\n      cur.continue();\n    };\n    req.onerror = () => reject(req.error);\n  });\n}\n\nfunction toSet<T extends string>(v: T | T[]): Set<T> {\n  return new Set(Array.isArray(v) ? v : [v]);\n}\n","/**\n * Canonical SQL schema for `dddk_events`.\n *\n * Every event the SDK emits (intent / interaction / lifecycle / audit /\n * experiment / custom — see `src/ingest/schema.ts`) maps to exactly one\n * row of this shape. Hosts who want to land events in their own SQL\n * store get a stable, versioned target to write a migration against.\n * Hosts who don't have a SQL store at all use the bundled\n * `EventStore` (IndexedDB) and reuse this row shape for export.\n *\n * Schema versioning rules mirror `EVENT_SCHEMA_VERSION` in\n * `src/ingest/schema.ts` — additive within a minor, bump on rename /\n * remove. The DDL strings here will track that.\n *\n * Three dialects ship out of the box: SQLite, Postgres, MySQL. Hosts\n * on other engines (BigQuery, Snowflake, ClickHouse, DuckDB, …) can\n * map the column list manually; the type annotations below give the\n * source of truth.\n *\n * Column choices:\n *   - `id` is the canonical primary key. UUID-like string, 36 chars\n *     in the default emit path, but the column allows any TEXT so\n *     custom emitters can use shorter ids.\n *   - `props_json` is a TEXT-encoded JSON blob. We don't shred props\n *     into per-kind tables — that explodes schema-migration cost. For\n *     queries Postgres / MySQL / SQLite all have native JSON access\n *     (`->>`, `->`, `json_extract`); BigQuery / ClickHouse have their\n *     own JSON types. Keeping `props_json` as TEXT is the least\n *     surprising default that works everywhere.\n *   - `timestamp` is INTEGER ms-since-epoch. Native datetime types\n *     differ wildly per engine; ms-epoch round-trips cleanly into\n *     every one of them.\n *\n * Indexes shipped:\n *   - timestamp (range scans, ring-buffer eviction)\n *   - (category, kind) (typed event queries)\n *   - session_id (per-session funnels)\n *\n * Hosts running heavy BI workloads will want to add more indexes\n * (visitor_id, run_id, page_path). The DDL below is the minimum\n * sensible default — extend in your own migration.\n */\n\nimport type { BaseEvent } from '../ingest/schema';\n\n/**\n * Flat row shape — one row per event. Optional event fields land as\n * `null` so the SQL schema can declare them NULLable. `props_json`\n * is the JSON-stringified props object (always present, empty\n * object string `'{}'` if the event has no props).\n */\nexport interface DddkEventRow {\n  id: string;\n  schema_version: string;\n  category: string;\n  kind: string;\n  timestamp: number;\n  org_id: string | null;\n  visitor_id: string | null;\n  session_id: string | null;\n  run_id: string | null;\n  page_path: string | null;\n  page_locale: string | null;\n  page_title: string | null;\n  device_ua: string | null;\n  device_type: string | null;\n  device_locale: string | null;\n  props_json: string;\n}\n\n/** Column list in the order the DDL declares — useful for INSERTs. */\nexport const DDDK_EVENTS_COLUMNS: ReadonlyArray<keyof DddkEventRow> = [\n  'id',\n  'schema_version',\n  'category',\n  'kind',\n  'timestamp',\n  'org_id',\n  'visitor_id',\n  'session_id',\n  'run_id',\n  'page_path',\n  'page_locale',\n  'page_title',\n  'device_ua',\n  'device_type',\n  'device_locale',\n  'props_json',\n];\n\n/** SQLite DDL. Drop-in `sqlite3 mydb.sqlite < ddl.sql`. */\nexport const DDDK_EVENTS_DDL_SQLITE = `\\\nCREATE TABLE IF NOT EXISTS dddk_events (\n  id              TEXT PRIMARY KEY,\n  schema_version  TEXT NOT NULL,\n  category        TEXT NOT NULL,\n  kind            TEXT NOT NULL,\n  timestamp       INTEGER NOT NULL,\n  org_id          TEXT,\n  visitor_id      TEXT,\n  session_id      TEXT,\n  run_id          TEXT,\n  page_path       TEXT,\n  page_locale     TEXT,\n  page_title      TEXT,\n  device_ua       TEXT,\n  device_type     TEXT,\n  device_locale   TEXT,\n  props_json      TEXT NOT NULL DEFAULT '{}'\n);\nCREATE INDEX IF NOT EXISTS idx_dddk_events_timestamp      ON dddk_events(timestamp);\nCREATE INDEX IF NOT EXISTS idx_dddk_events_category_kind  ON dddk_events(category, kind);\nCREATE INDEX IF NOT EXISTS idx_dddk_events_session        ON dddk_events(session_id);\n`;\n\n/** Postgres DDL. `BIGINT` timestamp; `JSONB` if you'd rather move props\n *  out of TEXT — the row mapper still emits stringified JSON either way. */\nexport const DDDK_EVENTS_DDL_POSTGRES = `\\\nCREATE TABLE IF NOT EXISTS dddk_events (\n  id              TEXT PRIMARY KEY,\n  schema_version  TEXT NOT NULL,\n  category        TEXT NOT NULL,\n  kind            TEXT NOT NULL,\n  timestamp       BIGINT NOT NULL,\n  org_id          TEXT,\n  visitor_id      TEXT,\n  session_id      TEXT,\n  run_id          TEXT,\n  page_path       TEXT,\n  page_locale     TEXT,\n  page_title      TEXT,\n  device_ua       TEXT,\n  device_type     TEXT,\n  device_locale   TEXT,\n  props_json      TEXT NOT NULL DEFAULT '{}'\n);\nCREATE INDEX IF NOT EXISTS idx_dddk_events_timestamp      ON dddk_events(timestamp);\nCREATE INDEX IF NOT EXISTS idx_dddk_events_category_kind  ON dddk_events(category, kind);\nCREATE INDEX IF NOT EXISTS idx_dddk_events_session        ON dddk_events(session_id);\n`;\n\n/** MySQL DDL. `BIGINT` timestamp; utf8mb4 collation to accept any prop. */\nexport const DDDK_EVENTS_DDL_MYSQL = `\\\nCREATE TABLE IF NOT EXISTS dddk_events (\n  id              VARCHAR(64) PRIMARY KEY,\n  schema_version  VARCHAR(32) NOT NULL,\n  category        VARCHAR(32) NOT NULL,\n  kind            VARCHAR(64) NOT NULL,\n  timestamp       BIGINT NOT NULL,\n  org_id          VARCHAR(128),\n  visitor_id      VARCHAR(128),\n  session_id      VARCHAR(128),\n  run_id          VARCHAR(128),\n  page_path       VARCHAR(512),\n  page_locale     VARCHAR(32),\n  page_title      VARCHAR(512),\n  device_ua       VARCHAR(512),\n  device_type     VARCHAR(32),\n  device_locale   VARCHAR(32),\n  props_json      LONGTEXT NOT NULL,\n  INDEX idx_dddk_events_timestamp     (timestamp),\n  INDEX idx_dddk_events_category_kind (category, kind),\n  INDEX idx_dddk_events_session       (session_id)\n) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;\n`;\n\n/**\n * Pick the DDL for a given dialect. Hosts on other engines should\n * read the column list + types above and write their own.\n */\nexport type SqlDialect = 'sqlite' | 'postgres' | 'mysql';\nexport function dddkEventsDDL(dialect: SqlDialect): string {\n  switch (dialect) {\n    case 'sqlite':   return DDDK_EVENTS_DDL_SQLITE;\n    case 'postgres': return DDDK_EVENTS_DDL_POSTGRES;\n    case 'mysql':    return DDDK_EVENTS_DDL_MYSQL;\n  }\n}\n\n// ─── Row ↔ Event conversion ───────────────────────────────────────\n\n/** Flatten an event into the canonical SQL row shape. Lossless. */\nexport function eventToRow(event: BaseEvent): DddkEventRow {\n  return {\n    id: event.id,\n    schema_version: event.schemaVersion,\n    category: event.category,\n    kind: event.kind,\n    timestamp: event.timestamp,\n    org_id: event.orgId ?? null,\n    visitor_id: event.visitorId ?? null,\n    session_id: event.sessionId ?? null,\n    run_id: event.runId ?? null,\n    page_path: event.page?.path ?? null,\n    page_locale: event.page?.locale ?? null,\n    page_title: event.page?.title ?? null,\n    device_ua: event.device?.ua ?? null,\n    device_type: event.device?.deviceType ?? null,\n    device_locale: event.device?.locale ?? null,\n    props_json: event.props ? JSON.stringify(event.props) : '{}',\n  };\n}\n\n/** Reverse — useful when reading rows back from SQL to feed analytics\n *  code that expects `BaseEvent`. Throws on malformed `props_json`. */\nexport function rowToEvent(row: DddkEventRow): BaseEvent {\n  let props: Record<string, unknown> | undefined;\n  if (row.props_json && row.props_json !== '{}') {\n    try {\n      const parsed = JSON.parse(row.props_json);\n      if (parsed && typeof parsed === 'object') props = parsed as Record<string, unknown>;\n    } catch (err) {\n      throw new Error(`rowToEvent: props_json is not valid JSON for event ${row.id}: ${String(err)}`);\n    }\n  }\n  const page = row.page_path != null || row.page_locale != null || row.page_title != null\n    ? {\n        path: row.page_path ?? '',\n        locale: row.page_locale ?? undefined,\n        title: row.page_title ?? undefined,\n      }\n    : undefined;\n  const device = row.device_ua != null || row.device_type != null || row.device_locale != null\n    ? {\n        ua: row.device_ua ?? undefined,\n        deviceType: (row.device_type as BaseEvent['device'] extends infer D ? D extends { deviceType?: infer T } ? T : never : never) ?? undefined,\n        locale: row.device_locale ?? undefined,\n      }\n    : undefined;\n  return {\n    id: row.id,\n    schemaVersion: row.schema_version,\n    category: row.category as BaseEvent['category'],\n    kind: row.kind,\n    timestamp: row.timestamp,\n    orgId: row.org_id ?? undefined,\n    visitorId: row.visitor_id ?? undefined,\n    sessionId: row.session_id ?? undefined,\n    runId: row.run_id ?? undefined,\n    page,\n    device,\n    props,\n  };\n}\n","/**\n * Schema mapper — transform a `BaseEvent` into whatever row shape the\n * host's destination wants.\n *\n * The default mapper produces the canonical `DddkEventRow` (see\n * `sql-schema.ts`). Hosts on a different DB schema swap in their\n * own `(event) => row` and the rest of the pipeline (`EventStore`,\n * `toCSV`, `toNDJSON`, `toSQL`) honors it.\n *\n * Function-based (not declarative JSON) on purpose: declarative\n * mappings always run out of expressiveness around things like\n * \"derive `customer_tier` from `props.tier` when present, else fall\n * back to `props.tier_hint`\". Hosts write a function; we don't\n * invent a mapping DSL.\n *\n * Returning `null` from a mapper FILTERS the event out — useful when\n * a host wants to drop a category entirely (e.g. only ship intent\n * events to BI, drop interaction events that are too noisy).\n */\n\nimport type { BaseEvent } from '../ingest/schema';\nimport type { DddkEventRow } from './sql-schema';\nimport { eventToRow } from './sql-schema';\n\n/**\n * Map a `BaseEvent` to an arbitrary row shape. Return `null` to drop\n * the event.\n */\nexport type SqlSchemaMapper<Row = Record<string, unknown>> = (event: BaseEvent) => Row | null;\n\n/**\n * The bundled default — produces canonical `DddkEventRow`s. Use this\n * when your destination has run the `dddk_events` DDL unchanged.\n */\nexport const defaultMapper: SqlSchemaMapper<DddkEventRow> = (event) => eventToRow(event);\n\n/**\n * Build a mapper from a column → extractor map. Hosts who just want\n * to rename a few columns or compute a derived one don't need to\n * write a full function — they describe the row column by column.\n *\n * ```ts\n * const m = fieldMapper({\n *   event_id:       (e) => e.id,\n *   event_name:     (e) => `${e.category}.${e.kind}`,\n *   ts_ms:          (e) => e.timestamp,\n *   props:          (e) => JSON.stringify(e.props ?? {}),\n *   customer_tier:  (e) => (e.props?.tier as string | undefined) ?? null,\n * });\n * ```\n *\n * Returning `null` from any extractor is fine — it lands as `null` in\n * the row. To DROP the whole event, wrap the mapper in a function\n * that returns `null` from the outer call.\n */\nexport function fieldMapper<Row extends Record<string, unknown>>(\n  map: { [K in keyof Row]: (event: BaseEvent) => Row[K] },\n): SqlSchemaMapper<Row> {\n  const entries = Object.entries(map) as Array<[keyof Row, (e: BaseEvent) => Row[keyof Row]]>;\n  return (event) => {\n    const row = {} as Row;\n    for (const [col, fn] of entries) {\n      row[col] = fn(event);\n    }\n    return row;\n  };\n}\n\n/**\n * Compose: filter THEN map. Returns a mapper that drops events for\n * which `predicate(event)` is false; events that pass get the inner\n * mapper applied.\n *\n * ```ts\n * const onlyIntent = filterEvents((e) => e.category === 'intent');\n * const m = onlyIntent(defaultMapper);\n * ```\n */\nexport function filterEvents(\n  predicate: (event: BaseEvent) => boolean,\n): <Row>(inner: SqlSchemaMapper<Row>) => SqlSchemaMapper<Row> {\n  return <Row>(inner: SqlSchemaMapper<Row>) => (event) =>\n    predicate(event) ? inner(event) : null;\n}\n","/**\n * Exporters — turn events into a string the host can save, share, or\n * paste straight into a SQL client.\n *\n * Three formats out of the box: CSV, NDJSON, SQL. Each runs the event\n * through an optional `SqlSchemaMapper` first so hosts can reshape\n * rows to match their own destination schema. Default mapper produces\n * canonical `DddkEventRow` (see `sql-schema.ts`).\n *\n * Returns strings — not files. Hosts decide where they go: download\n * via `URL.createObjectURL`, copy to clipboard, paste into their own\n * upload pipeline, whatever. Keeping the exporters string-pure means\n * they work everywhere (browser / Node / Workers) and never touch\n * the filesystem.\n */\n\nimport type { BaseEvent } from '../ingest/schema';\nimport { defaultMapper, type SqlSchemaMapper } from './mapper';\nimport { DDDK_EVENTS_COLUMNS, type SqlDialect, dddkEventsDDL } from './sql-schema';\n\n// ─── CSV ──────────────────────────────────────────────────────\n\nexport interface ToCSVOptions {\n  /** Mapper. Default: canonical row. */\n  mapper?: SqlSchemaMapper;\n  /** Restrict to these columns in the given order. Default: use the\n   *  union of all keys appearing in the mapped rows, sorted to a\n   *  stable order. */\n  columns?: string[];\n  /** Field delimiter. Default `,`. Use `\\t` for TSV. */\n  delimiter?: string;\n  /** Line ending. Default `\\n`. */\n  lineEnding?: string;\n  /** Emit the header row. Default `true`. */\n  header?: boolean;\n}\n\n/**\n * RFC-4180-ish CSV. Quotes any field that contains the delimiter, a\n * quote, a newline, or starts/ends with whitespace. Empty / null\n * fields render as empty (NOT the literal string \"null\").\n */\nexport function toCSV(events: BaseEvent[], opts: ToCSVOptions = {}): string {\n  const mapper = opts.mapper ?? defaultMapper;\n  const delimiter = opts.delimiter ?? ',';\n  const lineEnding = opts.lineEnding ?? '\\n';\n  const wantHeader = opts.header ?? true;\n\n  const rows: Record<string, unknown>[] = [];\n  for (const ev of events) {\n    const row = mapper(ev);\n    if (row !== null) rows.push(row as Record<string, unknown>);\n  }\n\n  const columns = opts.columns ?? collectColumns(rows);\n  const out: string[] = [];\n  if (wantHeader) {\n    out.push(columns.map((c) => escapeCsvField(c, delimiter)).join(delimiter));\n  }\n  for (const row of rows) {\n    out.push(columns.map((c) => escapeCsvField(row[c], delimiter)).join(delimiter));\n  }\n  return out.join(lineEnding) + (out.length > 0 ? lineEnding : '');\n}\n\nfunction escapeCsvField(v: unknown, delimiter: string): string {\n  if (v === null || v === undefined) return '';\n  let s: string;\n  if (typeof v === 'string') s = v;\n  else if (typeof v === 'number' || typeof v === 'boolean') s = String(v);\n  else s = JSON.stringify(v);\n  // Wrap in quotes if the field contains the delimiter, a quote, a\n  // newline, or leading/trailing whitespace.\n  const needsQuote = s.includes(delimiter) || s.includes('\"') || s.includes('\\n') || s.includes('\\r')\n    || /^\\s|\\s$/.test(s);\n  if (!needsQuote) return s;\n  return `\"${s.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction collectColumns(rows: Record<string, unknown>[]): string[] {\n  if (rows.length === 0) return Array.from(DDDK_EVENTS_COLUMNS);\n  const seen = new Set<string>();\n  for (const row of rows) for (const k of Object.keys(row)) seen.add(k);\n  return Array.from(seen).sort();\n}\n\n// ─── NDJSON ───────────────────────────────────────────────────\n\nexport interface ToNDJSONOptions {\n  /** Mapper. Default: canonical row. */\n  mapper?: SqlSchemaMapper;\n  /** Line ending. Default `\\n` — keep it for tools that strictly\n   *  parse NDJSON. */\n  lineEnding?: string;\n}\n\n/**\n * Newline-delimited JSON. One JSON object per line. Pipes cleanly\n * into `jq`, BigQuery `bq load`, ClickHouse `INSERT FROM INFILE`,\n * etc.\n */\nexport function toNDJSON(events: BaseEvent[], opts: ToNDJSONOptions = {}): string {\n  const mapper = opts.mapper ?? defaultMapper;\n  const lineEnding = opts.lineEnding ?? '\\n';\n  const lines: string[] = [];\n  for (const ev of events) {\n    const row = mapper(ev);\n    if (row !== null) lines.push(JSON.stringify(row));\n  }\n  return lines.length > 0 ? lines.join(lineEnding) + lineEnding : '';\n}\n\n// ─── SQL ──────────────────────────────────────────────────────\n\nexport interface ToSQLOptions {\n  /** Mapper. Default: canonical row. */\n  mapper?: SqlSchemaMapper;\n  /** Destination table. Default `'dddk_events'`. */\n  table?: string;\n  /** Dialect — drives identifier quoting + the prepended DDL.\n   *  Default `'sqlite'`. */\n  dialect?: SqlDialect;\n  /** Restrict to these columns. Default: union of mapped row keys. */\n  columns?: string[];\n  /** Prepend `CREATE TABLE IF NOT EXISTS …`. Default `false` —\n   *  most hosts run the migration once, not per-export. */\n  includeDDL?: boolean;\n  /** Batch inserts into multi-row VALUES groups of this size.\n   *  Default `100`. Drop to `1` for one INSERT per event when\n   *  debugging. Many SQL engines cap parsed statement size; 100\n   *  keeps each statement well under typical limits. */\n  batchSize?: number;\n}\n\n/**\n * Produce a runnable SQL script. Identifier + value quoting follows\n * each dialect's convention. Hosts should pipe the output straight\n * into their SQL client OR wrap in a transaction at the call site.\n */\nexport function toSQL(events: BaseEvent[], opts: ToSQLOptions = {}): string {\n  const mapper = opts.mapper ?? defaultMapper;\n  const table = opts.table ?? 'dddk_events';\n  const dialect = opts.dialect ?? 'sqlite';\n  const batchSize = Math.max(1, opts.batchSize ?? 100);\n\n  const rows: Record<string, unknown>[] = [];\n  for (const ev of events) {\n    const row = mapper(ev);\n    if (row !== null) rows.push(row as Record<string, unknown>);\n  }\n  const columns = opts.columns ?? collectColumns(rows);\n\n  const parts: string[] = [];\n  if (opts.includeDDL) {\n    parts.push(dddkEventsDDL(dialect).trim());\n    parts.push('');\n  }\n  if (rows.length === 0) return parts.join('\\n');\n\n  const qIdent = (s: string) => quoteIdent(s, dialect);\n  const colList = columns.map(qIdent).join(', ');\n\n  for (let i = 0; i < rows.length; i += batchSize) {\n    const chunk = rows.slice(i, i + batchSize);\n    const values = chunk\n      .map((row) => '(' + columns.map((c) => quoteValue(row[c], dialect)).join(', ') + ')')\n      .join(',\\n  ');\n    parts.push(`INSERT INTO ${qIdent(table)} (${colList}) VALUES\\n  ${values};`);\n  }\n  return parts.join('\\n');\n}\n\nfunction quoteIdent(name: string, dialect: SqlDialect): string {\n  // Reject anything that isn't a normal-looking identifier; this is a\n  // belt-and-braces guard, callers shouldn't be feeding hostile names\n  // here, but exporters are easy to misuse.\n  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {\n    throw new Error(`toSQL: invalid identifier ${JSON.stringify(name)} — only [A-Za-z_][A-Za-z0-9_]* allowed`);\n  }\n  if (dialect === 'mysql') return '`' + name + '`';\n  return '\"' + name + '\"';\n}\n\nfunction quoteValue(v: unknown, dialect: SqlDialect): string {\n  if (v === null || v === undefined) return 'NULL';\n  if (typeof v === 'number') {\n    if (!Number.isFinite(v)) return 'NULL';\n    return String(v);\n  }\n  if (typeof v === 'boolean') return v ? '1' : '0';\n  if (typeof v === 'string') return escapeSqlString(v, dialect);\n  // Objects, arrays — JSON-encode then quote as string.\n  return escapeSqlString(JSON.stringify(v), dialect);\n}\n\nfunction escapeSqlString(s: string, dialect: SqlDialect): string {\n  // Standard SQL single-quote escaping (double the quote) works on\n  // SQLite + Postgres + MySQL. We deliberately don't lean on the\n  // backslash-escape convention because Postgres standard_conforming_strings\n  // makes it dialect-state-dependent.\n  const escaped = s.replace(/'/g, \"''\");\n  // MySQL also recognises backslash escapes — escape them too so the\n  // value can't break out of the literal via `\\\\`.\n  if (dialect === 'mysql') return \"'\" + escaped.replace(/\\\\/g, '\\\\\\\\') + \"'\";\n  return \"'\" + escaped + \"'\";\n}\n"],"mappings":"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","names":["escapeHtml","escapeHtml","import_jsx_runtime","init_shared","import_jsx_runtime","init_layout","init_shared","import_jsx_runtime","init_content","init_shared","Tag","import_jsx_runtime","init_data","init_shared","import_jsx_runtime","init_inputs","init_shared","import_jsx_runtime","init_actions","init_shared","import_jsx_runtime","init_feedback","init_shared","import_jsx_runtime","init_shared","import_jsx_runtime","init_slot","init_shared","init_layout","init_content","init_data","init_inputs","init_actions","init_feedback","init_slot","init_builtin","init_builtin","resolve","truncate","walk","selection","images","createBuiltinCatalog","PieceDomRenderer","STYLE_ID","STYLE_ID","STYLE_ID","stylesEnsured","ensureStyles","s","resolve","field","field","window","recencyDecay","field","promoBoost","builtin","resolve","field","builtin","field","STYLE_ID","ensureStyles","text","window","ensureStyles","head","ensureStyles","resolve","ensureStyles","ensureStyles","cb","STYLE_ID","ensureStyles","position","objSchema","resolve","out","obj","resolve","sleep","resolve","narrateAction","sleep","narrateAction","result","moveCursorAndTap","readDOM","resolve","borderAction","StreamingEnvelopeParser","envelopeData","turnSummary","truncate","STYLE_ID","history","STYLE_ID","resolve","history","position","DEFAULT_LLM_TIMEOUT_MS","STYLE_ID","ensureStyles","resolve","KEY","pickStorage","tokenize","field","resolve","resolve","resolve","aria","STYLE_ID","ensureStyles","resolve","px","resolve","parts","safeParseJson","adapterId","STYLE_ID","DEFAULT_IGNORE","ensureStyles","resolve","resolve","resolve","STYLE_ID","ensureStyles","sleep","resolve","STORE","resolve","promisify"]}