@max-null/dsh-node-appearance 0.3.6 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/README.md +27 -3
  2. package/docs/shots//344/272/244/344/273/230/350/241/214-/345/261/225/345/274/200.png +0 -0
  3. package/docs/shots//344/272/244/344/273/230/350/241/214-/346/212/230/345/217/240.png +0 -0
  4. package/docs/shots//344/274/232/350/257/235/351/235/242/346/235/277/346/210/252/345/233/276.png +0 -0
  5. package/docs/shots//346/217/220/351/227/256/345/215/241/347/211/207/346/210/252/345/233/276.png +0 -0
  6. package/docs/shots//347/233/256/346/240/207/350/257/246/346/203/205-/345/261/225/345/274/200.png +0 -0
  7. package/docs/shots//347/233/256/346/240/207/350/257/246/346/203/205-/346/212/230/345/217/240.png +0 -0
  8. package/docs/shots//350/256/276/347/275/256/345/215/241/347/211/207.png +0 -0
  9. package/lib/client.js +782 -26
  10. package/lib/client.js.map +1 -1
  11. package/lib/index.js +4 -0
  12. package/lib/types/client/ask-card.d.ts +19 -0
  13. package/lib/types/client/ask-card.d.ts.map +1 -0
  14. package/lib/types/client/ask-model.d.ts +92 -0
  15. package/lib/types/client/ask-model.d.ts.map +1 -0
  16. package/lib/types/client/deliverable-model.d.ts +69 -0
  17. package/lib/types/client/deliverable-model.d.ts.map +1 -0
  18. package/lib/types/client/deliverable-row.d.ts +19 -0
  19. package/lib/types/client/deliverable-row.d.ts.map +1 -0
  20. package/lib/types/client/goal-detail.d.ts +32 -0
  21. package/lib/types/client/goal-detail.d.ts.map +1 -0
  22. package/lib/types/client/index.d.ts.map +1 -1
  23. package/lib/types/client/palette.d.ts +1 -1
  24. package/lib/types/client/palette.d.ts.map +1 -1
  25. package/lib/types/client/settings-card.d.ts.map +1 -1
  26. package/lib/types/index.d.ts +2 -0
  27. package/lib/types/index.d.ts.map +1 -1
  28. package/package.json +3 -4
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 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 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 * 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 // 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"],"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","DisclosureRow","StateDot","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/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 { 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 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 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 * 交付行数据派生:把一次 `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, IconInspectOutline12, 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 <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 { DeliverableRow } from './deliverable-row.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 // 接管官方交付行。姿势与理由同提问卡: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":"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"}
package/lib/index.js CHANGED
@@ -11,7 +11,9 @@ const DEFAULT_COLORS = {
11
11
  agent: "#a855f7",
12
12
  execute: "#f59e0b",
13
13
  file: "#22c55e",
14
+ deliver: "#06b6d4",
14
15
  task: "#ec4899",
16
+ ask: "#65a30d",
15
17
  command: "#f97316",
16
18
  thinking: "#c4b5fd",
17
19
  context: "#8a9bb5",
@@ -25,7 +27,9 @@ const Config = z.object({
25
27
  agent: z.string().default(DEFAULT_COLORS.agent),
26
28
  execute: z.string().default(DEFAULT_COLORS.execute),
27
29
  file: z.string().default(DEFAULT_COLORS.file),
30
+ deliver: z.string().default(DEFAULT_COLORS.deliver),
28
31
  task: z.string().default(DEFAULT_COLORS.task),
32
+ ask: z.string().default(DEFAULT_COLORS.ask),
29
33
  command: z.string().default(DEFAULT_COLORS.command),
30
34
  thinking: z.string().default(DEFAULT_COLORS.thinking),
31
35
  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,69 @@
1
+ /**
2
+ * 交付行数据派生:把一次 `present` 调用还原成「状态 + 文件清单 + 结果文本」。
3
+ *
4
+ * 为什么要自己解析:官方 PresentRow 的折叠态把全部文件名逗号拼成一行
5
+ * (`ui-deliverables/src/client/PresentRow.tsx` 的 `fileNames()`),多文件时读不完,
6
+ * 也看不出这一轮交付了几个。完整清单只存在于调用的参数 JSON 里,所以折叠摘要与
7
+ * 展开态都得自己解一份。
8
+ *
9
+ * 本模块是纯函数:不碰 locale、不碰 DOM,解析失败一律降级而不是抛错(接管后
10
+ * 行由我们渲染,渲染不出来就等于用户什么都看不到)。
11
+ *
12
+ * 「等 N 个文件」这类摘要文案直写中文,与 goal-detail.tsx 同一取径:本插件不新造
13
+ * locale 命名空间,而官方 deliverables 字典没有「共计 N 个」的 key(`presented.more`
14
+ * 是「+ N 个文件」,用于溢出提示)。行内的标题、状态词与 inspect 仍取自官方字典。
15
+ */
16
+ /**
17
+ * 工具调用块里本行取用的字段(照官方 PresentRow 的取用面声明为鸭子类型,
18
+ * 不为此引入 @deepseek-ai/dsh-client-ui-tool 依赖)。
19
+ */
20
+ export interface DeliverableBlock {
21
+ /** 未结算时参数在块本身;结算后搬到 `call` 上。流式中途可能是截断的 JSON。 */
22
+ argsRaw?: string | undefined;
23
+ call?: {
24
+ argsRaw?: string | undefined;
25
+ } | undefined;
26
+ content?: ReadonlyArray<{
27
+ type: string;
28
+ text?: string | undefined;
29
+ }> | undefined;
30
+ error?: {
31
+ name?: string | undefined;
32
+ code?: string | undefined;
33
+ } | undefined;
34
+ isError?: boolean | undefined;
35
+ }
36
+ /** 交付状态:运行中 / 完成 / 中断 / 出错。 */
37
+ export type DeliverableState = 'running' | 'ok' | 'stopped' | 'error';
38
+ /** 展开态里的一行:文件名、所在目录与扩展名徽标已拆好。 */
39
+ export interface DeliverableFile {
40
+ /** 参数的完整路径,用于悬停提示。 */
41
+ path: string;
42
+ /** 文件名部分(正反斜杠都兼容)。 */
43
+ name: string;
44
+ /** 所在目录;纯文件名(没有分隔符)时为空串。 */
45
+ dir: string;
46
+ /** 扩展名徽标:大写、至多 4 字符;没有扩展名时为 null。 */
47
+ badge: string | null;
48
+ }
49
+ /** 交付行渲染需要的全部派生结果。 */
50
+ export interface DeliverableModel {
51
+ state: DeliverableState;
52
+ /** 折叠态摘要:单文件报文件名,多文件报「首个 + 数量」;参数未成形时报参数原文。 */
53
+ summary: string;
54
+ /** 逐文件数据;参数未成形时为空数组。 */
55
+ files: DeliverableFile[];
56
+ /** 展开后的结果文本(结果无文本时退回错误描述,再没有则为空串)。 */
57
+ details: string;
58
+ /** 结果文本的行数;没有文本时为 0。 */
59
+ lineCount: number;
60
+ /** 是否有可展开的内容。 */
61
+ expandable: boolean;
62
+ }
63
+ /**
64
+ * 派生一次交付的全部渲染数据。
65
+ * @param block - 工具调用/结果块。
66
+ * @returns 状态、折叠摘要、逐文件数据与结果文本。
67
+ */
68
+ export declare function deliverableModel(block: DeliverableBlock): DeliverableModel;
69
+ //# sourceMappingURL=deliverable-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deliverable-model.d.ts","sourceRoot":"","sources":["../../../src/client/deliverable-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5B,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GAAG,SAAS,CAAA;IACnD,OAAO,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC,GAAG,SAAS,CAAA;IAChF,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GAAG,SAAS,CAAA;IAC5E,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAC9B;AAED,+BAA+B;AAC/B,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAA;AAErE,iCAAiC;AACjC,MAAM,WAAW,eAAe;IAC9B,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,4BAA4B;IAC5B,GAAG,EAAE,MAAM,CAAA;IACX,qCAAqC;IACrC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAED,sBAAsB;AACtB,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,gBAAgB,CAAA;IACvB,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAA;IACf,wBAAwB;IACxB,KAAK,EAAE,eAAe,EAAE,CAAA;IACxB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAA;IACf,wBAAwB;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,iBAAiB;IACjB,UAAU,EAAE,OAAO,CAAA;CACpB;AA0ED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,gBAAgB,CAuB1E"}
@@ -0,0 +1,19 @@
1
+ import { type DeliverableBlock } from './deliverable-model.ts';
2
+ /** 注入的 locale 翻译函数(注册时声明 `deliverables` 命名空间)。 */
3
+ export interface DeliverableTranslate {
4
+ (key: string, params?: Record<string, string | number>): string;
5
+ }
6
+ /** 本行从 slot owner 收到的字段;其余 owner props 与本行无关。 */
7
+ export interface DeliverableRowProps {
8
+ t: DeliverableTranslate;
9
+ block: DeliverableBlock;
10
+ /** 跳到轨迹视图查看原始调用;缺省时不渲染该入口。 */
11
+ inspect?: (() => void) | undefined;
12
+ }
13
+ /**
14
+ * 渲染一次交付的完整记录。
15
+ * @param props - locale 翻译函数、调用/结果切片与可选的轨迹入口。
16
+ * @returns 折叠行 + 展开后的文件清单与结果文本。
17
+ */
18
+ export declare function DeliverableRow({ t, block, inspect }: DeliverableRowProps): import("react").JSX.Element;
19
+ //# sourceMappingURL=deliverable-row.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deliverable-row.d.ts","sourceRoot":"","sources":["../../../src/client/deliverable-row.tsx"],"names":[],"mappings":"AA2BA,OAAO,EACa,KAAK,gBAAgB,EACxC,MAAM,wBAAwB,CAAA;AAG/B,kDAAkD;AAClD,MAAM,WAAW,oBAAoB;IACnC,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,mBAAmB;IAClC,CAAC,EAAE,oBAAoB,CAAA;IACvB,KAAK,EAAE,gBAAgB,CAAA;IACvB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAA;CACnC;AAqBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,mBAAmB,+BAsDxE"}
@@ -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,CA+C9C"}
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;AAgBnE,eAAO,MAAM,MAAM,UAAqD,CAAA;AAcxE;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CA+F9C"}
@@ -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' | 'deliver' | '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,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,CAAA;AAEpI,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,oBAa5B,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,CAS7H,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"}