@max-null/dsh-node-appearance 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -5
- package/docs/shots/Turn/346/221/230/350/246/201/346/235/241-/346/224/266/350/265/267.png +0 -0
- package/docs/shots//347/273/204/345/244/264/347/235/200/350/211/262-/345/261/225/345/274/200.png +0 -0
- package/docs/shots//347/273/204/345/244/264/347/235/200/350/211/262-/346/224/266/350/265/267.png +0 -0
- package/docs/shots//350/247/246/345/217/221/345/215/241-/345/261/225/345/274/200.png +0 -0
- package/docs/shots//350/247/246/345/217/221/345/215/241-/346/224/266/350/265/267.png +0 -0
- package/lib/client.js +562 -79
- package/lib/client.js.map +1 -1
- package/lib/index.js +2 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/palette.d.ts +20 -3
- package/lib/types/client/palette.d.ts.map +1 -1
- package/lib/types/client/settings-card.d.ts.map +1 -1
- package/lib/types/client/trigger-card.d.ts +20 -0
- package/lib/types/client/trigger-card.d.ts.map +1 -0
- package/lib/types/client/trigger-model.d.ts +135 -0
- package/lib/types/client/trigger-model.d.ts.map +1 -0
- package/lib/types/index.d.ts +5 -0
- package/lib/types/index.d.ts.map +1 -1
- package/package.json +7 -7
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["useState","css","IconChevronDownOutlineMedium","css","IconCheckOutlineMedium","useMemo","useState","StateDot","IconQuestionOutlineMedium","DisclosureRow","IconInspectOutlineMedium","css","useState","DisclosureRow","StateDot","IconInspectOutlineMedium","css","useState","IconGoalOutlineMedium","IconChevronUpOutlineMedium","IconChevronDownOutlineMedium"],"sources":["../src/client/palette.ts","../src/client/settings-card.tsx","../src/client/ask-model.ts","../src/client/ask-card.tsx","../src/client/deliverable-model.ts","../src/client/deliverable-row.tsx","../src/client/goal-detail.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * Node appearance palette: category/tool mapping, default colors, and the pure\n * CSS-rule generator that paints the chat flow. Browser-half owned; the Host\n * half mirrors the same defaults through its schemastery schema (the two\n * cannot share a value import — the browser bundle purity gate forbids\n * cross-package value imports).\n */\n\n/** The settings namespace this plugin owns (spelled identically in both halves). */\nexport const NODE_APPEARANCE_NS = 'node-appearance'\n\n/** The plugin's style tag identity (removed/replaced on every re-paint). */\nexport const STYLE_TAG_ID = `${NODE_APPEARANCE_NS}/rules`\n\n/** One paintable node category. `command`, `thinking`, `context` are non-tool rows. */\nexport type NodeCategory =\n | 'search' | 'agent' | 'execute' | 'file' | 'deliver' | 'task' | 'ask' | 'command' | 'thinking' | 'context' | 'steering' | 'other'\n\n/** Accent color per category (CSS colors). */\nexport type NodeAppearanceColors = Record<NodeCategory, string>\n\n/** The settings value this plugin reads from its namespace scope. */\nexport interface NodeAppearanceSettings {\n /** Show assistant reasoning blocks as Think rows; false hides them. */\n showThinking?: boolean | undefined\n /** Per-category accent colors; missing keys fall back to defaults. */\n colors?: Partial<NodeAppearanceColors> | undefined\n /** Per-tool accent overrides keyed by wire tool name. */\n toolColors?: Record<string, string> | undefined\n}\n\n/** Initial palette: mid-luminance hues readable on both light and dark themes. */\nexport const DEFAULT_COLORS: NodeAppearanceColors = {\n search: '#3b82f6', // blue — web_search / web_fetch\n agent: '#a855f7', // purple — subagent / workflow / send_message …\n execute: '#f59e0b', // amber — bash / pwsh / run_code / terminal_*\n file: '#22c55e', // green — read / write / edit / glob / grep\n deliver: '#06b6d4', // cyan — present 交付文件行。独立于 file:生成文件的那些行与交付行常在同一轮同屏出现,共用绿色分不清谁是谁(用户反馈)\n task: '#ec4899', // pink — todo_write / goal / job_* / schedule_*\n ask: '#65a30d', // lime — ask_user_question 提问卡(取作 --ask-accent;色相落在 execute 琥珀与 file 绿之间的空档,与 search 的蓝区分开)\n command: '#f97316', // orange — /command nodes\n thinking: '#c4b5fd', // light purple — Think rows\n context: '#8a9bb5', // slate blue — injected context rows (informational)\n steering: '#14b8a6', // teal — steering rows (rc.8)\n other: '#64748b', // slate — every unlisted tool\n}\n\n/** Wire tool name → category for the shipped mapping. */\nexport const TOOL_CATEGORIES: Record<Exclude<NodeCategory, 'command' | 'thinking' | 'context' | 'steering'>, readonly string[]> = {\n search: ['web_search', 'web_fetch'],\n agent: ['subagent', 'subagent_acp', 'subagent_fork', 'send_message', 'interrupt_agent', 'list_agents', 'report', 'workflow'],\n execute: ['bash', 'pwsh', 'run_code', 'terminal_open', 'terminal_close', 'terminal_list', 'terminal_read', 'terminal_send', 'terminal_signal', 'str_replace_editor'],\n file: ['read', 'write', 'edit', 'read_image', 'glob', 'grep'],\n deliver: ['present'],\n task: ['todo_write', 'create_goal', 'get_goal', 'update_goal', 'job_kill', 'job_list', 'job_output', 'schedule_create', 'schedule_delete', 'schedule_list', 'exit_plan_mode'],\n ask: ['ask_user_question'],\n other: [],\n}\n\n/** Selector matching every tool row inside a tool-call node. */\nconst TOOL_ROW = '[data-chat-flow-kind=\"tool-call\"] [data-tool]'\n/** The ToolRow root itself (carries data-variant; the wrapper callRow does not). */\nconst TOOL_ROW_ROOT = '[data-chat-flow-kind=\"tool-call\"] [data-tool][data-variant]'\n/** Selector of the command node wrapper. */\nconst COMMAND_ROW = '[data-chat-flow-kind=\"command\"]'\n/** Selector of the Think reasoning row. */\nconst THINK_ROW = '[data-variant=\"think\"]'\n/** Selector of the injected-context row (the flow-item wrapper). */\nconst CONTEXT_ROW = '[data-chat-flow-kind=\"context\"]'\n/** Selector of a settled tool-result row (rc.8: tool results render as their own row). */\nconst TOOL_RESULT_ROW = '[data-chat-flow-kind=\"tool-result\"]'\n\n/**\n * The rows that carry the accent paint: the ToolRow root (not its wrapper\n * callRow — both carry data-tool, only the inner row carries data-variant),\n * command nodes, Think rows, injected-context rows, and tool-result rows.\n * User input rows are excluded — right-alignment already\n * distinguishes them (2026-08-20 用户反馈);steering rows 也走独立规则\n * (见 buildCss:在 userStack 层做 wash,不涂整行 rail)。\n * The 3px inset rail is compensated\n * with a matching padding-left so the rail never covers the row's leading icon.\n */\nconst ACCENTED_ROWS = [\n TOOL_ROW_ROOT, COMMAND_ROW, THINK_ROW, CONTEXT_ROW, TOOL_RESULT_ROW,\n].join(',\\n')\n\n/**\n * Accept a configured CSS color (hex, color functions) or reject it so an\n * invalid value falls back to the category default instead of poisoning CSS.\n * @param value - configured color string.\n * @returns whether the value is a plausible CSS color literal.\n */\nexport function isCssColor(value: string): boolean {\n const trimmed = value.trim()\n if (trimmed === '') return false\n if (/^#[0-9a-f]{3,8}$/i.test(trimmed)) return true\n return /^(rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch|color|device-cmyk)\\(/i.test(trimmed)\n}\n\n/** Resolve the effective palette from user settings merged over defaults. */\nexport function resolveColors(settings: NodeAppearanceSettings): NodeAppearanceColors {\n const colors: NodeAppearanceColors = { ...DEFAULT_COLORS }\n const configured = settings.colors\n if (configured !== undefined && typeof configured === 'object' && configured !== null) {\n for (const key of Object.keys(DEFAULT_COLORS) as NodeCategory[]) {\n const value = configured[key]\n if (typeof value === 'string' && isCssColor(value)) colors[key] = value\n }\n }\n return colors\n}\n\n/** Escape a tool name into a CSS attribute selector string literal. */\nfunction attributeLiteral(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')\n}\n\n/**\n * Steering marker icon: a corner-up-left arrow (mid-turn guidance inserted\n * into the running answer), drawn as a mask so the icon inherits the\n * configured steering color. Encoded data URI, no external asset.\n */\nconst STEERING_ICON = \"data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 14 4 9 9 4'/%3E%3Cpath d='M20 20v-7a4 4 0 0 0-4-4H4'/%3E%3C/svg%3E\"\n\n/**\n * Build the complete stylesheet text for one settings snapshot.\n * @param settings - the namespace scope value (may be partial or undefined).\n * @returns CSS text painting accent rows and (optionally) hiding Think rows.\n */\nexport function buildCss(settings: NodeAppearanceSettings | undefined): string {\n const colors = resolveColors(settings ?? {})\n const toolOverrides = settings?.toolColors\n const lines: string[] = []\n\n // Unlisted tools keep the neutral fallback. Declared BEFORE the per-tool\n // rules: both selectors carry equal specificity (two attribute selectors),\n // so of two conflicting declarations the later one wins — a fallback\n // declared after the category rules would override every category color.\n lines.push(`${TOOL_ROW} { --ncolor-accent: ${colors.other}; }`)\n\n // Per-tool accent assignments (explicit overrides win over category color).\n for (const [category, tools] of Object.entries(TOOL_CATEGORIES)) {\n const key = category as keyof typeof TOOL_CATEGORIES\n for (const tool of tools) {\n const override = toolOverrides?.[tool]\n const color = typeof override === 'string' && isCssColor(override)\n ? override\n : colors[key]\n lines.push(`[data-chat-flow-kind=\"tool-call\"] [data-tool=\"${attributeLiteral(tool)}\"] { --ncolor-accent: ${color}; }`)\n }\n }\n\n // Non-tool accent rows.\n lines.push(`${COMMAND_ROW} { --ncolor-accent: ${colors.command}; }`)\n lines.push(`${THINK_ROW} { --ncolor-accent: ${colors.thinking}; }`)\n lines.push(`${CONTEXT_ROW} { --ncolor-accent: ${colors.context}; }`)\n lines.push(`${TOOL_RESULT_ROW} { --ncolor-accent: ${colors.file}; }`)\n\n // One shared paint rule: 3px inset left rail (layout-free) + 8% wash. The\n // matching padding-left moves the row content off the rail so the leading\n // icon is never covered.\n lines.push(`${ACCENTED_ROWS} {\n box-shadow: inset 3px 0 0 var(--ncolor-accent);\n background-color: color-mix(in srgb, var(--ncolor-accent) 8%, transparent);\n padding-left: 3px;\n}`)\n\n // Steering rows (mid-turn user steering) stay visually distinct from plain\n // user rows with a compass marker beside the right-aligned bubble. The\n // marker is a mask over the user-stack — the container that hugs the bubble\n // — positioned to the left of it, so the tint reads as a glyph next to the\n // message rather than a detached full-width rail (2026-08-21 用户反馈:\n // 整行 rail 突兀,改在 userStack 层做图标区分;slot 方案不可行:\n // conversation.message.images 是 single 槽且已被官方 ui-attachment 占用).\n // alpha.2 锚点迁移(2026-08-31):消息行\"时间悬浮\"标识 data-time-hover-root\n // 已被 TurnTail/MessageItem 的 data-actions-reveal(always|hover)取代;\n // kind 与 首子=userStack 结构不变(ChatNodeSeat L206 / MessageItem L178 验证)。\n lines.push(`[data-chat-flow-kind=\"steering\"] [data-actions-reveal] > :first-child {\n position: relative;\n}`)\n lines.push(`[data-chat-flow-kind=\"steering\"] [data-actions-reveal] > :first-child::before {\n content: '';\n position: absolute;\n right: 100%;\n margin-right: 6px;\n top: 50%;\n width: 14px;\n height: 14px;\n transform: translateY(-50%);\n background-color: ${colors.steering};\n -webkit-mask: url(\"${STEERING_ICON}\") center / contain no-repeat;\n mask: url(\"${STEERING_ICON}\") center / contain no-repeat;\n}`)\n\n // Visibility switch: hide Think rows entirely on the frontend. `!important`\n // outranks the module stylesheet's `.root { display: flex }` (same\n // specificity, but the plugin style tag is injected before the module's).\n if (settings?.showThinking === false) {\n lines.push(`${THINK_ROW} { display: none !important; }`)\n // A think-only node leaves its flowItem seat with zero height: the seat\n // still consumes the column's 16px flex gap on both sides, doubling the\n // spacing between the neighbors. Hide the whole seat when the think row\n // is the only child of its block container — block-internal thinks\n // (text + reasoning in one node) stay gap-neutral after hiding the row.\n lines.push(\n `[data-chat-flow-kind=\"assistant\"]:has(${THINK_ROW}:only-child),`,\n `[data-chat-flow-kind=\"assistant-step\"]:has(${THINK_ROW}:only-child) { display: none !important; }`,\n )\n }\n\n return lines.join('\\n')\n}\n","/**\n * The node-appearance plugin config card. Mirrors the official\n * `settings.plugin.item` card chrome (PluginCard: card shell, name-over-\n * description header, chevron disclosure) with the DSH design tokens —\n * drawn by hand because a feature plugin must not runtime-import another\n * feature plugin's values (bundle purity gate).\n *\n * Writes are immediate: picking a color or flipping the Think switch applies\n * it right away (a palette is a live preview, not a staged form). The footer\n * carries one「恢复初始设置」button that resets the whole namespace to the\n * shipped defaults — two-click confirmation so a miss cannot wipe a custom\n * palette.\n */\n\nimport { useState, type ChangeEvent, type FormEvent } from 'react'\nimport type { ObservableSnapshot } from '@deepseek-ai/dsh-client-store'\nimport type { ConfigFormSnapshot } from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { IconChevronDownOutlineMedium } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { InjectFace, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: the Plugins page's SlotMap merge (the `plugins.bundle.config` entry).\nimport type {} from '@deepseek-ai/dsh-client-ui-plugin-manager/client'\nimport {\n DEFAULT_COLORS, isCssColor, resolveColors, TOOL_CATEGORIES,\n type NodeAppearanceSettings, type NodeCategory,\n} from './palette.ts'\nimport css from './card.module.css'\n\n/** The card's inject face: the read-only form snapshot plus write actions. */\nexport interface NodeAppearanceRowFace {\n hooks: {\n /** The bound configuration-form snapshot, rendered as useNodeAppearance. */\n nodeAppearance: ObservableSnapshot<ConfigFormSnapshot<NodeAppearanceSettings>>\n }\n /** Persist one full value (reset-to-defaults path; resolves on Host settlement). */\n apply(value: NodeAppearanceSettings): Promise<void>\n /** Write the Think visibility switch. */\n setShowThinking(show: boolean): void\n /** Merge one category color into the palette section. */\n setCategoryColor(category: NodeCategory, color: string): void\n /** Merge one tool override into the toolColors section. */\n setToolColor(tool: string, color: string): void\n /** Remove one tool override. */\n removeToolColor(tool: string): void\n}\n\n/** Props the renderer binds for this plugin config card. */\nexport type NodeAppearanceRowProps =\n PropsRuntime<'plugins.bundle.config'>\n & InjectFace<NodeAppearanceRowFace>\n\n/** Chinese labels per category (product copy is Chinese). */\nconst CATEGORY_LABELS: Record<NodeCategory, string> = {\n search: '联网搜索',\n agent: '智能体调用',\n execute: '代码 / 指令执行',\n file: '文件操作',\n deliver: '交付文件',\n task: '任务 / 目标',\n ask: '提问卡片',\n command: '指令节点',\n thinking: '思考过程',\n context: '上下文注入',\n steering: '模型引导',\n other: '其他工具',\n}\n\n/** Tools shown in the add-override autocomplete-free text input placeholder. */\nconst TOOL_SUGGESTIONS = Object.values(TOOL_CATEGORIES).flat().join('、')\n\n/** The card copy (one locale). */\nconst COPY = {\n title: '节点外观',\n description: '消息节点外观与颜色的偏好设置',\n reset: '恢复初始设置',\n resetConfirm: '再次点击确认恢复',\n resetting: '恢复中…',\n readOnly: '配置只读:插件主机侧未挂载或连接非本机。',\n loading: '配置加载中…',\n showThinking: '显示思考过程',\n showThinkingHint: '关闭后会话中的 Think 思考行隐藏',\n toolColors: '工具颜色覆盖(可选)',\n addTool: '添加',\n removeTool: '删除',\n}\n\n/** The shipped defaults, one face call away from any custom palette. */\nconst INITIAL_SETTINGS: NodeAppearanceSettings = {\n showThinking: true,\n colors: DEFAULT_COLORS,\n toolColors: {},\n}\n\n/**\n * Render the node-appearance config card.\n * @param props - the injected scope snapshot hook, its write actions.\n * @returns the card, matching the official plugin-card chrome.\n */\nexport function NodeAppearanceRow({ useNodeAppearance, apply, setShowThinking, setCategoryColor, setToolColor, removeToolColor }: NodeAppearanceRowProps) {\n // 默认展开:卡片是插件页上唯一承载本插件设置的位置,折叠态会让用户以为\n // 「设置不见了」(2026-09-26 用户反馈)。折叠仍可手动收起。\n const [open, setOpen] = useState(true)\n const [confirmReset, setConfirmReset] = useState(false)\n const [resetting, setResetting] = useState(false)\n const [toolName, setToolName] = useState('')\n const [toolColor, setToolColorDraft] = useState('#64748b')\n const snapshot = useNodeAppearance(snapshot => snapshot)\n const served = snapshot.value ?? {}\n const colors = resolveColors(served)\n const toolColors = served.toolColors ?? {}\n const showThinking = served.showThinking ?? true\n const disabled = snapshot.writable === false\n const unavailable = snapshot.status !== 'ready'\n\n const resetInitial = async (): Promise<void> => {\n if (resetting) return\n setResetting(true)\n try {\n await apply(INITIAL_SETTINGS)\n setConfirmReset(false)\n } catch {\n // A refused reset just leaves the current palette in place.\n } finally {\n setResetting(false)\n }\n }\n\n const handleReset = (): void => {\n if (confirmReset) {\n void resetInitial()\n } else {\n setConfirmReset(true)\n }\n }\n\n const addTool = (event: FormEvent): void => {\n event.preventDefault()\n const name = toolName.trim()\n if (name === '' || !isCssColor(toolColor)) return\n setToolColor(name, toolColor)\n setToolName('')\n }\n\n return (\n <li className={css.card + (open ? ' ' + css.cardOpen : '')}>\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={open}\n aria-label={`${open ? '收起' : '展开'}:${COPY.title}`}\n onClick={() => { setOpen(!open) }}\n >\n <span className={css.headText}>\n <span className={css.name}>{COPY.title}</span>\n <span className={css.description}>{COPY.description}</span>\n </span>\n <IconChevronDownOutlineMedium className={css.chevron + (open ? ' ' + css.chevronOpen : '')} />\n </button>\n {open && (\n <div className={css.body}>\n {unavailable && !disabled && <p className={css.statusLine}>{COPY.loading}</p>}\n {disabled && <p className={css.readOnly} role=\"status\">{COPY.readOnly}</p>}\n <div className={disabled ? css.disabled : ''}>\n <div className={css.row}>\n <label className={css.rowLabel} htmlFor=\"node-appearance-show-thinking\">{COPY.showThinking}</label>\n <span className={css.rowHint}>{COPY.showThinkingHint}</span>\n <button\n id=\"node-appearance-show-thinking\"\n className={css.switch + (showThinking ? ' ' + css.on : '')}\n type=\"button\"\n aria-pressed={showThinking}\n onClick={() => { setShowThinking(!showThinking) }}\n >\n <span className={css.knob} />\n </button>\n </div>\n {(Object.keys(CATEGORY_LABELS) as NodeCategory[]).map(category => (\n <div className={css.row} key={category}>\n <label className={css.rowLabel} htmlFor={`node-appearance-color-${category}`}>{CATEGORY_LABELS[category]}</label>\n <input\n id={`node-appearance-color-${category}`}\n className={css.colorInput}\n type=\"color\"\n value={colors[category]}\n onChange={(event: ChangeEvent<HTMLInputElement>) => { setCategoryColor(category, event.target.value) }}\n />\n <span className={css.colorValue}>{colors[category]}</span>\n </div>\n ))}\n <div className={css.sectionTitle}>{COPY.toolColors}</div>\n {Object.entries(toolColors).map(([tool, color]) => (\n <div className={css.row} key={tool}>\n <span className={css.toolName} title={tool}>{tool}</span>\n <input\n className={css.colorInput}\n type=\"color\"\n value={isCssColor(color) ? color : DEFAULT_COLORS.other}\n onChange={(event: ChangeEvent<HTMLInputElement>) => { setToolColor(tool, event.target.value) }}\n />\n <button type=\"button\" className={css.removeButton} onClick={() => { removeToolColor(tool) }}>{COPY.removeTool}</button>\n </div>\n ))}\n <form className={css.addRow} onSubmit={addTool}>\n <input\n className={css.toolInput}\n type=\"text\"\n placeholder={`工具名,如 ${TOOL_SUGGESTIONS}`}\n value={toolName}\n onChange={(event: ChangeEvent<HTMLInputElement>) => { setToolName(event.target.value) }}\n />\n <input className={css.colorInput} type=\"color\" value={toolColor} onChange={(event: ChangeEvent<HTMLInputElement>) => { setToolColorDraft(event.target.value) }} />\n <button type=\"submit\" className={css.addButton} disabled={toolName.trim() === ''}>{COPY.addTool}</button>\n </form>\n </div>\n <div className={css.footer}>\n <button\n type=\"button\"\n className={css.reset + (confirmReset ? ' ' + css.resetConfirm : '')}\n disabled={resetting}\n onClick={handleReset}\n >{resetting ? COPY.resetting : confirmReset ? COPY.resetConfirm : COPY.reset}</button>\n </div>\n </div>\n )}\n </li>\n )\n}\n","/**\n * 提问卡数据派生:把一次 `ask_user_question` 调用还原成「问题 + 全部选项 +\n * 实际选中项」。\n *\n * 为什么要自己解析:DSH 官方的转录卡只保留**已选答案**\n * (`ui-tool/src/client/tool/toolviews/ask-question-row.tsx` 的\n * `questionEntries()` 只取 `id`/`question`,把 `options` 丢掉了),所以提问\n * 结算后「当时还有哪些选项」在客户端管线上就没了。选项列表只存在于调用的\n * 参数 JSON 里 —— 这也是本插件接管 `ask_user_question` toolview 的唯一原因。\n *\n * 本模块是纯函数:不碰 locale、不碰 DOM,解析失败一律降级而不是抛错\n * (接管后卡片由我们渲染,渲染不出来就等于用户什么都看不到)。\n */\n\n/** 模型给出的一个可选项。 */\nexport interface AskOption {\n /** 选项文本;同时是被 `selected` 回传的那个值。 */\n label: string\n /** 选项下方的补充说明,模型没给时为空。 */\n description: string\n}\n\n/** 一个问题:全部选项 + 实际回答。 */\nexport interface AskQuestion {\n id: string\n question: string\n /** 可选的短标题(模型提供时显示在问题上方)。 */\n header: string\n /** 可选的补充说明。 */\n detail: string\n /** 模型是否允许多选。 */\n multiSelect: boolean\n /** 模型当时给出的全部选项;调用没带选项时为空数组。 */\n options: AskOption[]\n /** 被选中的选项文本,按回答记录的顺序。 */\n selected: string[]\n /** 直接输入的文本答案(没选选项或额外补充时)。 */\n custom: string\n}\n\n/** 行的运行状态,与通用工具行保持同一套词汇。 */\nexport type AskRowState = 'running' | 'ok' | 'error' | 'stopped'\n\n/** 问题集的结算程度。 */\nexport type AskPhase = 'pending' | 'answered' | 'unanswered'\n\n/** 卡片渲染所需的全部派生结果。 */\nexport interface AskCardModel {\n state: AskRowState\n phase: AskPhase\n /** 被取消或被中断时记录判定来源;正常结算为 undefined。 */\n verdict: 'cancelled' | 'aborted' | undefined\n questions: AskQuestion[]\n /** 至少选了选项或填了自定义答案的问题数(折叠行的 N/M 用)。 */\n answeredCount: number\n /**\n * 参数 JSON 解析不出来时用于兜底展示的结果文本;运行中或结果无文本时为\n * null。没有它,一次畸形调用会让接管后的行变成空白。\n */\n fallbackText: string | null\n}\n\n/**\n * `ask_user_question` 的 block 里本卡读到的字段子集。\n * 结构照 DSH 的 `ToolCallBlock`(运行中=调用自身,结算后=带 `kind` 的结果\n * 节点)声明为鸭子类型:跨插件只允许 type-only 引用,这里连类型引用都不需要。\n */\nexport interface AskToolBlock {\n /** 运行中的调用没有这个字段;结算后为 `'tool-result'`。 */\n kind?: string | undefined\n callId?: string | undefined\n /** 运行中形态:调用自身携带参数。 */\n argsRaw?: string | undefined\n /** 结算形态:调用头(子调用被剥掉时为 null)。 */\n call?: { argsRaw?: string | undefined } | null | undefined\n /** 结算形态:结果内容块。 */\n content?: readonly unknown[] | undefined\n error?: { code?: string | undefined } | undefined\n isError?: boolean | undefined\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/** 读一个字符串字段,非字符串一律当空串。 */\nfunction text(value: unknown): string {\n return typeof value === 'string' ? value : ''\n}\n\nfunction parseJson(source: string): unknown {\n try {\n return JSON.parse(source)\n } catch {\n // 流式截断的半截 JSON 是正常现象:降级为「无问题」,由调用方兜底展示原文。\n return undefined\n }\n}\n\n/** 从结果内容块拼出展示文本(文本块原样、其余块转 JSON)。 */\nexport function resultTextOf(block: AskToolBlock): string | null {\n const content = block.content\n if (!Array.isArray(content) || content.length === 0) return null\n const parts: string[] = []\n for (const part of content) {\n if (isRecord(part) && part.type === 'text' && typeof part.text === 'string') parts.push(part.text)\n else parts.push(JSON.stringify(part, null, 2))\n }\n return parts.length === 0 ? null : parts.join('\\n')\n}\n\n/** 参数 JSON 里的原始问题(未经回答配对)。 */\ninterface RawQuestion {\n id: string\n question: string\n header: string\n detail: string\n multiSelect: boolean\n options: AskOption[]\n}\n\nfunction readOptions(value: unknown): AskOption[] {\n if (!Array.isArray(value)) return []\n const options: AskOption[] = []\n for (const item of value) {\n if (typeof item === 'string') {\n // 宽容形态:模型偶尔直接给字符串数组而不是 {label} 对象。\n if (item !== '') options.push({ label: item, description: '' })\n continue\n }\n if (!isRecord(item)) continue\n const label = text(item.label)\n if (label === '') continue\n options.push({ label, description: text(item.description) })\n }\n return options\n}\n\n/** 读调用参数里的问题列表;拿不到合法问题时返回 null(由调用方兜底)。 */\nfunction readQuestions(argsRaw: string): RawQuestion[] | null {\n const parsed = parseJson(argsRaw)\n if (!isRecord(parsed) || !Array.isArray(parsed.questions)) return null\n const questions: RawQuestion[] = []\n for (const item of parsed.questions) {\n if (!isRecord(item)) continue\n const question = text(item.question)\n if (question === '') continue\n questions.push({\n id: text(item.id),\n question,\n header: text(item.header),\n detail: text(item.detail),\n multiSelect: item.multiSelect === true,\n options: readOptions(item.options),\n })\n }\n return questions.length === 0 ? null : questions\n}\n\n/** 一条回答记录。 */\ninterface RawAnswer {\n id: string\n selected: string[]\n custom: string\n}\n\nfunction readAnswers(resultText: string | null): RawAnswer[] | null {\n if (resultText === null) return null\n const parsed = parseJson(resultText)\n if (!isRecord(parsed) || !Array.isArray(parsed.answers)) return null\n const answers: RawAnswer[] = []\n for (const item of parsed.answers) {\n if (!isRecord(item)) continue\n const selected = Array.isArray(item.selected)\n ? item.selected.filter((v): v is string => typeof v === 'string')\n : []\n answers.push({ id: text(item.id), selected, custom: text(item.custom) })\n }\n return answers\n}\n\n/** 调用参数:运行中取 block 自身,结算后取结算节点的调用头。 */\nfunction argsRawOf(block: AskToolBlock): string {\n return 'kind' in block ? block.call?.argsRaw ?? '' : block.argsRaw ?? ''\n}\n\n/**\n * 从一次提问调用的冻结切片派生卡片模型。\n * @param block - 运行中的调用或已结算的结果节点。\n * @returns 卡片模型;参数或结果畸形时 `questions` 为空并带兜底文本。\n */\nexport function askCardModel(block: AskToolBlock): AskCardModel {\n const settled = 'kind' in block\n const code = settled ? block.error?.code : undefined\n // Composer 的两种判定自带专用 error code,不能按通用失败处理:用户自己\n // 取消(ASK_CANCELLED)是一次正常结算,中断(ASK_ABORTED)沿用其他被中断\n // 工具调用的 amber「已停止」语义 —— 与官方 ask-question-row 的 state 覆盖\n // 逐条一致。\n const state: AskRowState = !settled ? 'running'\n : code === 'ASK_ABORTED' || code === 'interrupted' ? 'stopped'\n : code === 'ASK_CANCELLED' ? 'ok'\n : block.isError === true ? 'error' : 'ok'\n const argsRaw = argsRawOf(block)\n const resultText = settled ? resultTextOf(block) : null\n\n // 判定来源优先于结算形态:Composer 取消 / 回合中断都会带自己的 error code,\n // 此时结果里没有答案,但仍应列出问题本身(与官方转录卡的语义一致)。\n let verdict: AskCardModel['verdict']\n let phase: AskPhase\n if (code === 'ASK_CANCELLED') {\n verdict = 'cancelled'\n phase = 'unanswered'\n } else if (code === 'ASK_ABORTED') {\n verdict = 'aborted'\n phase = 'unanswered'\n } else if (!settled) {\n phase = 'pending'\n } else {\n phase = resultText === null ? 'unanswered' : 'answered'\n }\n\n const raw = readQuestions(argsRaw)\n if (raw === null) {\n return {\n state, phase, verdict, questions: [], answeredCount: 0,\n fallbackText: resultText ?? (argsRaw === '' ? null : argsRaw),\n }\n }\n\n // 回答按 id 配对;配不上的问题保留全部选项、标记为未选 —— 官方在严格配对\n // 失败时整卡降级,这里宁可少标一个\"已选\"也不丢掉用户想看的选项列表。\n const byId = new Map<string, RawAnswer>()\n for (const answer of readAnswers(resultText) ?? []) {\n if (!byId.has(answer.id)) byId.set(answer.id, answer)\n }\n const questions: AskQuestion[] = raw.map(question => {\n const answer = byId.get(question.id)\n return {\n ...question,\n selected: answer?.selected ?? [],\n custom: answer?.custom ?? '',\n }\n })\n const answeredCount = questions\n .filter(question => question.selected.length > 0 || question.custom !== '')\n .length\n return { state, phase, verdict, questions, answeredCount, fallbackText: resultText }\n}\n\n/** 折叠行右侧的进度计数(文案由组件用 locale 组装)。 */\nexport function askProgress(model: AskCardModel): { answered: number; total: number } {\n return { answered: model.answeredCount, total: model.questions.length }\n}\n","/**\n * 提问卡:接管 `ask_user_question` 的工具行。\n *\n * 官方转录卡只列**已选答案**,结算后就再也看不到当时还有哪些选项。本卡片\n * 用调用参数里的 `options` 把每个选项都渲染成一块,被选中的那块用插件色板\n * 里 ask 类别的强调色(默认蓝)反显并打勾。\n *\n * 接管是 DSH 支持的机制(keyed slot 用不同 priority 遮蔽既有占用者,\n * 见 ui-slots 的 `register()`),代价是本文件要自己承担官方 ToolRow 的\n * 折叠行外观 —— 因此行外壳逐项对齐 ToolRow.module.css 的既有视觉\n * (24px 行高、2px 分隔点、13px 次级摘要、running 扫光、hover 才现的\n * Inspect 胶囊),组件则全部来自共享的 ui-primitives。\n */\nimport { useMemo, useState } from 'react'\nimport {\n DisclosureRow, IconCheckOutlineMedium, IconInspectOutlineMedium, IconQuestionOutlineMedium, StateDot,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport { askCardModel, askProgress, type AskCardModel, type AskToolBlock } from './ask-model.ts'\nimport css from './ask-card.module.css'\n\n/** 注入的 locale 翻译函数(注册时声明 `conversation` 命名空间)。 */\nexport interface AskTranslate {\n (key: string, params?: Record<string, string | number>): string\n}\n\n/** 卡片从 slot owner 收到的字段;其余 owner props 与本行无关。 */\nexport interface AskCardProps {\n t: AskTranslate\n block: AskToolBlock\n /** 跳到轨迹视图查看原始调用;缺省时不渲染该入口。 */\n inspect?: (() => void) | undefined\n}\n\n/** 折叠行右侧的摘要:等待 / 已取消 / 已中断 / 未回答 / N-M 已回答。 */\nfunction summaryText(model: AskCardModel, t: AskTranslate): string {\n if (model.phase === 'pending') return t('ask.waiting')\n if (model.phase === 'unanswered') {\n if (model.verdict === 'cancelled') return t('ask.cancelled')\n if (model.verdict === 'aborted') return t('ask.interrupted')\n return t('ask.skipped')\n }\n const { answered, total } = askProgress(model)\n return t('ask.answered', { answered, total })\n}\n\n/** 一行「未选/已选」选项块。 */\nfunction OptionRow({ label, description, chosen }: {\n label: string\n description?: string | undefined\n chosen: boolean\n}) {\n return (\n <div className={css.option} data-chosen={chosen ? '' : undefined}>\n <span className={css.marker} aria-hidden=\"true\">\n {chosen && <IconCheckOutlineMedium />}\n </span>\n <span className={css.optionText}>\n <span className={css.label}>{label}</span>\n {description !== undefined && description !== '' && (\n <span className={css.desc}>{description}</span>\n )}\n </span>\n </div>\n )\n}\n\n/** 展开后的卡片体:逐问题列出全部选项并标出选中项。 */\nfunction QuestionList({ model, t }: { model: AskCardModel; t: AskTranslate }) {\n return (\n <div className={css.card}>\n {model.verdict !== undefined && (\n <p className={css.verdict}>\n {model.verdict === 'cancelled' ? t('ask.cancelledDetail') : t('ask.interruptedDetail')}\n </p>\n )}\n {model.questions.map((question, index) => (\n <div className={css.item} key={question.id !== '' ? question.id : `q${String(index)}`}>\n {question.header !== '' && <div className={css.header}>{question.header}</div>}\n <div className={css.question}>{question.question}</div>\n {question.detail !== '' && <div className={css.detail}>{question.detail}</div>}\n {question.options.length > 0\n ? (\n <div className={css.options}>\n {question.options.map((option, optionIndex) => (\n <OptionRow\n key={`${String(optionIndex)}-${option.label}`}\n label={option.label}\n description={option.description}\n chosen={question.selected.includes(option.label)}\n />\n ))}\n {/* 直接输入的答案不在选项表里,单独补一块,否则这次回答会消失。 */}\n {question.custom !== '' && <OptionRow label={question.custom} chosen />}\n </div>\n )\n : (\n <div className={css.answers}>\n {question.selected.map((answer, answerIndex) => (\n <span className={css.answerLine} key={`${String(answerIndex)}-${answer}`}>{answer}</span>\n ))}\n {question.custom !== '' && <span className={css.answerLine}>{question.custom}</span>}\n {question.selected.length === 0 && question.custom === '' && (\n <span className={css.answersEmpty}>{t('ask.skipped')}</span>\n )}\n </div>\n )}\n </div>\n ))}\n </div>\n )\n}\n\n/**\n * 渲染一次提问的完整记录。\n * @param props - locale 翻译函数、冻结的调用切片与可选的轨迹入口。\n * @returns 折叠行 + 展开后的选项卡片。\n */\nexport function AskQuestionRow({ t, block, inspect }: AskCardProps) {\n const model = useMemo(() => askCardModel(block), [block])\n const [expanded, setExpanded] = useState(false)\n const hasBody = model.questions.length > 0 || model.fallbackText !== null\n const open = expanded && hasBody\n const leading = model.state === 'error'\n ? <StateDot state=\"error\" />\n : model.state === 'stopped'\n ? <StateDot state=\"warning\" />\n : <IconQuestionOutlineMedium />\n return (\n // data-tool / data-variant / data-state 必须保留:插件既有的强调色规则\n // (palette.ts 的 TOOL_ROW_ROOT)与其他行样式都按这三个属性匹配。\n <div className={css.root} data-variant=\"others\" data-tool=\"ask_user_question\" data-state={model.state}>\n <DisclosureRow\n rowClassName={css.row}\n leadingClassName={css.leading}\n titleClassName={css.title}\n chevronClassName={css.chevron}\n icon={leading}\n title={t('ask.rowTitle')}\n open={open}\n expandable={hasBody}\n expandOnRowClick\n keepContentWhenOpen\n onToggle={() => { setExpanded(value => !value) }}\n collapsedContent={(\n <>\n <span className={css.sep} aria-hidden />\n <span className={css.summary}>{summaryText(model, t)}</span>\n </>\n )}\n >\n <div className={css.bodyWrap}>\n {model.questions.length > 0\n ? <QuestionList model={model} t={t} />\n // 参数或结果畸形时的兜底:接管后不渲染就等于用户什么都看不到。\n : <pre className={css.fallback}>{model.fallbackText}</pre>}\n {inspect !== undefined && (\n <button type=\"button\" className={css.inspectButton} onClick={inspect}>\n <IconInspectOutlineMedium />\n {t('row.inspect')}\n </button>\n )}\n </div>\n </DisclosureRow>\n </div>\n )\n}\n","/**\n * 交付行数据派生:把一次 `present` 调用还原成「状态 + 文件清单 + 结果文本」。\n *\n * 为什么要自己解析:官方 PresentRow 的折叠态把全部文件名逗号拼成一行\n * (`ui-deliverables/src/client/PresentRow.tsx` 的 `fileNames()`),多文件时读不完,\n * 也看不出这一轮交付了几个。完整清单只存在于调用的参数 JSON 里,所以折叠摘要与\n * 展开态都得自己解一份。\n *\n * 本模块是纯函数:不碰 locale、不碰 DOM,解析失败一律降级而不是抛错(接管后\n * 行由我们渲染,渲染不出来就等于用户什么都看不到)。\n *\n * 「等 N 个文件」这类摘要文案直写中文,与 goal-detail.tsx 同一取径:本插件不新造\n * locale 命名空间,而官方 deliverables 字典没有「共计 N 个」的 key(`presented.more`\n * 是「+ N 个文件」,用于溢出提示)。行内的标题、状态词与 inspect 仍取自官方字典。\n */\n\n/**\n * 工具调用块里本行取用的字段(照官方 PresentRow 的取用面声明为鸭子类型,\n * 不为此引入 @deepseek-ai/dsh-client-ui-tool 依赖)。\n */\nexport interface DeliverableBlock {\n /** 未结算时参数在块本身;结算后搬到 `call` 上。流式中途可能是截断的 JSON。 */\n argsRaw?: string | undefined\n call?: { argsRaw?: string | undefined } | undefined\n content?: ReadonlyArray<{ type: string, text?: string | undefined }> | undefined\n error?: { name?: string | undefined, code?: string | undefined } | undefined\n isError?: boolean | undefined\n}\n\n/** 交付状态:运行中 / 完成 / 中断 / 出错。 */\nexport type DeliverableState = 'running' | 'ok' | 'stopped' | 'error'\n\n/** 展开态里的一行:文件名、所在目录与扩展名徽标已拆好。 */\nexport interface DeliverableFile {\n /** 参数的完整路径,用于悬停提示。 */\n path: string\n /** 文件名部分(正反斜杠都兼容)。 */\n name: string\n /** 所在目录;纯文件名(没有分隔符)时为空串。 */\n dir: string\n /** 扩展名徽标:大写、至多 4 字符;没有扩展名时为 null。 */\n badge: string | null\n}\n\n/** 交付行渲染需要的全部派生结果。 */\nexport interface DeliverableModel {\n state: DeliverableState\n /** 折叠态摘要:单文件报文件名,多文件报「首个 + 数量」;参数未成形时报参数原文。 */\n summary: string\n /** 逐文件数据;参数未成形时为空数组。 */\n files: DeliverableFile[]\n /** 展开后的结果文本(结果无文本时退回错误描述,再没有则为空串)。 */\n details: string\n /** 结果文本的行数;没有文本时为 0。 */\n lineCount: number\n /** 是否有可展开的内容。 */\n expandable: boolean\n}\n\n/**\n * 从参数 JSON 里取文件路径。\n * 截断的 JSON(调用仍在流式输出)返回 null —— 与官方一致:那时原样显示参数\n * 文本,而不是当成「零个文件」。\n * @param raw - 参数 JSON 原文。\n * @returns 路径数组;JSON 未成形时为 null。\n */\nfunction parsePaths(raw: string): string[] | null {\n let args: unknown\n try {\n args = JSON.parse(raw)\n } catch {\n return null\n }\n if (typeof args !== 'object' || args === null || !('files' in args)) return null\n const files = (args as { files?: unknown }).files\n if (!Array.isArray(files)) return null\n return files.flatMap((file: unknown) => {\n if (typeof file !== 'object' || file === null || !('path' in file)) return []\n const path = (file as { path?: unknown }).path\n return typeof path === 'string' ? [path] : []\n })\n}\n\n/** 最后一个路径分隔符的下标;没有分隔符时为 -1。 */\nfunction separatorAt(path: string): number {\n return Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\\\'))\n}\n\n/** 扩展名徽标:最后一个点之后的部分,过长截断;无扩展名返回 null。 */\nfunction extensionBadge(name: string): string | null {\n const dot = name.lastIndexOf('.')\n if (dot <= 0 || dot === name.length - 1) return null\n const ext = name.slice(dot + 1)\n return (ext.length <= 4 ? ext : ext.slice(0, 4)).toUpperCase()\n}\n\n/** 拆一行:路径 → 文件名 + 所在目录 + 扩展名徽标。 */\nfunction fileOf(path: string): DeliverableFile {\n const cut = separatorAt(path)\n const name = cut === -1 ? path : path.slice(cut + 1)\n return { path, name, dir: cut === -1 ? '' : path.slice(0, cut), badge: extensionBadge(name) }\n}\n\n/**\n * 折叠态摘要。\n * `paths === null` 表示参数 JSON 未成形,此时按官方做法原样显示参数文本;解析\n * 成功但一个路径都没取到时返回空串,不把 `{\"files\":[]}` 这种原文当摘要抛出去。\n */\nfunction summaryOf(paths: string[] | null, fallback: string): string {\n if (paths === null) return fallback\n const first = paths[0]\n if (first === undefined) return ''\n const name = fileOf(first).name\n return paths.length === 1 ? name : `${name} 等 ${String(paths.length)} 个文件`\n}\n\n/** 结果文本:把结果节点拼成一段;未结算时没有结果。 */\nfunction outputOf(settled: boolean, block: DeliverableBlock): string {\n if (!settled) return ''\n return (block.content ?? [])\n .map(item => item.type === 'text' ? item.text ?? '' : JSON.stringify(item))\n .join('\\n')\n}\n\n/** 错误描述:没有结果文本时的兜底,比整行空白有用。 */\nfunction errorTextOf(error: DeliverableBlock['error']): string {\n if (error === undefined) return ''\n const name = error.name ?? 'error'\n return error.code === undefined ? name : `${name}: ${error.code}`\n}\n\n/**\n * 派生一次交付的全部渲染数据。\n * @param block - 工具调用/结果块。\n * @returns 状态、折叠摘要、逐文件数据与结果文本。\n */\nexport function deliverableModel(block: DeliverableBlock): DeliverableModel {\n const settled = 'kind' in block\n const state: DeliverableState = !settled\n ? 'running'\n : block.error?.code === 'interrupted'\n ? 'stopped'\n : block.isError === true ? 'error' : 'ok'\n const args = (settled ? block.call?.argsRaw : block.argsRaw) ?? ''\n const output = outputOf(settled, block)\n const details = output !== ''\n ? output\n : settled ? errorTextOf(block.error) : ''\n const paths = parsePaths(args)\n const files = paths?.map(fileOf) ?? []\n return {\n state,\n summary: summaryOf(paths, args),\n files,\n details,\n lineCount: details === '' ? 0 : details.split('\\n').length,\n // 比官方宽:官方只在有结果文本时可展开,这里交付了文件也允许展开看清单。\n expandable: files.length > 0 || details !== '',\n }\n}\n","/**\n * 交付行:接管 `present` 的工具行。\n *\n * 官方 PresentRow 是一个 45 行的折叠行:状态点 + 「交付文件」标题 + **逗号拼接\n * 的文件名** + 可展开的结果文本 + inspect 入口。多文件时那串文件名会挤成一行\n * 读不完,也看不出这一轮交付了几个。\n *\n * 本组件保留官方全部信息与交互(四态、状态词、文件名、结果文本、inspect,以及\n * `data-tool=\"present\"` / `data-state` 这两个样式与快照测试的锚点),另加三件:\n * ① 折叠态文件名只报「首个 + 数量」,多文件不再挤成一行;\n * ② 展开态逐文件成行,带扩展名徽标与所在目录;\n * ③ 结果文本标注行数。\n *\n * 全部派生在 deliverable-model.ts 里,本文件只做 JSX。\n *\n * 接管是 DSH 支持的机制(keyed slot 用不同 priority 遮蔽既有占用者,见\n * ui-slots 的 `register()`;官方插件开发 skill:registering an existing key\n * may replace the product's default card)。代价是本文件要自己承担官方行的\n * 折叠外观 —— 因此行外壳逐项对齐 ToolRow.module.css 与同插件的提问卡\n * (24px 行高、2px 分隔点、13px 次级摘要、running 扫光、hover 才现的\n * Inspect 胶囊),组件全部来自共享 ui-primitives。\n *\n * 下载卡片与「打开」菜单不在这里:它们属于 `conversation.chat.turnTail` 槽的\n * Deliverables 网格,与本 toolview 是两个不同的槽,接管互不影响。\n */\nimport { useState } from 'react'\nimport { DisclosureRow, IconInspectOutlineMedium, StateDot } from '@deepseek-ai/dsh-client-ui-primitives'\nimport {\n deliverableModel, type DeliverableBlock, type DeliverableFile, type DeliverableState,\n} from './deliverable-model.ts'\nimport css from './deliverable-row.module.css'\n\n/** 注入的 locale 翻译函数(注册时声明 `deliverables` 命名空间)。 */\nexport interface DeliverableTranslate {\n (key: string, params?: Record<string, string | number>): string\n}\n\n/** 本行从 slot owner 收到的字段;其余 owner props 与本行无关。 */\nexport interface DeliverableRowProps {\n t: DeliverableTranslate\n block: DeliverableBlock\n /** 跳到轨迹视图查看原始调用;缺省时不渲染该入口。 */\n inspect?: (() => void) | undefined\n}\n\n/** 状态点的外观名,四态映射与官方 PresentRow 一致。 */\nconst DOT: Record<DeliverableState, 'ongoing' | 'done' | 'warning' | 'error'> = {\n running: 'ongoing',\n ok: 'done',\n stopped: 'warning',\n error: 'error',\n}\n\n/** 逐文件一行:扩展名徽标 + 文件名 + 所在目录(完整路径挂在 title 上)。 */\nfunction FileLine({ file }: { file: DeliverableFile }) {\n return (\n <li className={css.file}>\n {file.badge !== null && <span className={css.ext} aria-hidden>{file.badge}</span>}\n <span className={css.name}>{file.name}</span>\n {file.dir !== '' && <span className={css.path} title={file.path}>{file.dir}</span>}\n </li>\n )\n}\n\n/**\n * 渲染一次交付的完整记录。\n * @param props - locale 翻译函数、调用/结果切片与可选的轨迹入口。\n * @returns 折叠行 + 展开后的文件清单与结果文本。\n */\nexport function DeliverableRow({ t, block, inspect }: DeliverableRowProps) {\n const model = deliverableModel(block)\n const [expanded, setExpanded] = useState(false)\n const open = expanded && model.expandable\n return (\n // data-tool / data-variant / data-state 必须保留:palette.ts 的 TOOL_ROW_ROOT\n // 与其他行样式都按它们匹配(同 ask-card 的约定)。\n <div className={css.root} data-variant=\"others\" data-tool=\"present\" data-state={model.state}>\n <DisclosureRow\n rowClassName={css.row}\n leadingClassName={css.leading}\n titleClassName={css.title}\n chevronClassName={css.chevron}\n icon={<StateDot state={DOT[model.state]} />}\n title={t('row.title')}\n open={open}\n expandable={model.expandable}\n expandOnRowClick\n keepContentWhenOpen\n onToggle={() => { setExpanded(value => !value) }}\n collapsedContent={(\n <>\n <span className={css.sep} aria-hidden />\n <span className={css.summary}>\n <span className={css.state}>{t(`row.${model.state}`)}</span>\n <span className={css.paths}>{model.summary}</span>\n </span>\n </>\n )}\n >\n <div className={css.bodyWrap}>\n {model.files.length > 0 && (\n <ul className={css.files} aria-label={t('presented.all', { count: model.files.length })}>\n {model.files.map((file, index) => (\n <FileLine key={`${String(index)}-${file.path}`} file={file} />\n ))}\n </ul>\n )}\n {model.details !== '' && (\n <>\n {model.files.length > 0 && <div className={css.meta}>{`输出 ${String(model.lineCount)} 行`}</div>}\n <pre className={css.output}>{model.details}</pre>\n </>\n )}\n {inspect !== undefined && (\n <button type=\"button\" className={css.inspectButton} onClick={inspect}>\n <IconInspectOutlineMedium />\n {t('row.inspect')}\n </button>\n )}\n </div>\n </DisclosureRow>\n </div>\n )\n}\n","/**\n * 目标详情折叠条:接在官方 GoalBar 下面(`conversation.input.dock` 里\n * `order: 11`,官方那条是 10),把官方条上被 ellipsis 截断的目标展开成可读\n * 详情。\n *\n * 卡片形态照同槽的待办面板(ui-conversation 的 TodoPanel):同一套 dock 宽度\n * 公式、同一张 `--dsw-specific-tip` 卡片、同一个「标题 + 右侧摘要 + chevron」\n * 折叠头,默认收起。折叠头只放官方条**没有**的元信息(版本号、自主轮次),\n * 目标原文放在展开区 —— 这样两块不会互相重复。\n *\n * 为什么是「另加一条」而不是接管官方条:`conversation.input.dock` 是 list\n * 槽,不同 id 各自成格并列渲染;而官方 ui-goal 的注入面(edit/pause/resume/\n * clear 四个 Remote 动词 + 一个带竞态防护的 activation 订阅源)是**注册者\n * 私有**的,接管就得整套复刻 —— 那会把这个「只读地多看一行」的需求变成\n * 插件里多一处会写会话数据的 RPC 客户端。这里只读 `useProjection('goal')`。\n */\nimport { useEffect, useState } from 'react'\nimport {\n IconChevronDownOutlineMedium, IconChevronUpOutlineMedium, IconGoalOutlineMedium,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ReactNode } from 'react'\nimport css from './goal-detail.module.css'\n\n/** 投影里本卡渲染的字段(照 DSH 的 `GoalSnapshot` 声明为鸭子类型)。 */\nexport interface GoalSnapshotLike {\n id: string\n revision: number\n objective: string\n phase: 'active' | 'paused' | 'blocked' | 'complete'\n /** 自主轮次上限;未设置时为 undefined。 */\n maxGoalRounds?: number | undefined\n /** 已开始的自主轮次;旧快照可能没有该字段。 */\n roundsStarted?: number | undefined\n /** 仅 blocked 阶段存在。 */\n blockedReason?: { code: string; message: string } | undefined\n}\n\n/** `useProjection('goal')` 的返回形状。 */\nexport interface GoalProjectionLike {\n goal: GoalSnapshotLike\n}\n\n/** 本卡从 slot 标准 props 取用的部分(其余 owner props 与本卡无关)。 */\nexport interface GoalDetailProps {\n /** 框架标准投影席位:按 key 读当前会话的投影。 */\n useProjection: (key: string) => GoalProjectionLike | null | undefined\n}\n\n/** 阶段文案:与官方 goal 字典同义,按本插件既有做法直写中文。 */\nconst PHASE_LABEL: Record<GoalSnapshotLike['phase'], string> = {\n active: '进行中',\n paused: '已暂停',\n blocked: '已阻塞',\n complete: '已完成',\n}\n\n/** 折叠头右侧摘要:只放官方条没有的元信息。 */\nfunction summaryLabel(goal: GoalSnapshotLike): string {\n const parts = [`rev ${String(goal.revision)}`]\n if (goal.roundsStarted !== undefined) {\n parts.push(goal.maxGoalRounds === undefined\n ? `${String(goal.roundsStarted)} 轮`\n : `${String(goal.roundsStarted)} / ${String(goal.maxGoalRounds)} 轮`)\n }\n return parts.join('\\u2002·\\u2002')\n}\n\n/** 展开区里的一组「键 / 值」。 */\nfunction Row({ label, children }: { label: string; children: ReactNode }) {\n return (\n <div className={css.row}>\n <dt className={css.key}>{label}</dt>\n <dd className={css.value}>{children}</dd>\n </div>\n )\n}\n\n/**\n * 渲染目标详情折叠条。\n * @param props - 框架标准投影席位。\n * @returns 折叠条;加载中、无目标、或目标已完成时不渲染(与官方条一致)。\n */\nexport function GoalDetail({ useProjection }: GoalDetailProps) {\n const projection = useProjection('goal')\n const [collapsed, setCollapsed] = useState(true)\n const goalId = projection?.goal.id\n\n // 目标换了一个(新建 / 清除后重建)就收起:否则展开态会挂在新目标上。\n useEffect(() => { setCollapsed(true) }, [goalId])\n\n const goal = projection?.goal\n if (goal === undefined || goal === null || goal.phase === 'complete') return null\n\n return (\n <section className={css.root} data-goal-detail aria-label=\"目标详情\">\n <div className={css.body}>\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={!collapsed}\n onClick={() => { setCollapsed(value => !value) }}\n >\n <span className={css.lead} aria-hidden><IconGoalOutlineMedium size={14} /></span>\n <span className={css.title}>目标详情</span>\n <span className={css.summary}>{summaryLabel(goal)}</span>\n <span className={css.chevron} aria-hidden>\n {collapsed ? <IconChevronUpOutlineMedium /> : <IconChevronDownOutlineMedium />}\n </span>\n </button>\n {!collapsed && (\n <dl className={css.detail}>\n <Row label=\"目标\">{goal.objective}</Row>\n <Row label=\"阶段\">{PHASE_LABEL[goal.phase]}</Row>\n {goal.blockedReason !== undefined && (\n <Row label=\"阻塞\">\n {goal.blockedReason.message}\n <span className={css.code}>{goal.blockedReason.code}</span>\n </Row>\n )}\n <Row label=\"标识\">\n <span className={css.code}>{goal.id}</span>\n </Row>\n </dl>\n )}\n </div>\n </section>\n )\n}\n","/**\n * Browser half: binds the `node-appearance` settings scope, paints the chat\n * flow from it (a single <style data-plugin-css> tag rebuilt on every\n * snapshot change), and registers the settings card.\n */\n\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type { ConfigForm } from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: the `ctx.configForms` Context merge, plus the Plugins page's SlotMap\n// merge (the `plugins.bundle.config` entry). Cross-plugin collaboration goes through\n// cordis services; a value import would fail the client bundle-purity gate.\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-plugin-manager/client'\n// Type-only: the ctx.slots Context merge comes from the renderer package\n// (slot registry), not from the removed dsh-client-runtime module.\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport { buildCss, NODE_APPEARANCE_NS, STYLE_TAG_ID, type NodeAppearanceSettings } from './palette.ts'\nimport { NodeAppearanceRow, type NodeAppearanceRowFace } from './settings-card.tsx'\nimport { AskQuestionRow } from './ask-card.tsx'\nimport { DeliverableRow } from './deliverable-row.tsx'\nimport { GoalDetail } from './goal-detail.tsx'\n\nexport const inject = ['slots', 'connection', 'remote', 'configForms']\n\n/** Upsert the plugin's paint stylesheet with the current snapshot's CSS. */\nfunction paint(form: ConfigForm<NodeAppearanceSettings>): void {\n let tag = document.querySelector<HTMLStyleElement>(`style[data-plugin-css=\"${STYLE_TAG_ID}\"]`)\n if (tag === null) {\n tag = document.createElement('style')\n tag.dataset.plugin = NODE_APPEARANCE_NS\n tag.dataset.pluginCss = STYLE_TAG_ID\n document.head.appendChild(tag)\n }\n tag.textContent = buildCss(form.getSnapshot().value)\n}\n\n/**\n * Mount the node-appearance plugin on the page.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n // 0.1.7:`settingsScope` 已从 client 服务面移除(`settingsScope` 在 client 包里\n // 0 命中),取而代之的是官方 ui-settings 提供的 `configForms`。`configForms.get(ns)`\n // 返回的 `ConfigForm<T>` 与旧的 scope 面几乎同形——`getSnapshot()` / `subscribe()` /\n // `set(field, value)` 同名同义,额外提供 `mutate(ops, rev)` 与 `unset(field)`。\n // 参数 ns 是 Host 插件的 entry id(`ConfigForms.get` 的 JSDoc:Unique Host plugin\n // entry id),与本插件的 `cordis.patch.yml` 行 id(`node-appearance`)同值。\n const form = ctx.configForms.get<NodeAppearanceSettings>(NODE_APPEARANCE_NS)\n // Paint once from the current snapshot (defaults before the first Host read).\n paint(form)\n ctx.effect(\n () => form.subscribe(() => { paint(form) }),\n 'dsh-node-appearance: repaint on settings change',\n )\n\n const face: NodeAppearanceRowFace = {\n hooks: { nodeAppearance: form },\n // Staged-edit save: write the three keys in one write.\n //\n // `colors` / `toolColors` 是**对象**字段,不能走 `set(field, value)`——它的\n // JSDoc 写明只接受 scalar field。改用 `mutate()` 的路径操作:`SettingsPathOpView`\n // 是 `{ op: 'set'; path: string[]; value }`,其注释说明写入会「creating\n // intermediate objects」,所以 `['colors']` 整个子树可以一次写掉。\n apply: async (value) => {\n await form.mutate([\n { op: 'set', path: ['showThinking'], value: value.showThinking ?? true },\n { op: 'set', path: ['colors'], value: value.colors ?? {} },\n { op: 'set', path: ['toolColors'], value: value.toolColors ?? {} },\n ] as never)\n },\n setShowThinking: (show) => { void form.set('showThinking', show) },\n setCategoryColor: (category, color) => {\n const value = form.getSnapshot().value\n void form.mutate([\n { op: 'set', path: ['colors'], value: { ...value?.colors, [category]: color } },\n ] as never)\n },\n setToolColor: (tool, color) => {\n const value = form.getSnapshot().value\n void form.mutate([\n { op: 'set', path: ['toolColors'], value: { ...value?.toolColors, [tool]: color } },\n ] as never)\n },\n removeToolColor: (tool) => {\n const value = form.getSnapshot().value\n const toolColors = { ...value?.toolColors }\n delete toolColors[tool]\n void form.mutate([{ op: 'set', path: ['toolColors'], value: toolColors }] as never)\n },\n }\n\n // 0.1.7:卡片挂到 Plugins 页的 `plugins.bundle.config`(旧 `settings.plugin.item`\n // 已不存在——它在 client 包里 0 命中,且替代者 `plugins.item` 按契约注释是\n // 「OCCUPIED by the official settings pages」的官方专区,第三方不该占)。\n // 本插件的 package.json 声明了 `dsh.bundle.patch`,因此它自身就是一个 bundle,\n // key 用**包名**(`config-ledger.ts` 的 `keysOf('plugins.bundle.config')` 直接取\n // `entry.options.key`,而 `plugins.row.config` 才用 `包名#行id`)。\n // 该槽只渲染 `view: 'page'`,卡片在 summary 下返回 null(见 settings-card.tsx)。\n ctx.slots.inject('plugins.bundle.config', () => ctx.slots.register({\n name: 'plugins.bundle.config',\n key: '@max-null/dsh-node-appearance',\n inject: () => face,\n }, NodeAppearanceRow))\n\n // 接管官方提问卡。官方 ui-tool 在 `tool.call.toolview` 的\n // `ask_user_question` key 上有一条 priority 0 的注册,而 keyed cell 只\n // 渲染最低 priority 的条目(ui-slots `register()` 的 shadowing 规则),\n // priority -1 因此遮蔽它——这是 DSH 支持的接管姿势(ui-tool 的 slot 契约\n // 原文:a key the shipped composition already covers is replaced, not shared)。\n //\n // 接管的唯一原因:官方转录卡只保留已选答案,把调用参数里的 `options`\n // 丢掉了,提问一旦结算就再也看不到当时有哪些选项(详见 ask-model.ts)。\n //\n // 类型期放宽同 settings 那条:`tool.call.toolview` 的 SlotMap 声明属于官方\n // @deepseek-ai/dsh-client-ui-tool,本插件不为此引入依赖。\n ctx.slots.inject('tool.call.toolview' as never, () => ctx.slots.register({\n name: 'tool.call.toolview',\n key: 'ask_user_question',\n priority: -1,\n // 复用官方 conversation 字典:卡片文案(提问 / N/M 已回答 / 未回答 /\n // 查看 …)全部取自它,插件不新造 locale 命名空间。\n locale: 'conversation',\n } as never, AskQuestionRow as never))\n\n // 接管官方交付行。姿势与理由同提问卡:ui-deliverables 在 `tool.call.toolview`\n // 的 `present` key 上有一条 priority 0 的注册,keyed cell 只渲染最低 priority\n // 的条目,priority -1 因此遮蔽它。\n //\n // 接管的唯一原因:官方折叠态把全部文件名逗号拼成一行,多文件时读不完,也看不出\n // 这一轮交付了几个(详见 deliverable-row.tsx)。\n ctx.slots.inject('tool.call.toolview' as never, () => ctx.slots.register({\n name: 'tool.call.toolview',\n key: 'present',\n priority: -1,\n // 复用官方 deliverables 字典:「交付文件 / 正在交付 / 已交付 / 交付失败 /\n // 已中断 / 查看调用」全部取自它,插件不新造 locale 命名空间。\n locale: 'deliverables',\n } as never, DeliverableRow as never))\n\n // 目标详情折叠条:挂进输入框上方的 `conversation.input.dock`(list 槽,\n // 不同 id 各自成格、并列渲染),order 11 紧随官方 ui-goal 的 order 10 ——\n // 官方条只显示一行被 ellipsis 截断的目标,这里补一个可展开的详情。\n //\n // 只读 `useProjection('goal')`,不碰官方条的 edit/pause/resume/clear ——\n // 那四个 Remote 动词与 activation 订阅源都是 ui-goal 的注册者私有注入面,\n // 接管它们等于在本插件里再养一套会写会话数据的 RPC 客户端。\n ctx.slots.inject('conversation.input.dock' as never, () => ctx.slots.register({\n name: 'conversation.input.dock',\n id: 'max-null/goal-detail',\n order: 11,\n } as never, GoalDetail as never))\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;EASA,MAAa,qBAAqB;;EAGlC,MAAa,eAAe,GAAG,mBAAmB;;EAoBlD,MAAa,iBAAuC;GAClD,QAAQ;GACR,OAAO;GACP,SAAS;GACT,MAAM;GACN,SAAS;GACT,MAAM;GACN,KAAK;GACL,SAAS;GACT,UAAU;GACV,SAAS;GACT,UAAU;GACV,OAAO;EACT;;EAGA,MAAa,kBAAqH;GAChI,QAAQ,CAAC,cAAc,WAAW;GAClC,OAAO;IAAC;IAAY;IAAgB;IAAiB;IAAgB;IAAmB;IAAe;IAAU;GAAU;GAC3H,SAAS;IAAC;IAAQ;IAAQ;IAAY;IAAiB;IAAkB;IAAiB;IAAiB;IAAiB;IAAmB;GAAoB;GACnK,MAAM;IAAC;IAAQ;IAAS;IAAQ;IAAc;IAAQ;GAAM;GAC5D,SAAS,CAAC,SAAS;GACnB,MAAM;IAAC;IAAc;IAAe;IAAY;IAAe;IAAY;IAAY;IAAc;IAAmB;IAAmB;IAAiB;GAAgB;GAC5K,KAAK,CAAC,mBAAmB;GACzB,OAAO,CAAC;EACV;;EAGA,MAAM,WAAW;;EAEjB,MAAM,gBAAgB;;EAEtB,MAAM,cAAc;;EAEpB,MAAM,YAAY;;EAElB,MAAM,cAAc;;EAEpB,MAAM,kBAAkB;;;;;;;;;;;EAYxB,MAAM,gBAAgB;GACpB;GAAe;GAAa;GAAW;GAAa;EACtD,CAAC,CAAC,KAAK,KAAK;;;;;;;EAQZ,SAAgB,WAAW,OAAwB;GACjD,MAAM,UAAU,MAAM,KAAK;GAC3B,IAAI,YAAY,IAAI,OAAO;GAC3B,IAAI,oBAAoB,KAAK,OAAO,GAAG,OAAO;GAC9C,OAAO,oEAAoE,KAAK,OAAO;EACzF;;EAGA,SAAgB,cAAc,UAAwD;GACpF,MAAM,SAA+B,EAAE,GAAG,eAAe;GACzD,MAAM,aAAa,SAAS;GAC5B,IAAI,eAAe,KAAA,KAAa,OAAO,eAAe,YAAY,eAAe,MAC/E,KAAK,MAAM,OAAO,OAAO,KAAK,cAAc,GAAqB;IAC/D,MAAM,QAAQ,WAAW;IACzB,IAAI,OAAO,UAAU,YAAY,WAAW,KAAK,GAAG,OAAO,OAAO;GACpE;GAEF,OAAO;EACT;;EAGA,SAAS,iBAAiB,OAAuB;GAC/C,OAAO,MAAM,QAAQ,OAAO,MAAM,CAAC,CAAC,QAAQ,MAAM,MAAK;EACzD;;;;;;EAOA,MAAM,gBAAgB;;;;;;EAOtB,SAAgB,SAAS,UAAsD;GAC7E,MAAM,SAAS,cAAc,YAAY,CAAC,CAAC;GAC3C,MAAM,gBAAgB,UAAU;GAChC,MAAM,QAAkB,CAAC;GAMzB,MAAM,KAAK,GAAG,SAAS,sBAAsB,OAAO,MAAM,IAAI;GAG9D,KAAK,MAAM,CAAC,UAAU,UAAU,OAAO,QAAQ,eAAe,GAAG;IAC/D,MAAM,MAAM;IACZ,KAAK,MAAM,QAAQ,OAAO;KACxB,MAAM,WAAW,gBAAgB;KACjC,MAAM,QAAQ,OAAO,aAAa,YAAY,WAAW,QAAQ,IAC7D,WACA,OAAO;KACX,MAAM,KAAK,iDAAiD,iBAAiB,IAAI,EAAE,wBAAwB,MAAM,IAAI;IACvH;GACF;GAGA,MAAM,KAAK,GAAG,YAAY,sBAAsB,OAAO,QAAQ,IAAI;GACnE,MAAM,KAAK,GAAG,UAAU,sBAAsB,OAAO,SAAS,IAAI;GAClE,MAAM,KAAK,GAAG,YAAY,sBAAsB,OAAO,QAAQ,IAAI;GACnE,MAAM,KAAK,GAAG,gBAAgB,sBAAsB,OAAO,KAAK,IAAI;GAKpE,MAAM,KAAK,GAAG,cAAc;;;;EAI5B;GAYA,MAAM,KAAK;;EAEX;GACA,MAAM,KAAK;;;;;;;;;sBASS,OAAO,SAAS;uBACf,cAAc;eACtB,cAAc;EAC3B;GAKA,IAAI,UAAU,iBAAiB,OAAO;IACpC,MAAM,KAAK,GAAG,UAAU,+BAA+B;IAMvD,MAAM,KACJ,yCAAyC,UAAU,gBACnD,8CAA8C,UAAU,2CAC1D;GACF;GAEA,OAAO,MAAM,KAAK,IAAI;EACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC/JA,MAAM,kBAAgD;GACpD,QAAQ;GACR,OAAO;GACP,SAAS;GACT,MAAM;GACN,SAAS;GACT,MAAM;GACN,KAAK;GACL,SAAS;GACT,UAAU;GACV,SAAS;GACT,UAAU;GACV,OAAO;EACT;;EAGA,MAAM,mBAAmB,OAAO,OAAO,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG;;EAGvE,MAAM,OAAO;GACX,OAAO;GACP,aAAa;GACb,OAAO;GACP,cAAc;GACd,WAAW;GACX,UAAU;GACV,SAAS;GACT,cAAc;GACd,kBAAkB;GAClB,YAAY;GACZ,SAAS;GACT,YAAY;EACd;;EAGA,MAAM,mBAA2C;GAC/C,cAAc;GACd,QAAQ;GACR,YAAY,CAAC;EACf;;;;;;EAOA,SAAgB,kBAAkB,EAAE,mBAAmB,OAAO,iBAAiB,kBAAkB,cAAc,mBAA2C;GAGxJ,MAAM,CAAC,MAAM,YAAA,GAAWA,MAAAA,SAAAA,CAAS,IAAI;GACrC,MAAM,CAAC,cAAc,oBAAA,GAAmBA,MAAAA,SAAAA,CAAS,KAAK;GACtD,MAAM,CAAC,WAAW,iBAAA,GAAgBA,MAAAA,SAAAA,CAAS,KAAK;GAChD,MAAM,CAAC,UAAU,gBAAA,GAAeA,MAAAA,SAAAA,CAAS,EAAE;GAC3C,MAAM,CAAC,WAAW,sBAAA,GAAqBA,MAAAA,SAAAA,CAAS,SAAS;GACzD,MAAM,WAAW,mBAAkB,aAAY,QAAQ;GACvD,MAAM,SAAS,SAAS,SAAS,CAAC;GAClC,MAAM,SAAS,cAAc,MAAM;GACnC,MAAM,aAAa,OAAO,cAAc,CAAC;GACzC,MAAM,eAAe,OAAO,gBAAgB;GAC5C,MAAM,WAAW,SAAS,aAAa;GACvC,MAAM,cAAc,SAAS,WAAW;GAExC,MAAM,eAAe,YAA2B;IAC9C,IAAI,WAAW;IACf,aAAa,IAAI;IACjB,IAAI;KACF,MAAM,MAAM,gBAAgB;KAC5B,gBAAgB,KAAK;IACvB,QAAQ,CAER,UAAU;KACR,aAAa,KAAK;IACpB;GACF;GAEA,MAAM,oBAA0B;IAC9B,IAAI,cACF,aAAkB;SAElB,gBAAgB,IAAI;GAExB;GAEA,MAAM,WAAW,UAA2B;IAC1C,MAAM,eAAe;IACrB,MAAM,OAAO,SAAS,KAAK;IAC3B,IAAI,SAAS,MAAM,CAAC,WAAW,SAAS,GAAG;IAC3C,aAAa,MAAM,SAAS;IAC5B,YAAY,EAAE;GAChB;GAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;IAAI,WAAWC,wBAAI,QAAQ,OAAO,MAAMA,wBAAI,WAAW;IAAvD,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;KACE,MAAK;KACL,WAAWA,wBAAI;KACf,iBAAe;KACf,cAAY,GAAG,OAAO,OAAO,KAAK,GAAG,KAAK;KAC1C,eAAe;MAAE,QAAQ,CAAC,IAAI;KAAE;KALlC,UAAA,CAOE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;MAAM,WAAWA,wBAAI;MAArB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,wBAAI;OAAO,UAAA,KAAK;MAAY,CAAA,GAC7C,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,wBAAI;OAAc,UAAA,KAAK;MAAkB,CAAA,CACtD;KACN,CAAA,GAAA,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,8BAAD,EAA8B,WAAWD,wBAAI,WAAW,OAAO,MAAMA,wBAAI,cAAc,IAAM,CAAA,CACvF;IACP,CAAA,GAAA,QACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAWA,wBAAI;KAApB,UAAA;MACG,eAAe,CAAC,YAAY,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAWA,wBAAI;OAAa,UAAA,KAAK;MAAW,CAAA;MAC3E,YAAY,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAWA,wBAAI;OAAU,MAAK;OAAU,UAAA,KAAK;MAAY,CAAA;MACzE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAW,WAAWA,wBAAI,WAAW;OAA1C,UAAA;QACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAWA,wBAAI;SAApB,UAAA;UACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;WAAO,WAAWA,wBAAI;WAAU,SAAQ;WAAiC,UAAA,KAAK;UAAoB,CAAA;UAClG,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;WAAM,WAAWA,wBAAI;WAAU,UAAA,KAAK;UAAuB,CAAA;UAC3D,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;WACE,IAAG;WACH,WAAWA,wBAAI,UAAU,eAAe,MAAMA,wBAAI,KAAK;WACvD,MAAK;WACL,gBAAc;WACd,eAAe;YAAE,gBAAgB,CAAC,YAAY;WAAE;WAEhD,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,WAAWA,wBAAI,KAAO,CAAA;UACtB,CAAA;SACL;;QACH,OAAO,KAAK,eAAe,CAAC,CAAoB,KAAI,aACpD,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAWA,wBAAI;SAApB,UAAA;UACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;WAAO,WAAWA,wBAAI;WAAU,SAAS,yBAAyB;WAAa,UAAA,gBAAgB;UAAiB,CAAA;UAChH,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;WACE,IAAI,yBAAyB;WAC7B,WAAWA,wBAAI;WACf,MAAK;WACL,OAAO,OAAO;WACd,WAAW,UAAyC;YAAE,iBAAiB,UAAU,MAAM,OAAO,KAAK;WAAE;UACtG,CAAA;UACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;WAAM,WAAWA,wBAAI;WAAa,UAAA,OAAO;UAAgB,CAAA;SACtD;QAVyB,GAAA,QAUzB,CACN;QACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;SAAK,WAAWA,wBAAI;SAAe,UAAA,KAAK;QAAgB,CAAA;QACvD,OAAO,QAAQ,UAAU,CAAC,CAAC,KAAK,CAAC,MAAM,WACtC,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAWA,wBAAI;SAApB,UAAA;UACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;WAAM,WAAWA,wBAAI;WAAU,OAAO;WAAO,UAAA;UAAW,CAAA;UACxD,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;WACE,WAAWA,wBAAI;WACf,MAAK;WACL,OAAO,WAAW,KAAK,IAAI,QAAQ,eAAe;WAClD,WAAW,UAAyC;YAAE,aAAa,MAAM,MAAM,OAAO,KAAK;WAAE;UAC9F,CAAA;UACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;WAAQ,MAAK;WAAS,WAAWA,wBAAI;WAAc,eAAe;YAAE,gBAAgB,IAAI;WAAE;WAAI,UAAA,KAAK;UAAmB,CAAA;SACnH;QATyB,GAAA,IASzB,CACN;QACD,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;SAAM,WAAWA,wBAAI;SAAQ,UAAU;SAAvC,UAAA;UACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;WACE,WAAWA,wBAAI;WACf,MAAK;WACL,aAAa,SAAS;WACtB,OAAO;WACP,WAAW,UAAyC;YAAE,YAAY,MAAM,OAAO,KAAK;WAAE;UACvF,CAAA;UACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;WAAO,WAAWA,wBAAI;WAAY,MAAK;WAAQ,OAAO;WAAW,WAAW,UAAyC;YAAE,kBAAkB,MAAM,OAAO,KAAK;WAAE;UAAI,CAAA;UACjK,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;WAAQ,MAAK;WAAS,WAAWA,wBAAI;WAAW,UAAU,SAAS,KAAK,MAAM;WAAK,UAAA,KAAK;UAAgB,CAAA;SACpG;;OACH;;MACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,wBAAI;OAClB,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAWA,wBAAI,SAAS,eAAe,MAAMA,wBAAI,eAAe;QAChE,UAAU;QACV,SAAS;QACT,UAAA,YAAY,KAAK,YAAY,eAAe,KAAK,eAAe,KAAK;OAAc,CAAA;MAClF,CAAA;KACF;IAEL,CAAA,CAAA;;EAER;;;ECjJA,SAAS,SAAS,OAAkD;GAClE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;EAC5E;;EAGA,SAAS,KAAK,OAAwB;GACpC,OAAO,OAAO,UAAU,WAAW,QAAQ;EAC7C;EAEA,SAAS,UAAU,QAAyB;GAC1C,IAAI;IACF,OAAO,KAAK,MAAM,MAAM;GAC1B,QAAQ;IAEN;GACF;EACF;;EAGA,SAAgB,aAAa,OAAoC;GAC/D,MAAM,UAAU,MAAM;GACtB,IAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW,GAAG,OAAO;GAC5D,MAAM,QAAkB,CAAC;GACzB,KAAK,MAAM,QAAQ,SACjB,IAAI,SAAS,IAAI,KAAK,KAAK,SAAS,UAAU,OAAO,KAAK,SAAS,UAAU,MAAM,KAAK,KAAK,IAAI;QAC5F,MAAM,KAAK,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;GAE/C,OAAO,MAAM,WAAW,IAAI,OAAO,MAAM,KAAK,IAAI;EACpD;EAYA,SAAS,YAAY,OAA6B;GAChD,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO,CAAC;GACnC,MAAM,UAAuB,CAAC;GAC9B,KAAK,MAAM,QAAQ,OAAO;IACxB,IAAI,OAAO,SAAS,UAAU;KAE5B,IAAI,SAAS,IAAI,QAAQ,KAAK;MAAE,OAAO;MAAM,aAAa;KAAG,CAAC;KAC9D;IACF;IACA,IAAI,CAAC,SAAS,IAAI,GAAG;IACrB,MAAM,QAAQ,KAAK,KAAK,KAAK;IAC7B,IAAI,UAAU,IAAI;IAClB,QAAQ,KAAK;KAAE;KAAO,aAAa,KAAK,KAAK,WAAW;IAAE,CAAC;GAC7D;GACA,OAAO;EACT;;EAGA,SAAS,cAAc,SAAuC;GAC5D,MAAM,SAAS,UAAU,OAAO;GAChC,IAAI,CAAC,SAAS,MAAM,KAAK,CAAC,MAAM,QAAQ,OAAO,SAAS,GAAG,OAAO;GAClE,MAAM,YAA2B,CAAC;GAClC,KAAK,MAAM,QAAQ,OAAO,WAAW;IACnC,IAAI,CAAC,SAAS,IAAI,GAAG;IACrB,MAAM,WAAW,KAAK,KAAK,QAAQ;IACnC,IAAI,aAAa,IAAI;IACrB,UAAU,KAAK;KACb,IAAI,KAAK,KAAK,EAAE;KAChB;KACA,QAAQ,KAAK,KAAK,MAAM;KACxB,QAAQ,KAAK,KAAK,MAAM;KACxB,aAAa,KAAK,gBAAgB;KAClC,SAAS,YAAY,KAAK,OAAO;IACnC,CAAC;GACH;GACA,OAAO,UAAU,WAAW,IAAI,OAAO;EACzC;EASA,SAAS,YAAY,YAA+C;GAClE,IAAI,eAAe,MAAM,OAAO;GAChC,MAAM,SAAS,UAAU,UAAU;GACnC,IAAI,CAAC,SAAS,MAAM,KAAK,CAAC,MAAM,QAAQ,OAAO,OAAO,GAAG,OAAO;GAChE,MAAM,UAAuB,CAAC;GAC9B,KAAK,MAAM,QAAQ,OAAO,SAAS;IACjC,IAAI,CAAC,SAAS,IAAI,GAAG;IACrB,MAAM,WAAW,MAAM,QAAQ,KAAK,QAAQ,IACxC,KAAK,SAAS,QAAQ,MAAmB,OAAO,MAAM,QAAQ,IAC9D,CAAC;IACL,QAAQ,KAAK;KAAE,IAAI,KAAK,KAAK,EAAE;KAAG;KAAU,QAAQ,KAAK,KAAK,MAAM;IAAE,CAAC;GACzE;GACA,OAAO;EACT;;EAGA,SAAS,UAAU,OAA6B;GAC9C,OAAO,UAAU,QAAQ,MAAM,MAAM,WAAW,KAAK,MAAM,WAAW;EACxE;;;;;;EAOA,SAAgB,aAAa,OAAmC;GAC9D,MAAM,UAAU,UAAU;GAC1B,MAAM,OAAO,UAAU,MAAM,OAAO,OAAO,KAAA;GAK3C,MAAM,QAAqB,CAAC,UAAU,YAClC,SAAS,iBAAiB,SAAS,gBAAgB,YACjD,SAAS,kBAAkB,OACzB,MAAM,YAAY,OAAO,UAAU;GAC3C,MAAM,UAAU,UAAU,KAAK;GAC/B,MAAM,aAAa,UAAU,aAAa,KAAK,IAAI;GAInD,IAAI;GACJ,IAAI;GACJ,IAAI,SAAS,iBAAiB;IAC5B,UAAU;IACV,QAAQ;GACV,OAAO,IAAI,SAAS,eAAe;IACjC,UAAU;IACV,QAAQ;GACV,OAAO,IAAI,CAAC,SACV,QAAQ;QAER,QAAQ,eAAe,OAAO,eAAe;GAG/C,MAAM,MAAM,cAAc,OAAO;GACjC,IAAI,QAAQ,MACV,OAAO;IACL;IAAO;IAAO;IAAS,WAAW,CAAC;IAAG,eAAe;IACrD,cAAc,eAAe,YAAY,KAAK,OAAO;GACvD;GAKF,MAAM,uBAAO,IAAI,IAAuB;GACxC,KAAK,MAAM,UAAU,YAAY,UAAU,KAAK,CAAC,GAC/C,IAAI,CAAC,KAAK,IAAI,OAAO,EAAE,GAAG,KAAK,IAAI,OAAO,IAAI,MAAM;GAEtD,MAAM,YAA2B,IAAI,KAAI,aAAY;IACnD,MAAM,SAAS,KAAK,IAAI,SAAS,EAAE;IACnC,OAAO;KACL,GAAG;KACH,UAAU,QAAQ,YAAY,CAAC;KAC/B,QAAQ,QAAQ,UAAU;IAC5B;GACF,CAAC;GACD,MAAM,gBAAgB,UACnB,QAAO,aAAY,SAAS,SAAS,SAAS,KAAK,SAAS,WAAW,EAAE,CAAC,CAC1E;GACH,OAAO;IAAE;IAAO;IAAO;IAAS;IAAW;IAAe,cAAc;GAAW;EACrF;;EAGA,SAAgB,YAAY,OAA0D;GACpF,OAAO;IAAE,UAAU,MAAM;IAAe,OAAO,MAAM,UAAU;GAAO;EACxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC1NA,SAAS,YAAY,OAAqB,GAAyB;GACjE,IAAI,MAAM,UAAU,WAAW,OAAO,EAAE,aAAa;GACrD,IAAI,MAAM,UAAU,cAAc;IAChC,IAAI,MAAM,YAAY,aAAa,OAAO,EAAE,eAAe;IAC3D,IAAI,MAAM,YAAY,WAAW,OAAO,EAAE,iBAAiB;IAC3D,OAAO,EAAE,aAAa;GACxB;GACA,MAAM,EAAE,UAAU,UAAU,YAAY,KAAK;GAC7C,OAAO,EAAE,gBAAgB;IAAE;IAAU;GAAM,CAAC;EAC9C;;EAGA,SAAS,UAAU,EAAE,OAAO,aAAa,UAItC;GACD,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWE,4BAAI;IAAQ,eAAa,SAAS,KAAK,KAAA;IAAvD,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,WAAWA,4BAAI;KAAQ,eAAY;KACtC,UAAA,UAAU,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,wBAAD,CAAyB,CAAA;IAChC,CAAA,GACN,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;KAAM,WAAWD,4BAAI;KAArB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,4BAAI;MAAQ,UAAA;KAAY,CAAA,GACxC,gBAAgB,KAAA,KAAa,gBAAgB,MAC5C,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,4BAAI;MAAO,UAAA;KAAkB,CAAA,CAE5C;IACH,CAAA,CAAA;;EAET;;EAGA,SAAS,aAAa,EAAE,OAAO,KAA+C;GAC5E,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,4BAAI;IAApB,UAAA,CACG,MAAM,YAAY,KAAA,KACjB,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;KAAG,WAAWA,4BAAI;KACf,UAAA,MAAM,YAAY,cAAc,EAAE,qBAAqB,IAAI,EAAE,uBAAuB;IACpF,CAAA,GAEJ,MAAM,UAAU,KAAK,UAAU,UAC9B,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAWA,4BAAI;KAApB,UAAA;MACG,SAAS,WAAW,MAAM,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,4BAAI;OAAS,UAAA,SAAS;MAAY,CAAA;MAC7E,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,4BAAI;OAAW,UAAA,SAAS;MAAc,CAAA;MACrD,SAAS,WAAW,MAAM,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,4BAAI;OAAS,UAAA,SAAS;MAAY,CAAA;MAC5E,SAAS,QAAQ,SAAS,IAEvB,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,4BAAI;OAApB,UAAA,CACG,SAAS,QAAQ,KAAK,QAAQ,gBAC7B,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD;QAEE,OAAO,OAAO;QACd,aAAa,OAAO;QACpB,QAAQ,SAAS,SAAS,SAAS,OAAO,KAAK;OAChD,GAJM,GAAG,OAAO,WAAW,EAAE,GAAG,OAAO,OAIvC,CACF,GAEA,SAAS,WAAW,MAAM,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD;QAAW,OAAO,SAAS;QAAQ,QAAA;OAAQ,CAAA,CACnE;MAGL,CAAA,IAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,4BAAI;OAApB,UAAA;QACG,SAAS,SAAS,KAAK,QAAQ,gBAC9B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,4BAAI;SAAsD,UAAA;QAAa,GAAlD,GAAG,OAAO,WAAW,EAAE,GAAG,QAAwB,CACzF;QACA,SAAS,WAAW,MAAM,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,4BAAI;SAAa,UAAA,SAAS;QAAa,CAAA;QAClF,SAAS,SAAS,WAAW,KAAK,SAAS,WAAW,MACrD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,4BAAI;SAAe,UAAA,EAAE,aAAa;QAAQ,CAAA;OAE1D;;KAEN;IA9B0B,GAAA,SAAS,OAAO,KAAK,SAAS,KAAK,IAAI,OAAO,KAAK,GA8B7E,CACN,CACE;;EAET;;;;;;EAOA,SAAgB,eAAe,EAAE,GAAG,OAAO,WAAyB;GAClE,MAAM,SAAA,GAAQE,MAAAA,QAAAA,OAAc,aAAa,KAAK,GAAG,CAAC,KAAK,CAAC;GACxD,MAAM,CAAC,UAAU,gBAAA,GAAeC,MAAAA,SAAAA,CAAS,KAAK;GAC9C,MAAM,UAAU,MAAM,UAAU,SAAS,KAAK,MAAM,iBAAiB;GACrE,MAAM,OAAO,YAAY;GACzB,MAAM,UAAU,MAAM,UAAU,UAC5B,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,UAAD,EAAU,OAAM,QAAS,CAAA,IACzB,MAAM,UAAU,YACd,iBAAA,GAAA,kBAAA,IAAA,CAACA,sCAAAA,UAAD,EAAU,OAAM,UAAW,CAAA,IAC3B,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,2BAAD,CAA4B,CAAA;GAClC,OAGE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAWL,4BAAI;IAAM,gBAAa;IAAS,aAAU;IAAoB,cAAY,MAAM;IAC9F,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACM,sCAAAA,eAAD;KACE,cAAcN,4BAAI;KAClB,kBAAkBA,4BAAI;KACtB,gBAAgBA,4BAAI;KACpB,kBAAkBA,4BAAI;KACtB,MAAM;KACN,OAAO,EAAE,cAAc;KACjB;KACN,YAAY;KACZ,kBAAA;KACA,qBAAA;KACA,gBAAgB;MAAE,aAAY,UAAS,CAAC,KAAK;KAAE;KAC/C,kBACE,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,4BAAI;MAAK,eAAA;KAAa,CAAA,GACvC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,4BAAI;MAAU,UAAA,YAAY,OAAO,CAAC;KAAQ,CAAA,CAC3D,EAAA,CAAA;KAGJ,UAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,4BAAI;MAApB,UAAA,CACG,MAAM,UAAU,SAAS,IACtB,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;OAAqB;OAAU;MAAI,CAAA,IAEnC,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,4BAAI;OAAW,UAAA,MAAM;MAAkB,CAAA,GAC1D,YAAY,KAAA,KACX,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;OAAQ,MAAK;OAAS,WAAWA,4BAAI;OAAe,SAAS;OAA7D,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAACO,sCAAAA,0BAAD,CAA2B,CAAA,GAC1B,EAAE,aAAa,CACV;MAEP,CAAA,CAAA;;IACQ,CAAA;GACZ,CAAA;EAET;;;;;;;;;;ECnGA,SAAS,WAAW,KAA8B;GAChD,IAAI;GACJ,IAAI;IACF,OAAO,KAAK,MAAM,GAAG;GACvB,QAAQ;IACN,OAAO;GACT;GACA,IAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,EAAE,WAAW,OAAO,OAAO;GAC5E,MAAM,QAAS,KAA6B;GAC5C,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO;GAClC,OAAO,MAAM,SAAS,SAAkB;IACtC,IAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,EAAE,UAAU,OAAO,OAAO,CAAC;IAC5E,MAAM,OAAQ,KAA4B;IAC1C,OAAO,OAAO,SAAS,WAAW,CAAC,IAAI,IAAI,CAAC;GAC9C,CAAC;EACH;;EAGA,SAAS,YAAY,MAAsB;GACzC,OAAO,KAAK,IAAI,KAAK,YAAY,GAAG,GAAG,KAAK,YAAY,IAAI,CAAC;EAC/D;;EAGA,SAAS,eAAe,MAA6B;GACnD,MAAM,MAAM,KAAK,YAAY,GAAG;GAChC,IAAI,OAAO,KAAK,QAAQ,KAAK,SAAS,GAAG,OAAO;GAChD,MAAM,MAAM,KAAK,MAAM,MAAM,CAAC;GAC9B,QAAQ,IAAI,UAAU,IAAI,MAAM,IAAI,MAAM,GAAG,CAAC,EAAA,CAAG,YAAY;EAC/D;;EAGA,SAAS,OAAO,MAA+B;GAC7C,MAAM,MAAM,YAAY,IAAI;GAC5B,MAAM,OAAO,QAAQ,KAAK,OAAO,KAAK,MAAM,MAAM,CAAC;GACnD,OAAO;IAAE;IAAM;IAAM,KAAK,QAAQ,KAAK,KAAK,KAAK,MAAM,GAAG,GAAG;IAAG,OAAO,eAAe,IAAI;GAAE;EAC9F;;;;;;EAOA,SAAS,UAAU,OAAwB,UAA0B;GACnE,IAAI,UAAU,MAAM,OAAO;GAC3B,MAAM,QAAQ,MAAM;GACpB,IAAI,UAAU,KAAA,GAAW,OAAO;GAChC,MAAM,OAAO,OAAO,KAAK,CAAC,CAAC;GAC3B,OAAO,MAAM,WAAW,IAAI,OAAO,GAAG,KAAK,KAAK,OAAO,MAAM,MAAM,EAAE;EACvE;;EAGA,SAAS,SAAS,SAAkB,OAAiC;GACnE,IAAI,CAAC,SAAS,OAAO;GACrB,QAAQ,MAAM,WAAW,CAAC,EAAA,CACvB,KAAI,SAAQ,KAAK,SAAS,SAAS,KAAK,QAAQ,KAAK,KAAK,UAAU,IAAI,CAAC,CAAC,CAC1E,KAAK,IAAI;EACd;;EAGA,SAAS,YAAY,OAA0C;GAC7D,IAAI,UAAU,KAAA,GAAW,OAAO;GAChC,MAAM,OAAO,MAAM,QAAQ;GAC3B,OAAO,MAAM,SAAS,KAAA,IAAY,OAAO,GAAG,KAAK,IAAI,MAAM;EAC7D;;;;;;EAOA,SAAgB,iBAAiB,OAA2C;GAC1E,MAAM,UAAU,UAAU;GAC1B,MAAM,QAA0B,CAAC,UAC7B,YACA,MAAM,OAAO,SAAS,gBACpB,YACA,MAAM,YAAY,OAAO,UAAU;GACzC,MAAM,QAAQ,UAAU,MAAM,MAAM,UAAU,MAAM,YAAY;GAChE,MAAM,SAAS,SAAS,SAAS,KAAK;GACtC,MAAM,UAAU,WAAW,KACvB,SACA,UAAU,YAAY,MAAM,KAAK,IAAI;GACzC,MAAM,QAAQ,WAAW,IAAI;GAC7B,MAAM,QAAQ,OAAO,IAAI,MAAM,KAAK,CAAC;GACrC,OAAO;IACL;IACA,SAAS,UAAU,OAAO,IAAI;IAC9B;IACA;IACA,WAAW,YAAY,KAAK,IAAI,QAAQ,MAAM,IAAI,CAAC,CAAC;IAEpD,YAAY,MAAM,SAAS,KAAK,YAAY;GAC9C;EACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECjHA,MAAM,MAA0E;GAC9E,SAAS;GACT,IAAI;GACJ,SAAS;GACT,OAAO;EACT;;EAGA,SAAS,SAAS,EAAE,QAAmC;GACrD,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;IAAI,WAAWC,mCAAI;IAAnB,UAAA;KACG,KAAK,UAAU,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,mCAAI;MAAK,eAAA;MAAa,UAAA,KAAK;KAAY,CAAA;KAChF,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,mCAAI;MAAO,UAAA,KAAK;KAAW,CAAA;KAC3C,KAAK,QAAQ,MAAM,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,mCAAI;MAAM,OAAO,KAAK;MAAO,UAAA,KAAK;KAAU,CAAA;IAC/E;;EAER;;;;;;EAOA,SAAgB,eAAe,EAAE,GAAG,OAAO,WAAgC;GACzE,MAAM,QAAQ,iBAAiB,KAAK;GACpC,MAAM,CAAC,UAAU,gBAAA,GAAeC,MAAAA,SAAAA,CAAS,KAAK;GAC9C,MAAM,OAAO,YAAY,MAAM;GAC/B,OAGE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAWD,mCAAI;IAAM,gBAAa;IAAS,aAAU;IAAU,cAAY,MAAM;IACpF,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACE,sCAAAA,eAAD;KACE,cAAcF,mCAAI;KAClB,kBAAkBA,mCAAI;KACtB,gBAAgBA,mCAAI;KACpB,kBAAkBA,mCAAI;KACtB,MAAM,iBAAA,GAAA,kBAAA,IAAA,CAACG,sCAAAA,UAAD,EAAU,OAAO,IAAI,MAAM,OAAS,CAAA;KAC1C,OAAO,EAAE,WAAW;KACd;KACN,YAAY,MAAM;KAClB,kBAAA;KACA,qBAAA;KACA,gBAAgB;MAAE,aAAY,UAAS,CAAC,KAAK;KAAE;KAC/C,kBACE,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWH,mCAAI;MAAK,eAAA;KAAa,CAAA,GACvC,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;MAAM,WAAWA,mCAAI;MAArB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,mCAAI;OAAQ,UAAA,EAAE,OAAO,MAAM,OAAO;MAAQ,CAAA,GAC3D,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,mCAAI;OAAQ,UAAA,MAAM;MAAc,CAAA,CAC7C;KACN,CAAA,CAAA,EAAA,CAAA;KAGJ,UAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,mCAAI;MAApB,UAAA;OACG,MAAM,MAAM,SAAS,KACpB,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;QAAI,WAAWA,mCAAI;QAAO,cAAY,EAAE,iBAAiB,EAAE,OAAO,MAAM,MAAM,OAAO,CAAC;QACnF,UAAA,MAAM,MAAM,KAAK,MAAM,UACtB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAsD,KAAO,GAA9C,GAAG,OAAO,KAAK,EAAE,GAAG,KAAK,MAAqB,CAC9D;OACC,CAAA;OAEL,MAAM,YAAY,MACjB,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACG,MAAM,MAAM,SAAS,KAAK,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QAAK,WAAWA,mCAAI;QAAO,UAAA,MAAM,OAAO,MAAM,SAAS,EAAE;OAAS,CAAA,GAC7F,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QAAK,WAAWA,mCAAI;QAAS,UAAA,MAAM;OAAa,CAAA,CAChD,EAAA,CAAA;OAEH,YAAY,KAAA,KACX,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;QAAQ,MAAK;QAAS,WAAWA,mCAAI;QAAe,SAAS;QAA7D,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAACI,sCAAAA,0BAAD,CAA2B,CAAA,GAC1B,EAAE,aAAa,CACV;;MAEP;;IACQ,CAAA;GACZ,CAAA;EAET;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC1EA,MAAM,cAAyD;GAC7D,QAAQ;GACR,QAAQ;GACR,SAAS;GACT,UAAU;EACZ;;EAGA,SAAS,aAAa,MAAgC;GACpD,MAAM,QAAQ,CAAC,OAAO,OAAO,KAAK,QAAQ,GAAG;GAC7C,IAAI,KAAK,kBAAkB,KAAA,GACzB,MAAM,KAAK,KAAK,kBAAkB,KAAA,IAC9B,GAAG,OAAO,KAAK,aAAa,EAAE,MAC9B,GAAG,OAAO,KAAK,aAAa,EAAE,KAAK,OAAO,KAAK,aAAa,EAAE,GAAG;GAEvE,OAAO,MAAM,KAAK,KAAe;EACnC;;EAGA,SAAS,IAAI,EAAE,OAAO,YAAoD;GACxE,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWC,+BAAI;IAApB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;KAAI,WAAWA,+BAAI;KAAM,UAAA;IAAU,CAAA,GACnC,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;KAAI,WAAWA,+BAAI;KAAQ;IAAa,CAAA,CACrC;;EAET;;;;;;EAOA,SAAgB,WAAW,EAAE,iBAAkC;GAC7D,MAAM,aAAa,cAAc,MAAM;GACvC,MAAM,CAAC,WAAW,iBAAA,GAAgBC,MAAAA,SAAAA,CAAS,IAAI;GAC/C,MAAM,SAAS,YAAY,KAAK;GAGhC,CAAA,GAAA,MAAA,UAAA,OAAgB;IAAE,aAAa,IAAI;GAAE,GAAG,CAAC,MAAM,CAAC;GAEhD,MAAM,OAAO,YAAY;GACzB,IAAI,SAAS,KAAA,KAAa,SAAS,QAAQ,KAAK,UAAU,YAAY,OAAO;GAE7E,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD;IAAS,WAAWD,+BAAI;IAAM,oBAAA;IAAiB,cAAW;IACxD,UAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAWA,+BAAI;KAApB,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;MACE,MAAK;MACL,WAAWA,+BAAI;MACf,iBAAe,CAAC;MAChB,eAAe;OAAE,cAAa,UAAS,CAAC,KAAK;MAAE;MAJjD,UAAA;OAME,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,+BAAI;QAAM,eAAA;QAAY,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACE,sCAAAA,uBAAD,EAAuB,MAAM,GAAK,CAAA;OAAO,CAAA;OAChF,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWF,+BAAI;QAAO,UAAA;OAAU,CAAA;OACtC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,+BAAI;QAAU,UAAA,aAAa,IAAI;OAAQ,CAAA;OACxD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,+BAAI;QAAS,eAAA;QAC3B,UAAA,YAAY,iBAAA,GAAA,kBAAA,IAAA,CAACG,sCAAAA,4BAAD,CAA6B,CAAA,IAAI,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,8BAAD,CAA+B,CAAA;OACzE,CAAA;MACA;KACP,CAAA,GAAA,CAAC,aACA,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;MAAI,WAAWJ,+BAAI;MAAnB,UAAA;OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;QAAK,OAAM;QAAM,UAAA,KAAK;OAAe,CAAA;OACrC,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;QAAK,OAAM;QAAM,UAAA,YAAY,KAAK;OAAY,CAAA;OAC7C,KAAK,kBAAkB,KAAA,KACtB,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;QAAK,OAAM;QAAX,UAAA,CACG,KAAK,cAAc,SACpB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,+BAAI;SAAO,UAAA,KAAK,cAAc;QAAW,CAAA,CACvD;;OAEP,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;QAAK,OAAM;QACT,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,+BAAI;SAAO,UAAA,KAAK;QAAS,CAAA;OACvC,CAAA;MACH;KAEH,CAAA,CAAA;;GACE,CAAA;EAEb;;;ECzGA,MAAa,SAAS;GAAC;GAAS;GAAc;GAAU;EAAa;;EAGrE,SAAS,MAAM,MAAgD;GAC7D,IAAI,MAAM,SAAS,cAAgC,0BAA0B,aAAa,GAAG;GAC7F,IAAI,QAAQ,MAAM;IAChB,MAAM,SAAS,cAAc,OAAO;IACpC,IAAI,QAAQ,SAAS;IACrB,IAAI,QAAQ,YAAY;IACxB,SAAS,KAAK,YAAY,GAAG;GAC/B;GACA,IAAI,cAAc,SAAS,KAAK,YAAY,CAAC,CAAC,KAAK;EACrD;;;;;EAMA,SAAgB,MAAM,KAA0B;GAO9C,MAAM,OAAO,IAAI,YAAY,IAA4B,kBAAkB;GAE3E,MAAM,IAAI;GACV,IAAI,aACI,KAAK,gBAAgB;IAAE,MAAM,IAAI;GAAE,CAAC,GAC1C,iDACF;GAEA,MAAM,OAA8B;IAClC,OAAO,EAAE,gBAAgB,KAAK;IAO9B,OAAO,OAAO,UAAU;KACtB,MAAM,KAAK,OAAO;MAChB;OAAE,IAAI;OAAO,MAAM,CAAC,cAAc;OAAG,OAAO,MAAM,gBAAgB;MAAK;MACvE;OAAE,IAAI;OAAO,MAAM,CAAC,QAAQ;OAAG,OAAO,MAAM,UAAU,CAAC;MAAE;MACzD;OAAE,IAAI;OAAO,MAAM,CAAC,YAAY;OAAG,OAAO,MAAM,cAAc,CAAC;MAAE;KACnE,CAAU;IACZ;IACA,kBAAkB,SAAS;KAAE,KAAU,IAAI,gBAAgB,IAAI;IAAE;IACjE,mBAAmB,UAAU,UAAU;KACrC,MAAM,QAAQ,KAAK,YAAY,CAAC,CAAC;KACjC,KAAU,OAAO,CACf;MAAE,IAAI;MAAO,MAAM,CAAC,QAAQ;MAAG,OAAO;OAAE,GAAG,OAAO;QAAS,WAAW;MAAM;KAAE,CAChF,CAAU;IACZ;IACA,eAAe,MAAM,UAAU;KAC7B,MAAM,QAAQ,KAAK,YAAY,CAAC,CAAC;KACjC,KAAU,OAAO,CACf;MAAE,IAAI;MAAO,MAAM,CAAC,YAAY;MAAG,OAAO;OAAE,GAAG,OAAO;QAAa,OAAO;MAAM;KAAE,CACpF,CAAU;IACZ;IACA,kBAAkB,SAAS;KAEzB,MAAM,aAAa,EAAE,GADP,KAAK,YAAY,CAAC,CAAC,OACF,WAAW;KAC1C,OAAO,WAAW;KAClB,KAAU,OAAO,CAAC;MAAE,IAAI;MAAO,MAAM,CAAC,YAAY;MAAG,OAAO;KAAW,CAAC,CAAU;IACpF;GACF;GASA,IAAI,MAAM,OAAO,+BAA+B,IAAI,MAAM,SAAS;IACjE,MAAM;IACN,KAAK;IACL,cAAc;GAChB,GAAG,iBAAiB,CAAC;GAarB,IAAI,MAAM,OAAO,4BAAqC,IAAI,MAAM,SAAS;IACvE,MAAM;IACN,KAAK;IACL,UAAU;IAGV,QAAQ;GACV,GAAY,cAAuB,CAAC;GAQpC,IAAI,MAAM,OAAO,4BAAqC,IAAI,MAAM,SAAS;IACvE,MAAM;IACN,KAAK;IACL,UAAU;IAGV,QAAQ;GACV,GAAY,cAAuB,CAAC;GASpC,IAAI,MAAM,OAAO,iCAA0C,IAAI,MAAM,SAAS;IAC5E,MAAM;IACN,IAAI;IACJ,OAAO;GACT,GAAY,UAAmB,CAAC;EAClC"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["useState","css","IconChevronDownOutlineMedium","css","IconCheckOutlineMedium","useMemo","useState","StateDot","IconQuestionOutlineMedium","DisclosureRow","IconInspectOutlineMedium","css","useState","DisclosureRow","StateDot","IconInspectOutlineMedium","css","useState","IconGoalOutlineMedium","IconChevronUpOutlineMedium","IconChevronDownOutlineMedium","IconContextInjectionOutlineRegular","IconGoalOutlineRegular","IconPaperPlaneOutlineRegular","IconAgentPresetOutlineRegular","IconBranchOutlineRegular","IconGlobeOutlineRegular","IconClockOutlineRegular","IconQueueOutlineRegular","IconCordisPluginOutlineRegular","css","JsonBlock","useState","useId","IconChevronDownOutlineRegular"],"sources":["../src/client/palette.ts","../src/client/settings-card.tsx","../src/client/ask-model.ts","../src/client/ask-card.tsx","../src/client/deliverable-model.ts","../src/client/deliverable-row.tsx","../src/client/goal-detail.tsx","../src/client/trigger-model.ts","../src/client/trigger-card.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * Node appearance palette: category/tool mapping, default colors, and the pure\n * CSS-rule generator that paints the chat flow. Browser-half owned; the Host\n * half mirrors the same defaults through its schemastery schema (the two\n * cannot share a value import — the browser bundle purity gate forbids\n * cross-package value imports).\n */\n\n/** The settings namespace this plugin owns (spelled identically in both halves). */\nexport const NODE_APPEARANCE_NS = 'node-appearance'\n\n/** The plugin's style tag identity (removed/replaced on every re-paint). */\nexport const STYLE_TAG_ID = `${NODE_APPEARANCE_NS}/rules`\n\n/** One paintable node category. `command`, `thinking`, `context`, `summary` are non-tool rows. */\nexport type NodeCategory =\n | 'search' | 'agent' | 'execute' | 'file' | 'deliver' | 'task' | 'ask' | 'command' | 'thinking' | 'context' | 'summary' | 'steering' | 'other'\n\n/** Accent color per category (CSS colors). */\nexport type NodeAppearanceColors = Record<NodeCategory, string>\n\n/** The settings value this plugin reads from its namespace scope. */\nexport interface NodeAppearanceSettings {\n /** Show assistant reasoning blocks as Think rows; false hides them. */\n showThinking?: boolean | undefined\n /** Per-category accent colors; missing keys fall back to defaults. */\n colors?: Partial<NodeAppearanceColors> | undefined\n /** Per-tool accent overrides keyed by wire tool name. */\n toolColors?: Record<string, string> | undefined\n}\n\n/** Initial palette: mid-luminance hues readable on both light and dark themes. */\nexport const DEFAULT_COLORS: NodeAppearanceColors = {\n search: '#3b82f6', // blue — web_search / web_fetch\n agent: '#a855f7', // purple — subagent / workflow / send_message …\n execute: '#f59e0b', // amber — bash / pwsh / run_code / terminal_*\n file: '#22c55e', // green — read / write / edit / glob / grep\n deliver: '#06b6d4', // cyan — present 交付文件行。独立于 file:生成文件的那些行与交付行常在同一轮同屏出现,共用绿色分不清谁是谁(用户反馈)\n task: '#ec4899', // pink — todo_write / goal / job_* / schedule_*\n ask: '#65a30d', // lime — ask_user_question 提问卡(取作 --ask-accent;色相落在 execute 琥珀与 file 绿之间的空档,与 search 的蓝区分开)\n command: '#f97316', // orange — /command nodes\n thinking: '#c4b5fd', // light purple — Think rows\n context: '#8a9bb5', // slate blue — injected context rows (informational)\n summary: '#94a3b8', // slate 400 — Turn-level folded summary bar(容器层摘要,比 context 更淡)\n steering: '#14b8a6', // teal — steering rows (rc.8)\n other: '#64748b', // slate — every unlisted tool\n}\n\n/** Wire tool name → category for the shipped mapping. */\nexport const TOOL_CATEGORIES: Record<Exclude<NodeCategory, 'command' | 'thinking' | 'context' | 'summary' | 'steering'>, readonly string[]> = {\n search: ['web_search', 'web_fetch'],\n agent: ['subagent', 'subagent_acp', 'subagent_fork', 'send_message', 'interrupt_agent', 'list_agents', 'report', 'workflow'],\n execute: ['bash', 'pwsh', 'run_code', 'terminal_open', 'terminal_close', 'terminal_list', 'terminal_read', 'terminal_send', 'terminal_signal', 'str_replace_editor'],\n file: ['read', 'write', 'edit', 'read_image', 'glob', 'grep'],\n deliver: ['present'],\n task: ['todo_write', 'create_goal', 'get_goal', 'update_goal', 'job_kill', 'job_list', 'job_output', 'schedule_create', 'schedule_delete', 'schedule_list', 'exit_plan_mode'],\n ask: ['ask_user_question'],\n other: [],\n}\n\n/**\n * The activity keys a step-process group header publishes on its\n * `data-process-activity` attribute. The set is the key list of ui-chat's\n * `ChatGroupSeat` `PROCESS_ICONS`, which is identical in kernel 0.1.7-rc.2 and\n * 0.2.0-rc.1. A closed group reports the kernel's top-ranked category; a\n * running one reports its live activity.\n */\nexport type ProcessActivityKind =\n | 'thinking' | 'read' | 'readImage' | 'search' | 'edit' | 'write'\n | 'commands' | 'code' | 'webSearch' | 'webFetch'\n | 'subagents' | 'plan' | 'questions' | 'tools'\n\n/**\n * Process activity → the category whose color paints a collapsed group header.\n *\n * The mapping lands on categories the plugin already ships, so group headers\n * reuse the configured palette and add no settings field. It is deliberately\n * the same classification the expanded member rows get: `search` here means\n * code search (`grep`/`glob`, a `file` category tool), not `web_search`.\n */\nexport const PROCESS_ACTIVITIES: Record<ProcessActivityKind, NodeCategory> = {\n thinking: 'thinking',\n read: 'file',\n readImage: 'file',\n search: 'file',\n edit: 'file',\n write: 'file',\n commands: 'execute',\n code: 'execute',\n webSearch: 'search',\n webFetch: 'search',\n subagents: 'agent',\n plan: 'task',\n questions: 'ask',\n tools: 'other',\n}\n\n/** Selector matching every tool row inside a tool-call node. */\nconst TOOL_ROW = '[data-chat-flow-kind=\"tool-call\"] [data-tool]'\n/** The ToolRow root itself (carries data-variant; the wrapper callRow does not). */\nconst TOOL_ROW_ROOT = '[data-chat-flow-kind=\"tool-call\"] [data-tool][data-variant]'\n/** Selector of the command node wrapper. */\nconst COMMAND_ROW = '[data-chat-flow-kind=\"command\"]'\n/** Selector of the Think reasoning row. */\nconst THINK_ROW = '[data-variant=\"think\"]'\n/** Selector of the injected-context row (the flow-item wrapper). */\nconst CONTEXT_ROW = '[data-chat-flow-kind=\"context\"]'\n/** Selector of a settled tool-result row (rc.8: tool results render as their own row). */\nconst TOOL_RESULT_ROW = '[data-chat-flow-kind=\"tool-result\"]'\n/**\n * Selector of a **collapsed** Turn-level summary bar — the outermost fold\n * (\"已完成工作 · 用时 35 秒\" / \"深度求索中,用时 N\"). One Turn's members sit\n * under it, each painting itself.\n *\n * `data-open` is present exactly while those members are expanded, so\n * `:not([data-open])` is the folded state. Both kernel 0.1.7-rc.2 and\n * 0.2.0-rc.1 publish it on the same button; 0.2.0 moved the running label to\n * `RunningStatus` (`data-chat-running`) but left this node's attributes alone.\n *\n * Deliberately NOT in {@link ACCENTED_ROWS}: the kernel renders this one as a\n * full-width section divider (`padding: 0` over a bottom hairline), not as a\n * block row. An inset rail lands flush against the label and reads as a stray\n * vertical stroke, and the 3px `padding-left` that keeps the rail off the text\n * pushes the whole bar out of line with every other row. It takes the accent on\n * that existing hairline instead, plus the same 8% wash.\n */\nconst TURN_SUMMARY = '[data-turn-process]:not([data-open])'\n/**\n * Selector of a collapsed step-process group header — the one-line summary the\n * kernel folds a run of tool calls into (\"已读取文件并执行了命令\").\n *\n * Collapsed only: while the group is open its member rows carry their own\n * category colors, and painting the header too would stack two colored layers.\n * The `aria-expanded` attribute is the header button's own disclosure state.\n *\n * `activity` narrows the selector to one published value. Narrowing does NOT\n * raise specificity: `[attr]` and `[attr=\"value\"]` each count as exactly one\n * attribute selector. The general form must therefore be declared first and the\n * per-activity forms after it — `buildCss` does that, and the palette spec\n * guards the order. Same mechanism, same trap, as the unlisted-tool fallback.\n * @param activity - one published activity, or undefined for the general form.\n * @returns a CSS attribute selector for the collapsed process-group header.\n */\nfunction collapsedProcessHeader(activity?: ProcessActivityKind): string {\n const value = activity === undefined ? '' : `=\"${activity}\"`\n return `[data-step-process] [data-process-activity${value}][aria-expanded=\"false\"]`\n}\n\n/**\n * The same header while expanded: no paint, and no `--ncolor-accent` read. It\n * exists only to hold the paint rule's 3px `padding-left`, so opening a group\n * does not shift its header sideways.\n */\nconst PROCESS_HEADER_OPEN = '[data-step-process] [data-process-activity][aria-expanded=\"true\"]'\n\n/**\n * The rows that carry the accent rail + wash: the ToolRow root (not its wrapper\n * callRow — both carry data-tool, only the inner row carries data-variant),\n * command nodes, Think rows, injected-context rows, tool-result rows, and a\n * collapsed step-process group header. The collapsed Turn summary bar is\n * deliberately absent — see {@link TURN_SUMMARY}.\n * User input rows are excluded — right-alignment already\n * distinguishes them (2026-08-20 用户反馈);steering rows 也走独立规则\n * (见 buildCss:在 userStack 层做 wash,不涂整行 rail)。\n * The 3px inset rail is compensated\n * with a matching padding-left so the rail never covers the row's leading icon.\n */\nconst ACCENTED_ROWS = [\n TOOL_ROW_ROOT, COMMAND_ROW, THINK_ROW, CONTEXT_ROW, TOOL_RESULT_ROW, collapsedProcessHeader(),\n].join(',\\n')\n\n/**\n * Accept a configured CSS color (hex, color functions) or reject it so an\n * invalid value falls back to the category default instead of poisoning CSS.\n * @param value - configured color string.\n * @returns whether the value is a plausible CSS color literal.\n */\nexport function isCssColor(value: string): boolean {\n const trimmed = value.trim()\n if (trimmed === '') return false\n if (/^#[0-9a-f]{3,8}$/i.test(trimmed)) return true\n return /^(rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch|color|device-cmyk)\\(/i.test(trimmed)\n}\n\n/** Resolve the effective palette from user settings merged over defaults. */\nexport function resolveColors(settings: NodeAppearanceSettings): NodeAppearanceColors {\n const colors: NodeAppearanceColors = { ...DEFAULT_COLORS }\n const configured = settings.colors\n if (configured !== undefined && typeof configured === 'object' && configured !== null) {\n for (const key of Object.keys(DEFAULT_COLORS) as NodeCategory[]) {\n const value = configured[key]\n if (typeof value === 'string' && isCssColor(value)) colors[key] = value\n }\n }\n return colors\n}\n\n/** Escape a tool name into a CSS attribute selector string literal. */\nfunction attributeLiteral(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')\n}\n\n/**\n * Steering marker icon: a corner-up-left arrow (mid-turn guidance inserted\n * into the running answer), drawn as a mask so the icon inherits the\n * configured steering color. Encoded data URI, no external asset.\n */\nconst STEERING_ICON = \"data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 14 4 9 9 4'/%3E%3Cpath d='M20 20v-7a4 4 0 0 0-4-4H4'/%3E%3C/svg%3E\"\n\n/**\n * Build the complete stylesheet text for one settings snapshot.\n * @param settings - the namespace scope value (may be partial or undefined).\n * @returns CSS text painting accent rows and (optionally) hiding Think rows.\n */\nexport function buildCss(settings: NodeAppearanceSettings | undefined): string {\n const colors = resolveColors(settings ?? {})\n const toolOverrides = settings?.toolColors\n const lines: string[] = []\n\n // Unlisted tools keep the neutral fallback. Declared BEFORE the per-tool\n // rules: both selectors carry equal specificity (two attribute selectors),\n // so of two conflicting declarations the later one wins — a fallback\n // declared after the category rules would override every category color.\n lines.push(`${TOOL_ROW} { --ncolor-accent: ${colors.other}; }`)\n\n // Per-tool accent assignments (explicit overrides win over category color).\n for (const [category, tools] of Object.entries(TOOL_CATEGORIES)) {\n const key = category as keyof typeof TOOL_CATEGORIES\n for (const tool of tools) {\n const override = toolOverrides?.[tool]\n const color = typeof override === 'string' && isCssColor(override)\n ? override\n : colors[key]\n lines.push(`[data-chat-flow-kind=\"tool-call\"] [data-tool=\"${attributeLiteral(tool)}\"] { --ncolor-accent: ${color}; }`)\n }\n }\n\n // Non-tool accent rows.\n lines.push(`${COMMAND_ROW} { --ncolor-accent: ${colors.command}; }`)\n lines.push(`${THINK_ROW} { --ncolor-accent: ${colors.thinking}; }`)\n lines.push(`${CONTEXT_ROW} { --ncolor-accent: ${colors.context}; }`)\n lines.push(`${TOOL_RESULT_ROW} { --ncolor-accent: ${colors.file}; }`)\n lines.push(`${TURN_SUMMARY} { --ncolor-accent: ${colors.summary}; }`)\n\n // Collapsed process-group headers, keyed by the activity the kernel publishes\n // on the header button. The general form is the fallback for an activity this\n // build does not know about, declared FIRST for the same cascade reason as the\n // unlisted-tool fallback above: narrowing an attribute selector does not raise\n // specificity, so a fallback emitted after these mappings would override every\n // one of them and turn all group headers gray.\n lines.push(`${collapsedProcessHeader()} { --ncolor-accent: ${colors.other}; }`)\n for (const activity of Object.keys(PROCESS_ACTIVITIES) as ProcessActivityKind[]) {\n lines.push(`${collapsedProcessHeader(activity)} { --ncolor-accent: ${colors[PROCESS_ACTIVITIES[activity]]}; }`)\n }\n\n // One shared paint rule: 3px inset left rail (layout-free) + 8% wash. The\n // matching padding-left moves the row content off the rail so the leading\n // icon is never covered.\n lines.push(`${ACCENTED_ROWS} {\n box-shadow: inset 3px 0 0 var(--ncolor-accent);\n background-color: color-mix(in srgb, var(--ncolor-accent) 8%, transparent);\n padding-left: 3px;\n}`)\n\n // Group headers lead with an icon, so their rail wants more air than the\n // shared 3px — at 3px the rail sits flush against the glyph and reads as a\n // stray stroke. Declared after the shared rule (equal specificity, so the\n // later one wins) and held identical while open so toggling cannot shift it.\n lines.push(`${collapsedProcessHeader()} { padding-left: 8px; }`)\n lines.push(`${PROCESS_HEADER_OPEN} { padding-left: 8px; }`)\n\n // The Turn summary bar is a section divider, not a block row: it takes the\n // accent on the hairline the kernel already draws under it, plus the shared\n // 8% wash. No rail and no indent, so it stays flush with the rows around it.\n lines.push(`${TURN_SUMMARY} {\n border-bottom-color: var(--ncolor-accent);\n background-color: color-mix(in srgb, var(--ncolor-accent) 8%, transparent);\n}`)\n\n // Steering rows (mid-turn user steering) stay visually distinct from plain\n // user rows with a compass marker beside the right-aligned bubble. The\n // marker is a mask over the user-stack — the container that hugs the bubble\n // — positioned to the left of it, so the tint reads as a glyph next to the\n // message rather than a detached full-width rail (2026-08-21 用户反馈:\n // 整行 rail 突兀,改在 userStack 层做图标区分;slot 方案不可行:\n // conversation.message.images 是 single 槽且已被官方 ui-attachment 占用).\n // alpha.2 锚点迁移(2026-08-31):消息行\"时间悬浮\"标识 data-time-hover-root\n // 已被 TurnTail/MessageItem 的 data-actions-reveal(always|hover)取代;\n // kind 与 首子=userStack 结构不变(ChatNodeSeat L206 / MessageItem L178 验证)。\n lines.push(`[data-chat-flow-kind=\"steering\"] [data-actions-reveal] > :first-child {\n position: relative;\n}`)\n lines.push(`[data-chat-flow-kind=\"steering\"] [data-actions-reveal] > :first-child::before {\n content: '';\n position: absolute;\n right: 100%;\n margin-right: 6px;\n top: 50%;\n width: 14px;\n height: 14px;\n transform: translateY(-50%);\n background-color: ${colors.steering};\n -webkit-mask: url(\"${STEERING_ICON}\") center / contain no-repeat;\n mask: url(\"${STEERING_ICON}\") center / contain no-repeat;\n}`)\n\n // Visibility switch: hide Think rows entirely on the frontend. `!important`\n // outranks the module stylesheet's `.root { display: flex }` (same\n // specificity, but the plugin style tag is injected before the module's).\n if (settings?.showThinking === false) {\n lines.push(`${THINK_ROW} { display: none !important; }`)\n // A think-only node leaves its flowItem seat with zero height: the seat\n // still consumes the column's 16px flex gap on both sides, doubling the\n // spacing between the neighbors. Hide the whole seat when the think row\n // is the only child of its block container — block-internal thinks\n // (text + reasoning in one node) stay gap-neutral after hiding the row.\n lines.push(\n `[data-chat-flow-kind=\"assistant\"]:has(${THINK_ROW}:only-child),`,\n `[data-chat-flow-kind=\"assistant-step\"]:has(${THINK_ROW}:only-child) { display: none !important; }`,\n )\n }\n\n return lines.join('\\n')\n}\n","/**\n * The node-appearance plugin config card. Mirrors the official\n * `settings.plugin.item` card chrome (PluginCard: card shell, name-over-\n * description header, chevron disclosure) with the DSH design tokens —\n * drawn by hand because a feature plugin must not runtime-import another\n * feature plugin's values (bundle purity gate).\n *\n * Writes are immediate: picking a color or flipping the Think switch applies\n * it right away (a palette is a live preview, not a staged form). The footer\n * carries one「恢复初始设置」button that resets the whole namespace to the\n * shipped defaults — two-click confirmation so a miss cannot wipe a custom\n * palette.\n */\n\nimport { useState, type ChangeEvent, type FormEvent } from 'react'\nimport type { ObservableSnapshot } from '@deepseek-ai/dsh-client-store'\nimport type { ConfigFormSnapshot } from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { IconChevronDownOutlineMedium } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { InjectFace, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: the Plugins page's SlotMap merge (the `plugins.bundle.config` entry).\nimport type {} from '@deepseek-ai/dsh-client-ui-plugin-manager/client'\nimport {\n DEFAULT_COLORS, isCssColor, resolveColors, TOOL_CATEGORIES,\n type NodeAppearanceSettings, type NodeCategory,\n} from './palette.ts'\nimport css from './card.module.css'\n\n/** The card's inject face: the read-only form snapshot plus write actions. */\nexport interface NodeAppearanceRowFace {\n hooks: {\n /** The bound configuration-form snapshot, rendered as useNodeAppearance. */\n nodeAppearance: ObservableSnapshot<ConfigFormSnapshot<NodeAppearanceSettings>>\n }\n /** Persist one full value (reset-to-defaults path; resolves on Host settlement). */\n apply(value: NodeAppearanceSettings): Promise<void>\n /** Write the Think visibility switch. */\n setShowThinking(show: boolean): void\n /** Merge one category color into the palette section. */\n setCategoryColor(category: NodeCategory, color: string): void\n /** Merge one tool override into the toolColors section. */\n setToolColor(tool: string, color: string): void\n /** Remove one tool override. */\n removeToolColor(tool: string): void\n}\n\n/** Props the renderer binds for this plugin config card. */\nexport type NodeAppearanceRowProps =\n PropsRuntime<'plugins.bundle.config'>\n & InjectFace<NodeAppearanceRowFace>\n\n/** Chinese labels per category (product copy is Chinese). */\nconst CATEGORY_LABELS: Record<NodeCategory, string> = {\n search: '联网搜索',\n agent: '智能体调用',\n execute: '代码 / 指令执行',\n file: '文件操作',\n deliver: '交付文件',\n task: '任务 / 目标',\n ask: '提问卡片',\n command: '指令节点',\n thinking: '思考过程',\n context: '上下文注入',\n summary: '工作摘要',\n steering: '模型引导',\n other: '其他工具',\n}\n\n/** Tools shown in the add-override autocomplete-free text input placeholder. */\nconst TOOL_SUGGESTIONS = Object.values(TOOL_CATEGORIES).flat().join('、')\n\n/** The card copy (one locale). */\nconst COPY = {\n title: '节点外观',\n description: '消息节点外观与颜色的偏好设置',\n reset: '恢复初始设置',\n resetConfirm: '再次点击确认恢复',\n resetting: '恢复中…',\n readOnly: '配置只读:插件主机侧未挂载或连接非本机。',\n loading: '配置加载中…',\n showThinking: '显示思考过程',\n showThinkingHint: '关闭后会话中的 Think 思考行隐藏',\n toolColors: '工具颜色覆盖(可选)',\n addTool: '添加',\n removeTool: '删除',\n}\n\n/** The shipped defaults, one face call away from any custom palette. */\nconst INITIAL_SETTINGS: NodeAppearanceSettings = {\n showThinking: true,\n colors: DEFAULT_COLORS,\n toolColors: {},\n}\n\n/**\n * Render the node-appearance config card.\n * @param props - the injected scope snapshot hook, its write actions.\n * @returns the card, matching the official plugin-card chrome.\n */\nexport function NodeAppearanceRow({ useNodeAppearance, apply, setShowThinking, setCategoryColor, setToolColor, removeToolColor }: NodeAppearanceRowProps) {\n // 默认展开:卡片是插件页上唯一承载本插件设置的位置,折叠态会让用户以为\n // 「设置不见了」(2026-09-26 用户反馈)。折叠仍可手动收起。\n const [open, setOpen] = useState(true)\n const [confirmReset, setConfirmReset] = useState(false)\n const [resetting, setResetting] = useState(false)\n const [toolName, setToolName] = useState('')\n const [toolColor, setToolColorDraft] = useState('#64748b')\n const snapshot = useNodeAppearance(snapshot => snapshot)\n const served = snapshot.value ?? {}\n const colors = resolveColors(served)\n const toolColors = served.toolColors ?? {}\n const showThinking = served.showThinking ?? true\n const disabled = snapshot.writable === false\n const unavailable = snapshot.status !== 'ready'\n\n const resetInitial = async (): Promise<void> => {\n if (resetting) return\n setResetting(true)\n try {\n await apply(INITIAL_SETTINGS)\n setConfirmReset(false)\n } catch {\n // A refused reset just leaves the current palette in place.\n } finally {\n setResetting(false)\n }\n }\n\n const handleReset = (): void => {\n if (confirmReset) {\n void resetInitial()\n } else {\n setConfirmReset(true)\n }\n }\n\n const addTool = (event: FormEvent): void => {\n event.preventDefault()\n const name = toolName.trim()\n if (name === '' || !isCssColor(toolColor)) return\n setToolColor(name, toolColor)\n setToolName('')\n }\n\n return (\n <li className={css.card + (open ? ' ' + css.cardOpen : '')}>\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={open}\n aria-label={`${open ? '收起' : '展开'}:${COPY.title}`}\n onClick={() => { setOpen(!open) }}\n >\n <span className={css.headText}>\n <span className={css.name}>{COPY.title}</span>\n <span className={css.description}>{COPY.description}</span>\n </span>\n <IconChevronDownOutlineMedium className={css.chevron + (open ? ' ' + css.chevronOpen : '')} />\n </button>\n {open && (\n <div className={css.body}>\n {unavailable && !disabled && <p className={css.statusLine}>{COPY.loading}</p>}\n {disabled && <p className={css.readOnly} role=\"status\">{COPY.readOnly}</p>}\n <div className={disabled ? css.disabled : ''}>\n <div className={css.row}>\n <label className={css.rowLabel} htmlFor=\"node-appearance-show-thinking\">{COPY.showThinking}</label>\n <span className={css.rowHint}>{COPY.showThinkingHint}</span>\n <button\n id=\"node-appearance-show-thinking\"\n className={css.switch + (showThinking ? ' ' + css.on : '')}\n type=\"button\"\n aria-pressed={showThinking}\n onClick={() => { setShowThinking(!showThinking) }}\n >\n <span className={css.knob} />\n </button>\n </div>\n {(Object.keys(CATEGORY_LABELS) as NodeCategory[]).map(category => (\n <div className={css.row} key={category}>\n <label className={css.rowLabel} htmlFor={`node-appearance-color-${category}`}>{CATEGORY_LABELS[category]}</label>\n <input\n id={`node-appearance-color-${category}`}\n className={css.colorInput}\n type=\"color\"\n value={colors[category]}\n onChange={(event: ChangeEvent<HTMLInputElement>) => { setCategoryColor(category, event.target.value) }}\n />\n <span className={css.colorValue}>{colors[category]}</span>\n </div>\n ))}\n <div className={css.sectionTitle}>{COPY.toolColors}</div>\n {Object.entries(toolColors).map(([tool, color]) => (\n <div className={css.row} key={tool}>\n <span className={css.toolName} title={tool}>{tool}</span>\n <input\n className={css.colorInput}\n type=\"color\"\n value={isCssColor(color) ? color : DEFAULT_COLORS.other}\n onChange={(event: ChangeEvent<HTMLInputElement>) => { setToolColor(tool, event.target.value) }}\n />\n <button type=\"button\" className={css.removeButton} onClick={() => { removeToolColor(tool) }}>{COPY.removeTool}</button>\n </div>\n ))}\n <form className={css.addRow} onSubmit={addTool}>\n <input\n className={css.toolInput}\n type=\"text\"\n placeholder={`工具名,如 ${TOOL_SUGGESTIONS}`}\n value={toolName}\n onChange={(event: ChangeEvent<HTMLInputElement>) => { setToolName(event.target.value) }}\n />\n <input className={css.colorInput} type=\"color\" value={toolColor} onChange={(event: ChangeEvent<HTMLInputElement>) => { setToolColorDraft(event.target.value) }} />\n <button type=\"submit\" className={css.addButton} disabled={toolName.trim() === ''}>{COPY.addTool}</button>\n </form>\n </div>\n <div className={css.footer}>\n <button\n type=\"button\"\n className={css.reset + (confirmReset ? ' ' + css.resetConfirm : '')}\n disabled={resetting}\n onClick={handleReset}\n >{resetting ? COPY.resetting : confirmReset ? COPY.resetConfirm : COPY.reset}</button>\n </div>\n </div>\n )}\n </li>\n )\n}\n","/**\n * 提问卡数据派生:把一次 `ask_user_question` 调用还原成「问题 + 全部选项 +\n * 实际选中项」。\n *\n * 为什么要自己解析:DSH 官方的转录卡只保留**已选答案**\n * (`ui-tool/src/client/tool/toolviews/ask-question-row.tsx` 的\n * `questionEntries()` 只取 `id`/`question`,把 `options` 丢掉了),所以提问\n * 结算后「当时还有哪些选项」在客户端管线上就没了。选项列表只存在于调用的\n * 参数 JSON 里 —— 这也是本插件接管 `ask_user_question` toolview 的唯一原因。\n *\n * 本模块是纯函数:不碰 locale、不碰 DOM,解析失败一律降级而不是抛错\n * (接管后卡片由我们渲染,渲染不出来就等于用户什么都看不到)。\n */\n\n/** 模型给出的一个可选项。 */\nexport interface AskOption {\n /** 选项文本;同时是被 `selected` 回传的那个值。 */\n label: string\n /** 选项下方的补充说明,模型没给时为空。 */\n description: string\n}\n\n/** 一个问题:全部选项 + 实际回答。 */\nexport interface AskQuestion {\n id: string\n question: string\n /** 可选的短标题(模型提供时显示在问题上方)。 */\n header: string\n /** 可选的补充说明。 */\n detail: string\n /** 模型是否允许多选。 */\n multiSelect: boolean\n /** 模型当时给出的全部选项;调用没带选项时为空数组。 */\n options: AskOption[]\n /** 被选中的选项文本,按回答记录的顺序。 */\n selected: string[]\n /** 直接输入的文本答案(没选选项或额外补充时)。 */\n custom: string\n}\n\n/** 行的运行状态,与通用工具行保持同一套词汇。 */\nexport type AskRowState = 'running' | 'ok' | 'error' | 'stopped'\n\n/** 问题集的结算程度。 */\nexport type AskPhase = 'pending' | 'answered' | 'unanswered'\n\n/** 卡片渲染所需的全部派生结果。 */\nexport interface AskCardModel {\n state: AskRowState\n phase: AskPhase\n /** 被取消或被中断时记录判定来源;正常结算为 undefined。 */\n verdict: 'cancelled' | 'aborted' | undefined\n questions: AskQuestion[]\n /** 至少选了选项或填了自定义答案的问题数(折叠行的 N/M 用)。 */\n answeredCount: number\n /**\n * 参数 JSON 解析不出来时用于兜底展示的结果文本;运行中或结果无文本时为\n * null。没有它,一次畸形调用会让接管后的行变成空白。\n */\n fallbackText: string | null\n}\n\n/**\n * `ask_user_question` 的 block 里本卡读到的字段子集。\n * 结构照 DSH 的 `ToolCallBlock`(运行中=调用自身,结算后=带 `kind` 的结果\n * 节点)声明为鸭子类型:跨插件只允许 type-only 引用,这里连类型引用都不需要。\n */\nexport interface AskToolBlock {\n /** 运行中的调用没有这个字段;结算后为 `'tool-result'`。 */\n kind?: string | undefined\n callId?: string | undefined\n /** 运行中形态:调用自身携带参数。 */\n argsRaw?: string | undefined\n /** 结算形态:调用头(子调用被剥掉时为 null)。 */\n call?: { argsRaw?: string | undefined } | null | undefined\n /** 结算形态:结果内容块。 */\n content?: readonly unknown[] | undefined\n error?: { code?: string | undefined } | undefined\n isError?: boolean | undefined\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/** 读一个字符串字段,非字符串一律当空串。 */\nfunction text(value: unknown): string {\n return typeof value === 'string' ? value : ''\n}\n\nfunction parseJson(source: string): unknown {\n try {\n return JSON.parse(source)\n } catch {\n // 流式截断的半截 JSON 是正常现象:降级为「无问题」,由调用方兜底展示原文。\n return undefined\n }\n}\n\n/** 从结果内容块拼出展示文本(文本块原样、其余块转 JSON)。 */\nexport function resultTextOf(block: AskToolBlock): string | null {\n const content = block.content\n if (!Array.isArray(content) || content.length === 0) return null\n const parts: string[] = []\n for (const part of content) {\n if (isRecord(part) && part.type === 'text' && typeof part.text === 'string') parts.push(part.text)\n else parts.push(JSON.stringify(part, null, 2))\n }\n return parts.length === 0 ? null : parts.join('\\n')\n}\n\n/** 参数 JSON 里的原始问题(未经回答配对)。 */\ninterface RawQuestion {\n id: string\n question: string\n header: string\n detail: string\n multiSelect: boolean\n options: AskOption[]\n}\n\nfunction readOptions(value: unknown): AskOption[] {\n if (!Array.isArray(value)) return []\n const options: AskOption[] = []\n for (const item of value) {\n if (typeof item === 'string') {\n // 宽容形态:模型偶尔直接给字符串数组而不是 {label} 对象。\n if (item !== '') options.push({ label: item, description: '' })\n continue\n }\n if (!isRecord(item)) continue\n const label = text(item.label)\n if (label === '') continue\n options.push({ label, description: text(item.description) })\n }\n return options\n}\n\n/** 读调用参数里的问题列表;拿不到合法问题时返回 null(由调用方兜底)。 */\nfunction readQuestions(argsRaw: string): RawQuestion[] | null {\n const parsed = parseJson(argsRaw)\n if (!isRecord(parsed) || !Array.isArray(parsed.questions)) return null\n const questions: RawQuestion[] = []\n for (const item of parsed.questions) {\n if (!isRecord(item)) continue\n const question = text(item.question)\n if (question === '') continue\n questions.push({\n id: text(item.id),\n question,\n header: text(item.header),\n detail: text(item.detail),\n multiSelect: item.multiSelect === true,\n options: readOptions(item.options),\n })\n }\n return questions.length === 0 ? null : questions\n}\n\n/** 一条回答记录。 */\ninterface RawAnswer {\n id: string\n selected: string[]\n custom: string\n}\n\nfunction readAnswers(resultText: string | null): RawAnswer[] | null {\n if (resultText === null) return null\n const parsed = parseJson(resultText)\n if (!isRecord(parsed) || !Array.isArray(parsed.answers)) return null\n const answers: RawAnswer[] = []\n for (const item of parsed.answers) {\n if (!isRecord(item)) continue\n const selected = Array.isArray(item.selected)\n ? item.selected.filter((v): v is string => typeof v === 'string')\n : []\n answers.push({ id: text(item.id), selected, custom: text(item.custom) })\n }\n return answers\n}\n\n/** 调用参数:运行中取 block 自身,结算后取结算节点的调用头。 */\nfunction argsRawOf(block: AskToolBlock): string {\n return 'kind' in block ? block.call?.argsRaw ?? '' : block.argsRaw ?? ''\n}\n\n/**\n * 从一次提问调用的冻结切片派生卡片模型。\n * @param block - 运行中的调用或已结算的结果节点。\n * @returns 卡片模型;参数或结果畸形时 `questions` 为空并带兜底文本。\n */\nexport function askCardModel(block: AskToolBlock): AskCardModel {\n const settled = 'kind' in block\n const code = settled ? block.error?.code : undefined\n // Composer 的两种判定自带专用 error code,不能按通用失败处理:用户自己\n // 取消(ASK_CANCELLED)是一次正常结算,中断(ASK_ABORTED)沿用其他被中断\n // 工具调用的 amber「已停止」语义 —— 与官方 ask-question-row 的 state 覆盖\n // 逐条一致。\n const state: AskRowState = !settled ? 'running'\n : code === 'ASK_ABORTED' || code === 'interrupted' ? 'stopped'\n : code === 'ASK_CANCELLED' ? 'ok'\n : block.isError === true ? 'error' : 'ok'\n const argsRaw = argsRawOf(block)\n const resultText = settled ? resultTextOf(block) : null\n\n // 判定来源优先于结算形态:Composer 取消 / 回合中断都会带自己的 error code,\n // 此时结果里没有答案,但仍应列出问题本身(与官方转录卡的语义一致)。\n let verdict: AskCardModel['verdict']\n let phase: AskPhase\n if (code === 'ASK_CANCELLED') {\n verdict = 'cancelled'\n phase = 'unanswered'\n } else if (code === 'ASK_ABORTED') {\n verdict = 'aborted'\n phase = 'unanswered'\n } else if (!settled) {\n phase = 'pending'\n } else {\n phase = resultText === null ? 'unanswered' : 'answered'\n }\n\n const raw = readQuestions(argsRaw)\n if (raw === null) {\n return {\n state, phase, verdict, questions: [], answeredCount: 0,\n fallbackText: resultText ?? (argsRaw === '' ? null : argsRaw),\n }\n }\n\n // 回答按 id 配对;配不上的问题保留全部选项、标记为未选 —— 官方在严格配对\n // 失败时整卡降级,这里宁可少标一个\"已选\"也不丢掉用户想看的选项列表。\n const byId = new Map<string, RawAnswer>()\n for (const answer of readAnswers(resultText) ?? []) {\n if (!byId.has(answer.id)) byId.set(answer.id, answer)\n }\n const questions: AskQuestion[] = raw.map(question => {\n const answer = byId.get(question.id)\n return {\n ...question,\n selected: answer?.selected ?? [],\n custom: answer?.custom ?? '',\n }\n })\n const answeredCount = questions\n .filter(question => question.selected.length > 0 || question.custom !== '')\n .length\n return { state, phase, verdict, questions, answeredCount, fallbackText: resultText }\n}\n\n/** 折叠行右侧的进度计数(文案由组件用 locale 组装)。 */\nexport function askProgress(model: AskCardModel): { answered: number; total: number } {\n return { answered: model.answeredCount, total: model.questions.length }\n}\n","/**\n * 提问卡:接管 `ask_user_question` 的工具行。\n *\n * 官方转录卡只列**已选答案**,结算后就再也看不到当时还有哪些选项。本卡片\n * 用调用参数里的 `options` 把每个选项都渲染成一块,被选中的那块用插件色板\n * 里 ask 类别的强调色(默认蓝)反显并打勾。\n *\n * 接管是 DSH 支持的机制(keyed slot 用不同 priority 遮蔽既有占用者,\n * 见 ui-slots 的 `register()`),代价是本文件要自己承担官方 ToolRow 的\n * 折叠行外观 —— 因此行外壳逐项对齐 ToolRow.module.css 的既有视觉\n * (24px 行高、2px 分隔点、13px 次级摘要、running 扫光、hover 才现的\n * Inspect 胶囊),组件则全部来自共享的 ui-primitives。\n */\nimport { useMemo, useState } from 'react'\nimport {\n DisclosureRow, IconCheckOutlineMedium, IconInspectOutlineMedium, IconQuestionOutlineMedium, StateDot,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport { askCardModel, askProgress, type AskCardModel, type AskToolBlock } from './ask-model.ts'\nimport css from './ask-card.module.css'\n\n/** 注入的 locale 翻译函数(注册时声明 `conversation` 命名空间)。 */\nexport interface AskTranslate {\n (key: string, params?: Record<string, string | number>): string\n}\n\n/** 卡片从 slot owner 收到的字段;其余 owner props 与本行无关。 */\nexport interface AskCardProps {\n t: AskTranslate\n block: AskToolBlock\n /** 跳到轨迹视图查看原始调用;缺省时不渲染该入口。 */\n inspect?: (() => void) | undefined\n}\n\n/** 折叠行右侧的摘要:等待 / 已取消 / 已中断 / 未回答 / N-M 已回答。 */\nfunction summaryText(model: AskCardModel, t: AskTranslate): string {\n if (model.phase === 'pending') return t('ask.waiting')\n if (model.phase === 'unanswered') {\n if (model.verdict === 'cancelled') return t('ask.cancelled')\n if (model.verdict === 'aborted') return t('ask.interrupted')\n return t('ask.skipped')\n }\n const { answered, total } = askProgress(model)\n return t('ask.answered', { answered, total })\n}\n\n/** 一行「未选/已选」选项块。 */\nfunction OptionRow({ label, description, chosen }: {\n label: string\n description?: string | undefined\n chosen: boolean\n}) {\n return (\n <div className={css.option} data-chosen={chosen ? '' : undefined}>\n <span className={css.marker} aria-hidden=\"true\">\n {chosen && <IconCheckOutlineMedium />}\n </span>\n <span className={css.optionText}>\n <span className={css.label}>{label}</span>\n {description !== undefined && description !== '' && (\n <span className={css.desc}>{description}</span>\n )}\n </span>\n </div>\n )\n}\n\n/** 展开后的卡片体:逐问题列出全部选项并标出选中项。 */\nfunction QuestionList({ model, t }: { model: AskCardModel; t: AskTranslate }) {\n return (\n <div className={css.card}>\n {model.verdict !== undefined && (\n <p className={css.verdict}>\n {model.verdict === 'cancelled' ? t('ask.cancelledDetail') : t('ask.interruptedDetail')}\n </p>\n )}\n {model.questions.map((question, index) => (\n <div className={css.item} key={question.id !== '' ? question.id : `q${String(index)}`}>\n {question.header !== '' && <div className={css.header}>{question.header}</div>}\n <div className={css.question}>{question.question}</div>\n {question.detail !== '' && <div className={css.detail}>{question.detail}</div>}\n {question.options.length > 0\n ? (\n <div className={css.options}>\n {question.options.map((option, optionIndex) => (\n <OptionRow\n key={`${String(optionIndex)}-${option.label}`}\n label={option.label}\n description={option.description}\n chosen={question.selected.includes(option.label)}\n />\n ))}\n {/* 直接输入的答案不在选项表里,单独补一块,否则这次回答会消失。 */}\n {question.custom !== '' && <OptionRow label={question.custom} chosen />}\n </div>\n )\n : (\n <div className={css.answers}>\n {question.selected.map((answer, answerIndex) => (\n <span className={css.answerLine} key={`${String(answerIndex)}-${answer}`}>{answer}</span>\n ))}\n {question.custom !== '' && <span className={css.answerLine}>{question.custom}</span>}\n {question.selected.length === 0 && question.custom === '' && (\n <span className={css.answersEmpty}>{t('ask.skipped')}</span>\n )}\n </div>\n )}\n </div>\n ))}\n </div>\n )\n}\n\n/**\n * 渲染一次提问的完整记录。\n * @param props - locale 翻译函数、冻结的调用切片与可选的轨迹入口。\n * @returns 折叠行 + 展开后的选项卡片。\n */\nexport function AskQuestionRow({ t, block, inspect }: AskCardProps) {\n const model = useMemo(() => askCardModel(block), [block])\n const [expanded, setExpanded] = useState(false)\n const hasBody = model.questions.length > 0 || model.fallbackText !== null\n const open = expanded && hasBody\n const leading = model.state === 'error'\n ? <StateDot state=\"error\" />\n : model.state === 'stopped'\n ? <StateDot state=\"warning\" />\n : <IconQuestionOutlineMedium />\n return (\n // data-tool / data-variant / data-state 必须保留:插件既有的强调色规则\n // (palette.ts 的 TOOL_ROW_ROOT)与其他行样式都按这三个属性匹配。\n <div className={css.root} data-variant=\"others\" data-tool=\"ask_user_question\" data-state={model.state}>\n <DisclosureRow\n rowClassName={css.row}\n leadingClassName={css.leading}\n titleClassName={css.title}\n chevronClassName={css.chevron}\n icon={leading}\n title={t('ask.rowTitle')}\n open={open}\n expandable={hasBody}\n expandOnRowClick\n keepContentWhenOpen\n onToggle={() => { setExpanded(value => !value) }}\n collapsedContent={(\n <>\n <span className={css.sep} aria-hidden />\n <span className={css.summary}>{summaryText(model, t)}</span>\n </>\n )}\n >\n <div className={css.bodyWrap}>\n {model.questions.length > 0\n ? <QuestionList model={model} t={t} />\n // 参数或结果畸形时的兜底:接管后不渲染就等于用户什么都看不到。\n : <pre className={css.fallback}>{model.fallbackText}</pre>}\n {inspect !== undefined && (\n <button type=\"button\" className={css.inspectButton} onClick={inspect}>\n <IconInspectOutlineMedium />\n {t('row.inspect')}\n </button>\n )}\n </div>\n </DisclosureRow>\n </div>\n )\n}\n","/**\n * 交付行数据派生:把一次 `present` 调用还原成「状态 + 文件清单 + 结果文本」。\n *\n * 为什么要自己解析:官方 PresentRow 的折叠态把全部文件名逗号拼成一行\n * (`ui-deliverables/src/client/PresentRow.tsx` 的 `fileNames()`),多文件时读不完,\n * 也看不出这一轮交付了几个。完整清单只存在于调用的参数 JSON 里,所以折叠摘要与\n * 展开态都得自己解一份。\n *\n * 本模块是纯函数:不碰 locale、不碰 DOM,解析失败一律降级而不是抛错(接管后\n * 行由我们渲染,渲染不出来就等于用户什么都看不到)。\n *\n * 「等 N 个文件」这类摘要文案直写中文,与 goal-detail.tsx 同一取径:本插件不新造\n * locale 命名空间,而官方 deliverables 字典没有「共计 N 个」的 key(`presented.more`\n * 是「+ N 个文件」,用于溢出提示)。行内的标题、状态词与 inspect 仍取自官方字典。\n */\n\n/**\n * 工具调用块里本行取用的字段(照官方 PresentRow 的取用面声明为鸭子类型,\n * 不为此引入 @deepseek-ai/dsh-client-ui-tool 依赖)。\n */\nexport interface DeliverableBlock {\n /** 未结算时参数在块本身;结算后搬到 `call` 上。流式中途可能是截断的 JSON。 */\n argsRaw?: string | undefined\n call?: { argsRaw?: string | undefined } | undefined\n content?: ReadonlyArray<{ type: string, text?: string | undefined }> | undefined\n error?: { name?: string | undefined, code?: string | undefined } | undefined\n isError?: boolean | undefined\n}\n\n/** 交付状态:运行中 / 完成 / 中断 / 出错。 */\nexport type DeliverableState = 'running' | 'ok' | 'stopped' | 'error'\n\n/** 展开态里的一行:文件名、所在目录与扩展名徽标已拆好。 */\nexport interface DeliverableFile {\n /** 参数的完整路径,用于悬停提示。 */\n path: string\n /** 文件名部分(正反斜杠都兼容)。 */\n name: string\n /** 所在目录;纯文件名(没有分隔符)时为空串。 */\n dir: string\n /** 扩展名徽标:大写、至多 4 字符;没有扩展名时为 null。 */\n badge: string | null\n}\n\n/** 交付行渲染需要的全部派生结果。 */\nexport interface DeliverableModel {\n state: DeliverableState\n /** 折叠态摘要:单文件报文件名,多文件报「首个 + 数量」;参数未成形时报参数原文。 */\n summary: string\n /** 逐文件数据;参数未成形时为空数组。 */\n files: DeliverableFile[]\n /** 展开后的结果文本(结果无文本时退回错误描述,再没有则为空串)。 */\n details: string\n /** 结果文本的行数;没有文本时为 0。 */\n lineCount: number\n /** 是否有可展开的内容。 */\n expandable: boolean\n}\n\n/**\n * 从参数 JSON 里取文件路径。\n * 截断的 JSON(调用仍在流式输出)返回 null —— 与官方一致:那时原样显示参数\n * 文本,而不是当成「零个文件」。\n * @param raw - 参数 JSON 原文。\n * @returns 路径数组;JSON 未成形时为 null。\n */\nfunction parsePaths(raw: string): string[] | null {\n let args: unknown\n try {\n args = JSON.parse(raw)\n } catch {\n return null\n }\n if (typeof args !== 'object' || args === null || !('files' in args)) return null\n const files = (args as { files?: unknown }).files\n if (!Array.isArray(files)) return null\n return files.flatMap((file: unknown) => {\n if (typeof file !== 'object' || file === null || !('path' in file)) return []\n const path = (file as { path?: unknown }).path\n return typeof path === 'string' ? [path] : []\n })\n}\n\n/** 最后一个路径分隔符的下标;没有分隔符时为 -1。 */\nfunction separatorAt(path: string): number {\n return Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\\\'))\n}\n\n/** 扩展名徽标:最后一个点之后的部分,过长截断;无扩展名返回 null。 */\nfunction extensionBadge(name: string): string | null {\n const dot = name.lastIndexOf('.')\n if (dot <= 0 || dot === name.length - 1) return null\n const ext = name.slice(dot + 1)\n return (ext.length <= 4 ? ext : ext.slice(0, 4)).toUpperCase()\n}\n\n/** 拆一行:路径 → 文件名 + 所在目录 + 扩展名徽标。 */\nfunction fileOf(path: string): DeliverableFile {\n const cut = separatorAt(path)\n const name = cut === -1 ? path : path.slice(cut + 1)\n return { path, name, dir: cut === -1 ? '' : path.slice(0, cut), badge: extensionBadge(name) }\n}\n\n/**\n * 折叠态摘要。\n * `paths === null` 表示参数 JSON 未成形,此时按官方做法原样显示参数文本;解析\n * 成功但一个路径都没取到时返回空串,不把 `{\"files\":[]}` 这种原文当摘要抛出去。\n */\nfunction summaryOf(paths: string[] | null, fallback: string): string {\n if (paths === null) return fallback\n const first = paths[0]\n if (first === undefined) return ''\n const name = fileOf(first).name\n return paths.length === 1 ? name : `${name} 等 ${String(paths.length)} 个文件`\n}\n\n/** 结果文本:把结果节点拼成一段;未结算时没有结果。 */\nfunction outputOf(settled: boolean, block: DeliverableBlock): string {\n if (!settled) return ''\n return (block.content ?? [])\n .map(item => item.type === 'text' ? item.text ?? '' : JSON.stringify(item))\n .join('\\n')\n}\n\n/** 错误描述:没有结果文本时的兜底,比整行空白有用。 */\nfunction errorTextOf(error: DeliverableBlock['error']): string {\n if (error === undefined) return ''\n const name = error.name ?? 'error'\n return error.code === undefined ? name : `${name}: ${error.code}`\n}\n\n/**\n * 派生一次交付的全部渲染数据。\n * @param block - 工具调用/结果块。\n * @returns 状态、折叠摘要、逐文件数据与结果文本。\n */\nexport function deliverableModel(block: DeliverableBlock): DeliverableModel {\n const settled = 'kind' in block\n const state: DeliverableState = !settled\n ? 'running'\n : block.error?.code === 'interrupted'\n ? 'stopped'\n : block.isError === true ? 'error' : 'ok'\n const args = (settled ? block.call?.argsRaw : block.argsRaw) ?? ''\n const output = outputOf(settled, block)\n const details = output !== ''\n ? output\n : settled ? errorTextOf(block.error) : ''\n const paths = parsePaths(args)\n const files = paths?.map(fileOf) ?? []\n return {\n state,\n summary: summaryOf(paths, args),\n files,\n details,\n lineCount: details === '' ? 0 : details.split('\\n').length,\n // 比官方宽:官方只在有结果文本时可展开,这里交付了文件也允许展开看清单。\n expandable: files.length > 0 || details !== '',\n }\n}\n","/**\n * 交付行:接管 `present` 的工具行。\n *\n * 官方 PresentRow 是一个 45 行的折叠行:状态点 + 「交付文件」标题 + **逗号拼接\n * 的文件名** + 可展开的结果文本 + inspect 入口。多文件时那串文件名会挤成一行\n * 读不完,也看不出这一轮交付了几个。\n *\n * 本组件保留官方全部信息与交互(四态、状态词、文件名、结果文本、inspect,以及\n * `data-tool=\"present\"` / `data-state` 这两个样式与快照测试的锚点),另加三件:\n * ① 折叠态文件名只报「首个 + 数量」,多文件不再挤成一行;\n * ② 展开态逐文件成行,带扩展名徽标与所在目录;\n * ③ 结果文本标注行数。\n *\n * 全部派生在 deliverable-model.ts 里,本文件只做 JSX。\n *\n * 接管是 DSH 支持的机制(keyed slot 用不同 priority 遮蔽既有占用者,见\n * ui-slots 的 `register()`;官方插件开发 skill:registering an existing key\n * may replace the product's default card)。代价是本文件要自己承担官方行的\n * 折叠外观 —— 因此行外壳逐项对齐 ToolRow.module.css 与同插件的提问卡\n * (24px 行高、2px 分隔点、13px 次级摘要、running 扫光、hover 才现的\n * Inspect 胶囊),组件全部来自共享 ui-primitives。\n *\n * 下载卡片与「打开」菜单不在这里:它们属于 `conversation.chat.turnTail` 槽的\n * Deliverables 网格,与本 toolview 是两个不同的槽,接管互不影响。\n */\nimport { useState } from 'react'\nimport { DisclosureRow, IconInspectOutlineMedium, StateDot } from '@deepseek-ai/dsh-client-ui-primitives'\nimport {\n deliverableModel, type DeliverableBlock, type DeliverableFile, type DeliverableState,\n} from './deliverable-model.ts'\nimport css from './deliverable-row.module.css'\n\n/** 注入的 locale 翻译函数(注册时声明 `deliverables` 命名空间)。 */\nexport interface DeliverableTranslate {\n (key: string, params?: Record<string, string | number>): string\n}\n\n/** 本行从 slot owner 收到的字段;其余 owner props 与本行无关。 */\nexport interface DeliverableRowProps {\n t: DeliverableTranslate\n block: DeliverableBlock\n /** 跳到轨迹视图查看原始调用;缺省时不渲染该入口。 */\n inspect?: (() => void) | undefined\n}\n\n/** 状态点的外观名,四态映射与官方 PresentRow 一致。 */\nconst DOT: Record<DeliverableState, 'ongoing' | 'done' | 'warning' | 'error'> = {\n running: 'ongoing',\n ok: 'done',\n stopped: 'warning',\n error: 'error',\n}\n\n/** 逐文件一行:扩展名徽标 + 文件名 + 所在目录(完整路径挂在 title 上)。 */\nfunction FileLine({ file }: { file: DeliverableFile }) {\n return (\n <li className={css.file}>\n {file.badge !== null && <span className={css.ext} aria-hidden>{file.badge}</span>}\n <span className={css.name}>{file.name}</span>\n {file.dir !== '' && <span className={css.path} title={file.path}>{file.dir}</span>}\n </li>\n )\n}\n\n/**\n * 渲染一次交付的完整记录。\n * @param props - locale 翻译函数、调用/结果切片与可选的轨迹入口。\n * @returns 折叠行 + 展开后的文件清单与结果文本。\n */\nexport function DeliverableRow({ t, block, inspect }: DeliverableRowProps) {\n const model = deliverableModel(block)\n const [expanded, setExpanded] = useState(false)\n const open = expanded && model.expandable\n return (\n // data-tool / data-variant / data-state 必须保留:palette.ts 的 TOOL_ROW_ROOT\n // 与其他行样式都按它们匹配(同 ask-card 的约定)。\n <div className={css.root} data-variant=\"others\" data-tool=\"present\" data-state={model.state}>\n <DisclosureRow\n rowClassName={css.row}\n leadingClassName={css.leading}\n titleClassName={css.title}\n chevronClassName={css.chevron}\n icon={<StateDot state={DOT[model.state]} />}\n title={t('row.title')}\n open={open}\n expandable={model.expandable}\n expandOnRowClick\n keepContentWhenOpen\n onToggle={() => { setExpanded(value => !value) }}\n collapsedContent={(\n <>\n <span className={css.sep} aria-hidden />\n <span className={css.summary}>\n <span className={css.state}>{t(`row.${model.state}`)}</span>\n <span className={css.paths}>{model.summary}</span>\n </span>\n </>\n )}\n >\n <div className={css.bodyWrap}>\n {model.files.length > 0 && (\n <ul className={css.files} aria-label={t('presented.all', { count: model.files.length })}>\n {model.files.map((file, index) => (\n <FileLine key={`${String(index)}-${file.path}`} file={file} />\n ))}\n </ul>\n )}\n {model.details !== '' && (\n <>\n {model.files.length > 0 && <div className={css.meta}>{`输出 ${String(model.lineCount)} 行`}</div>}\n <pre className={css.output}>{model.details}</pre>\n </>\n )}\n {inspect !== undefined && (\n <button type=\"button\" className={css.inspectButton} onClick={inspect}>\n <IconInspectOutlineMedium />\n {t('row.inspect')}\n </button>\n )}\n </div>\n </DisclosureRow>\n </div>\n )\n}\n","/**\n * 目标详情折叠条:接在官方 GoalBar 下面(`conversation.input.dock` 里\n * `order: 11`,官方那条是 10),把官方条上被 ellipsis 截断的目标展开成可读\n * 详情。\n *\n * 卡片形态照同槽的待办面板(ui-conversation 的 TodoPanel):同一套 dock 宽度\n * 公式、同一张 `--dsw-specific-tip` 卡片、同一个「标题 + 右侧摘要 + chevron」\n * 折叠头,默认收起。折叠头只放官方条**没有**的元信息(版本号、自主轮次),\n * 目标原文放在展开区 —— 这样两块不会互相重复。\n *\n * 为什么是「另加一条」而不是接管官方条:`conversation.input.dock` 是 list\n * 槽,不同 id 各自成格并列渲染;而官方 ui-goal 的注入面(edit/pause/resume/\n * clear 四个 Remote 动词 + 一个带竞态防护的 activation 订阅源)是**注册者\n * 私有**的,接管就得整套复刻 —— 那会把这个「只读地多看一行」的需求变成\n * 插件里多一处会写会话数据的 RPC 客户端。这里只读 `useProjection('goal')`。\n */\nimport { useEffect, useState } from 'react'\nimport {\n IconChevronDownOutlineMedium, IconChevronUpOutlineMedium, IconGoalOutlineMedium,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ReactNode } from 'react'\nimport css from './goal-detail.module.css'\n\n/** 投影里本卡渲染的字段(照 DSH 的 `GoalSnapshot` 声明为鸭子类型)。 */\nexport interface GoalSnapshotLike {\n id: string\n revision: number\n objective: string\n phase: 'active' | 'paused' | 'blocked' | 'complete'\n /** 自主轮次上限;未设置时为 undefined。 */\n maxGoalRounds?: number | undefined\n /** 已开始的自主轮次;旧快照可能没有该字段。 */\n roundsStarted?: number | undefined\n /** 仅 blocked 阶段存在。 */\n blockedReason?: { code: string; message: string } | undefined\n}\n\n/** `useProjection('goal')` 的返回形状。 */\nexport interface GoalProjectionLike {\n goal: GoalSnapshotLike\n}\n\n/** 本卡从 slot 标准 props 取用的部分(其余 owner props 与本卡无关)。 */\nexport interface GoalDetailProps {\n /** 框架标准投影席位:按 key 读当前会话的投影。 */\n useProjection: (key: string) => GoalProjectionLike | null | undefined\n}\n\n/** 阶段文案:与官方 goal 字典同义,按本插件既有做法直写中文。 */\nconst PHASE_LABEL: Record<GoalSnapshotLike['phase'], string> = {\n active: '进行中',\n paused: '已暂停',\n blocked: '已阻塞',\n complete: '已完成',\n}\n\n/** 折叠头右侧摘要:只放官方条没有的元信息。 */\nfunction summaryLabel(goal: GoalSnapshotLike): string {\n const parts = [`rev ${String(goal.revision)}`]\n if (goal.roundsStarted !== undefined) {\n parts.push(goal.maxGoalRounds === undefined\n ? `${String(goal.roundsStarted)} 轮`\n : `${String(goal.roundsStarted)} / ${String(goal.maxGoalRounds)} 轮`)\n }\n return parts.join('\\u2002·\\u2002')\n}\n\n/** 展开区里的一组「键 / 值」。 */\nfunction Row({ label, children }: { label: string; children: ReactNode }) {\n return (\n <div className={css.row}>\n <dt className={css.key}>{label}</dt>\n <dd className={css.value}>{children}</dd>\n </div>\n )\n}\n\n/**\n * 渲染目标详情折叠条。\n * @param props - 框架标准投影席位。\n * @returns 折叠条;加载中、无目标、或目标已完成时不渲染(与官方条一致)。\n */\nexport function GoalDetail({ useProjection }: GoalDetailProps) {\n const projection = useProjection('goal')\n const [collapsed, setCollapsed] = useState(true)\n const goalId = projection?.goal.id\n\n // 目标换了一个(新建 / 清除后重建)就收起:否则展开态会挂在新目标上。\n useEffect(() => { setCollapsed(true) }, [goalId])\n\n const goal = projection?.goal\n if (goal === undefined || goal === null || goal.phase === 'complete') return null\n\n return (\n <section className={css.root} data-goal-detail aria-label=\"目标详情\">\n <div className={css.body}>\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={!collapsed}\n onClick={() => { setCollapsed(value => !value) }}\n >\n <span className={css.lead} aria-hidden><IconGoalOutlineMedium size={14} /></span>\n <span className={css.title}>目标详情</span>\n <span className={css.summary}>{summaryLabel(goal)}</span>\n <span className={css.chevron} aria-hidden>\n {collapsed ? <IconChevronUpOutlineMedium /> : <IconChevronDownOutlineMedium />}\n </span>\n </button>\n {!collapsed && (\n <dl className={css.detail}>\n <Row label=\"目标\">{goal.objective}</Row>\n <Row label=\"阶段\">{PHASE_LABEL[goal.phase]}</Row>\n {goal.blockedReason !== undefined && (\n <Row label=\"阻塞\">\n {goal.blockedReason.message}\n <span className={css.code}>{goal.blockedReason.code}</span>\n </Row>\n )}\n <Row label=\"标识\">\n <span className={css.code}>{goal.id}</span>\n </Row>\n </dl>\n )}\n </div>\n </section>\n )\n}\n","/**\n * 触发通知卡的派生逻辑:把内核发来的那条「唤醒本轮」的上下文消息,变成卡片\n * 要显示的东西 —— 标题与图标、目标轮次的字段、以及时间戳。\n *\n * 本文件只放纯函数,组件只做 JSX(与 `ask-model` / `deliverable-model` 同构)。\n *\n * ## 为什么需要它\n *\n * 官方 `TurnTriggerNodeView` 把 `node.data.content` 原样交给 `NoticeBody`\n * (→ `ModelFacingContent` → `<pre>`)。对目标轮次来说,那段 content 是\n * **模型提示词的原文**:\n *\n * ```\n * <goal_round>\n * Objective: \"……\"\n * Round: 1/256\n *\n * Continue working toward the objective …\n * </goal_round>\n * ```\n *\n * 骨架(标签、`Objective:` 前缀、JSON 转义)对人不构成信息,却占满了展开区。\n * 本插件接管这个 key,把这些字段还原成人读的形式。\n *\n * ## 解析是「全有或全无」\n *\n * `<goal_round>` 的结构是内核私有约定(`goal-round-driver/src/prompt.ts`),\n * 它一变,任何半解析的结果都会显示成一张自信但不完整的卡片。所以解析失败时\n * 整卡退回「原文 + 等宽显示」的等价形态,绝不显示半截字段 —— 判据与\n * `deliverable-model`、`ContextBody` 的 `instructionChanges()` 同一条。\n *\n * ## 接管是全 key 的\n *\n * `conversation.chat.node` 是 keyed cell,同一 key 只有 priority 最低的注册\n * 会渲染。注册 `turn-trigger` 的 `priority: -1` 会让**全部**触发来源都走本\n * 插件组件,所以 {@link turnTriggerDetails} 复刻官方的 kind → 标题/图标映射\n * (含默认分支),非目标轮次的来源原样显示。\n */\n\n/** 注入的 locale 翻译函数(注册时声明 `chat` 命名空间)。 */\nexport interface TriggerTranslate {\n (key: string, params?: Record<string, string | number>): string\n}\n\n/** 官方 `turn-trigger.ts` 的 `TurnTriggerIcon`:一族里挑一个已有的图标字形。 */\nexport type TriggerIcon =\n | 'agent' | 'github' | 'goal' | 'job' | 'plugin' | 'request' | 'schedule' | 'subagent' | 'team' | 'webhook'\n\n/** 本卡从 `node.source` 读到的形状(内核记录的来源,鸭子类型)。 */\nexport interface TriggerSourceLike {\n kind?: unknown\n provider?: unknown\n round?: unknown\n}\n\n/** 本卡从 `node` 取用的字段(其余字段与本卡无关)。 */\nexport interface TriggerNodeLike {\n /** 记录时间(Unix epoch ms)。 */\n time: number\n /** 模型可见的内容块。 */\n content: unknown\n /** 持久化的来源标注。 */\n source: unknown\n}\n\n/** 内容的一段:文本,或本版本不认识的块(照官方做法单独渲染,不让它消失)。 */\nexport type ContentRun = { kind: 'text'; text: string } | { kind: 'block'; block: unknown }\n\n/**\n * 拆开内容块:文本与未知块各成一段。\n * @param content - 持久化的内容块数组。\n * @returns 分段结果;不是数组时返回 null(调用方走等价外壳)。\n */\nexport function contentRuns(content: unknown): ContentRun[] | null {\n if (!Array.isArray(content)) return null\n const runs: ContentRun[] = []\n for (const block of content as readonly unknown[]) {\n const text = textBlock(block)\n runs.push(text === null ? { kind: 'block', block } : { kind: 'text', text })\n }\n return runs\n}\n\n/** 一个块是不是文本块;是则给出文本。 */\nfunction textBlock(block: unknown): string | null {\n if (typeof block !== 'object' || block === null) return null\n const candidate = block as { type?: unknown; text?: unknown }\n return candidate.type === 'text' && typeof candidate.text === 'string' ? candidate.text : null\n}\n\n/**\n * 全部内容都是文本块时把它们拼起来。\n *\n * 目标轮次的提示词是**单个**文本块,所以拼起来就能直接拿去解析。出现任何\n * 非文本块即返回 null —— 那种内容本卡不负责解释,交给等价外壳按块渲染。\n * @param content - 持久化的内容块数组。\n * @returns 拼接后的文本,或 null。\n */\nexport function plainText(content: unknown): string | null {\n const runs = contentRuns(content)\n if (runs === null) return null\n let text = ''\n for (const run of runs) {\n if (run.kind !== 'text') return null\n text += run.text\n }\n return text\n}\n\n/** 记下的一段来源,读成对象。 */\nfunction sourceRecord(source: unknown): TriggerSourceLike {\n return typeof source === 'object' && source !== null ? source as TriggerSourceLike : {}\n}\n\n/** 读一个字符串字段,非字符串当空串。 */\nfunction textField(source: TriggerSourceLike, key: 'kind' | 'provider'): string {\n const value = source[key]\n return typeof value === 'string' ? value : ''\n}\n\n/** 识别出的触发来源:chat 字典的标题 key + 一族图标。 */\nexport interface TriggerDetails {\n /** `message.trigger.*` 的 key,交给 `t()` 取文案。 */\n titleKey: string\n icon: TriggerIcon\n}\n\n/**\n * 由来源标注判断该显示成什么 —— 逐条复刻官方 `turn-trigger.ts` 的 switch。\n *\n * 未识别的来源保留「收到执行请求」这一默认,**不假装知道**它的身份或结果\n * (官方注释:Custom sources remain visible without attributing unrecorded\n * identity or success)。\n * @param source - 持久化的来源标注。\n * @returns 标题 key 与图标。\n */\nexport function turnTriggerDetails(source: unknown): TriggerDetails {\n const record = sourceRecord(source)\n switch (textField(record, 'kind')) {\n case 'goal':\n return { titleKey: 'message.trigger.goal', icon: 'goal' }\n case 'agent-message':\n return { titleKey: 'message.trigger.agent', icon: 'agent' }\n case 'team-message':\n return { titleKey: 'message.trigger.team', icon: 'team' }\n case 'subagent-settled':\n return { titleKey: 'message.trigger.subagent', icon: 'subagent' }\n case 'webhook': {\n const github = textField(record, 'provider') === 'github'\n return github\n ? { titleKey: 'message.trigger.github', icon: 'github' }\n : { titleKey: 'message.trigger.webhook', icon: 'webhook' }\n }\n case 'schedule':\n return { titleKey: 'message.trigger.schedule', icon: 'schedule' }\n case 'tool-jobs':\n return { titleKey: 'message.trigger.job', icon: 'job' }\n case 'cordis-host-runner':\n return { titleKey: 'message.trigger.plugin', icon: 'plugin' }\n default:\n return { titleKey: 'message.trigger.request', icon: 'request' }\n }\n}\n\n/** 一次目标轮次,字段已从提示词里还原。 */\nexport interface GoalRound {\n /** 目标原文(JSON 转义已还原)。 */\n objective: string\n /** 本轮序号。 */\n round: number\n /** 轮次上限。 */\n maxRounds: number\n /** `Round:` 行之后那段发给模型的执行指令。 */\n instruction: string\n}\n\n/**\n * 目标轮次提示词的骨架。锚定整串:开头、`Objective:` 行、`Round:` 行、\n * 结尾的闭合标签缺一不可。\n *\n * `(\\d+)\\/(\\d+)` 顺带挡住上限缺失的情形(内核在 `maxGoalRounds` 未设时会\n * 写出 `Round: 1/undefined`),那种文本会解析失败并整卡回退。\n */\nconst GOAL_ROUND = /^<goal_round>\\nObjective: (.*)\\nRound: (\\d+)\\/(\\d+)\\n\\n([\\s\\S]*)\\n<\\/goal_round>$/\n\n/**\n * 解析一段目标轮次提示词;结构不符即整体放弃。\n * @param text - 内容拼接后的文本。\n * @returns 还原后的字段,或 null。\n */\nexport function parseGoalRound(text: string): GoalRound | null {\n const matched = GOAL_ROUND.exec(text)\n if (matched === null) return null\n const [, encoded, round, maxRounds, instruction] = matched\n if (encoded === undefined || round === undefined || maxRounds === undefined || instruction === undefined) {\n return null\n }\n // `Objective` 侧做过 JSON.stringify,转义必须经 JSON.parse 还原;目标里本来\n // 含 `</goal_round>` 字样时它也是转义的,不会破坏上面的分段。\n let objective: unknown\n try {\n objective = JSON.parse(encoded)\n } catch {\n return null\n }\n if (typeof objective !== 'string') return null\n return {\n objective,\n round: Number(round),\n maxRounds: Number(maxRounds),\n instruction,\n }\n}\n\n/**\n * 来源里记录的轮次号。\n *\n * 它是**结构化事实**,比提示词文本可靠 —— 两者不一致时以它为准(解析成功但\n * 来源缺失的情况也存在,例如旧记录,那时回落到文本里的数字)。\n */\nfunction roundFromSource(source: unknown): number | null {\n const record = sourceRecord(source)\n if (textField(record, 'kind') !== 'goal') return null\n const round = record.round\n return typeof round === 'number' && Number.isInteger(round) && round > 0 ? round : null\n}\n\n/**\n * 取一条消息的目标轮次,供卡片决定用哪种展开体。\n * @param node - 触发节点的时间、内容与来源。\n * @returns 字段齐备的目标轮次,或 null(调用方渲染等价外壳)。\n */\nexport function goalRoundOf(node: Pick<TriggerNodeLike, 'content' | 'source'>): GoalRound | null {\n const text = plainText(node.content)\n if (text === null) return null\n const parsed = parseGoalRound(text)\n if (parsed === null) return null\n const fromSource = roundFromSource(node.source)\n return fromSource === null ? parsed : { ...parsed, round: fromSource }\n}\n\n/** 两位补零。 */\nfunction pad2(value: number): string {\n return String(value).padStart(2, '0')\n}\n\n/**\n * 紧凑的本地时间戳 —— 复刻 ui-chat 的 `formatMessageClock`。\n *\n * 跨插件不能 import 它的值(client bundle 的 purity gate 禁止 feature plugin\n * 之间做运行时 import),所以这份实现与它同源:同一天只给 `HH:mm`,同年补上\n * `clock.md` 的日期模板,跨年用 `clock.ymd`。日期模板仍从调用方的 locale\n * seat 取,插件不自带文案。\n * @param time - 记录时间(Unix epoch ms)。\n * @param t - 提供 `clock.md` / `clock.ymd` 模板的翻译席位。\n * @param now - 判定「今天 / 今年」的参照时刻。\n * @returns 与官方卡片一致的时钟串。\n */\nexport function formatClock(time: number, t: TriggerTranslate, now: number = Date.now()): string {\n const date = new Date(time)\n const reference = new Date(now)\n const clock = `${pad2(date.getHours())}:${pad2(date.getMinutes())}`\n if (\n date.getFullYear() === reference.getFullYear()\n && date.getMonth() === reference.getMonth()\n && date.getDate() === reference.getDate()\n ) {\n return clock\n }\n const params = { y: date.getFullYear(), m: date.getMonth() + 1, d: date.getDate() }\n const day = date.getFullYear() === reference.getFullYear()\n ? t('clock.md', params)\n : t('clock.ymd', params)\n return `${day} ${clock}`\n}\n","/**\n * 触发通知卡:接管 `conversation.chat.node` 的 `turn-trigger` key。\n *\n * 官方 `TurnTriggerNodeView` 是「图标 + 标题 + 时间 + chevron」的折叠条,\n * 展开体把模型看到的那段文本原样交给 `NoticeBody`(→ `<pre>`)。对目标轮次\n * 来说,那段文本是**提示词原文**(`<goal_round>` / `Objective:` / `Round:`),\n * 骨架对人不构成信息却占满展开区。\n *\n * 本组件保留官方全部信息与交互(折叠、时间、explanation、原文可查),另加:\n * ① 折叠头补**轮次徽标**(收起态即可读到走到第几轮);\n * ② 目标轮次的展开体改为字段化(目标 / 模型收到的指令),标签与转义消失;\n * ③ 其余触发来源按官方同构渲染(见下)。\n *\n * ## 接管是全 key 的\n *\n * `conversation.chat.node` 是 keyed cell,`priority` 最低者渲染 —— 注册\n * `turn-trigger` 的 `priority: -1` 会让**全部**触发来源都走本组件,这正是\n * 官方 `turnTriggerDetails` 被逐条复刻到 `trigger-model.ts` 的原因。判别只\n * 认 `source.kind`,不认标题文本。\n *\n * 代价:官方对该面板的后续改进会被遮蔽(0.2.0 就把 `schedule` 的图标从\n * `IconAlarmClockOutlineRegular` 换成了 `IconClockOutlineRegular`),今后要\n * 手动跟进。与 `ask_user_question`、`present` 两处接管同一性质。\n *\n * 全部派生在 `trigger-model.ts` 里,本文件只做 JSX。\n */\nimport { useId, useState, type ComponentType, type ReactNode } from 'react'\nimport {\n IconAgentPresetOutlineRegular, IconBranchOutlineRegular, IconChevronDownOutlineRegular,\n IconClockOutlineRegular, IconContextInjectionOutlineRegular, IconCordisPluginOutlineRegular,\n IconGlobeOutlineRegular, IconGoalOutlineRegular, IconPaperPlaneOutlineRegular,\n IconQueueOutlineRegular, JsonBlock, type IconProps,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport {\n contentRuns, formatClock, goalRoundOf, turnTriggerDetails,\n type ContentRun, type GoalRound, type TriggerIcon, type TriggerNodeLike, type TriggerTranslate,\n} from './trigger-model.ts'\nimport css from './trigger-card.module.css'\n\n/** 本卡从 slot owner 收到的字段;其余 owner props 与本卡无关。 */\nexport interface TriggerCardProps {\n /**\n * Chat Node。上下文消息在 `node.data` 上 —— 官方 `TurnTriggerNodeView`\n * 读的也是 `node.data.content` / `.source` / `.time`,`node` 本身只有\n * kind / key / location 这些位置信息。\n */\n node: { data: TriggerNodeLike }\n t: TriggerTranslate\n}\n\n/** 与官方 `TurnTriggerNodeView` 逐项相同的图标映射(`schedule` 用 0.2.0 的选择,两版内核都导出它)。 */\nconst TRIGGER_ICONS: Record<TriggerIcon, ComponentType<IconProps>> = {\n request: IconContextInjectionOutlineRegular,\n goal: IconGoalOutlineRegular,\n agent: IconPaperPlaneOutlineRegular,\n team: IconAgentPresetOutlineRegular,\n subagent: IconAgentPresetOutlineRegular,\n github: IconBranchOutlineRegular,\n webhook: IconGlobeOutlineRegular,\n schedule: IconClockOutlineRegular,\n job: IconQueueOutlineRegular,\n plugin: IconCordisPluginOutlineRegular,\n}\n\n/**\n * 轮次徽标。文案是插件自有 —— chat 字典里没有「第 N / M 轮」这样的 key,\n * 与交付行的折叠摘要直写中文同一取径。\n * @param props - 已还原的轮次字段。\n * @returns 徽标。\n */\nfunction RoundBadge({ goal }: { goal: GoalRound }) {\n return <span className={css.round}>{`第 ${String(goal.round)} / ${String(goal.maxRounds)} 轮`}</span>\n}\n\n/**\n * 目标轮次的展开体:字段化,标签与转义都不再出现。\n *\n * 指令段独立成一节并默认收起 —— 它是给模型的执行要求,对人是噪音,但**不该\n * 销毁**(它解释了模型这一轮为什么会这么干),所以保留可查性而不是删掉。\n * @param props - 已还原的轮次字段。\n * @returns 两节字段。\n */\nfunction GoalRoundBody({ goal }: { goal: GoalRound }) {\n return (\n <div className={css.detail}>\n <dl className={css.pair}>\n <dt className={css.key}>目标</dt>\n <dd className={css.value} data-trigger-objective>{goal.objective}</dd>\n </dl>\n <details className={css.instruction}>\n <summary className={css.instructionSummary}>模型收到的指令</summary>\n <pre className={css.instructionText}>{goal.instruction}</pre>\n </details>\n </div>\n )\n}\n\n/**\n * 非目标轮次的展开体:与官方 `NoticeBody` 同构 —— 文本按真实换行显示,\n * 本版本不认识的块单独渲染而不是消失。\n * @param props - 内容分段与翻译席位。\n * @returns 原文块。\n */\nfunction PlainBody({ runs, t }: { runs: readonly ContentRun[]; t: TriggerTranslate }): ReactNode {\n return runs.map((run, index) => (run.kind === 'text'\n ? <pre key={index} className={css.text} data-context-text>{run.text}</pre>\n : (\n <JsonBlock\n key={index}\n label={t('message.unknownBlock')}\n payload={run.block}\n truncatedLabel={total => t('json.truncated', { total })}\n />\n )))\n}\n\n/**\n * 渲染一张触发通知卡。\n * @param props - 节点数据与翻译席位(注册时声明 `chat` 命名空间)。\n * @returns 折叠卡;收起的展开体由内容形态决定。\n */\nexport function TriggerCard({ node, t }: TriggerCardProps) {\n const [open, setOpen] = useState(false)\n const bodyId = useId()\n const data = node.data\n const details = turnTriggerDetails(data.source)\n const TriggerIcon = TRIGGER_ICONS[details.icon]\n const goal = goalRoundOf(data)\n const runs = contentRuns(data.content)\n const time = formatClock(data.time, t)\n // 时间来自会话日志(durable 数据),缺一个合法值时不该整卡崩掉 ——\n // 崩溃会被 slot 系统接住并静默回落到官方注册,用户只看到\"插件没生效\"。\n const instant = new Date(data.time)\n const stamp = Number.isNaN(instant.getTime()) ? undefined : instant.toISOString()\n return (\n <section className={css.root} data-turn-trigger data-trigger-card>\n <button\n className={css.header}\n type=\"button\"\n aria-expanded={open}\n aria-controls={bodyId}\n onClick={() => { setOpen(!open) }}\n >\n <span className={css.icon} aria-hidden><TriggerIcon size={14} /></span>\n <span className={css.title}>{t(details.titleKey)}</span>\n {goal !== null && <RoundBadge goal={goal} />}\n <time className={css.time} dateTime={stamp}>{time}</time>\n <IconChevronDownOutlineRegular size={12} className={open ? css.openChevron : css.chevron} />\n </button>\n {open && (\n <div id={bodyId} className={css.body}>\n <p className={css.explanation}>{t('message.trigger.explanation')}</p>\n {goal !== null\n ? <GoalRoundBody goal={goal} />\n : <div className={css.content}>{runs !== null && <PlainBody runs={runs} t={t} />}</div>}\n </div>\n )}\n </section>\n )\n}\n","/**\n * Browser half: binds the `node-appearance` settings scope, paints the chat\n * flow from it (a single <style data-plugin-css> tag rebuilt on every\n * snapshot change), and registers the settings card.\n */\n\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type { ConfigForm } from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: the `ctx.configForms` Context merge, plus the Plugins page's SlotMap\n// merge (the `plugins.bundle.config` entry). Cross-plugin collaboration goes through\n// cordis services; a value import would fail the client bundle-purity gate.\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-plugin-manager/client'\n// Type-only: the ctx.slots Context merge comes from the renderer package\n// (slot registry), not from the removed dsh-client-runtime module.\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport { buildCss, NODE_APPEARANCE_NS, STYLE_TAG_ID, type NodeAppearanceSettings } from './palette.ts'\nimport { NodeAppearanceRow, type NodeAppearanceRowFace } from './settings-card.tsx'\nimport { AskQuestionRow } from './ask-card.tsx'\nimport { DeliverableRow } from './deliverable-row.tsx'\nimport { GoalDetail } from './goal-detail.tsx'\nimport { TriggerCard } from './trigger-card.tsx'\n\nexport const inject = ['slots', 'connection', 'remote', 'configForms']\n\n/** Upsert the plugin's paint stylesheet with the current snapshot's CSS. */\nfunction paint(form: ConfigForm<NodeAppearanceSettings>): void {\n let tag = document.querySelector<HTMLStyleElement>(`style[data-plugin-css=\"${STYLE_TAG_ID}\"]`)\n if (tag === null) {\n tag = document.createElement('style')\n tag.dataset.plugin = NODE_APPEARANCE_NS\n tag.dataset.pluginCss = STYLE_TAG_ID\n document.head.appendChild(tag)\n }\n tag.textContent = buildCss(form.getSnapshot().value)\n}\n\n/**\n * Mount the node-appearance plugin on the page.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n // 0.1.7:`settingsScope` 已从 client 服务面移除(`settingsScope` 在 client 包里\n // 0 命中),取而代之的是官方 ui-settings 提供的 `configForms`。`configForms.get(ns)`\n // 返回的 `ConfigForm<T>` 与旧的 scope 面几乎同形——`getSnapshot()` / `subscribe()` /\n // `set(field, value)` 同名同义,额外提供 `mutate(ops, rev)` 与 `unset(field)`。\n // 参数 ns 是 Host 插件的 entry id(`ConfigForms.get` 的 JSDoc:Unique Host plugin\n // entry id),与本插件的 `cordis.patch.yml` 行 id(`node-appearance`)同值。\n const form = ctx.configForms.get<NodeAppearanceSettings>(NODE_APPEARANCE_NS)\n // Paint once from the current snapshot (defaults before the first Host read).\n paint(form)\n ctx.effect(\n () => form.subscribe(() => { paint(form) }),\n 'dsh-node-appearance: repaint on settings change',\n )\n\n const face: NodeAppearanceRowFace = {\n hooks: { nodeAppearance: form },\n // Staged-edit save: write the three keys in one write.\n //\n // `colors` / `toolColors` 是**对象**字段,不能走 `set(field, value)`——它的\n // JSDoc 写明只接受 scalar field。改用 `mutate()` 的路径操作:`SettingsPathOpView`\n // 是 `{ op: 'set'; path: string[]; value }`,其注释说明写入会「creating\n // intermediate objects」,所以 `['colors']` 整个子树可以一次写掉。\n apply: async (value) => {\n await form.mutate([\n { op: 'set', path: ['showThinking'], value: value.showThinking ?? true },\n { op: 'set', path: ['colors'], value: value.colors ?? {} },\n { op: 'set', path: ['toolColors'], value: value.toolColors ?? {} },\n ] as never)\n },\n setShowThinking: (show) => { void form.set('showThinking', show) },\n setCategoryColor: (category, color) => {\n const value = form.getSnapshot().value\n void form.mutate([\n { op: 'set', path: ['colors'], value: { ...value?.colors, [category]: color } },\n ] as never)\n },\n setToolColor: (tool, color) => {\n const value = form.getSnapshot().value\n void form.mutate([\n { op: 'set', path: ['toolColors'], value: { ...value?.toolColors, [tool]: color } },\n ] as never)\n },\n removeToolColor: (tool) => {\n const value = form.getSnapshot().value\n const toolColors = { ...value?.toolColors }\n delete toolColors[tool]\n void form.mutate([{ op: 'set', path: ['toolColors'], value: toolColors }] as never)\n },\n }\n\n // 0.1.7:卡片挂到 Plugins 页的 `plugins.bundle.config`(旧 `settings.plugin.item`\n // 已不存在——它在 client 包里 0 命中,且替代者 `plugins.item` 按契约注释是\n // 「OCCUPIED by the official settings pages」的官方专区,第三方不该占)。\n // 本插件的 package.json 声明了 `dsh.bundle.patch`,因此它自身就是一个 bundle,\n // key 用**包名**(`config-ledger.ts` 的 `keysOf('plugins.bundle.config')` 直接取\n // `entry.options.key`,而 `plugins.row.config` 才用 `包名#行id`)。\n // 该槽只渲染 `view: 'page'`,卡片在 summary 下返回 null(见 settings-card.tsx)。\n ctx.slots.inject('plugins.bundle.config', () => ctx.slots.register({\n name: 'plugins.bundle.config',\n key: '@max-null/dsh-node-appearance',\n inject: () => face,\n }, NodeAppearanceRow))\n\n // 接管官方提问卡。官方 ui-tool 在 `tool.call.toolview` 的\n // `ask_user_question` key 上有一条 priority 0 的注册,而 keyed cell 只\n // 渲染最低 priority 的条目(ui-slots `register()` 的 shadowing 规则),\n // priority -1 因此遮蔽它——这是 DSH 支持的接管姿势(ui-tool 的 slot 契约\n // 原文:a key the shipped composition already covers is replaced, not shared)。\n //\n // 接管的唯一原因:官方转录卡只保留已选答案,把调用参数里的 `options`\n // 丢掉了,提问一旦结算就再也看不到当时有哪些选项(详见 ask-model.ts)。\n //\n // 类型期放宽同 settings 那条:`tool.call.toolview` 的 SlotMap 声明属于官方\n // @deepseek-ai/dsh-client-ui-tool,本插件不为此引入依赖。\n ctx.slots.inject('tool.call.toolview' as never, () => ctx.slots.register({\n name: 'tool.call.toolview',\n key: 'ask_user_question',\n priority: -1,\n // 复用官方 conversation 字典:卡片文案(提问 / N/M 已回答 / 未回答 /\n // 查看 …)全部取自它,插件不新造 locale 命名空间。\n locale: 'conversation',\n } as never, AskQuestionRow as never))\n\n // 接管官方交付行。姿势与理由同提问卡:ui-deliverables 在 `tool.call.toolview`\n // 的 `present` key 上有一条 priority 0 的注册,keyed cell 只渲染最低 priority\n // 的条目,priority -1 因此遮蔽它。\n //\n // 接管的唯一原因:官方折叠态把全部文件名逗号拼成一行,多文件时读不完,也看不出\n // 这一轮交付了几个(详见 deliverable-row.tsx)。\n ctx.slots.inject('tool.call.toolview' as never, () => ctx.slots.register({\n name: 'tool.call.toolview',\n key: 'present',\n priority: -1,\n // 复用官方 deliverables 字典:「交付文件 / 正在交付 / 已交付 / 交付失败 /\n // 已中断 / 查看调用」全部取自它,插件不新造 locale 命名空间。\n locale: 'deliverables',\n } as never, DeliverableRow as never))\n\n // 目标详情折叠条:挂进输入框上方的 `conversation.input.dock`(list 槽,\n // 不同 id 各自成格、并列渲染),order 11 紧随官方 ui-goal 的 order 10 ——\n // 官方条只显示一行被 ellipsis 截断的目标,这里补一个可展开的详情。\n //\n // 只读 `useProjection('goal')`,不碰官方条的 edit/pause/resume/clear ——\n // 那四个 Remote 动词与 activation 订阅源都是 ui-goal 的注册者私有注入面,\n // 接管它们等于在本插件里再养一套会写会话数据的 RPC 客户端。\n ctx.slots.inject('conversation.input.dock' as never, () => ctx.slots.register({\n name: 'conversation.input.dock',\n id: 'max-null/goal-detail',\n order: 11,\n } as never, GoalDetail as never))\n\n // 接管官方触发通知卡(「继续执行目标」那一类)。姿势同前两处:keyed cell 只\n // 渲染最低 priority 的条目,priority -1 因此遮蔽官方的 TurnTriggerNodeView。\n //\n // 接管的唯一原因:官方展开体把模型提示词原文(`<goal_round>` / `Objective:`\n // / `Round:` / JSON 转义)连同骨架一起显示,而骨架对人不构成信息却占满版面\n // (详见 trigger-card.tsx)。折叠头另加轮次徽标,收起态即可读到走到第几轮。\n //\n // 注意遮蔽是**全 key** 的:全部触发来源(goal / schedule / webhook / job …)\n // 都会走本插件组件,所以 trigger-model.ts 逐条复刻了官方的 kind → 标题/图标\n // 映射,非目标轮次的来源按官方同构渲染。\n //\n // 类型期放宽同前两处:`conversation.chat.node` 的 SlotMap 声明属于官方\n // @deepseek-ai/dsh-client-ui-chat,本插件不为此引入依赖。\n ctx.slots.inject('conversation.chat.node' as never, () => ctx.slots.register({\n name: 'conversation.chat.node',\n key: 'turn-trigger',\n priority: -1,\n // 复用官方 chat 字典:标题(message.trigger.*)、说明\n // (message.trigger.explanation)、时间模板(clock.md / clock.ymd)全部取自\n // 它,插件不新造 locale 命名空间。\n locale: 'chat',\n } as never, TriggerCard as never))\n}\n"],"mappings":"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"}
|
package/lib/index.js
CHANGED
|
@@ -17,6 +17,7 @@ const DEFAULT_COLORS = {
|
|
|
17
17
|
command: "#f97316",
|
|
18
18
|
thinking: "#c4b5fd",
|
|
19
19
|
context: "#8a9bb5",
|
|
20
|
+
summary: "#94a3b8",
|
|
20
21
|
steering: "#14b8a6",
|
|
21
22
|
other: "#64748b"
|
|
22
23
|
};
|
|
@@ -33,6 +34,7 @@ const Config = z.object({
|
|
|
33
34
|
command: z.string().default(DEFAULT_COLORS.command),
|
|
34
35
|
thinking: z.string().default(DEFAULT_COLORS.thinking),
|
|
35
36
|
context: z.string().default(DEFAULT_COLORS.context),
|
|
37
|
+
summary: z.string().default(DEFAULT_COLORS.summary),
|
|
36
38
|
steering: z.string().default(DEFAULT_COLORS.steering),
|
|
37
39
|
other: z.string().default(DEFAULT_COLORS.other)
|
|
38
40
|
}).default(DEFAULT_COLORS).volatile(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAiBnE,eAAO,MAAM,MAAM,UAAmD,CAAA;AActE;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAsI9C"}
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
export declare const NODE_APPEARANCE_NS = "node-appearance";
|
|
10
10
|
/** The plugin's style tag identity (removed/replaced on every re-paint). */
|
|
11
11
|
export declare const STYLE_TAG_ID = "node-appearance/rules";
|
|
12
|
-
/** One paintable node category. `command`, `thinking`, `context` are non-tool rows. */
|
|
13
|
-
export type NodeCategory = 'search' | 'agent' | 'execute' | 'file' | 'deliver' | 'task' | 'ask' | 'command' | 'thinking' | 'context' | 'steering' | 'other';
|
|
12
|
+
/** One paintable node category. `command`, `thinking`, `context`, `summary` are non-tool rows. */
|
|
13
|
+
export type NodeCategory = 'search' | 'agent' | 'execute' | 'file' | 'deliver' | 'task' | 'ask' | 'command' | 'thinking' | 'context' | 'summary' | 'steering' | 'other';
|
|
14
14
|
/** Accent color per category (CSS colors). */
|
|
15
15
|
export type NodeAppearanceColors = Record<NodeCategory, string>;
|
|
16
16
|
/** The settings value this plugin reads from its namespace scope. */
|
|
@@ -25,7 +25,24 @@ export interface NodeAppearanceSettings {
|
|
|
25
25
|
/** Initial palette: mid-luminance hues readable on both light and dark themes. */
|
|
26
26
|
export declare const DEFAULT_COLORS: NodeAppearanceColors;
|
|
27
27
|
/** Wire tool name → category for the shipped mapping. */
|
|
28
|
-
export declare const TOOL_CATEGORIES: Record<Exclude<NodeCategory, 'command' | 'thinking' | 'context' | 'steering'>, readonly string[]>;
|
|
28
|
+
export declare const TOOL_CATEGORIES: Record<Exclude<NodeCategory, 'command' | 'thinking' | 'context' | 'summary' | 'steering'>, readonly string[]>;
|
|
29
|
+
/**
|
|
30
|
+
* The activity keys a step-process group header publishes on its
|
|
31
|
+
* `data-process-activity` attribute. The set is the key list of ui-chat's
|
|
32
|
+
* `ChatGroupSeat` `PROCESS_ICONS`, which is identical in kernel 0.1.7-rc.2 and
|
|
33
|
+
* 0.2.0-rc.1. A closed group reports the kernel's top-ranked category; a
|
|
34
|
+
* running one reports its live activity.
|
|
35
|
+
*/
|
|
36
|
+
export type ProcessActivityKind = 'thinking' | 'read' | 'readImage' | 'search' | 'edit' | 'write' | 'commands' | 'code' | 'webSearch' | 'webFetch' | 'subagents' | 'plan' | 'questions' | 'tools';
|
|
37
|
+
/**
|
|
38
|
+
* Process activity → the category whose color paints a collapsed group header.
|
|
39
|
+
*
|
|
40
|
+
* The mapping lands on categories the plugin already ships, so group headers
|
|
41
|
+
* reuse the configured palette and add no settings field. It is deliberately
|
|
42
|
+
* the same classification the expanded member rows get: `search` here means
|
|
43
|
+
* code search (`grep`/`glob`, a `file` category tool), not `web_search`.
|
|
44
|
+
*/
|
|
45
|
+
export declare const PROCESS_ACTIVITIES: Record<ProcessActivityKind, NodeCategory>;
|
|
29
46
|
/**
|
|
30
47
|
* Accept a configured CSS color (hex, color functions) or reject it so an
|
|
31
48
|
* invalid value falls back to the category default instead of poisoning CSS.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"palette.d.ts","sourceRoot":"","sources":["../../../src/client/palette.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,oFAAoF;AACpF,eAAO,MAAM,kBAAkB,oBAAoB,CAAA;AAEnD,4EAA4E;AAC5E,eAAO,MAAM,YAAY,0BAAgC,CAAA;AAEzD,
|
|
1
|
+
{"version":3,"file":"palette.d.ts","sourceRoot":"","sources":["../../../src/client/palette.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,oFAAoF;AACpF,eAAO,MAAM,kBAAkB,oBAAoB,CAAA;AAEnD,4EAA4E;AAC5E,eAAO,MAAM,YAAY,0BAAgC,CAAA;AAEzD,kGAAkG;AAClG,MAAM,MAAM,YAAY,GACpB,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,CAAA;AAEhJ,8CAA8C;AAC9C,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAA;AAE/D,qEAAqE;AACrE,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAClC,sEAAsE;IACtE,MAAM,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,SAAS,CAAA;IAClD,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;CAChD;AAED,kFAAkF;AAClF,eAAO,MAAM,cAAc,EAAE,oBAc5B,CAAA;AAED,yDAAyD;AACzD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CASzI,CAAA;AAED;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,GAC3B,UAAU,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAC/D,UAAU,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,GAC9C,WAAW,GAAG,MAAM,GAAG,WAAW,GAAG,OAAO,CAAA;AAEhD;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,mBAAmB,EAAE,YAAY,CAexE,CAAA;AA4ED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAKjD;AAED,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,sBAAsB,GAAG,oBAAoB,CAUpF;AAcD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,GAAG,SAAS,GAAG,MAAM,CA6G7E"}
|