@jaychang1989/dsh-webchat 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +18 -0
  3. package/README.md +78 -0
  4. package/README.zh.md +83 -0
  5. package/cordis.patch.yml +22 -0
  6. package/lib/client.js +1725 -0
  7. package/lib/client.js.map +1 -0
  8. package/lib/index.js +3887 -0
  9. package/lib/types/client/api.d.ts +74 -0
  10. package/lib/types/client/controller.d.ts +19 -0
  11. package/lib/types/client/index.d.ts +30 -0
  12. package/lib/types/client/locales.d.ts +169 -0
  13. package/lib/types/client/mount.d.ts +23 -0
  14. package/lib/types/client/panel/Markdown.d.ts +15 -0
  15. package/lib/types/client/panel/WebChatPanel.d.ts +28 -0
  16. package/lib/types/client/sidebar-entry-core.d.ts +60 -0
  17. package/lib/types/client/sidebar-entry.d.ts +22 -0
  18. package/lib/types/engine/engine.d.ts +247 -0
  19. package/lib/types/engine/html-md.d.ts +23 -0
  20. package/lib/types/index.d.ts +63 -0
  21. package/lib/types/protocol.d.ts +107 -0
  22. package/lib/types/routes.d.ts +22 -0
  23. package/lib/types/store.d.ts +69 -0
  24. package/lib/types/tools.d.ts +27 -0
  25. package/lib/types/transfer.d.ts +138 -0
  26. package/package.json +96 -0
  27. package/src/client/api.ts +90 -0
  28. package/src/client/controller.ts +43 -0
  29. package/src/client/css-modules.d.ts +5 -0
  30. package/src/client/index.ts +75 -0
  31. package/src/client/locales.ts +172 -0
  32. package/src/client/mount.tsx +125 -0
  33. package/src/client/panel/Markdown.tsx +251 -0
  34. package/src/client/panel/WebChatPanel.tsx +760 -0
  35. package/src/client/panel/panel.module.css +936 -0
  36. package/src/client/sidebar-entry-core.ts +207 -0
  37. package/src/client/sidebar-entry.ts +49 -0
  38. package/src/engine/engine.ts +1385 -0
  39. package/src/engine/html-md.ts +126 -0
  40. package/src/index.ts +212 -0
  41. package/src/protocol.ts +116 -0
  42. package/src/routes.ts +307 -0
  43. package/src/store.ts +217 -0
  44. package/src/tools.ts +257 -0
  45. package/src/transfer.ts +602 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","names":["css","css","css","mountSidebarEntry","mountSharedSidebarEntry"],"sources":["../src/protocol.ts","../src/client/api.ts","../src/client/controller.ts","../src/client/locales.ts","../src/client/panel/Markdown.tsx","../src/client/panel/WebChatPanel.tsx","../src/client/mount.tsx","../src/client/sidebar-entry-core.ts","../src/client/sidebar-entry.ts","../src/client/index.ts"],"sourcesContent":["/**\n * Shared wire surface of the dsh-webchat plugin: API paths, transcript data\n * model, and engine status views. Imported by both the host routes and the\n * browser panel (the client bundle inlines it — no shared runtime identity).\n */\n\n/** One transcript message (markdown text). */\nexport interface WebChatMessage {\n /** Local stable id. */\n readonly id: string\n readonly role: 'user' | 'assistant'\n /** Markdown body. */\n readonly content: string\n /** Unix epoch ms. */\n readonly ts: number\n /** True while the engine is still streaming this message. */\n readonly streaming?: boolean\n /** Set when the exchange failed (content may be partial). */\n readonly error?: string\n /** Local absolute paths of images attached to a user message. */\n readonly attachments?: string[]\n}\n\n/** One web chat session transcript (persisted locally). */\nexport interface WebChatTranscript {\n readonly id: string\n title: string\n readonly createdAt: number\n updatedAt: number\n /** Model the chat currently runs on the web (deepseek-chat / deepseek-reasoner). */\n model: string\n readonly messages: WebChatMessage[]\n /** True while an assistant reply is streaming. */\n streaming: boolean\n}\n\n/**\n * Structured engine error codes so callers (panel / agent tools) can act on a\n * failure instead of only printing it: NEED_LOGIN → prompt the login window;\n * PAGE_CHANGED → the DeepSeek page/stream protocol moved and the plugin likely\n * needs an upgrade; TIMEOUT → generation exceeded the reply window; NETWORK →\n * browser launch / HTTP / connectivity failure.\n */\nexport type WebChatErrorCode = 'NEED_LOGIN' | 'PAGE_CHANGED' | 'TIMEOUT' | 'NETWORK'\n\n/** Coarse engine state for the panel. */\nexport type EngineState = 'stopped' | 'launching' | 'ready' | 'error'\n\n/** Snapshot the panel polls. */\nexport interface WebChatState {\n readonly engine: EngineState\n readonly engineError?: string\n /** null = unknown yet; false = browser up but not logged in; true = chat page ready. */\n readonly loggedIn: boolean | null\n readonly pageUrl?: string\n /** Deep-think (R1) toggle state read from the page. */\n readonly deepThink: boolean\n /** Internet-search toggle state read from the page. */\n readonly search: boolean\n readonly activeChatId?: string\n readonly chats: WebChatTranscript[]\n /** True while a message is being sent / replied (serialized engine busy). */\n readonly busy: boolean\n /** Last send error, transient for the panel to display. */\n readonly lastError?: string\n /** Structured code for the last error (so the panel can show a targeted action). */\n readonly lastErrorCode?: WebChatErrorCode\n}\n\n/** Engine-level operation results surfaced to agent tools. */\nexport interface SendResult {\n readonly ok: boolean\n readonly chatId?: string\n readonly reply?: string\n readonly error?: string\n /** Structured error code (when ok is false) for actionable handling. */\n readonly code?: WebChatErrorCode\n}\n\n/** Result of transferring a transcript into harness mode. */\nexport interface TransferResult {\n readonly ok: boolean\n readonly sessionId?: string\n readonly filePath?: string\n /** True when the session was attached to a workspace (grouped); false = ungrouped. */\n readonly attached?: boolean\n /** Workspace id the session landed in, when attached. */\n readonly workspaceId?: string\n readonly error?: string\n}\n\n/**\n * How a transfer seeds the new harness session: 'distill' condenses the web\n * conversation into an executable task brief via the harness LLM; 'raw'\n * replays the full transcript verbatim. The web panel lets the user choose.\n */\nexport type TransferMode = 'distill' | 'raw'\n\n/** API path constants shared by host routes and the browser panel. */\nexport const WEBChat_API = {\n state: '/api/dsh-webchat/state',\n openLogin: '/api/dsh-webchat/open-login',\n closeBrowser: '/api/dsh-webchat/close-browser',\n newChat: '/api/dsh-webchat/new-chat',\n send: '/api/dsh-webchat/send',\n stop: '/api/dsh-webchat/stop',\n deepThink: '/api/dsh-webchat/deep-think',\n search: '/api/dsh-webchat/search',\n transfer: '/api/dsh-webchat/transfer',\n exportFile: '/api/dsh-webchat/export',\n renameChat: '/api/dsh-webchat/rename',\n deleteChat: '/api/dsh-webchat/delete',\n clearChats: '/api/dsh-webchat/clear',\n webChats: '/api/dsh-webchat/web-chats',\n recover: '/api/dsh-webchat/recover',\n} as const\n","/**\n * Browser-side API client for the /api/dsh-webchat route family. The only\n * data access path the panel components use — plain fetch, same origin.\n */\n\nimport { WEBChat_API, type TransferMode, type WebChatState } from '../protocol.ts'\n\n/** Shape every /api/dsh-webchat response carries: ok plus optional error. */\ninterface ApiResult {\n ok: boolean\n error?: string\n}\n\n/** Endpoint payloads always extend ApiResult. */\ntype EndpointResult<T> = T & ApiResult\n\nasync function request<T>(path: string, body?: unknown): Promise<EndpointResult<T>> {\n const response = await fetch(path, {\n method: body === undefined ? 'GET' : 'POST',\n headers: body === undefined ? undefined : { 'content-type': 'application/json' },\n body: body === undefined ? undefined : JSON.stringify(body),\n })\n const payload = (await response.json().catch(() => ({}))) as EndpointResult<T>\n if (!response.ok && payload.ok !== true) {\n return { ...payload, ok: false, error: payload.error ?? `HTTP ${response.status}` }\n }\n return payload\n}\n\nexport class WebChatApi {\n state(): Promise<EndpointResult<WebChatState>> {\n return request<WebChatState>(WEBChat_API.state)\n }\n\n openLogin(): Promise<EndpointResult<{ ok: boolean }>> {\n return request<{ ok: boolean }>(WEBChat_API.openLogin)\n }\n\n closeBrowser(): Promise<EndpointResult<{ ok: boolean }>> {\n return request<{ ok: boolean }>(WEBChat_API.closeBrowser)\n }\n\n newChat(): Promise<EndpointResult<{ ok: boolean; chatId?: string }>> {\n return request<{ ok: boolean; chatId?: string }>(WEBChat_API.newChat)\n }\n\n send(text: string, images?: string[]): Promise<EndpointResult<{ ok: boolean; chatId?: string }>> {\n return request<{ ok: boolean; chatId?: string }>(WEBChat_API.send, { text, images })\n }\n\n stop(): Promise<EndpointResult<{ ok: boolean }>> {\n return request<{ ok: boolean }>(WEBChat_API.stop)\n }\n\n setDeepThink(enabled: boolean): Promise<EndpointResult<{ ok: boolean }>> {\n return request<{ ok: boolean }>(WEBChat_API.deepThink, { enabled })\n }\n\n setSearch(enabled: boolean): Promise<EndpointResult<{ ok: boolean }>> {\n return request<{ ok: boolean }>(WEBChat_API.search, { enabled })\n }\n\n transfer(chatId: string, cwd?: string, mode?: TransferMode, workspaceId?: string, targetSessionId?: string): Promise<EndpointResult<{ ok: boolean; sessionId?: string; distilled?: boolean; attached?: boolean; continued?: boolean; workspaceId?: string }>> {\n return request<{ ok: boolean; sessionId?: string; distilled?: boolean; attached?: boolean; continued?: boolean; workspaceId?: string }>(WEBChat_API.transfer, { chatId, cwd, mode, workspaceId, targetSessionId })\n }\n\n exportFile(chatId: string, cwd?: string): Promise<EndpointResult<{ ok: boolean; filePath?: string }>> {\n return request<{ ok: boolean; filePath?: string }>(WEBChat_API.exportFile, { chatId, cwd })\n }\n\n renameChat(chatId: string, title: string): Promise<EndpointResult<{ ok: boolean }>> {\n return request<{ ok: boolean }>(WEBChat_API.renameChat, { chatId, title })\n }\n\n deleteChat(chatId: string): Promise<EndpointResult<{ ok: boolean }>> {\n return request<{ ok: boolean }>(WEBChat_API.deleteChat, { chatId })\n }\n\n clearChats(): Promise<EndpointResult<{ ok: boolean; count?: number }>> {\n return request<{ ok: boolean; count?: number }>(WEBChat_API.clearChats)\n }\n\n webChats(): Promise<EndpointResult<{ ok: boolean; web: Array<{ title: string }>; missing: string[] }>> {\n return request<{ ok: boolean; web: Array<{ title: string }>; missing: string[] }>(WEBChat_API.webChats)\n }\n\n recover(title: string): Promise<EndpointResult<{ ok: boolean; chatId?: string; title?: string; created?: boolean }>> {\n return request<{ ok: boolean; chatId?: string; title?: string; created?: boolean }>(WEBChat_API.recover, { title })\n }\n}\n","/**\n * Panel controller: minimal external state the sidebar entry and the panel\n * share (open/closed), plus a tiny pub/sub. The chat data itself lives in the\n * panel component's polling loop.\n */\n\nexport interface PanelSnapshot {\n readonly panelOpen: boolean\n}\n\nconst INITIAL: PanelSnapshot = { panelOpen: false }\n\n/** Plain pub/sub store (no React dependency — used by the DOM sidebar entry). */\nexport class PanelController {\n private snapshot: PanelSnapshot = INITIAL\n private readonly listeners = new Set<() => void>()\n\n getSnapshot(): PanelSnapshot {\n return this.snapshot\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener)\n return () => { this.listeners.delete(listener) }\n }\n\n private set(patch: Partial<PanelSnapshot>): void {\n this.snapshot = { ...this.snapshot, ...patch }\n for (const listener of [...this.listeners]) listener()\n }\n\n open(): void {\n if (!this.snapshot.panelOpen) this.set({ panelOpen: true })\n }\n\n close(): void {\n if (this.snapshot.panelOpen) this.set({ panelOpen: false })\n }\n\n toggle(): void {\n this.set({ panelOpen: !this.snapshot.panelOpen })\n }\n}\n","/**\n * dsh-webchat surface copy: zh is the key source, en mirrors every key. The\n * key union (not an object shape) is what the locale machinery wants —\n * LocaleKeysOf<N> intersects the namespace with `string`, so the namespace\n * value must itself be the key union (same pattern as dsh-ssh).\n */\n\nexport const zh = {\n 'entry.label': '网页聊天',\n 'entry.tooltip': 'DeepSeek 网页端聊天(deepseek-chat,Codex ChatGPT 模式)',\n 'panel.title': 'DeepSeek 网页端聊天',\n 'status.engine.stopped': '浏览器未启动',\n 'status.engine.launching': '浏览器启动中…',\n 'status.engine.ready': '浏览器就绪',\n 'status.engine.error': '浏览器错误',\n 'status.loggedIn': '已登录',\n 'status.notLoggedIn': '未登录',\n 'status.unknown': '状态未知',\n 'action.openLogin': '打开登录窗口',\n 'action.closeBrowser': '关闭浏览器',\n 'action.newChat': '新对话',\n 'action.recover': '从网页恢复',\n 'action.refresh': '刷新',\n 'action.send': '发送',\n 'action.stop': '停止生成',\n 'action.transferToHarness': '转移到 Harness',\n 'action.exportFile': '导出为文件',\n 'transfer.mode.distill': '蒸馏为任务简报',\n 'transfer.mode.raw': '原始记录',\n 'transfer.mode.hint': '蒸馏:用 harness LLM 把对话提炼成可执行任务简报;原始记录:原样放入新会话首条消息',\n 'transfer.workspace.label': '目标工作区',\n 'transfer.workspace.ungrouped': '未分组',\n 'transfer.workspace.new': '新建工作区…',\n 'transfer.workspace.hint': '转移到所选工作区;未分组则不归入任何工作区',\n 'transfer.workspace.created': '已创建并选中工作区 {title}',\n 'transfer.workspace.createFailed': '创建工作区失败:{error}',\n 'transfer.session.label': '延续到会话',\n 'transfer.session.hint': '选择已有 harness 会话以延续(把简报作为新消息追加);默认新建会话',\n 'transfer.session.new': '新建会话',\n 'transfer.attached.failed': '会话已创建({sessionId}),但归入工作区失败,现为未分组',\n 'handoff.eyebrow': '交付到 Harness',\n 'toggle.deepThink': '深度思考',\n 'toggle.search': '智能搜索',\n 'toggle.deepThink.hint': '开启 R1 深度思考',\n 'toggle.search.hint': '开启联网检索',\n 'sidebar.empty': '暂无对话',\n 'chats.count': '{count} 条',\n 'role.you': '你',\n 'chat.rename': '重命名',\n 'chat.delete': '删除',\n 'chat.delete.confirm': '确认删除?',\n 'chat.clearAll': '清空全部',\n 'chat.clearAll.confirm': '确认清空全部?',\n 'chat.rename.placeholder': '输入新标题…',\n 'chat.rename.ok': '确定',\n 'chat.rename.cancel': '取消',\n 'chat.manage.hint': '管理本地保存的聊天记录(不影响网页端)',\n 'toast.rename.done': '已重命名',\n 'toast.rename.failed': '重命名失败:{error}',\n 'toast.delete.done': '已删除该对话',\n 'toast.delete.failed': '删除失败:{error}',\n 'toast.clear.done': '已清空全部对话',\n 'toast.clear.failed': '清空失败:{error}',\n 'model.deepseek-chat': 'DeepSeek',\n 'model.deepseek-reasoner': 'DeepSeek',\n 'composer.placeholder': '给 DeepSeek 发送消息…(将发送到网页端)',\n 'composer.hint': 'Enter 发送 · Shift+Enter 换行',\n 'composer.busy': '正在生成回复…',\n 'composer.notLoggedIn': '请先登录 DeepSeek 网页端',\n 'composer.attach': '图片',\n 'composer.attach.hint': '添加本地图片(绝对路径,逗号/换行分隔)',\n 'composer.attach.placeholder': '图片绝对路径,逗号或换行分隔',\n 'empty.eyebrow': 'DeepSeek 网页端 · 桥接开发',\n 'empty.title': '先聊,再交付',\n 'empty.body': '登录网页端即可开始对话;任何对话都能蒸馏成任务简报,转入 Harness 会话继续开发。',\n 'transfer.done': '已创建 Harness 会话 {sessionId},正在为你打开…',\n 'transfer.continued': '已延续 Harness 会话 {sessionId},正在为你打开…',\n 'transfer.failed': '转移到 Harness 失败:{error}',\n 'export.done': '已导出到工作区文件:{filePath}',\n 'export.failed': '导出失败:{error}',\n 'recover.hint': '列出网页端尚未导入本地的会话',\n 'recover.empty': '网页端没有未导入的会话',\n 'recover.done': '已恢复「{title}」',\n 'msg.empty': '(空)',\n 'msg.error': '(该回复可能不完整:{error})',\n 'streaming': '生成中',\n} as const\n\n/** Bilingual balance enforced: en must cover every zh key. */\nexport const en = {\n 'entry.label': 'Web Chat',\n 'entry.tooltip': 'DeepSeek web chat (deepseek-chat, Codex ChatGPT mode)',\n 'panel.title': 'DeepSeek Web Chat',\n 'status.engine.stopped': 'Browser not started',\n 'status.engine.launching': 'Starting browser…',\n 'status.engine.ready': 'Browser ready',\n 'status.engine.error': 'Browser error',\n 'status.loggedIn': 'Logged in',\n 'status.notLoggedIn': 'Not logged in',\n 'status.unknown': 'Unknown',\n 'action.openLogin': 'Open login window',\n 'action.closeBrowser': 'Close browser',\n 'action.newChat': 'New chat',\n 'action.recover': 'Recover from web',\n 'action.refresh': 'Refresh',\n 'action.send': 'Send',\n 'action.stop': 'Stop',\n 'action.transferToHarness': 'Transfer to Harness',\n 'action.exportFile': 'Export to file',\n 'transfer.mode.distill': 'Distill to task brief',\n 'transfer.mode.raw': 'Raw transcript',\n 'transfer.mode.hint': 'Distill: condense the chat into an executable brief via the harness LLM; Raw: replay the full transcript as the session\\'s first message',\n 'transfer.workspace.label': 'Target workspace',\n 'transfer.workspace.ungrouped': 'Ungrouped',\n 'transfer.workspace.new': 'New workspace…',\n 'transfer.workspace.hint': 'Transfer into the chosen workspace; ungrouped leaves it out of any workspace',\n 'transfer.workspace.created': 'Created and selected workspace {title}',\n 'transfer.workspace.createFailed': 'Create workspace failed: {error}',\n 'transfer.session.label': 'Continue into session',\n 'transfer.session.hint': 'Continue into an existing harness session (append the brief as a new message); default creates a new one',\n 'transfer.session.new': 'New session',\n 'transfer.attached.failed': 'Session created ({sessionId}) but attaching to workspace failed; it is ungrouped',\n 'handoff.eyebrow': 'Handoff to Harness',\n 'toggle.deepThink': 'DeepThink',\n 'toggle.search': 'Search',\n 'toggle.deepThink.hint': 'Enable R1 deep think',\n 'toggle.search.hint': 'Enable web search',\n 'sidebar.empty': 'No chats',\n 'chats.count': '{count} msgs',\n 'role.you': 'You',\n 'chat.rename': 'Rename',\n 'chat.delete': 'Delete',\n 'chat.delete.confirm': 'Delete?',\n 'chat.clearAll': 'Clear all',\n 'chat.clearAll.confirm': 'Clear all?',\n 'chat.rename.placeholder': 'New title…',\n 'chat.rename.ok': 'OK',\n 'chat.rename.cancel': 'Cancel',\n 'chat.manage.hint': 'Manage locally saved transcripts (does not affect the web)',\n 'toast.rename.done': 'Renamed',\n 'toast.rename.failed': 'Rename failed: {error}',\n 'toast.delete.done': 'Chat deleted',\n 'toast.delete.failed': 'Delete failed: {error}',\n 'toast.clear.done': 'All chats cleared',\n 'toast.clear.failed': 'Clear failed: {error}',\n 'model.deepseek-chat': 'DeepSeek',\n 'model.deepseek-reasoner': 'DeepSeek',\n 'composer.placeholder': 'Message DeepSeek… (sent via the web)',\n 'composer.hint': 'Enter to send · Shift+Enter for newline',\n 'composer.busy': 'Generating…',\n 'composer.notLoggedIn': 'Sign in to DeepSeek web first',\n 'composer.attach': 'Images',\n 'composer.attach.hint': 'Attach local images (absolute paths, comma/newline separated)',\n 'composer.attach.placeholder': 'Image absolute paths (comma or newline separated)',\n 'empty.eyebrow': 'DeepSeek Web · Bridge to Code',\n 'empty.title': 'Chat first, hand off later',\n 'empty.body': 'Sign in to the web and start chatting; any chat can be distilled into a task brief and handed off to Harness.',\n 'transfer.done': 'Created Harness session {sessionId}; opening it…',\n 'transfer.continued': 'Continued Harness session {sessionId}; opening it…',\n 'transfer.failed': 'Transfer failed: {error}',\n 'export.done': 'Exported to workspace file: {filePath}',\n 'export.failed': 'Export failed: {error}',\n 'recover.hint': 'List web conversations not yet imported locally',\n 'recover.empty': 'No unimported web conversations',\n 'recover.done': 'Recovered \"{title}\"',\n 'msg.empty': '(empty)',\n 'msg.error': '(reply may be incomplete: {error})',\n 'streaming': 'generating',\n} satisfies Record<keyof typeof zh, string>\n\n/** Key union of the web-chat surface copy. */\nexport type WebChatKey = keyof typeof zh\n","/**\n * Minimal markdown renderer for the web-chat panel. Deliberately small and\n * dependency-free: headings, paragraphs, bold/italic, inline + fenced code,\n * links, DeepSeek `[citation:N]` markers (rendered as superscript badges),\n * unordered/ordered lists, blockquotes, GFM tables, horizontal rules, and\n * <details> passthrough (used for DeepSeek R1 thinking blocks). Anything\n * unrecognized renders as plain text — never raw HTML.\n */\n\nimport { createElement, type ReactNode } from 'react'\nimport css from './panel.module.css'\n\n/** Escape text for safe rendering (no dangerouslySetInnerHTML anywhere). */\nfunction esc(text: string): string {\n return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')\n}\n\n/**\n * Inline markdown → React nodes. Single tokenizer pass over the string:\n * code spans win, then links, then `[citation:…]` markers, then bold, then\n * italic — each non-token run is escaped text. Bold/italic recurse so a\n * strong span can contain a citation or link.\n */\nfunction inline(text: string, keyBase = 'i'): ReactNode[] {\n const nodes: ReactNode[] = []\n // eslint-disable-next-line no-useless-escape\n const re = /(`[^`]+`)|(\\[[^\\]]+\\]\\([^)\\s]+\\))|(\\[citation:[^\\]]+\\])|(\\*\\*[^*]+\\*\\*|__[^_]+__)|(\\*[^*\\n]+\\*|_[^_\\n]+_)/g\n let last = 0\n let index = 0\n let match: RegExpExecArray | null\n while ((match = re.exec(text)) !== null) {\n if (match.index > last) nodes.push(esc(text.slice(last, match.index)))\n const key = `${keyBase}-${index}`\n if (match[1] !== undefined) {\n // `code`\n nodes.push(createElement('code', { key: `${key}-code` }, match[1].slice(1, -1)))\n } else if (match[2] !== undefined) {\n // [label](url)\n const link = /^\\[([^\\]]+)\\]\\(([^)\\s]+)\\)$/.exec(match[2])\n nodes.push(createElement('a', { key: `${key}-a`, href: link![2], target: '_blank', rel: 'noreferrer' }, link![1]))\n } else if (match[3] !== undefined) {\n // [citation:N] / [citation:N1,N2] — DeepSeek web search markers.\n const nums = match[3].slice('[citation:'.length, -1).trim()\n nodes.push(createElement('sup', { key: `${key}-cite`, className: css.citation }, nums))\n } else if (match[4] !== undefined) {\n // **bold** / __bold__\n const inner = match[4].slice(2, -2)\n nodes.push(createElement('strong', { key: `${key}-b` }, ...inline(inner, `${key}-b`)))\n } else if (match[5] !== undefined) {\n // *italic* / _italic_\n const inner = match[5].slice(1, -1)\n nodes.push(createElement('em', { key: `${key}-i` }, ...inline(inner, `${key}-i`)))\n }\n last = re.lastIndex\n index++\n }\n if (last < text.length) nodes.push(esc(text.slice(last)))\n return nodes\n}\n\n/** One fenced code block → <pre><code>. */\nfunction codeBlock(language: string, body: string, key: string): ReactNode {\n return createElement(\n 'pre',\n { key },\n createElement('code', { className: language === '' ? undefined : `language-${language}` }, body),\n )\n}\n\n/** Split a table row into cells, honoring escaped pipes (\\|). */\nfunction splitCells(line: string): string[] {\n const cells: string[] = []\n let current = ''\n let escaped = false\n for (const ch of line) {\n if (escaped) { current += ch; escaped = false }\n else if (ch === '\\\\') { escaped = true }\n else if (ch === '|') { cells.push(current); current = '' }\n else { current += ch }\n }\n cells.push(current)\n // Drop the leading/trailing empty artifacts produced by a leading/trailing\n // pipe, so `| a | b |` and `a | b` both yield ['a','b'].\n let start = 0\n let end = cells.length\n while (start < end && cells[start].trim() === '') start++\n while (end > start && cells[end - 1].trim() === '') end--\n return cells.slice(start, end).map(cell => cell.trim())\n}\n\n/** True when a line is a GFM table delimiter row (`:---`, `---:`, `:---:`, …). */\nfunction isDelimiterRow(line: string): boolean {\n const cells = splitCells(line)\n return cells.length > 0 && cells.every(cell => /^:?-{3,}:?$/.test(cell))\n}\n\n/** Render one block of markdown text into React nodes. */\nexport function renderMarkdown(source: string): ReactNode[] {\n const raw = source.replace(/\\r\\n/g, '\\n').trim()\n if (raw === '') return []\n const blocks: ReactNode[] = []\n const lines = raw.split('\\n')\n let index = 0\n let blockIndex = 0\n\n const push = (node: ReactNode): void => {\n blocks.push(createElement('div', { key: `b${blockIndex++}` }, node))\n }\n\n while (index < lines.length) {\n const line = lines[index]\n const trimmed = line.trim()\n\n // fenced code\n const fence = /^```([\\w+-]*)\\s*$/.exec(trimmed)\n if (fence !== null) {\n const language = fence[1] ?? ''\n const body: string[] = []\n index++\n while (index < lines.length && !/^```\\s*$/.test(lines[index].trim())) {\n body.push(lines[index])\n index++\n }\n index++ // closing fence\n push(codeBlock(language, body.join('\\n'), `code${blockIndex}`))\n continue\n }\n\n // headings\n const heading = /^(#{1,6})\\s+(.*)$/.exec(trimmed)\n if (heading !== null) {\n const level = heading[1].length\n push(createElement(`h${level}` as 'h1', null, ...inline(heading[2], `h${blockIndex}`)))\n index++\n continue\n }\n\n // GFM table (header row containing '|' immediately followed by a delimiter\n // row). Checked before the horizontal-rule branch so a delimiter like\n // `--- | ---` is never mistaken for an hr.\n if (line.includes('|') && lines[index + 1] !== undefined && isDelimiterRow(lines[index + 1])) {\n const header = splitCells(line)\n index += 2\n const rows: string[][] = []\n while (index < lines.length) {\n const row = lines[index]\n if (row.trim() === '' || !row.includes('|')) break\n rows.push(splitCells(row))\n index++\n }\n const width = Math.max(header.length, ...rows.map(row => row.length))\n const rowNode = (cells: string[], rowIndex: number): ReactNode =>\n createElement('tr', { key: rowIndex }, Array.from({ length: width }, (_, col) =>\n createElement('td', { key: col }, ...inline(cells[col] ?? '', `t${blockIndex}-${rowIndex}-${col}`))))\n blocks.push(createElement(\n 'div',\n { key: `tw${blockIndex}`, className: css.tableWrap },\n createElement('table', { key: `t${blockIndex}` },\n createElement('thead', null, createElement('tr', null, header.map((cell, col) =>\n createElement('th', { key: col }, ...inline(cell, `th${blockIndex}-${col}`))))),\n createElement('tbody', null, rows.map(rowNode))),\n ))\n blockIndex++\n continue\n }\n\n // horizontal rule\n if (/^(-{3,}|\\*{3,}|_{3,})$/.test(trimmed)) {\n push(createElement('hr', { key: `hr${blockIndex}` }))\n index++\n continue\n }\n\n // blockquote (collect consecutive quote lines)\n if (trimmed.startsWith('>')) {\n const quote: string[] = []\n while (index < lines.length && lines[index].trim().startsWith('>')) {\n quote.push(lines[index].trim().replace(/^>\\s?/, ''))\n index++\n }\n push(createElement('blockquote', { key: `q${blockIndex}` }, ...renderMarkdown(quote.join('\\n'))))\n continue\n }\n\n // details (DeepSeek R1 thinking)\n if (/^<details>/.test(trimmed)) {\n const body: string[] = []\n const summaryMatch = /^<summary>\\s*(.*?)\\s*<\\/summary>/.exec(trimmed)\n index++\n while (index < lines.length && !/^<\\/details>/.test(lines[index].trim())) {\n body.push(lines[index])\n index++\n }\n index++ // </details>\n push(createElement(\n 'details',\n { key: `d${blockIndex}` },\n createElement('summary', null, summaryMatch?.[1] ?? '详情'),\n ...renderMarkdown(body.join('\\n')),\n ))\n continue\n }\n\n // unordered list\n if (/^[-*+]\\s+/.test(trimmed)) {\n const items: string[] = []\n while (index < lines.length && /^[-*+]\\s+/.test(lines[index].trim())) {\n items.push(lines[index].trim().replace(/^[-*+]\\s+/, ''))\n index++\n }\n push(createElement('ul', { key: `ul${blockIndex}` }, items.map((item, itemIndex) =>\n createElement('li', { key: itemIndex }, ...inline(item, `uli${blockIndex}-${itemIndex}`)))))\n continue\n }\n\n // ordered list\n if (/^\\d+[.)]\\s+/.test(trimmed)) {\n const items: string[] = []\n while (index < lines.length && /^\\d+[.)]\\s+/.test(lines[index].trim())) {\n items.push(lines[index].trim().replace(/^\\d+[.)]\\s+/, ''))\n index++\n }\n push(createElement('ol', { key: `ol${blockIndex}` }, items.map((item, itemIndex) =>\n createElement('li', { key: itemIndex }, ...inline(item, `oli${blockIndex}-${itemIndex}`)))))\n continue\n }\n\n // plain paragraph: collect consecutive non-empty, non-special lines\n const paragraph: string[] = []\n while (index < lines.length) {\n const current = lines[index].trim()\n if (current === '') break\n if (/^(```|#{1,6}\\s|[-*+]\\s|\\d+[.)]\\s|>\\s|<\\/(details|table)>)/.test(current)) break\n if (current.includes('|') && lines[index + 1] !== undefined && isDelimiterRow(lines[index + 1])) break\n paragraph.push(current)\n index++\n }\n if (paragraph.length === 0) {\n index++\n continue\n }\n push(createElement('p', { key: `p${blockIndex}` }, ...inline(paragraph.join(' '), `p${blockIndex}`)))\n }\n\n return blocks\n}\n\n/** The markdown renderer component. */\nexport function Markdown({ source }: { source: string }): ReactNode {\n return createElement('div', { className: css.markdown }, ...renderMarkdown(source))\n}\n","/**\n * The web-chat panel: engine/login status, a conversation sidebar (the local\n * transcript list + management), the chat transcript with markdown rendering,\n * streaming updates (polled), the composer with deep-think / internet-search\n * toggles, and the transfer-to-Harness handoff. All data flows through the\n * /api/dsh-webchat routes; the panel is a plain React root in the center column.\n *\n * Layout mirrors chat.deepseek.com: a left conversation sidebar (new chat +\n * history + per-item rename/delete + clear-all) beside the main chat column\n * (messages → composer with 深度思考 / 智能搜索 toggles → handoff dock). The\n * mono register stays reserved for machine things — timestamps, counts,\n * status, and the handoff eyebrow.\n */\n\nimport { useCallback, useEffect, useRef, useState, useSyncExternalStore } from 'react'\nimport type { ISessions, IWorkspaces, SessionId } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { WebChatApi } from '../api.ts'\nimport type { TransferMode, WebChatState, WebChatTranscript } from '../../protocol.ts'\nimport type { WebChatKey } from '../locales.ts'\nimport { Markdown } from './Markdown.tsx'\nimport css from './panel.module.css'\n\n/** Interpolate {placeholder}s in a localized template. */\nfunction fmt(template: string, values: Record<string, string>): string {\n return template.replace(/\\{(\\w+)\\}/g, (_, key: string) => values[key] ?? `{${key}}`)\n}\n\n/** Compact inline icons (stroke = currentColor, 16px viewBox). */\nconst PENCIL_ICON = '<svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M11.3 2.2l2.5 2.5L5.5 13H3v-2.5L11.3 2.2z\"/></svg>'\nconst TRASH_ICON = '<svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M2.5 4h11M6.5 4V2.5h3V4M4 4l.5 9.5h7L12 4\"/></svg>'\nconst CHECK_ICON = '<svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M3 8.5L6.5 12 13 4.5\"/></svg>'\nconst CROSS_ICON = '<svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M4 4l8 8M12 4l-8 8\"/></svg>'\n\nexport interface WebChatPanelProps {\n api: WebChatApi\n /** Locale accessor (the plugin registers its dictionaries on ctx.locale). */\n tt: (key: WebChatKey) => string\n /** Client sessions service (ctx.sessions) for opening transferred sessions. */\n sessions: ISessions\n /** Client workspaces service (ctx.workspaces) for the transfer target picker. */\n workspaces: IWorkspaces\n /** Resolve the current workspace directory (cwd for new sessions / exports). */\n currentCwd: () => string | undefined\n}\n\n/** Time between /state polls while nothing is streaming. */\nconst POLL_IDLE_MS = 1_500\n/** Faster polling while a reply is streaming. */\nconst POLL_STREAM_MS = 600\n\nexport function WebChatPanel({ api, tt, sessions, workspaces, currentCwd }: WebChatPanelProps) {\n const [state, setState] = useState<WebChatState | null>(null)\n const [viewChatId, setViewChatId] = useState<string | undefined>(undefined)\n const [draft, setDraft] = useState('')\n const [attachOpen, setAttachOpen] = useState(false)\n const [imagePaths, setImagePaths] = useState('')\n const [toast, setToast] = useState<{ text: string; error?: boolean } | null>(null)\n const [transferring, setTransferring] = useState(false)\n const [exporting, setExporting] = useState(false)\n const [transferMode, setTransferMode] = useState<TransferMode>('distill')\n const [targetWorkspaceId, setTargetWorkspaceId] = useState<string | undefined>(undefined)\n const [targetSessionId, setTargetSessionId] = useState<string | undefined>(undefined)\n const [deepThink, setDeepThink] = useState(false)\n const [search, setSearch] = useState(false)\n const [renamingId, setRenamingId] = useState<string | undefined>(undefined)\n const [renameDraft, setRenameDraft] = useState('')\n const [deleteArmId, setDeleteArmId] = useState<string | undefined>(undefined)\n const [clearArm, setClearArm] = useState(false)\n const [recoverOpen, setRecoverOpen] = useState(false)\n const [webMissing, setWebMissing] = useState<string[]>([])\n const [recovering, setRecovering] = useState(false)\n const listRef = useRef<HTMLDivElement | null>(null)\n const toastTimer = useRef<number | undefined>(undefined)\n const armTimer = useRef<number | undefined>(undefined)\n const stateRef = useRef<WebChatState | null>(null)\n stateRef.current = state\n const pinnedRef = useRef(true) // user is following the latest message (not scrolled up)\n const prevChatRef = useRef<string | undefined>(undefined)\n\n const showToast = useCallback((text: string, error = false): void => {\n setToast({ text, error })\n window.clearTimeout(toastTimer.current)\n toastTimer.current = window.setTimeout(() => setToast(null), 5_000)\n }, [])\n\n // Workspace list feed for the transfer-target picker (reactive snapshot).\n const workspaceSnapshot = useSyncExternalStore(\n useCallback((listener: () => void) => workspaces.list.subscribe(listener), [workspaces]),\n () => workspaces.list.getSnapshot(),\n )\n const workspaceItems = workspaceSnapshot.items\n const workspaceBaselinesReady = workspaceSnapshot.baselinesReady\n\n // Sessions feed for the \"continue into\" picker, scoped to the active\n // workspace: a task is continued inside the workspace the user is working in,\n // so cross-workspace sessions are hidden.\n const sessionSnapshot = useSyncExternalStore(\n useCallback((listener: () => void) => sessions.list.subscribe(listener), [sessions]),\n () => sessions.list.getSnapshot(),\n )\n\n // The workspace the \"continue into\" list is scoped to. The transfer-target\n // workspace selector drives it (defaults to the current session's workspace,\n // set by the effect below); \"ungrouped\" leaves it undefined.\n const selectedWorkspace = targetWorkspaceId === undefined\n ? undefined\n : workspaceItems.find(ws => ws.workspaceId === targetWorkspaceId)\n const groupedSessionIds = new Set(workspaceItems.flatMap(ws => ws.sessionIds))\n const continuationTargets = sessionSnapshot.ids.flatMap(id => {\n const session = sessionSnapshot.byId[id]\n if (session === undefined || session.blank === true) return []\n if (selectedWorkspace !== undefined) {\n if (!selectedWorkspace.sessionIds.includes(id)) return []\n } else if (groupedSessionIds.has(id)) {\n return []\n }\n return [{ sessionId: session.id, title: session.displayTitle, running: session.running }]\n })\n\n // Pick a default target workspace once the list is ready: prefer the current\n // session's workspace, then the most recently active workspace, else ungrouped.\n // Keep the transfer-target workspace defaulted to the active workspace until\n // the user explicitly picks one; re-syncs as the current session moves.\n const workspaceOverridden = useRef(false)\n useEffect(() => {\n if (workspaceOverridden.current || !workspaceBaselinesReady) return\n const currentSessionId = sessions.list.getSnapshot().current\n const currentWorkspace = currentSessionId === undefined ? undefined : workspaceItems.find(ws => ws.sessionIds.includes(currentSessionId))\n setTargetWorkspaceId(currentWorkspace?.workspaceId ?? workspaceSnapshot.recentWorkspaceId)\n }, [workspaceBaselinesReady, workspaceItems, workspaceSnapshot.recentWorkspaceId, sessions])\n\n const creatingWorkspace = useRef(false)\n const createWorkspace = useCallback(async (): Promise<void> => {\n if (creatingWorkspace.current) return\n creatingWorkspace.current = true\n try {\n const path = await workspaces.pickDirectory()\n if (path === null || path === '') return\n const created = await workspaces.create({ path })\n setTargetWorkspaceId(created.workspaceId)\n showToast(fmt(tt('transfer.workspace.created'), { title: created.title }))\n } catch (error) {\n showToast(fmt(tt('transfer.workspace.createFailed'), { error: String(error) }), true)\n } finally {\n creatingWorkspace.current = false\n }\n }, [workspaces, showToast, tt])\n\n // Poll /state.\n useEffect(() => {\n let cancelled = false\n let timer: number | undefined\n const poll = async (): Promise<void> => {\n if (cancelled) return\n try {\n const snapshot = await api.state()\n if (cancelled) return\n setState(snapshot)\n setViewChatId(previous => {\n const active = snapshot.activeChatId\n if (previous !== undefined && snapshot.chats.some(chat => chat.id === previous)) return previous\n return active\n })\n } catch {\n // transient poll failure: keep the previous snapshot\n }\n const streaming = stateRef.current?.chats.some(chat => chat.streaming) ?? false\n timer = window.setTimeout(poll, streaming ? POLL_STREAM_MS : POLL_IDLE_MS)\n }\n void poll()\n return () => {\n cancelled = true\n window.clearTimeout(timer)\n }\n }, [api])\n\n // Reconcile the web page's toggle state whenever the server reports it.\n useEffect(() => {\n if (state === null) return\n setDeepThink(state.deepThink)\n setSearch(state.search)\n }, [state?.deepThink, state?.search])\n\n // Auto-scroll to the bottom only when the user is following the latest\n // message (pinned) or has just switched chats — never yank the view while\n // they are reading history.\n useEffect(() => {\n const list = listRef.current\n if (list === null) return\n const switched = prevChatRef.current !== viewChatId\n prevChatRef.current = viewChatId\n if (switched || pinnedRef.current) {\n list.scrollTop = list.scrollHeight\n }\n }, [state, viewChatId])\n\n // Track whether the user has scrolled away from the bottom.\n const handleScroll = useCallback((): void => {\n const list = listRef.current\n if (list === null) return\n const nearBottom = list.scrollHeight - list.scrollTop - list.clientHeight < 96\n pinnedRef.current = nearBottom\n }, [])\n\n const chats: WebChatTranscript[] = state?.chats ?? []\n const viewChat = chats.find(chat => chat.id === viewChatId) ?? chats[0]\n const busy = state?.busy ?? false\n const loggedIn = state?.loggedIn ?? null\n const streaming = viewChat?.streaming ?? false\n\n const modelLabel = useCallback((model: string): string => {\n return model === 'deepseek-reasoner' ? tt('model.deepseek-reasoner') : tt('model.deepseek-chat')\n }, [tt])\n\n const send = useCallback(async (): Promise<void> => {\n const text = draft.trim()\n const images = imagePaths.split(/[\\n,;]+/).map(path => path.trim()).filter(path => path !== '')\n if ((text === '' && images.length === 0) || busy) return\n setDraft('')\n setImagePaths('')\n pinnedRef.current = true // follow the reply we just sent\n try {\n const result = await api.send(text, images.length > 0 ? images : undefined)\n if (result.ok !== true) showToast(result.error ?? 'send failed', true)\n else setViewChatId(result.chatId)\n } catch (error) {\n showToast(String(error), true)\n }\n }, [draft, imagePaths, busy, api, showToast])\n\n const stop = useCallback(async (): Promise<void> => {\n await api.stop().catch(() => undefined)\n }, [api])\n\n const newChat = useCallback(async (): Promise<void> => {\n try {\n const result = await api.newChat()\n if (result.ok === true && result.chatId !== undefined) setViewChatId(result.chatId)\n else showToast(result.error ?? 'new chat failed', true)\n } catch (error) {\n showToast(String(error), true)\n }\n }, [api, showToast])\n\n const toggleDeepThink = useCallback(async (): Promise<void> => {\n const next = !deepThink\n setDeepThink(next)\n try {\n const result = await api.setDeepThink(next)\n if (result.ok !== true) showToast(result.error ?? 'toggle deep think failed', true)\n } catch (error) {\n showToast(String(error), true)\n }\n }, [deepThink, api, showToast])\n\n const toggleSearch = useCallback(async (): Promise<void> => {\n const next = !search\n setSearch(next)\n try {\n const result = await api.setSearch(next)\n if (result.ok !== true) showToast(result.error ?? 'toggle search failed', true)\n } catch (error) {\n showToast(String(error), true)\n }\n }, [search, api, showToast])\n\n const openLogin = useCallback(async (): Promise<void> => {\n try {\n const result = await api.openLogin()\n if (result.ok !== true) showToast(result.error ?? 'open login failed', true)\n } catch (error) {\n showToast(String(error), true)\n }\n }, [api, showToast])\n\n const closeBrowser = useCallback(async (): Promise<void> => {\n await api.closeBrowser().catch(() => undefined)\n }, [api])\n\n const toggleRecover = useCallback(async (): Promise<void> => {\n if (recoverOpen) {\n setRecoverOpen(false)\n return\n }\n try {\n const result = await api.webChats()\n setWebMissing(result.ok === true ? (result.missing ?? []) : [])\n setRecoverOpen(true)\n } catch (error) {\n showToast(String(error), true)\n }\n }, [recoverOpen, api, showToast])\n\n const recoverFromWeb = useCallback(async (title: string): Promise<void> => {\n if (recovering) return\n setRecovering(true)\n try {\n const result = await api.recover(title)\n if (result.ok !== true || result.chatId === undefined) {\n showToast(result.error ?? 'recover failed', true)\n return\n }\n setWebMissing(list => list.filter(item => item !== title))\n showToast(fmt(tt('recover.done'), { title: result.title ?? title }))\n } catch (error) {\n showToast(String(error), true)\n } finally {\n setRecovering(false)\n }\n }, [recovering, api, showToast, tt])\n\n const transferToHarness = useCallback(async (): Promise<void> => {\n if (viewChat === undefined || transferring) return\n setTransferring(true)\n try {\n const result = await api.transfer(viewChat.id, currentCwd(), transferMode, targetWorkspaceId, targetSessionId)\n if (result.ok !== true || result.sessionId === undefined) {\n showToast(result.error ?? 'transfer failed', true)\n return\n }\n const target = result.sessionId\n if (result.continued === true) {\n // Continuation: the session is already listed — just open it.\n showToast(fmt(tt('transfer.continued'), { sessionId: target }))\n sessions.open(target as SessionId)\n return\n }\n if (result.attached === false && targetWorkspaceId !== undefined) {\n showToast(fmt(tt('transfer.attached.failed'), { sessionId: target }), true)\n } else {\n showToast(fmt(tt('transfer.done'), { sessionId: target }))\n }\n // The session is persisted cold, so the cached list does not know about\n // it yet. Trigger a full list refresh (concrete-only on the runtime\n // sessions service), then poll until the row lands and open it.\n const refreshable = sessions as ISessions & { refresh?: () => Promise<void> }\n try {\n await refreshable.refresh?.()\n } catch {\n // Refresh is best-effort; fall through to the poll below.\n }\n const tryOpen = (): void => {\n const snapshot = sessions.list.getSnapshot()\n if (snapshot.byId[target as SessionId] !== undefined) {\n sessions.open(target as SessionId)\n return\n }\n window.setTimeout(tryOpen, 300)\n }\n window.setTimeout(tryOpen, 200)\n } catch (error) {\n showToast(String(error), true)\n } finally {\n setTransferring(false)\n }\n }, [viewChat, transferring, api, currentCwd, sessions, showToast, tt, transferMode, targetWorkspaceId, targetSessionId])\n\n const exportFile = useCallback(async (): Promise<void> => {\n if (viewChat === undefined || exporting) return\n setExporting(true)\n try {\n const result = await api.exportFile(viewChat.id, currentCwd())\n if (result.ok !== true || result.filePath === undefined) {\n showToast(result.error ?? 'export failed', true)\n } else {\n showToast(fmt(tt('export.done'), { filePath: result.filePath }))\n }\n } catch (error) {\n showToast(String(error), true)\n } finally {\n setExporting(false)\n }\n }, [viewChat, exporting, api, currentCwd, showToast, tt])\n\n // --- transcript management (rename / delete / clear-all) -------------------\n const resetArmTimer = useCallback((next: (() => void) | undefined): void => {\n window.clearTimeout(armTimer.current)\n armTimer.current = next === undefined ? undefined : window.setTimeout(next, 3_000)\n }, [])\n\n const startRename = useCallback((chat: WebChatTranscript): void => {\n setDeleteArmId(undefined)\n setClearArm(false)\n setRenameDraft(chat.title)\n setRenamingId(chat.id)\n }, [])\n\n const commitRename = useCallback(async (): Promise<void> => {\n const id = renamingId\n if (id === undefined) return\n const title = renameDraft.trim().replace(/\\s+/g, ' ')\n setRenamingId(undefined)\n const original = chats.find(chat => chat.id === id)\n if (title === '' || (original !== undefined && title === original.title)) return\n try {\n const result = await api.renameChat(id, title)\n if (result.ok !== true) showToast(fmt(tt('toast.rename.failed'), { error: result.error ?? '' }), true)\n else showToast(tt('toast.rename.done'))\n } catch (error) {\n showToast(fmt(tt('toast.rename.failed'), { error: String(error) }), true)\n }\n }, [renamingId, renameDraft, chats, api, showToast, tt])\n\n const cancelRename = useCallback((): void => {\n setRenamingId(undefined)\n setRenameDraft('')\n }, [])\n\n const requestDelete = useCallback(async (id: string): Promise<void> => {\n if (deleteArmId !== id) {\n setClearArm(false)\n setRenamingId(undefined)\n setDeleteArmId(id)\n resetArmTimer(() => setDeleteArmId(undefined))\n return\n }\n resetArmTimer(undefined)\n setDeleteArmId(undefined)\n try {\n const result = await api.deleteChat(id)\n if (result.ok !== true) showToast(fmt(tt('toast.delete.failed'), { error: result.error ?? '' }), true)\n else showToast(tt('toast.delete.done'))\n } catch (error) {\n showToast(fmt(tt('toast.delete.failed'), { error: String(error) }), true)\n }\n }, [deleteArmId, api, showToast, tt, resetArmTimer])\n\n const requestClear = useCallback(async (): Promise<void> => {\n if (chats.length === 0) return\n if (!clearArm) {\n setDeleteArmId(undefined)\n setRenamingId(undefined)\n setClearArm(true)\n resetArmTimer(() => setClearArm(false))\n return\n }\n resetArmTimer(undefined)\n setClearArm(false)\n try {\n const result = await api.clearChats()\n if (result.ok !== true) showToast(fmt(tt('toast.clear.failed'), { error: result.error ?? '' }), true)\n else showToast(tt('toast.clear.done'))\n } catch (error) {\n showToast(fmt(tt('toast.clear.failed'), { error: String(error) }), true)\n }\n }, [chats.length, clearArm, api, showToast, tt, resetArmTimer])\n\n const engineState = state?.engine ?? 'stopped'\n const engineError = state?.engineError\n const statusDot: 'ok' | 'warn' | 'bad' | 'busy' =\n busy ? 'busy'\n : engineState === 'error' ? 'bad'\n : loggedIn === true ? 'ok'\n : 'warn'\n const statusText = busy\n ? tt('composer.busy')\n : engineState === 'error'\n ? `${tt('status.engine.error')}${engineError !== undefined ? `: ${engineError}` : ''}`\n : engineState === 'launching'\n ? tt('status.engine.launching')\n : loggedIn === true\n ? tt('status.loggedIn')\n : loggedIn === false\n ? tt('status.notLoggedIn')\n : tt('status.unknown')\n\n const togglesDisabled = busy || loggedIn !== true\n\n return (\n <div className={css.panel}>\n {/* Identity + live status */}\n <header className={css.panelHeader}>\n <h2 className={css.panelTitle}>{tt('panel.title')}</h2>\n <div className={css.headerSpacer} />\n <div className={css.statusChip}>\n <span className={css.statusDot} data-state={statusDot} />\n <span className={css.statusText}>{statusText}</span>\n </div>\n {loggedIn !== true && (\n <button className={`${css.button} ${css.buttonPrimary}`} onClick={() => { void openLogin() }}>\n {tt('action.openLogin')}\n </button>\n )}\n {engineState !== 'stopped' && (\n <button className={css.buttonGhost} onClick={() => { void closeBrowser() }}>\n {tt('action.closeBrowser')}\n </button>\n )}\n </header>\n\n <div className={css.panelBody}>\n {/* Conversation sidebar (chat history + management) */}\n <aside className={css.sidebar}>\n <button className={`${css.button} ${css.buttonPrimary} ${css.sidebarNew}`} onClick={() => { void newChat() }}>\n {tt('action.newChat')}\n </button>\n <button\n className={`${css.buttonGhost} ${css.sidebarNew}`}\n disabled={loggedIn !== true}\n onClick={() => { void toggleRecover() }}\n title={tt('recover.hint')}\n >\n {tt('action.recover')}\n </button>\n {recoverOpen && (\n <div className={css.recoverList}>\n {webMissing.length === 0 ? (\n <div className={css.recoverEmpty}>{tt('recover.empty')}</div>\n ) : (\n webMissing.map(title => (\n <button\n className={css.recoverItem}\n key={title}\n disabled={recovering}\n onClick={() => { void recoverFromWeb(title) }}\n title={title}\n >\n <span className={css.recoverTitle}>{title}</span>\n </button>\n ))\n )}\n </div>\n )}\n <div className={css.sidebarList}>\n {chats.length === 0 ? (\n <div className={css.sidebarEmpty}>{tt('sidebar.empty')}</div>\n ) : (\n chats.map(chat => (\n renamingId === chat.id ? (\n <div className={css.sidebarItem} data-active={chat.id === viewChatId ? 'true' : undefined} key={chat.id}>\n <div className={css.sidebarRename}>\n <input\n className={css.sidebarRenameInput}\n value={renameDraft}\n placeholder={tt('chat.rename.placeholder')}\n aria-label=\"rename\"\n autoFocus\n onChange={event => setRenameDraft(event.target.value)}\n onKeyDown={event => {\n if (event.key === 'Enter') {\n event.preventDefault()\n void commitRename()\n } else if (event.key === 'Escape') {\n cancelRename()\n }\n }}\n />\n <button className={css.sidebarAction} onClick={() => { void commitRename() }} aria-label={tt('chat.rename.ok')} dangerouslySetInnerHTML={{ __html: CHECK_ICON }} />\n <button className={css.sidebarAction} onClick={cancelRename} aria-label={tt('chat.rename.cancel')} dangerouslySetInnerHTML={{ __html: CROSS_ICON }} />\n </div>\n </div>\n ) : (\n <div className={css.sidebarItem} data-active={chat.id === viewChatId ? 'true' : undefined} key={chat.id}>\n <button className={css.sidebarRow} onClick={() => setViewChatId(chat.id)} title={chat.title}>\n <span className={css.sidebarTitle}>{chat.title}</span>\n <span className={css.sidebarMeta}>{fmt(tt('chats.count'), { count: String(chat.messages.length) })}</span>\n </button>\n <span className={css.sidebarActions}>\n <button className={css.sidebarAction} onClick={() => startRename(chat)} aria-label={tt('chat.rename')} title={tt('chat.rename')} dangerouslySetInnerHTML={{ __html: PENCIL_ICON }} />\n <button\n className={deleteArmId === chat.id ? css.sidebarActionDanger : css.sidebarAction}\n onClick={() => { void requestDelete(chat.id) }}\n aria-label={deleteArmId === chat.id ? tt('chat.delete.confirm') : tt('chat.delete')}\n title={deleteArmId === chat.id ? tt('chat.delete.confirm') : tt('chat.delete')}\n >\n {deleteArmId === chat.id ? tt('chat.delete.confirm') : <span dangerouslySetInnerHTML={{ __html: TRASH_ICON }} />}\n </button>\n </span>\n </div>\n )\n ))\n )}\n </div>\n <button\n className={clearArm ? `${css.button} ${css.buttonDanger} ${css.sidebarClear}` : `${css.buttonGhost} ${css.sidebarClear}`}\n disabled={chats.length === 0}\n onClick={() => { void requestClear() }}\n >\n {clearArm ? tt('chat.clearAll.confirm') : tt('chat.clearAll')}\n </button>\n </aside>\n\n {/* Main chat column */}\n <div className={css.main}>\n <div className={css.messageList} ref={listRef} onScroll={handleScroll}>\n {viewChat === undefined || viewChat.messages.length === 0 ? (\n <div className={css.emptyState}>\n <div className={css.emptyEyebrow}>{tt('empty.eyebrow')}</div>\n <h3 className={css.emptyTitle}>{tt('empty.title')}</h3>\n <p className={css.emptyBody}>{tt('empty.body')}</p>\n {loggedIn !== true && (\n <button className={`${css.button} ${css.buttonPrimary}`} onClick={() => { void openLogin() }}>\n {tt('action.openLogin')}\n </button>\n )}\n </div>\n ) : (\n viewChat.messages.map(message => (\n <div className={css.messageRow} data-role={message.role} key={message.id}>\n <div className={css.messageMeta}>\n <span className={css.messageSpeaker}>{message.role === 'user' ? tt('role.you') : modelLabel(viewChat.model)}</span>\n <span className={css.messageTime}>{new Date(message.ts).toLocaleTimeString()}</span>\n {message.streaming === true && <span className={css.streamBadge}>{tt('streaming')}…</span>}\n </div>\n <div className={css.messageBubble}>\n <Markdown source={message.content} />\n {message.error !== undefined && message.content !== '' && (\n <div className={css.messageError}>{fmt(tt('msg.error'), { error: message.error })}</div>\n )}\n </div>\n </div>\n ))\n )}\n </div>\n\n <div className={css.composer}>\n <div className={css.composerToolbar}>\n <button\n className={css.toggleButton}\n data-active={deepThink ? 'true' : undefined}\n disabled={togglesDisabled}\n title={tt('toggle.deepThink.hint')}\n aria-pressed={deepThink}\n onClick={() => { void toggleDeepThink() }}\n >\n {tt('toggle.deepThink')}\n </button>\n <button\n className={css.toggleButton}\n data-active={search ? 'true' : undefined}\n disabled={togglesDisabled}\n title={tt('toggle.search.hint')}\n aria-pressed={search}\n onClick={() => { void toggleSearch() }}\n >\n {tt('toggle.search')}\n </button>\n </div>\n <textarea\n className={css.composerInput}\n value={draft}\n placeholder={busy ? tt('composer.busy') : loggedIn !== true ? tt('composer.notLoggedIn') : tt('composer.placeholder')}\n disabled={busy || loggedIn !== true}\n onChange={event => setDraft(event.target.value)}\n onKeyDown={event => {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault()\n void send()\n }\n }}\n />\n {attachOpen && (\n <input\n className={css.attachInput}\n value={imagePaths}\n placeholder={tt('composer.attach.placeholder')}\n disabled={busy || loggedIn !== true}\n onChange={event => setImagePaths(event.target.value)}\n />\n )}\n <div className={css.composerFooter}>\n <button\n className={css.toggleButton}\n data-active={attachOpen ? 'true' : undefined}\n title={tt('composer.attach.hint')}\n aria-pressed={attachOpen}\n disabled={busy || loggedIn !== true}\n onClick={() => setAttachOpen(open => !open)}\n >\n {tt('composer.attach')}\n </button>\n <span className={css.composerHint}>{tt('composer.hint')}</span>\n <div className={css.composerSpacer} />\n {streaming ? (\n <button className={`${css.button} ${css.buttonDanger}`} onClick={() => { void stop() }}>\n {tt('action.stop')}\n </button>\n ) : (\n <button\n className={`${css.button} ${css.buttonPrimary}`}\n disabled={busy || loggedIn !== true || (draft.trim() === '' && imagePaths.trim() === '')}\n onClick={() => { void send() }}\n >\n {tt('action.send')}\n </button>\n )}\n </div>\n </div>\n\n {/* Handoff dock — the chat → harness gateway (signature) */}\n <div className={css.handoffDock}>\n <span className={css.handoffEyebrow}>{tt('handoff.eyebrow')}</span>\n <div className={css.handoffSpacer} />\n <div className={css.segmented} role=\"group\" aria-label=\"transfer mode\" title={tt('transfer.mode.hint')}>\n <button\n className={css.segmentedButton}\n data-active={transferMode === 'distill' ? 'true' : undefined}\n onClick={() => setTransferMode('distill')}\n >\n {tt('transfer.mode.distill')}\n </button>\n <button\n className={css.segmentedButton}\n data-active={transferMode === 'raw' ? 'true' : undefined}\n onClick={() => setTransferMode('raw')}\n >\n {tt('transfer.mode.raw')}\n </button>\n </div>\n <select\n className={css.workspaceSelect}\n value={targetSessionId ?? ''}\n disabled={continuationTargets.length === 0}\n title={tt('transfer.session.hint')}\n aria-label={tt('transfer.session.label')}\n onChange={event => setTargetSessionId(event.target.value === '' ? undefined : event.target.value)}\n >\n <option value=\"\">{tt('transfer.session.new')}</option>\n {continuationTargets.map(session => (\n <option key={session.sessionId} value={session.sessionId}>\n {session.title}{session.running === true ? ' ·●' : ''}\n </option>\n ))}\n </select>\n <select\n className={css.workspaceSelect}\n value={targetWorkspaceId ?? ''}\n disabled={targetSessionId !== undefined}\n title={tt('transfer.workspace.hint')}\n aria-label={tt('transfer.workspace.label')}\n onChange={event => { workspaceOverridden.current = true; setTargetWorkspaceId(event.target.value === '' ? undefined : event.target.value) }}\n >\n <option value=\"\">{tt('transfer.workspace.ungrouped')}</option>\n {workspaceItems.map(ws => (\n <option key={ws.workspaceId} value={ws.workspaceId}>\n {ws.title}{ws.path !== ws.title ? ` — ${ws.path}` : ''}\n </option>\n ))}\n </select>\n <button className={css.buttonGhost} onClick={() => { void createWorkspace() }} title={tt('transfer.workspace.new')} disabled={targetSessionId !== undefined}>\n {tt('transfer.workspace.new')}\n </button>\n <button\n className={`${css.button} ${css.buttonPrimary}`}\n disabled={viewChat === undefined || transferring}\n onClick={() => { void transferToHarness() }}\n >\n {tt('action.transferToHarness')}\n </button>\n <button className={css.button} disabled={viewChat === undefined || exporting} onClick={() => { void exportFile() }}>\n {tt('action.exportFile')}\n </button>\n </div>\n </div>\n </div>\n\n {toast !== null && <div className={css.toast} data-error={toast.error === true ? 'true' : undefined}>{toast.text}</div>}\n </div>\n )\n}\n","/**\n * Panel view mounting. The conversation slot is single-occupant and external\n * plugins cannot declare slots, so the panel takes over the center column at\n * the DOM level (same strategy as dsh-ssh / dsh-task-board): a container is\n * appended inside the center column as an extra trailing child React never\n * manages, and a stylesheet rule hides the conversation content while the\n * panel is active. Toggling is a data attribute on <html> — no React\n * involvement, so the conversation subtree underneath stays mounted and\n * stateful.\n */\nimport { createRoot, type Root } from 'react-dom/client'\nimport type { ISessions, IWorkspaces } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { WebChatApi } from './api.ts'\nimport type { PanelController } from './controller.ts'\nimport type { WebChatKey } from './locales.ts'\nimport { WebChatPanel } from './panel/WebChatPanel.tsx'\nimport css from './panel/panel.module.css'\n\n/** The injected panel container (kept in the DOM, hidden when inactive). */\nexport const PANEL_VIEW_SELECTOR = '[data-dsh-webchat-view]'\n\nconst CONVERSATION_COLUMN_SELECTOR = '[data-pane=\"conversation\"], [class*=\"centerCol\"]'\nconst ACTIVE_ATTR = 'data-dsh-webchat-active'\n/** The sibling panels' activation attributes, removed when this panel opens. */\nconst OTHER_ACTIVE_ATTRS = ['data-dsh-taskboard-active', 'data-dsh-ssh-active']\n/** Cross-plugin activation event; detail is the activating panel name. */\nconst ACTIVATE_EVENT = 'dsh-panel-activate'\nconst PANEL_NAME = 'webchat'\n\n/** Find the center column, or undefined while the frame is not mounted. */\nfunction conversationColumn(): HTMLElement | undefined {\n return document.querySelector<HTMLElement>(CONVERSATION_COLUMN_SELECTOR) ?? undefined\n}\n\nexport interface MountPanelDeps {\n sessions: ISessions\n workspaces: IWorkspaces\n api: WebChatApi\n controller: PanelController\n /** Locale accessor bound to the plugin's registered dictionaries. */\n tt: (key: WebChatKey) => string\n /** Resolve the current session's cwd (for transfers / exports). */\n currentCwd: () => string | undefined\n}\n\n/**\n * Mount the panel React tree into the center column and bind its visibility\n * to the controller's panelOpen state.\n * @param deps - sessions, api, controller, locale accessor.\n * @returns disposer unmounting the tree and restoring the column.\n */\nexport function mountPanel(deps: MountPanelDeps): () => void {\n const { sessions, workspaces, api, controller, tt, currentCwd } = deps\n let root: Root | undefined\n let container: HTMLDivElement | undefined\n\n const ensure = (): void => {\n if (container !== undefined) {\n if (container.isConnected) return\n // The conversation pane was replaced; drop the stale tree and remount.\n root?.unmount()\n root = undefined\n container.remove()\n container = undefined\n }\n const column = conversationColumn()\n if (column === undefined) return\n container = document.createElement('div')\n container.dataset.dshWebchatView = ''\n container.dataset.dshPlugin = 'webchat'\n container.className = css.view\n column.appendChild(container)\n root = createRoot(container)\n root.render(<WebChatPanel api={api} tt={tt} sessions={sessions} workspaces={workspaces} currentCwd={currentCwd} />)\n }\n\n // The frame mounts after boot settlement; watch for the column's arrival.\n const waitObserver = new MutationObserver(() => { ensure() })\n waitObserver.observe(document.body, { childList: true, subtree: true })\n\n const applyActive = (): void => {\n if (controller.getSnapshot().panelOpen) {\n // Single-occupant center column: opening this panel must evict sibling\n // panels (task board / ssh), both their html attributes and their\n // controller state, otherwise visibility rules fight.\n for (const attr of OTHER_ACTIVE_ATTRS) document.documentElement.removeAttribute(attr)\n document.documentElement.setAttribute(ACTIVE_ATTR, '')\n document.dispatchEvent(new CustomEvent(ACTIVATE_EVENT, { detail: PANEL_NAME }))\n } else {\n document.documentElement.removeAttribute(ACTIVE_ATTR)\n }\n }\n const onOtherActivate = (event: Event): void => {\n const detail = (event as CustomEvent).detail\n if ((detail === 'taskboard' || detail === 'ssh') && controller.getSnapshot().panelOpen) {\n controller.close()\n }\n }\n // Jump out on sidebar context clicks: clicking a session/workspace row\n // hands the center column back to the conversation. Capture phase.\n const SIDEBAR_ROW_SELECTOR = '[class*=\"sessionRow\"], [class*=\"projectRow\"], [class*=\"searchResultRow\"], [class*=\"searchResultWorkspace\"], [class*=\"newSession\"]'\n const onClickSidebarRow = (event: MouseEvent): void => {\n if (!controller.getSnapshot().panelOpen) return\n const target = event.target as HTMLElement | null\n if (target === null) return\n if (target.closest(SIDEBAR_ROW_SELECTOR) !== null) controller.close()\n }\n document.addEventListener('click', onClickSidebarRow, true)\n document.addEventListener(ACTIVATE_EVENT, onOtherActivate)\n const unsubscribe = controller.subscribe(applyActive)\n applyActive()\n ensure()\n\n return () => {\n document.removeEventListener('click', onClickSidebarRow, true)\n document.removeEventListener(ACTIVATE_EVENT, onOtherActivate)\n waitObserver.disconnect()\n unsubscribe()\n document.documentElement.removeAttribute(ACTIVE_ATTR)\n root?.unmount()\n root = undefined\n container?.remove()\n container = undefined\n }\n}\n","/**\n * Shared sidebar entry injection core.\n *\n * dsh's sidebar shell exposes no slot an external plugin can register into,\n * so the entry row is injected between the shell's New Session button and the\n * workspace browser. The injection self-heals: a MutationObserver watches the\n * sidebar root and re-inserts the row whenever a React re-render displaces it\n * (re-insertion happens in the same frame, before paint, so no flicker).\n *\n * The row is plain DOM (no React tree) so it can never disturb the shell's\n * reconciliation; the view it toggles is a separate root owned by the caller.\n *\n * Packages receive this file as a generated copy via scripts/sync-shared.mjs;\n * edit the shared source and re-run the sync instead of editing a copy.\n */\n\n/** Per-package configuration for one sidebar entry row. */\nexport interface SidebarEntryOptions {\n /** Full attribute name identifying the injected row (idempotency key), e.g. 'data-dsh-ssh-entry'. */\n rowAttribute: string\n /** CSS selector matching the injected row, e.g. '[data-dsh-ssh-entry]'. */\n rowSelector: string\n /**\n * L2 semantic-attribute plugin id (issue #506, enum table:\n * skins/skin-center/contracts/semantic-attrs-v1.md). When set, the row also\n * outputs data-dsh-plugin=\"<id>\" and data-dsh-part=\"sidebar-entry\"; unset\n * leaves the row without semantic attributes.\n */\n plugin?: string\n /** Inline icon markup (matches the shell's 16px nav-icon look). */\n icon: string\n /** CSS module class names for the row and its two spans (entry / entryIcon / entryLabel). */\n css: Record<string, string>\n /** Localized row label (aria-label + visible text). */\n label(): string\n /** Optional localized tooltip (title attribute). */\n tooltip?(): string\n /** Click action (open/toggle the owning panel). */\n onToggle(): void\n /** Family-block position: 'before' inserts ahead of sibling plugin rows, 'after' behind them. */\n position: 'before' | 'after'\n /**\n * Selectors of the sibling plugin entry rows this package orders against\n * (its own row included — the placement guard excludes a row that is\n * already inside the root). Each package passes the same list it used\n * before the consolidation so the rendered order stays stable.\n */\n familySelectors: readonly string[]\n /** Optional active-state bridge; highlights the row while the panel is open. */\n active?: {\n subscribe(listener: () => void): () => void\n isOpen(): boolean\n }\n}\n\n/** Find the sidebar shell root element, or undefined while not yet mounted. */\nfunction sidebarRoot(): HTMLElement | undefined {\n const column = document.querySelector<HTMLElement>('[data-pane=\"sidebar\"], [class*=\"sidebarCol\"]')\n if (column === null) return undefined\n // Current shells wrap the sidebar UI: column > wrapper > root(logoRow owner).\n // Prefer the element that owns the logo row — the real sidebar UI root —\n // and fall back to the column's first child for legacy shells.\n const logoOwner = column.querySelector<HTMLElement>('[class*=\"logoRow\"]')?.parentElement\n return logoOwner ?? (column.firstElementChild as HTMLElement | undefined)\n}\n\n/** The New Session button: nested in the logo row on current shells, a direct child on legacy shells. */\nfunction newSessionButton(root: HTMLElement): HTMLButtonElement | undefined {\n const nested = root.querySelector<HTMLButtonElement>('button[class*=\"newSession\"]')\n if (nested !== null) return nested\n for (const child of root.children) {\n if (child.tagName === 'BUTTON') return child as HTMLButtonElement\n }\n return undefined\n}\n\n/** Build the entry row (a detached button; insert once the shell is up). */\nfunction createEntry(options: SidebarEntryOptions): HTMLButtonElement {\n const entry = document.createElement('button')\n entry.type = 'button'\n entry.setAttribute(options.rowAttribute, '')\n if (options.plugin !== undefined) {\n entry.setAttribute('data-dsh-plugin', options.plugin)\n entry.setAttribute('data-dsh-part', 'sidebar-entry')\n }\n entry.className = options.css['entry'] ?? ''\n entry.setAttribute('aria-label', options.label())\n if (options.tooltip !== undefined) entry.setAttribute('title', options.tooltip())\n entry.innerHTML = '<span class=\"' + (options.css['entryIcon'] ?? '') + '\">' + options.icon\n + '</span><span class=\"' + (options.css['entryLabel'] ?? '') + '\">' + options.label() + '</span>'\n entry.addEventListener('click', options.onToggle)\n return entry\n}\n\n/** Re-insert the entry after the New Session row (before the browser region). */\nfunction placeEntry(root: HTMLElement, entry: HTMLButtonElement, options: SidebarEntryOptions): boolean {\n const button = newSessionButton(root)\n if (button === undefined) return false\n if (entry.parentElement !== root) {\n // Position relative to the family block (entries injected by sibling\n // plugins), never relative to transient logoRow geometry: every family\n // plugin that self-heals during a re-render then lands in the same\n // relative order, so the entries cannot swap positions regardless of\n // observer callback order or of shell wrapper changes. There is no\n // append-to-end fallback: appending at the end would randomly reorder\n // the block after a shell re-render.\n const row = button.closest('[class*=\"logoRow\"]')\n const base = (row !== null && row.parentElement === root) ? row : button\n const family = Array.from(root.children).filter(\n (el): el is HTMLElement => el instanceof HTMLElement && el.matches(options.familySelectors.join(', ')),\n )\n const anchor = options.position === 'before'\n ? (family.length > 0 ? family[0] : base.nextElementSibling)\n : (family.length > 0 ? family[family.length - 1]!.nextElementSibling : base.nextElementSibling)\n root.insertBefore(entry, anchor)\n }\n return true\n}\n\n/**\n * Mount the sidebar entry, waiting for the shell to render and self-healing\n * on later React re-renders.\n * @param options - the row's attribute/icon/copy/action/ordering configuration.\n * @returns disposer removing the entry and its observers.\n */\nexport function mountSidebarEntry(options: SidebarEntryOptions): () => void {\n // DOM-level idempotency: whatever path mounted an entry row before this\n // call (a duplicated apply, an HMR re-injection, a stale module still\n // alive), never mount a second one. The existing row keeps working; a full\n // page reload is the ultimate reset.\n if (typeof document !== 'undefined' && document.querySelector(options.rowSelector) !== null) {\n return () => {}\n }\n const entry = createEntry(options)\n let root: HTMLElement | undefined\n let placed = false\n\n const tryPlace = (): void => {\n if (root !== undefined && !root.isConnected) {\n // The shell rebuilt the sidebar pane (whole-tree teardown); the root\n // observer is gone with the old tree, so detach it and re-query from\n // scratch. The new pane is later noticed by the body-level watcher.\n rootObserver.disconnect()\n root = undefined\n placed = false\n }\n if (placed) {\n // Cheap short-circuit: entry still lives in a mountable subtree.\n if (document.body.contains(entry)) return\n // Entry was torn down together with the old tree; reset and re-place.\n rootObserver.disconnect()\n root = undefined\n placed = false\n }\n root ??= sidebarRoot()\n if (root === undefined) return\n placed = placeEntry(root, entry, options)\n if (placed) {\n rootObserver.observe(root, { childList: true, subtree: true })\n }\n }\n\n // Body-level watcher retained as the \"whole rebuild\" fallback: when the shell\n // tears down the whole sidebar pane, the root observer is gone with it and\n // only this body observation can notice the new pane mounting. It is no\n // longer disconnected after placement; the placed-and-still-mounted case\n // short-circuits through the cheap document.body.contains(entry) check, so\n // unrelated app mutations (e.g. chat streaming) cost one contains check\n // instead of churning the full re-query.\n const waitObserver = new MutationObserver(() => { tryPlace() })\n waitObserver.observe(document.body, { childList: true, subtree: true })\n\n // Self-heal: if a React re-render displaces the row, re-insert it in the\n // same frame (microtask before paint -> no visible flicker).\n const rootObserver = new MutationObserver(() => {\n if (root === undefined || !root.isConnected) {\n placed = false\n tryPlace()\n return\n }\n if (!root.contains(entry)) {\n placed = placeEntry(root, entry, options)\n }\n })\n\n // Reflect the panel's open state on the row (active highlight). Note: assigning\n // undefined to dataset.active materializes data-active=\"undefined\" and keeps the\n // row permanently highlighted — delete the attribute instead.\n const unsubscribeActive = options.active === undefined ? undefined : (() => {\n const syncActive = (): void => {\n if (options.active!.isOpen()) entry.dataset.active = 'true'\n else delete entry.dataset.active\n }\n const unsubscribe = options.active.subscribe(syncActive)\n syncActive()\n return unsubscribe\n })()\n\n tryPlace()\n\n return () => {\n waitObserver.disconnect()\n rootObserver.disconnect()\n unsubscribeActive?.()\n entry.remove()\n }\n}\n","/**\n * Sidebar entry injection — package-specific wiring over the shared core\n * (sidebar-entry-core.ts). The row is plain DOM so it can never disturb the\n * shell's reconciliation; the panel view it toggles is a separate React root\n * mounted in the center column (see mount.tsx).\n */\nimport type { PanelController } from './controller.ts'\nimport { mountSidebarEntry as mountSharedSidebarEntry } from './sidebar-entry-core.ts'\nimport type { WebChatKey } from './locales.ts'\n// The hashed CSS module map (entry / entryIcon / entryLabel keys) — the same\n// pattern dsh-ssh uses, so the row matches the shell's nav-item look.\nimport css from './panel/panel.module.css'\n\n/** Stable data attribute identifying the injected entry row. */\nexport const ENTRY_SELECTOR = '[data-dsh-webchat-entry]'\n\n/** Inline icon (matches the shell's 16px nav-icon look): a chat bubble with a globe dot. */\nconst ICON = '<svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M8 2.5a5.5 5.5 0 0 0-4.7 8.3L2.5 13.5l2.8-.8A5.5 5.5 0 1 0 8 2.5z\"/><circle cx=\"8\" cy=\"8\" r=\"1.1\" fill=\"currentColor\" stroke=\"none\"/></svg>'\n\nexport interface SidebarEntryDeps {\n controller: PanelController\n /** Locale accessor (spelled here to keep the core dependency-free). */\n tt: (key: WebChatKey) => string\n}\n\n/**\n * Mount the sidebar entry, waiting for the shell to render and self-healing\n * on later React re-renders.\n * @param deps - controller and copy accessor.\n * @returns disposer removing the entry and its observers.\n */\nexport function mountSidebarEntry(deps: SidebarEntryDeps): () => void {\n return mountSharedSidebarEntry({\n rowAttribute: 'data-dsh-webchat-entry',\n rowSelector: ENTRY_SELECTOR,\n plugin: 'webchat',\n icon: ICON,\n css,\n label: () => deps.tt('entry.label'),\n tooltip: () => deps.tt('entry.tooltip'),\n onToggle: () => { deps.controller.toggle() },\n position: 'after',\n familySelectors: ['[data-dsh-taskboard-entry]', '[data-dsh-ssh-entry]', '[data-dsh-webchat-entry]'],\n active: {\n subscribe: (listener) => deps.controller.subscribe(listener),\n isOpen: () => deps.controller.getSnapshot().panelOpen,\n },\n })\n}\n","/**\n * Browser-half entry for the dsh-webchat plugin — runs inside the dsh web GUI.\n *\n * Registers the locale dictionaries and mounts the two DOM surfaces: the\n * sidebar entry row (toggles the panel) and the web-chat panel in the center\n * column. Failure policy: DOM mounting problems are logged, never thrown —\n * the web shell fails the whole boot when a plugin apply throws, and an\n * external plugin must not take the GUI down.\n *\n * Export discipline (packages/client rule): the /client surface carries what\n * cordis loading needs plus types only — all value exports stay internal.\n */\nimport type { ClientContext, ISessions, IWorkspaces } from '@deepseek-ai/dsh-client-runtime/client'\n// Type-only: pulls the locale plugin's Context merge (ctx.locale).\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\n// Type-only: pulls the LocaleNamespaceMap merge table.\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport { WebChatApi } from './api.ts'\nimport { PanelController } from './controller.ts'\nimport { en, zh, type WebChatKey } from './locales.ts'\nimport { mountPanel } from './mount.tsx'\nimport { mountSidebarEntry } from './sidebar-entry.ts'\n\n/** Locale namespace this plugin owns. */\nconst NS = 'dsh-webchat'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** dsh-webchat surface copy. */\n 'dsh-webchat': WebChatKey\n }\n}\n\n/** Required services (fiber inject waiting — the runtime must be up first). */\nexport const inject = ['slots', 'locale', 'sessions', 'workspaces']\n\n/** Type-only surface (export discipline: no value exports beyond the plugin contract). */\nexport type { WebChatPanelProps } from './panel/WebChatPanel.tsx'\nexport type { WebChatKey } from './locales.ts'\n\n/**\n * Mount the web-chat panel.\n * @param ctx - client root context (locale + sessions services).\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-webchat: dictionaries')\n\n const controller = new PanelController()\n const api = new WebChatApi()\n // The host-side dsh-session package also merges `Context.sessions` into\n // cordis types; the client runtime's ISessions is the authoritative shape\n // here, so read it through a narrow cast rather than trusting the merged\n // type (which the host package wins during a shared typecheck).\n const sessions = (ctx as unknown as { sessions: ISessions }).sessions\n const workspaces = (ctx as unknown as { workspaces: IWorkspaces }).workspaces\n const tt = ctx.locale.bind(NS)\n const currentCwd = (): string | undefined => {\n const snapshot = sessions.list.getSnapshot()\n const current = snapshot.current\n if (current === undefined) return undefined\n return snapshot.byId[current]?.cwd\n }\n\n const disposers: Array<() => void> = []\n try {\n disposers.push(mountSidebarEntry({ controller, tt }))\n disposers.push(mountPanel({ sessions, workspaces, api, controller, tt, currentCwd }))\n } catch (error) {\n // DOM failures degrade the panel, never the GUI.\n console.warn('[dsh-webchat] mount failed:', error)\n }\n ctx.effect(() => () => {\n for (const dispose of disposers.splice(0)) dispose()\n }, 'dsh-webchat: ui mounts')\n}\n"],"mappings":"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"}