@max-null/dsh-node-appearance 0.3.5 → 0.4.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/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["useState","css","IconChevronDownOutline14"],"sources":["../src/client/palette.ts","../src/client/settings-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` are non-tool rows. */\nexport type NodeCategory =\n | 'search' | 'agent' | 'execute' | 'file' | 'task' | '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 task: '#ec4899', // pink — todo_write / goal / job_* / schedule_*\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 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 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 plugin's General-settings row: a \"节点外观\" title with the standard\n * chevron, expanding to palette rows, tool overrides, and the Think\n * visibility switch. Reads the namespace scope through the injected hooks\n * face and writes through the injected actions; every change applies\n * immediately. Drawn by hand (no value import from ui-settings-plugins — the\n * client bundle purity gate forbids cross-plugin value imports), styled with\n * the DSH design tokens like the shipped Appearance row.\n */\n\nimport { useState, type ChangeEvent, type FormEvent } from 'react'\nimport type { ObservableSnapshot } from '@deepseek-ai/dsh-client-store'\nimport type { SettingsScope, SettingsScopeSnapshot } from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { IconChevronDownOutline14 } 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'\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 row's inject face: the read-only scope snapshot plus write actions. */\nexport interface NodeAppearanceRowFace {\n hooks: {\n /** The bound settings-scope snapshot, rendered as useNodeAppearance. */\n nodeAppearance: ObservableSnapshot<SettingsScopeSnapshot<NodeAppearanceSettings>>\n }\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<'settings.plugin.item'>\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 task: '任务 / 目标',\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/**\n * Render the node-appearance General row.\n * @param props - the injected scope snapshot hook and write actions.\n * @returns the row, always visible once its namespace is served.\n */\nexport function NodeAppearanceRow({ useNodeAppearance, setShowThinking, setCategoryColor, setToolColor, removeToolColor }: NodeAppearanceRowProps) {\n const [open, setOpen] = useState(false)\n const [toolName, setToolName] = useState('')\n const [toolColor, setToolColorDraft] = useState('#64748b')\n const snapshot = useNodeAppearance(snapshot => snapshot)\n const colors = resolveColors(snapshot.value ?? {})\n const toolColors = snapshot.value?.toolColors ?? {}\n const showThinking = snapshot.value?.showThinking ?? true\n const disabled = snapshot.writable === false\n\n const addTool = (event: FormEvent) => {\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 <div className={css.group}>\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={open}\n onClick={() => { setOpen(!open) }}\n >\n <span className={css.title}>节点外观</span>\n <IconChevronDownOutline14 className={open ? css.chevronOpen : css.chevron} />\n </button>\n {open && (\n <div className={css.body}>\n {snapshot.status !== 'ready' && (\n <p className={css.statusLine}>\n {snapshot.status === 'unavailable'\n ? '配置暂不可用:插件主机侧未挂载或连接非本机。'\n : '配置加载中…'}\n </p>\n )}\n <div className={`${disabled ? css.disabled : ''}`}>\n <div className={css.row}>\n <label className={css.rowLabel} htmlFor=\"node-appearance-show-thinking\">显示思考过程</label>\n <span className={css.rowHint}>关闭后会话中的 Think 思考行隐藏</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}`}>\n {CATEGORY_LABELS[category]}\n </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}>工具颜色覆盖(可选)</div>\n {Object.entries(toolColors).map(([tool, color]) => (\n <div className={css.toolRow} 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) }}>删除</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\n className={css.colorInput}\n type=\"color\"\n value={toolColor}\n onChange={(event: ChangeEvent<HTMLInputElement>) => { setToolColorDraft(event.target.value) }}\n />\n <button type=\"submit\" className={css.addButton} disabled={toolName.trim() === ''}>添加</button>\n </form>\n </div>\n </div>\n )}\n </div>\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 { SettingsScope } from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: the ctx.settingsScope Context merge and the slot's declaration.\n// Cross-plugin collaboration goes through cordis services; a value import\n// 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-settings-plugins/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'\n\nexport const inject = ['slots', 'connection', 'remote', 'settingsScope']\n\n/** Upsert the plugin's paint stylesheet with the current snapshot's CSS. */\nfunction paint(scope: SettingsScope<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(scope.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 // settingsScope 由官方 ui-settings 服务提供(DSH 0.1.2-alpha 内核 client\n // 模块表);bind 返回该命名空间的强类型 scope(read/set/unset/subscribe)。\n const scope = ctx.settingsScope.bind<NodeAppearanceSettings>({ namespace: NODE_APPEARANCE_NS })\n // Paint once from the current snapshot (defaults before the first Host read).\n paint(scope)\n ctx.effect(\n () => scope.subscribe(() => { paint(scope) }),\n 'dsh-node-appearance: repaint on settings change',\n )\n\n const face: NodeAppearanceRowFace = {\n hooks: { nodeAppearance: scope },\n setShowThinking: (show) => { void scope.set('showThinking', show) },\n setCategoryColor: (category, color) => {\n const value = scope.getSnapshot().value\n void scope.set('colors', { ...value?.colors, [category]: color })\n },\n setToolColor: (tool, color) => {\n const value = scope.getSnapshot().value\n void scope.set('toolColors', { ...value?.toolColors, [tool]: color })\n },\n removeToolColor: (tool) => {\n const value = scope.getSnapshot().value\n const toolColors = { ...value?.toolColors }\n delete toolColors[tool]\n void scope.set('toolColors', toolColors)\n },\n }\n\n // alpha.2:General 区 slot(settings.general.item)已退役,接入官方\n // 「可配置插件」Tab 的 settings.plugin.item(keyed by namespace)——官方\n // 卡片姿势见 dsh-client-ui-settings-plugins/src/client/index.ts(BashCard 等)。\n ctx.slots.inject('settings.plugin.item', () => ctx.slots.register({\n name: 'settings.plugin.item',\n key: NODE_APPEARANCE_NS,\n inject: () => face,\n // npm ui-slots (0.0.1-rc.1) 类型未合并 keyed-slot 选项(官方 monorepo 类型\n // 才有)——运行时与官方源码一致,类型期放宽(官方类型同步后收紧)。\n } as never, NodeAppearanceRow))\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["useState","css","IconChevronDownOutline14","css","IconCheckOutline14","useMemo","useState","StateDot","IconQuestionOutline14","DisclosureRow","IconInspectOutline12","css","useState","IconGoalOutline16","IconChevronUpOutline14","IconChevronDownOutline14"],"sources":["../src/client/palette.ts","../src/client/settings-card.tsx","../src/client/ask-model.ts","../src/client/ask-card.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' | '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 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 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 { SettingsScope, SettingsScopeSnapshot } from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { IconChevronDownOutline14 } 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'\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 scope snapshot plus write actions. */\nexport interface NodeAppearanceRowFace {\n hooks: {\n /** The bound settings-scope snapshot, rendered as useNodeAppearance. */\n nodeAppearance: ObservableSnapshot<SettingsScopeSnapshot<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<'settings.plugin.item'>\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 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 const [open, setOpen] = useState(false)\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 <IconChevronDownOutline14 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, IconCheckOutline14, IconInspectOutline12, IconQuestionOutline14, 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 && <IconCheckOutline14 />}\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 : <IconQuestionOutline14 />\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 <IconInspectOutline12 />\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 IconChevronDownOutline14, IconChevronUpOutline14, IconGoalOutline16,\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><IconGoalOutline16 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 ? <IconChevronUpOutline14 /> : <IconChevronDownOutline14 />}\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 { SettingsScope } from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: the ctx.settingsScope Context merge and the slot's declaration.\n// Cross-plugin collaboration goes through cordis services; a value import\n// 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-settings-plugins/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 { GoalDetail } from './goal-detail.tsx'\n\nexport const inject = ['slots', 'connection', 'remote', 'settingsScope']\n\n/** Upsert the plugin's paint stylesheet with the current snapshot's CSS. */\nfunction paint(scope: SettingsScope<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(scope.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 // settingsScope 由官方 ui-settings 服务提供(DSH 0.1.2-alpha 内核 client\n // 模块表);bind 返回该命名空间的强类型 scope(read/set/unset/subscribe)。\n const scope = ctx.settingsScope.bind<NodeAppearanceSettings>({ namespace: NODE_APPEARANCE_NS })\n // Paint once from the current snapshot (defaults before the first Host read).\n paint(scope)\n ctx.effect(\n () => scope.subscribe(() => { paint(scope) }),\n 'dsh-node-appearance: repaint on settings change',\n )\n\n const face: NodeAppearanceRowFace = {\n hooks: { nodeAppearance: scope },\n // Staged-edit save: write the three keys in one face call (Host settles\n // the whole namespace; per-key resolution keeps observable semantics).\n apply: async (value) => {\n await scope.set('showThinking', value.showThinking ?? true)\n await scope.set('colors', value.colors ?? {})\n await scope.set('toolColors', value.toolColors ?? {})\n },\n setShowThinking: (show) => { void scope.set('showThinking', show) },\n setCategoryColor: (category, color) => {\n const value = scope.getSnapshot().value\n void scope.set('colors', { ...value?.colors, [category]: color })\n },\n setToolColor: (tool, color) => {\n const value = scope.getSnapshot().value\n void scope.set('toolColors', { ...value?.toolColors, [tool]: color })\n },\n removeToolColor: (tool) => {\n const value = scope.getSnapshot().value\n const toolColors = { ...value?.toolColors }\n delete toolColors[tool]\n void scope.set('toolColors', toolColors)\n },\n }\n\n // alpha.2:General 区 slot(settings.general.item)已退役,接入官方\n // 「可配置插件」Tab 的 settings.plugin.item(keyed by namespace)——官方\n // 卡片姿势见 dsh-client-ui-settings-plugins/src/client/index.ts(BashCard 等)。\n ctx.slots.inject('settings.plugin.item', () => ctx.slots.register({\n name: 'settings.plugin.item',\n key: NODE_APPEARANCE_NS,\n inject: () => face,\n // npm ui-slots (0.0.1-rc.1) 类型未合并 keyed-slot 选项(官方 monorepo 类型\n // 才有)——运行时与官方源码一致,类型期放宽(官方类型同步后收紧)。\n } as never, 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 // 目标详情折叠条:挂进输入框上方的 `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":"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"}
package/lib/index.js CHANGED
@@ -12,6 +12,7 @@ const DEFAULT_COLORS = {
12
12
  execute: "#f59e0b",
13
13
  file: "#22c55e",
14
14
  task: "#ec4899",
15
+ ask: "#65a30d",
15
16
  command: "#f97316",
16
17
  thinking: "#c4b5fd",
17
18
  context: "#8a9bb5",
@@ -26,6 +27,7 @@ const Config = z.object({
26
27
  execute: z.string().default(DEFAULT_COLORS.execute),
27
28
  file: z.string().default(DEFAULT_COLORS.file),
28
29
  task: z.string().default(DEFAULT_COLORS.task),
30
+ ask: z.string().default(DEFAULT_COLORS.ask),
29
31
  command: z.string().default(DEFAULT_COLORS.command),
30
32
  thinking: z.string().default(DEFAULT_COLORS.thinking),
31
33
  context: z.string().default(DEFAULT_COLORS.context),
@@ -0,0 +1,19 @@
1
+ import { type AskToolBlock } from './ask-model.ts';
2
+ /** 注入的 locale 翻译函数(注册时声明 `conversation` 命名空间)。 */
3
+ export interface AskTranslate {
4
+ (key: string, params?: Record<string, string | number>): string;
5
+ }
6
+ /** 卡片从 slot owner 收到的字段;其余 owner props 与本行无关。 */
7
+ export interface AskCardProps {
8
+ t: AskTranslate;
9
+ block: AskToolBlock;
10
+ /** 跳到轨迹视图查看原始调用;缺省时不渲染该入口。 */
11
+ inspect?: (() => void) | undefined;
12
+ }
13
+ /**
14
+ * 渲染一次提问的完整记录。
15
+ * @param props - locale 翻译函数、冻结的调用切片与可选的轨迹入口。
16
+ * @returns 折叠行 + 展开后的选项卡片。
17
+ */
18
+ export declare function AskQuestionRow({ t, block, inspect }: AskCardProps): import("react").JSX.Element;
19
+ //# sourceMappingURL=ask-card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask-card.d.ts","sourceRoot":"","sources":["../../../src/client/ask-card.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAgD,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAGhG,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC3B,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAAA;CAChE;AAED,iDAAiD;AACjD,MAAM,WAAW,YAAY;IAC3B,CAAC,EAAE,YAAY,CAAA;IACf,KAAK,EAAE,YAAY,CAAA;IACnB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAA;CACnC;AAiFD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,YAAY,+BAgDjE"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * 提问卡数据派生:把一次 `ask_user_question` 调用还原成「问题 + 全部选项 +
3
+ * 实际选中项」。
4
+ *
5
+ * 为什么要自己解析:DSH 官方的转录卡只保留**已选答案**
6
+ * (`ui-tool/src/client/tool/toolviews/ask-question-row.tsx` 的
7
+ * `questionEntries()` 只取 `id`/`question`,把 `options` 丢掉了),所以提问
8
+ * 结算后「当时还有哪些选项」在客户端管线上就没了。选项列表只存在于调用的
9
+ * 参数 JSON 里 —— 这也是本插件接管 `ask_user_question` toolview 的唯一原因。
10
+ *
11
+ * 本模块是纯函数:不碰 locale、不碰 DOM,解析失败一律降级而不是抛错
12
+ * (接管后卡片由我们渲染,渲染不出来就等于用户什么都看不到)。
13
+ */
14
+ /** 模型给出的一个可选项。 */
15
+ export interface AskOption {
16
+ /** 选项文本;同时是被 `selected` 回传的那个值。 */
17
+ label: string;
18
+ /** 选项下方的补充说明,模型没给时为空。 */
19
+ description: string;
20
+ }
21
+ /** 一个问题:全部选项 + 实际回答。 */
22
+ export interface AskQuestion {
23
+ id: string;
24
+ question: string;
25
+ /** 可选的短标题(模型提供时显示在问题上方)。 */
26
+ header: string;
27
+ /** 可选的补充说明。 */
28
+ detail: string;
29
+ /** 模型是否允许多选。 */
30
+ multiSelect: boolean;
31
+ /** 模型当时给出的全部选项;调用没带选项时为空数组。 */
32
+ options: AskOption[];
33
+ /** 被选中的选项文本,按回答记录的顺序。 */
34
+ selected: string[];
35
+ /** 直接输入的文本答案(没选选项或额外补充时)。 */
36
+ custom: string;
37
+ }
38
+ /** 行的运行状态,与通用工具行保持同一套词汇。 */
39
+ export type AskRowState = 'running' | 'ok' | 'error' | 'stopped';
40
+ /** 问题集的结算程度。 */
41
+ export type AskPhase = 'pending' | 'answered' | 'unanswered';
42
+ /** 卡片渲染所需的全部派生结果。 */
43
+ export interface AskCardModel {
44
+ state: AskRowState;
45
+ phase: AskPhase;
46
+ /** 被取消或被中断时记录判定来源;正常结算为 undefined。 */
47
+ verdict: 'cancelled' | 'aborted' | undefined;
48
+ questions: AskQuestion[];
49
+ /** 至少选了选项或填了自定义答案的问题数(折叠行的 N/M 用)。 */
50
+ answeredCount: number;
51
+ /**
52
+ * 参数 JSON 解析不出来时用于兜底展示的结果文本;运行中或结果无文本时为
53
+ * null。没有它,一次畸形调用会让接管后的行变成空白。
54
+ */
55
+ fallbackText: string | null;
56
+ }
57
+ /**
58
+ * `ask_user_question` 的 block 里本卡读到的字段子集。
59
+ * 结构照 DSH 的 `ToolCallBlock`(运行中=调用自身,结算后=带 `kind` 的结果
60
+ * 节点)声明为鸭子类型:跨插件只允许 type-only 引用,这里连类型引用都不需要。
61
+ */
62
+ export interface AskToolBlock {
63
+ /** 运行中的调用没有这个字段;结算后为 `'tool-result'`。 */
64
+ kind?: string | undefined;
65
+ callId?: string | undefined;
66
+ /** 运行中形态:调用自身携带参数。 */
67
+ argsRaw?: string | undefined;
68
+ /** 结算形态:调用头(子调用被剥掉时为 null)。 */
69
+ call?: {
70
+ argsRaw?: string | undefined;
71
+ } | null | undefined;
72
+ /** 结算形态:结果内容块。 */
73
+ content?: readonly unknown[] | undefined;
74
+ error?: {
75
+ code?: string | undefined;
76
+ } | undefined;
77
+ isError?: boolean | undefined;
78
+ }
79
+ /** 从结果内容块拼出展示文本(文本块原样、其余块转 JSON)。 */
80
+ export declare function resultTextOf(block: AskToolBlock): string | null;
81
+ /**
82
+ * 从一次提问调用的冻结切片派生卡片模型。
83
+ * @param block - 运行中的调用或已结算的结果节点。
84
+ * @returns 卡片模型;参数或结果畸形时 `questions` 为空并带兜底文本。
85
+ */
86
+ export declare function askCardModel(block: AskToolBlock): AskCardModel;
87
+ /** 折叠行右侧的进度计数(文案由组件用 locale 组装)。 */
88
+ export declare function askProgress(model: AskCardModel): {
89
+ answered: number;
90
+ total: number;
91
+ };
92
+ //# sourceMappingURL=ask-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask-model.d.ts","sourceRoot":"","sources":["../../../src/client/ask-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,kBAAkB;AAClB,MAAM,WAAW,SAAS;IACxB,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,yBAAyB;IACzB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,wBAAwB;AACxB,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,eAAe;IACf,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB;IAChB,WAAW,EAAE,OAAO,CAAA;IACpB,+BAA+B;IAC/B,OAAO,EAAE,SAAS,EAAE,CAAA;IACpB,yBAAyB;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAA;CACf;AAED,4BAA4B;AAC5B,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,GAAG,SAAS,CAAA;AAEhE,gBAAgB;AAChB,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,YAAY,CAAA;AAE5D,qBAAqB;AACrB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,WAAW,CAAA;IAClB,KAAK,EAAE,QAAQ,CAAA;IACf,sCAAsC;IACtC,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,CAAA;IAC5C,SAAS,EAAE,WAAW,EAAE,CAAA;IACxB,sCAAsC;IACtC,aAAa,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,sBAAsB;IACtB,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5B,+BAA+B;IAC/B,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GAAG,IAAI,GAAG,SAAS,CAAA;IAC1D,kBAAkB;IAClB,OAAO,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,CAAA;IACxC,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GAAG,SAAS,CAAA;IACjD,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAC9B;AAoBD,qCAAqC;AACrC,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAS/D;AA6ED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,YAAY,CAwD9D;AAED,oCAAoC;AACpC,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAEpF"}
@@ -0,0 +1,32 @@
1
+ /** 投影里本卡渲染的字段(照 DSH 的 `GoalSnapshot` 声明为鸭子类型)。 */
2
+ export interface GoalSnapshotLike {
3
+ id: string;
4
+ revision: number;
5
+ objective: string;
6
+ phase: 'active' | 'paused' | 'blocked' | 'complete';
7
+ /** 自主轮次上限;未设置时为 undefined。 */
8
+ maxGoalRounds?: number | undefined;
9
+ /** 已开始的自主轮次;旧快照可能没有该字段。 */
10
+ roundsStarted?: number | undefined;
11
+ /** 仅 blocked 阶段存在。 */
12
+ blockedReason?: {
13
+ code: string;
14
+ message: string;
15
+ } | undefined;
16
+ }
17
+ /** `useProjection('goal')` 的返回形状。 */
18
+ export interface GoalProjectionLike {
19
+ goal: GoalSnapshotLike;
20
+ }
21
+ /** 本卡从 slot 标准 props 取用的部分(其余 owner props 与本卡无关)。 */
22
+ export interface GoalDetailProps {
23
+ /** 框架标准投影席位:按 key 读当前会话的投影。 */
24
+ useProjection: (key: string) => GoalProjectionLike | null | undefined;
25
+ }
26
+ /**
27
+ * 渲染目标详情折叠条。
28
+ * @param props - 框架标准投影席位。
29
+ * @returns 折叠条;加载中、无目标、或目标已完成时不渲染(与官方条一致)。
30
+ */
31
+ export declare function GoalDetail({ useProjection }: GoalDetailProps): import("react").JSX.Element | null;
32
+ //# sourceMappingURL=goal-detail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"goal-detail.d.ts","sourceRoot":"","sources":["../../../src/client/goal-detail.tsx"],"names":[],"mappings":"AAuBA,kDAAkD;AAClD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAA;IACnD,8BAA8B;IAC9B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,2BAA2B;IAC3B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,sBAAsB;IACtB,aAAa,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAA;CAC9D;AAED,qCAAqC;AACrC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,gBAAgB,CAAA;CACvB;AAED,qDAAqD;AACrD,MAAM,WAAW,eAAe;IAC9B,+BAA+B;IAC/B,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,kBAAkB,GAAG,IAAI,GAAG,SAAS,CAAA;CACtE;AA+BD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EAAE,aAAa,EAAE,EAAE,eAAe,sCA6C5D"}
@@ -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;AAanE,eAAO,MAAM,MAAM,UAAqD,CAAA;AAcxE;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAwC9C"}
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;AAenE,eAAO,MAAM,MAAM,UAAqD,CAAA;AAcxE;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAgF9C"}
@@ -10,7 +10,7 @@ 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
12
  /** One paintable node category. `command`, `thinking`, `context` are non-tool rows. */
13
- export type NodeCategory = 'search' | 'agent' | 'execute' | 'file' | 'task' | 'command' | 'thinking' | 'context' | 'steering' | 'other';
13
+ export type NodeCategory = 'search' | 'agent' | 'execute' | 'file' | 'task' | 'ask' | 'command' | 'thinking' | 'context' | '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. */
@@ -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,uFAAuF;AACvF,MAAM,MAAM,YAAY,GACpB,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,CAAA;AAEhH,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,oBAW5B,CAAA;AAED,yDAAyD;AACzD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAO7H,CAAA;AA6BD;;;;;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,CAkF7E"}
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,uFAAuF;AACvF,MAAM,MAAM,YAAY,GACpB,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,CAAA;AAExH,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,oBAY5B,CAAA;AAED,yDAAyD;AACzD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAQ7H,CAAA;AA6BD;;;;;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,CAkF7E"}
@@ -1,22 +1,28 @@
1
1
  /**
2
- * The plugin's General-settings row: a "节点外观" title with the standard
3
- * chevron, expanding to palette rows, tool overrides, and the Think
4
- * visibility switch. Reads the namespace scope through the injected hooks
5
- * face and writes through the injected actions; every change applies
6
- * immediately. Drawn by hand (no value import from ui-settings-plugins — the
7
- * client bundle purity gate forbids cross-plugin value imports), styled with
8
- * the DSH design tokens like the shipped Appearance row.
2
+ * The node-appearance plugin config card. Mirrors the official
3
+ * `settings.plugin.item` card chrome (PluginCard: card shell, name-over-
4
+ * description header, chevron disclosure) with the DSH design tokens —
5
+ * drawn by hand because a feature plugin must not runtime-import another
6
+ * feature plugin's values (bundle purity gate).
7
+ *
8
+ * Writes are immediate: picking a color or flipping the Think switch applies
9
+ * it right away (a palette is a live preview, not a staged form). The footer
10
+ * carries one「恢复初始设置」button that resets the whole namespace to the
11
+ * shipped defaults — two-click confirmation so a miss cannot wipe a custom
12
+ * palette.
9
13
  */
10
14
  import type { ObservableSnapshot } from '@deepseek-ai/dsh-client-store';
11
15
  import type { SettingsScopeSnapshot } from '@deepseek-ai/dsh-client-ui-settings/client';
12
16
  import type { InjectFace, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
13
17
  import { type NodeAppearanceSettings, type NodeCategory } from './palette.ts';
14
- /** The row's inject face: the read-only scope snapshot plus write actions. */
18
+ /** The card's inject face: the read-only scope snapshot plus write actions. */
15
19
  export interface NodeAppearanceRowFace {
16
20
  hooks: {
17
21
  /** The bound settings-scope snapshot, rendered as useNodeAppearance. */
18
22
  nodeAppearance: ObservableSnapshot<SettingsScopeSnapshot<NodeAppearanceSettings>>;
19
23
  };
24
+ /** Persist one full value (reset-to-defaults path; resolves on Host settlement). */
25
+ apply(value: NodeAppearanceSettings): Promise<void>;
20
26
  /** Write the Think visibility switch. */
21
27
  setShowThinking(show: boolean): void;
22
28
  /** Merge one category color into the palette section. */
@@ -29,9 +35,9 @@ export interface NodeAppearanceRowFace {
29
35
  /** Props the renderer binds for this plugin config card. */
30
36
  export type NodeAppearanceRowProps = PropsRuntime<'settings.plugin.item'> & InjectFace<NodeAppearanceRowFace>;
31
37
  /**
32
- * Render the node-appearance General row.
33
- * @param props - the injected scope snapshot hook and write actions.
34
- * @returns the row, always visible once its namespace is served.
38
+ * Render the node-appearance config card.
39
+ * @param props - the injected scope snapshot hook, its write actions.
40
+ * @returns the card, matching the official plugin-card chrome.
35
41
  */
36
- export declare function NodeAppearanceRow({ useNodeAppearance, setShowThinking, setCategoryColor, setToolColor, removeToolColor }: NodeAppearanceRowProps): import("react").JSX.Element;
42
+ export declare function NodeAppearanceRow({ useNodeAppearance, apply, setShowThinking, setCategoryColor, setToolColor, removeToolColor }: NodeAppearanceRowProps): import("react").JSX.Element;
37
43
  //# sourceMappingURL=settings-card.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"settings-card.d.ts","sourceRoot":"","sources":["../../../src/client/settings-card.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAA;AACvE,OAAO,KAAK,EAAiB,qBAAqB,EAAE,MAAM,4CAA4C,CAAA;AAEtG,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAEhF,OAAO,EAEL,KAAK,sBAAsB,EAAE,KAAK,YAAY,EAC/C,MAAM,cAAc,CAAA;AAGrB,8EAA8E;AAC9E,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE;QACL,wEAAwE;QACxE,cAAc,EAAE,kBAAkB,CAAC,qBAAqB,CAAC,sBAAsB,CAAC,CAAC,CAAA;KAClF,CAAA;IACD,yCAAyC;IACzC,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACpC,yDAAyD;IACzD,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7D,2DAA2D;IAC3D,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/C,gCAAgC;IAChC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC;AAED,4DAA4D;AAC5D,MAAM,MAAM,sBAAsB,GAChC,YAAY,CAAC,sBAAsB,CAAC,GAClC,UAAU,CAAC,qBAAqB,CAAC,CAAA;AAmBrC;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,iBAAiB,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAE,eAAe,EAAE,EAAE,sBAAsB,+BAqGhJ"}
1
+ {"version":3,"file":"settings-card.d.ts","sourceRoot":"","sources":["../../../src/client/settings-card.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAA;AACvE,OAAO,KAAK,EAAiB,qBAAqB,EAAE,MAAM,4CAA4C,CAAA;AAEtG,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAEhF,OAAO,EAEL,KAAK,sBAAsB,EAAE,KAAK,YAAY,EAC/C,MAAM,cAAc,CAAA;AAGrB,+EAA+E;AAC/E,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE;QACL,wEAAwE;QACxE,cAAc,EAAE,kBAAkB,CAAC,qBAAqB,CAAC,sBAAsB,CAAC,CAAC,CAAA;KAClF,CAAA;IACD,oFAAoF;IACpF,KAAK,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnD,yCAAyC;IACzC,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACpC,yDAAyD;IACzD,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7D,2DAA2D;IAC3D,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/C,gCAAgC;IAChC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC;AAED,4DAA4D;AAC5D,MAAM,MAAM,sBAAsB,GAChC,YAAY,CAAC,sBAAsB,CAAC,GAClC,UAAU,CAAC,qBAAqB,CAAC,CAAA;AA2CrC;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,iBAAiB,EAAE,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAE,eAAe,EAAE,EAAE,sBAAsB,+BA8HvJ"}
@@ -18,6 +18,7 @@ export interface NodeAppearanceColors {
18
18
  execute: string;
19
19
  file: string;
20
20
  task: string;
21
+ ask: string;
21
22
  command: string;
22
23
  thinking: string;
23
24
  context: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAExC,eAAO,MAAM,IAAI,wBAAwB,CAAA;AAEzC;;sDAEsD;AACtD,eAAO,MAAM,kBAAkB,oBAAoB,CAAA;AAEnD,8CAA8C;AAC9C,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,0EAA0E;AAC1E,MAAM,WAAW,MAAM;IACrB,uFAAuF;IACvF,YAAY,EAAE,OAAO,CAAA;IACrB,kCAAkC;IAClC,MAAM,EAAE,oBAAoB,CAAA;IAC5B,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACnC;AAED,kFAAkF;AAClF,eAAO,MAAM,cAAc,EAAE,oBAW5B,CAAA;AAED,eAAO,MAAM,MAAM,EAAE,CAAC,CAAC,MAAM,CAe3B,CAAA;AAEF;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAUxD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAExC,eAAO,MAAM,IAAI,wBAAwB,CAAA;AAEzC;;sDAEsD;AACtD,eAAO,MAAM,kBAAkB,oBAAoB,CAAA;AAEnD,8CAA8C;AAC9C,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,0EAA0E;AAC1E,MAAM,WAAW,MAAM;IACrB,uFAAuF;IACvF,YAAY,EAAE,OAAO,CAAA;IACrB,kCAAkC;IAClC,MAAM,EAAE,oBAAoB,CAAA;IAC5B,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACnC;AAED,kFAAkF;AAClF,eAAO,MAAM,cAAc,EAAE,oBAY5B,CAAA;AAED,eAAO,MAAM,MAAM,EAAE,CAAC,CAAC,MAAM,CAgB3B,CAAA;AAEF;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAUxD"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@max-null/dsh-node-appearance",
3
- "version": "0.3.5",
4
- "description": "会话节点外观插件:按节点类型/工具名着色的可配置配色,思考过程显示开关(DeepSeek Harness Web GUI)",
3
+ "version": "0.4.0",
4
+ "description": "会话节点外观插件:节点/工具分类着色(可配置)、提问卡展示全部选项并高亮选中、目标详情折叠条、思考过程显示开关(DeepSeek Harness Web GUI)",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -24,8 +24,7 @@
24
24
  "files": [
25
25
  "lib",
26
26
  "cordis.patch.yml",
27
- "README.md"
28
- ],
27
+ "README.md", "docs/shots"],
29
28
  "dsh": {
30
29
  "bundle": {
31
30
  "patch": "./cordis.patch.yml"