@deepseek-ai/dsh-client-ui-chat 0.1.5-rc.2 → 0.1.6-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/client/ui-chat/README.md
5
- README.md: cbf8fb88670913fac83154f5450e452674b2ed65
6
- README.zh.md: 9ee73474b2848ef19252bb26c5f0a215e323b413
5
+ README.md: c7c9fb7cb2a9a149fae9b27db78e019d821dfb95
6
+ README.zh.md: 386d7aae91b157a7b09fcd0515bfd8d075a39638
package/README.md CHANGED
@@ -14,6 +14,7 @@ File-mention providers receive the viewed Session ID with the closing-turn owner
14
14
 
15
15
  ## Table of Contents
16
16
 
17
+ - [Reference previews](#reference-previews)
17
18
  - [System prompt row](#system-prompt-row)
18
19
  - [Turn token usage](#turn-token-usage)
19
20
  - [Completed-turn footer](#completed-turn-footer)
@@ -25,6 +26,11 @@ File-mention providers receive the viewed Session ID with the closing-turn owner
25
26
 
26
27
  -----
27
28
 
29
+ <a id="reference-previews"></a>
30
+ ## Reference previews
31
+
32
+ Sent file references and skills confirmed by the message’s logged invocation open in the right Sidebar. File paths use the viewed Session; skill names resolve through its current input-trigger source. Both use the prose file-link dotted underline on hover or focus. Sessions, directories, and command labels remain non-navigating references.
33
+
28
34
  <a id="system-prompt-row"></a>
29
35
  ## System prompt row
30
36
 
@@ -35,6 +41,8 @@ Each nonempty appended `system/message` owns a collapsed prompt row, including a
35
41
 
36
42
  A completed Turn shows an expandable usage row only when the loaded window includes `turn/start` and every started model attempt reports safe, exact usage. The row omits unavailable optional buckets. Incomplete or contradictory accounting hides the complete disclosure instead of presenting a partial total.
37
43
 
44
+ After Assistant replies settle, the completed-turn timing dialog omits TTFT and decoding speed, both after live replies and after reopening history. Elapsed turn time remains available. The Session Stats pill reads timing independently from its durable projection.
45
+
38
46
  <a id="completed-turn-footer"></a>
39
47
  ## Completed-turn footer
40
48
 
@@ -45,6 +53,8 @@ The completed-turn action footer starts 20px below the preceding prose or extens
45
53
  <a id="turn-process-folding"></a>
46
54
  ## Turn Process Folding
47
55
 
56
+ Each reasoning row starts collapsed, including during streaming and in reasoning-only replies. Clicking the row opens or closes its complete text; incoming answer text, Tool calls, and stream completion preserve that choice. The collapsed summary follows the latest reasoning line while streaming and shows the first line after settlement.
57
+
48
58
  Settings → General exposes a persisted, localized `Normal` / `Compact` conversation-display preference in the `ui-chat` namespace; `Compact` is the default. Normal leaves process rows visible and renders no Turn-process control. In Compact mode, the System prompt remains independently visible before the opening User throughout the Turn. Context injection, reasoning, Assistant material, Tool rows, and Retry rows remain expanded while a Turn is open. At `turn/end`, its latest Step becomes the final-answer boundary only when it contains non-blank text, an image, or an unknown visible block—and no Tool-call block; preceding Context injection, reasoning, earlier Assistant material, Tool rows, and Retry rows then collapse by default. The control reports Turn-wide durable counts for non-subagent Tool calls, reply-bearing Assistant messages before the final answer, and subagent delegation calls; zero-valued segments are omitted, the Tool and subagent figures are mutually exclusive, and neither System prompt nor Context injection contributes a count. When all three counts are zero, the process still folds and the control reads `Thought for a while`. A full-width divider below the summary separates it from the answer or expanded process rows. User and steering messages, System prompt, error, max-token, and turn-tail rows stay outside, and a closed Turn with no final answer keeps all process evidence visible. A newly available process control is inserted without changing the relative order of existing rows: opening human input precedes the control and process rows from their first projection, while System prompt remains above that input. While older history remains available through Load earlier, process controls stay absent and no members are hidden; once history is complete, every eligible closed Turn uses the collapsed default immediately. Stable Chat Node Seats keep every renderer mounted, hidden members add no flow spacing, and a closed control sits 8px above its answer only when no independent input intervenes. Completion collapse does not depend on tail-follow position, so a reader above the tail may see the transcript reflow. An automatic collapse that would hide keyboard focus keeps the group open and leaves focus in place; a manual close focuses the process control before hiding its members. The session-scoped store records only manually expanded Turn-and-answer-Step generations; a different answer generation starts collapsed.
49
59
 
50
60
  -----
package/README.zh.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "渲染 Session 对话节点、历史图片、操作、本地化和滚动状态的浏览器 Chat target。"
2
+ description: "渲染会话对话节点、历史图片、操作、本地化和滚动状态的浏览器 Chat target。"
3
3
  kind: "package-reference"
4
4
  ---
5
5
  # @deepseek-ai/dsh-client-ui-chat
@@ -8,12 +8,13 @@ kind: "package-reference"
8
8
 
9
9
  ## 概述
10
10
 
11
- 使用本包可在浏览器中渲染已记录的 Session 对话,包括历史图片、本地化操作和滚动位置恢复。紧凑显示会收起已完成轮次的过程行,同时保持最终答案和独立有用的上下文可见;已打包的历史 Assistant 连续消息保持收起。本地 transcript 与 steering 提交会立即显示并保留在原区域,在权威 Session 记录到达时原子地消失,而 queued 提交始终不进入 Chat。本包不组装或修改模型请求。
11
+ 使用本包可在浏览器中渲染已记录的 Session 对话,包括历史图片、本地化操作和滚动位置恢复。紧凑显示会收起已完成轮次的过程行,同时保持最终答案和独立有用的上下文可见;已打包的历史 Assistant 连续消息保持收起。本地 transcript(文本记录)与 steering(中途引导)提交会立即显示并保留在原区域,在权威会话记录到达时原子地消失,而排队中的提交始终不进入 Chat。本包不组装或修改模型请求。
12
12
 
13
- 文件引用提供方同时接收当前查看的 Session ID 与收尾 turn 的属主信息,因此继承历史中的链接可以指向 fork 自身。
13
+ 文件提及提供方同时接收当前查看的会话 ID 与收尾轮次的属主信息,因此继承历史中的链接可以指向 fork 自身。
14
14
 
15
15
  ## 目录
16
16
 
17
+ - [引用预览](#reference-previews)
17
18
  - [系统提示词行](#system-prompt-row)
18
19
  - [轮次 token 用量](#turn-token-usage)
19
20
  - [已完成轮次的页脚](#completed-turn-footer)
@@ -25,17 +26,24 @@ kind: "package-reference"
25
26
 
26
27
  -----
27
28
 
29
+ <a id="reference-previews"></a>
30
+ ## 引用预览
31
+
32
+ 已发送的文件引用及消息日志确认调用的 skill 可在右侧栏打开预览。文件路径使用当前查看的 Session;skill 名称由该 Session 当前的输入触发源解析。两者悬停或聚焦时均使用正文文件链接的虚线下划线。会话、目录和命令标签仍只作为引用展示。
33
+
28
34
  <a id="system-prompt-row"></a>
29
35
  ## 系统提示词行
30
36
 
31
- 每个非空追加的 `system/message` 都拥有一行折叠提示词,包括无 header 窗口起点的完整提示词;同一步骤的 header 不会重复它。Chat 也会为非空的初始请求、显式消息序列起点、文本发生变化的 `system/message` surface 节点替换(文本读取自 `request/header` 处 surface 顺序中最后一个非空存活系统节点),或前序 header 尚未进入已加载历史窗口的非初始请求显示一行默认折叠的`系统提示词`。即使系统文本未变,resume 也会重复该行,包括分页补齐前序 header 和系统节点后;同一序列内仅配置或仅工具变化、工具步骤与重试不会重复,且 `system/message` 事件绝不会渲染为对话消息。该行位于请求的用户消息之前,与提供方 envelope 顺序一致;展开后显示保留原始换行的精确模型可见文本。系统节点为空或位于已加载窗口之外的请求不创建该行,直到包含该节点的分页到达。
37
+ 每个非空追加的 `system/message` 都拥有一行折叠提示词,包括无 header 窗口起点的完整提示词;同一步骤的 header 不会重复它。Chat 也会为非空的初始请求、显式消息序列起点、文本发生变化的 `system/message` surface 节点替换(文本读取自 `request/header` 处 surface 顺序中最后一个非空存活系统节点),或前序 header 尚未进入已加载历史窗口的非初始请求显示一行默认折叠的 `系统提示词`。即使系统文本未变,恢复也会重复该行,包括分页补齐前序 header 和系统节点后;同一序列内仅配置或仅工具变化、工具步骤与重试不会重复,且 `system/message` 事件绝不会渲染为对话消息。该行位于请求的用户消息之前,与提供方 envelope 顺序一致;展开后显示模型所见的确切文本,并保留其原始换行。系统节点为空或位于已加载窗口之外的请求不创建该行,直到包含该节点的分页到达。
32
38
 
33
39
  -----
34
40
 
35
41
  <a id="turn-token-usage"></a>
36
42
  ## 轮次 token 用量
37
43
 
38
- 只有当已加载窗口包含 `turn/start`,且每次已启动的模型尝试都报告安全、精确的用量时,已完成 Turn 才显示可展开的用量行。该行会省略不可用的可选用量桶。记账不完整或相互矛盾时,整个详情都不显示,避免把部分总量冒充完整结果。
44
+ 只有当已加载窗口包含 `turn/start`,且每次已启动的模型尝试都报告安全、精确的用量时,已完成轮次才显示可展开的用量行。该行会省略不可用的可选用量桶。记账不完整或相互矛盾时,整个详情都不显示,避免把部分总量冒充完整结果。
45
+
46
+ Assistant 回复结算后,已完成轮次的计时对话框不显示 TTFT 和解码速度,实时回复完成后和重新打开历史后都如此。轮次总耗时仍可用。Session Stats 药丸从其持久化投影独立读取计时。
39
47
 
40
48
  <a id="completed-turn-footer"></a>
41
49
  ## 已完成轮次的页脚
@@ -47,14 +55,16 @@ kind: "package-reference"
47
55
  <a id="turn-process-folding"></a>
48
56
  ## 轮次过程折叠
49
57
 
50
- 「设置 → 通用设置」提供持久化到 `ui-chat` 命名空间的「标准」/「紧凑」对话显示偏好,默认使用「紧凑」。标准模式保持所有过程行可见且不渲染轮次过程控件。紧凑模式下,系统提示词在整个轮次中始终独立显示于开场 User 上方。轮次打开期间,上下文注入、推理、Assistant 内容、工具行与重试行始终展开。到 `turn/end` 时,最后一个步骤只有在包含非空文本、图片或未知可见块且不含工具调用块时才成为最终正文边界;边界之前的上下文注入、推理、较早 Assistant 内容、工具行与重试行随后默认收起。控件展示覆盖整个轮次的非 subagent 工具调用数、最终正文之前带回复内容的 Assistant 消息数和 subagent 委派数;值为 0 的分段省略,工具调用与 subagent 两项互斥,系统提示词与上下文注入都不增加计数。三项全为 0 时过程仍会收起,控件标题显示「已思考」(英文为 `Thought for a while`)。摘要下方的通栏分隔线将其与正文或展开后的过程行隔开。用户与 steering 消息、系统提示词、错误、最大 token 与 turn-tail 行留在过程组外;关闭时没有最终正文的轮次保留全部过程证据。新的过程控件插入时不会改变既有行的相对顺序:开场人工输入从首次投影起便位于控件和过程行之前,系统提示词则始终位于该输入上方。只要仍可通过「加载更早」获取历史,过程控件就不出现,也不会隐藏任何成员;历史加载完整后,每个合格的已关闭轮次立即使用默认收起状态。稳定 Chat Node Seat 会让每个 renderer 保持挂载,隐藏成员不产生消息流间距;只有中间没有独立输入时,收起控件才与正文相隔 8px。完成后的收起不依赖是否跟随尾部,因此正在上方阅读的用户可能看到 transcript 高度变化。若自动收起会隐藏当前键盘焦点,则过程组保持展开且焦点留在原处;手动收起会先把焦点移到过程控件,再隐藏成员。会话作用域 store 只记录用户手动展开的「轮次 + 正文步骤」generation;不同正文 generation 默认收起。
58
+ 每个思考行初始都折叠,包括流式输出期间和仅含思考的回复。点击该行可展开或收起完整文本;后续回答文本、工具调用和流结束都保留用户的选择。折叠摘要在流式输出期间跟随最新思考行,结算后显示第一行。
59
+
60
+ 「设置 → 通用设置」提供持久化到 `ui-chat` 命名空间的「标准」/「紧凑」对话显示偏好,默认使用「紧凑」。标准模式保持所有过程行可见且不渲染轮次过程控件。紧凑模式下,系统提示词在整个轮次中始终独立显示于开场 User 上方。轮次打开期间,上下文注入、推理、Assistant 内容、工具行与重试行始终展开。到 `turn/end` 时,最后一个步骤只有在包含非空文本、图片或未知可见块且不含工具调用块时才成为最终答案边界;边界之前的上下文注入、推理、较早 Assistant 内容、工具行与重试行随后默认收起。控件展示覆盖整个轮次的非 subagent 工具调用数、最终答案之前带回复内容的 Assistant 消息数和 subagent 委派数;值为 0 的分段省略,工具调用与 subagent 两项互斥,系统提示词与上下文注入都不增加计数。三项全为 0 时过程仍会收起,控件标题显示「已思考」(英文为 `Thought for a while`)。摘要下方的通栏分隔线将其与正文或展开后的过程行隔开。用户与 steering 消息、系统提示词、错误、最大 token 与 turn-tail 行留在过程组外;关闭时没有最终答案的轮次保留全部过程证据。新的过程控件插入时不会改变既有行的相对顺序:开场人工输入从首次投影起便位于控件和过程行之前,系统提示词则始终位于该输入上方。只要仍可通过「加载更早」获取历史,过程控件就不出现,也不会隐藏任何成员;历史加载完整后,每个合格的已关闭轮次立即使用默认收起状态。稳定 Chat Node Seat 会让每个 renderer 保持挂载,隐藏成员不产生消息流间距;只有中间没有独立输入时,收起控件才与正文相隔 8px。完成后的收起不依赖是否跟随尾部,因此正在上方阅读的用户可能看到 transcript 重排。若自动收起会隐藏当前键盘焦点,则过程组保持展开且焦点留在原处;手动收起会先把焦点移到过程控件,再隐藏成员。会话作用域存储只记录用户手动展开的「轮次 + 正文步骤」generation;不同正文 generation 默认收起。
51
61
 
52
62
  -----
53
63
 
54
64
  <a id="scroll-ownership"></a>
55
65
  ## 滚动归属
56
66
 
57
- Chat 会在历史前插与 renderer 重新挂载时恢复语义锚点。没有读者移动的贴底滚动事件会立即更新跟随归属,避免后续布局变化使其底部位置失效。读者移动即使位于跟随阈值内,也保持待处理直到采样周期或 `scrollend`,防止布局增长抵消小幅滚动操作。读者跟随底部时,`ResizeObserver` 追随新的底部,并且无需读取行几何就选中最后一个已加载 Turn;读者离开底部后,高度变化会保持顶部位置,再由阅读线几何选择活跃 Turn。轮次导航预览位于 Markdown 代码块粘性头栏上方,而导航外框始终处于 composer 上方的 transcript 区域内。
67
+ Chat 会在历史前插与 renderer 重新挂载时恢复语义锚点。没有读者移动的贴底滚动事件会立即更新跟随归属,避免后续布局变化使其底部位置失效。读者移动即使位于跟随阈值内,也保持待处理直到采样周期或 `scrollend`,防止布局增长抵消小幅滚动操作。读者跟随底部时,`ResizeObserver` 追随新的底部,并且无需读取行几何就选中最后一个已加载轮次;读者离开底部后,高度变化会保持顶部位置,再由阅读线几何选择活跃轮次。轮次导航预览位于 Markdown 代码块粘性头栏上方,而导航外框始终处于 composer 上方的 transcript 区域内。
58
68
 
59
69
  -----
60
70
 
@@ -71,7 +81,7 @@ Chat 会在历史前插与 renderer 重新挂载时恢复语义锚点。没有
71
81
 
72
82
  <a id="known-limitations-and-deferred-work"></a>
73
83
 
74
- - **transcript 只反映已加载的 Session 窗口**——只有 Session Controller 加载前一页 event 后,更早的 transcript node 才会出现。轮次导航比窗口更宽:轨道把已加载的 Turn 与宿主 `turnOutline` 投影合并,每个已开始的 Turn 都有固定间距刻度(相隔 10px;阶梯高于外框时在框内滚动并以渐变淡出标示可滚方向),激活未加载刻度会先把历史分页拉到该 Turn 的 `turn/start` seq 再落到它的行上。没有该投影时(未挂载 `dsh-session-turn-outline` 的装配),轨道回退到仅显示已加载 Turn。
84
+ - **transcript 只反映已加载的 Session 窗口**——只有会话控制器加载前一页事件后,更早的 transcript node 才会出现。轮次导航比窗口更宽:轨道把已加载的轮次与宿主 `turnOutline` 投影合并,每个已开始的轮次都有固定间距刻度(相隔 10px;阶梯高于外框时在框内滚动并以渐变淡出标示可滚方向),激活未加载刻度会先把历史分页拉到该轮次的 `turn/start` seq 再落到它的行上。没有该投影时(未挂载 `dsh-session-turn-outline` 的装配),轨道回退到仅显示已加载轮次。
75
85
  - **导航预览按卡片尺寸截断**——提示词一行(50 字符)、回复至多三行(120 字符),已加载与未加载 Turn 一致;未加载 Turn 的回复要等该轮落定后才随大纲到达,进行中的轮次在此之前只预览提示词(或仅轮次号)。
76
86
 
77
87
 
@@ -85,4 +95,4 @@ Chat 会在历史前插与 renderer 重新挂载时恢复语义锚点。没有
85
95
 
86
96
  </details>
87
97
 
88
- **运行时不变式:** 不发布伴生入口。Conversation 与 Slot 注册已经强制 Chat target 一致。
98
+ **运行时不变式:** 不发布伴生入口。Conversation 与 slot 注册已经强制 Chat target 一致。
package/lib/client.js CHANGED
@@ -152,7 +152,7 @@ window.__ModuleLoader__.load({
152
152
  }
153
153
  //#endregion
154
154
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-chat/src/client/chat/MessageItem.module.css.mjs
155
- const css$15 = ".Sixlwa_userRow{flex-direction:column;align-items:flex-end;gap:6px;display:flex}.Sixlwa_userStack{min-width:0;max-width:min(calc(var(--dsh-chat-content-width,748px) * .702), 82%);flex-direction:column;align-items:flex-end;gap:8px;display:flex}.Sixlwa_bubble{background:var(--dsw-specific-bubble);max-width:100%;font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;border-radius:22px;padding:10px 16px}.Sixlwa_referenceSummary{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px))}.Sixlwa_contextRow,.Sixlwa_compactionRow{padding:2px 0}.Sixlwa_compactionButton{width:100%;height:calc(24px + var(--dsh-content-font-delta,0px));min-width:0;color:inherit;font:inherit;text-align:left;background:0 0;border:none;border-radius:6px;align-items:center;padding:0;display:flex}.Sixlwa_compactionButton:not(:disabled){cursor:pointer}.Sixlwa_compactionButton:not(:disabled):hover{background:var(--dsw-alias-interactive-bg-hover)}.Sixlwa_compactionLeading{width:calc(16px + var(--dsh-content-font-delta,0px));height:calc(16px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-secondary);flex:none;place-items:center;margin-right:6px;display:inline-grid}.Sixlwa_compactionLeading svg{width:calc(14px + var(--dsh-content-font-delta,0px));height:calc(14px + var(--dsh-content-font-delta,0px))}.Sixlwa_compactionContextIcon,.Sixlwa_compactionDisclosureIcon{grid-area:1/1;justify-content:center;align-items:center;display:inline-flex}.Sixlwa_compactionDisclosureIcon,.Sixlwa_compactionButton:not(:disabled):hover .Sixlwa_compactionContextIcon,.Sixlwa_compactionButton:not(:disabled):focus-visible .Sixlwa_compactionContextIcon{opacity:0}.Sixlwa_compactionButton:not(:disabled):hover .Sixlwa_compactionDisclosureIcon,.Sixlwa_compactionButton:not(:disabled):focus-visible .Sixlwa_compactionDisclosureIcon{opacity:1}.Sixlwa_compactionTitle{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-primary-dimmed);flex:none}.Sixlwa_compactionSep{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.Sixlwa_compactionSummary{min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));text-overflow:ellipsis;white-space:nowrap;flex:auto;overflow:hidden}.Sixlwa_compactionBody{padding:4px 0 4px calc(22px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px))}.Sixlwa_retryRow{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px))}.Sixlwa_retrySummary{width:fit-content;color:inherit;cursor:pointer;user-select:none;border-radius:3px;align-items:center;gap:7px;padding:2px 0;list-style:none;display:inline-flex}.Sixlwa_retrySummary::-webkit-details-marker{display:none}.Sixlwa_retrySummary:after{content:\"\";opacity:.8;border-bottom:1.5px solid;border-right:1.5px solid;width:6px;height:6px;transition:transform .12s;transform:rotate(-45deg)}.Sixlwa_retrySummary:hover{color:var(--dsw-alias-label-secondary)}.Sixlwa_retrySummary:focus-visible{outline:1.5px solid var(--dsw-alias-button-info-fill);outline-offset:2px}.Sixlwa_retryText{color:inherit}.Sixlwa_retryRow[data-active] .Sixlwa_retryText{background:linear-gradient(90deg, var(--dsw-alias-label-tertiary) 0%, var(--dsw-alias-label-tertiary) 40%, var(--dsw-alias-label-secondary) 50%, var(--dsw-alias-label-tertiary) 60%, var(--dsw-alias-label-tertiary) 100%);color:#0000;background-position:100%;background-size:200% 100%;background-clip:text;animation:1.6s ease-in-out infinite Sixlwa_retry-shimmer}.Sixlwa_retryRow[open] .Sixlwa_retrySummary:after{transform:rotate(45deg)}.Sixlwa_retryDetails{overflow-wrap:anywhere;font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px));gap:2px;margin-top:3px;padding-left:14px;display:grid}.Sixlwa_retryDetailLabel{color:var(--dsw-alias-label-secondary)}.Sixlwa_turnErrorRow{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));grid-template-columns:10px minmax(0,1fr) auto;align-items:start;gap:8px;padding:2px 0;display:grid}.Sixlwa_turnErrorDot{margin-top:5px}.Sixlwa_turnErrorCopy{overflow-wrap:anywhere;min-width:0}.Sixlwa_turnErrorTitle{color:var(--dsw-alias-state-error-primary);margin-right:6px;font-weight:600}.Sixlwa_turnErrorMessage{color:var(--dsw-alias-label-secondary)}.Sixlwa_turnErrorCode{color:var(--dsw-alias-label-tertiary);font:var(--dsw-font-markdown-code-block-small)}.Sixlwa_maxTokensTitle{color:var(--dsw-alias-state-warn-primary);margin-right:6px;font-weight:600}@keyframes Sixlwa_retry-shimmer{0%{background-position:100%}to{background-position:0}}@media (prefers-reduced-motion:reduce){.Sixlwa_retryRow[data-active] .Sixlwa_retryText{color:inherit;background:0 0;animation:none}}.Sixlwa_attachmentRow{flex-wrap:wrap;justify-content:flex-end;gap:8px;max-width:100%;display:flex}.Sixlwa_fileCard{border:.5px solid var(--dsw-alias-border-l2,#0000001f);background:var(--dsw-specific-input-major,transparent);box-sizing:border-box;border-radius:16px;flex:0 0 240px;align-items:center;gap:10px;width:240px;min-height:64px;padding:8px 12px;display:inline-flex}.Sixlwa_fileIcon{flex:none;width:28px;height:28px}.Sixlwa_fileContent{flex-direction:column;flex:1;min-width:0;display:flex}.Sixlwa_fileName{white-space:nowrap;text-overflow:ellipsis;color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px;overflow:hidden}.Sixlwa_fileMeta{white-space:nowrap;text-overflow:ellipsis;color:var(--dsw-alias-label-tertiary,#00000073);font-size:12px;line-height:15px;overflow:hidden}";
155
+ const css$15 = ".Sixlwa_userRow{flex-direction:column;align-items:flex-end;gap:6px;display:flex}.Sixlwa_userStack{min-width:0;max-width:min(calc(var(--dsh-chat-content-width,748px) * .702), 82%);flex-direction:column;align-items:flex-end;gap:8px;display:flex}.Sixlwa_bubble{background:var(--dsw-specific-bubble);max-width:100%;font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;border-radius:22px;padding:10px 16px}.Sixlwa_referenceSummary{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px))}.Sixlwa_contextRow{padding:2px 0}.Sixlwa_compactionRow{--dsh-compaction-header-height:calc(24px + var(--dsh-content-font-delta,0px));padding:2px 0}.Sixlwa_compactionButton{width:100%;height:var(--dsh-compaction-header-height);min-width:0;color:inherit;font:inherit;text-align:left;background:0 0;border:none;border-radius:6px;align-items:center;padding:0;display:flex}.Sixlwa_compactionRow:has(.Sixlwa_compactionBody) .Sixlwa_compactionButton{z-index:7;background:var(--dsw-alias-bg-base);border-radius:0;position:sticky;top:0}.Sixlwa_compactionBody :has(>[data-code-block-banner]){top:var(--dsh-compaction-header-height)}.Sixlwa_compactionRow:has(.Sixlwa_compactionBody) .Sixlwa_compactionButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.Sixlwa_compactionButton:not(:disabled){cursor:pointer}.Sixlwa_compactionButton:not(:disabled):hover{background:var(--dsw-alias-interactive-bg-hover)}.Sixlwa_compactionLeading{width:calc(16px + var(--dsh-content-font-delta,0px));height:calc(16px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-secondary);flex:none;place-items:center;margin-right:6px;display:inline-grid}.Sixlwa_compactionLeading svg{width:calc(14px + var(--dsh-content-font-delta,0px));height:calc(14px + var(--dsh-content-font-delta,0px))}.Sixlwa_compactionContextIcon,.Sixlwa_compactionDisclosureIcon{grid-area:1/1;justify-content:center;align-items:center;display:inline-flex}.Sixlwa_compactionDisclosureIcon,.Sixlwa_compactionButton:not(:disabled):hover .Sixlwa_compactionContextIcon,.Sixlwa_compactionButton:not(:disabled):focus-visible .Sixlwa_compactionContextIcon{opacity:0}.Sixlwa_compactionButton:not(:disabled):hover .Sixlwa_compactionDisclosureIcon,.Sixlwa_compactionButton:not(:disabled):focus-visible .Sixlwa_compactionDisclosureIcon{opacity:1}.Sixlwa_compactionTitle{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-primary-dimmed);flex:none}.Sixlwa_compactionSep{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.Sixlwa_compactionSummary{min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));text-overflow:ellipsis;white-space:nowrap;flex:auto;overflow:hidden}.Sixlwa_compactionBody{padding:4px 0 4px calc(22px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px))}.Sixlwa_retryRow{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px))}.Sixlwa_retrySummary{width:fit-content;color:inherit;cursor:pointer;user-select:none;border-radius:3px;align-items:center;gap:7px;padding:2px 0;list-style:none;display:inline-flex}.Sixlwa_retrySummary::-webkit-details-marker{display:none}.Sixlwa_retrySummary:after{content:\"\";opacity:.8;border-bottom:1.5px solid;border-right:1.5px solid;width:6px;height:6px;transition:transform .12s;transform:rotate(-45deg)}.Sixlwa_retrySummary:hover{color:var(--dsw-alias-label-secondary)}.Sixlwa_retrySummary:focus-visible{outline:1.5px solid var(--dsw-alias-button-info-fill);outline-offset:2px}.Sixlwa_retryText{color:inherit}.Sixlwa_retryRow[data-active] .Sixlwa_retryText{background:linear-gradient(90deg, var(--dsw-alias-label-tertiary) 0%, var(--dsw-alias-label-tertiary) 40%, var(--dsw-alias-label-secondary) 50%, var(--dsw-alias-label-tertiary) 60%, var(--dsw-alias-label-tertiary) 100%);color:#0000;background-position:100%;background-size:200% 100%;background-clip:text;animation:1.6s ease-in-out infinite Sixlwa_retry-shimmer}.Sixlwa_retryRow[open] .Sixlwa_retrySummary:after{transform:rotate(45deg)}.Sixlwa_retryDetails{overflow-wrap:anywhere;font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px));gap:2px;margin-top:3px;padding-left:14px;display:grid}.Sixlwa_retryDetailLabel{color:var(--dsw-alias-label-secondary)}.Sixlwa_turnErrorRow{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));grid-template-columns:10px minmax(0,1fr) auto;align-items:start;gap:8px;padding:2px 0;display:grid}.Sixlwa_turnErrorDot{margin-top:5px}.Sixlwa_turnErrorCopy{overflow-wrap:anywhere;min-width:0}.Sixlwa_turnErrorTitle{color:var(--dsw-alias-state-error-primary);margin-right:6px;font-weight:600}.Sixlwa_turnErrorMessage{color:var(--dsw-alias-label-secondary)}.Sixlwa_turnErrorCode{color:var(--dsw-alias-label-tertiary);font:var(--dsw-font-markdown-code-block-small)}.Sixlwa_maxTokensTitle{color:var(--dsw-alias-state-warn-primary);margin-right:6px;font-weight:600}@keyframes Sixlwa_retry-shimmer{0%{background-position:100%}to{background-position:0}}@media (prefers-reduced-motion:reduce){.Sixlwa_retryRow[data-active] .Sixlwa_retryText{color:inherit;background:0 0;animation:none}}.Sixlwa_attachmentRow{flex-wrap:wrap;justify-content:flex-end;gap:8px;max-width:100%;display:flex}.Sixlwa_fileCard{border:.5px solid var(--dsw-alias-border-l2,#0000001f);background:var(--dsw-specific-input-major,transparent);box-sizing:border-box;border-radius:16px;flex:0 0 240px;align-items:center;gap:10px;width:240px;min-height:64px;padding:8px 12px;display:inline-flex}.Sixlwa_fileIcon{flex:none;width:28px;height:28px}.Sixlwa_fileContent{flex-direction:column;flex:1;min-width:0;display:flex}.Sixlwa_fileName{white-space:nowrap;text-overflow:ellipsis;color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px;overflow:hidden}.Sixlwa_fileMeta{white-space:nowrap;text-overflow:ellipsis;color:var(--dsw-alias-label-tertiary,#00000073);font-size:12px;line-height:15px;overflow:hidden}";
156
156
  const tagId$15 = "@deepseek-ai/dsh-client-ui-chat/MessageItem.module.css";
157
157
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$15) + "]") === null) {
158
158
  const tag = document.createElement("style");
@@ -847,7 +847,7 @@ window.__ModuleLoader__.load({
847
847
  * @param props - Durable content, its projected producer role/name and form, and the locale seat.
848
848
  * @returns A collapsed context row with a bounded, form-specific body.
849
849
  */
850
- function ContextInjectionRow({ content, source, provenance, form, t }) {
850
+ function ContextInjectionRow({ content, source, producer, form, t }) {
851
851
  const [open, setOpen] = (0, react.useState)(false);
852
852
  const { rendered, summary, body } = contextBody(form, {
853
853
  content,
@@ -856,13 +856,13 @@ window.__ModuleLoader__.load({
856
856
  });
857
857
  return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.DisclosureRow, {
858
858
  className: ContextInjectionRow_module_css_default.root,
859
- icon: provenance.role === "recall" ? (0, react_jsx_runtime.jsx)("span", {
859
+ icon: producer.role === "recall" ? (0, react_jsx_runtime.jsx)("span", {
860
860
  "data-context-recall-icon": true,
861
861
  children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.ReferenceIcon, { kind: "session" })
862
862
  }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconContextInjectionOutline16, { size: 14 }),
863
863
  chevronClassName: ContextInjectionRow_module_css_default.chevron,
864
- title: t(provenance.role === "recall" ? "message.contextRecall" : "message.contextInjection"),
865
- collapsedContent: provenance.label === null ? void 0 : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
864
+ title: t(producer.role === "recall" ? "message.contextRecall" : "message.contextInjection"),
865
+ collapsedContent: producer.label === null ? void 0 : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
866
866
  (0, react_jsx_runtime.jsx)("span", {
867
867
  className: ContextInjectionRow_module_css_default.sep,
868
868
  "aria-hidden": true
@@ -870,7 +870,7 @@ window.__ModuleLoader__.load({
870
870
  (0, react_jsx_runtime.jsx)("span", {
871
871
  className: ContextInjectionRow_module_css_default.source,
872
872
  "data-context-source": true,
873
- children: provenance.label
873
+ children: producer.label
874
874
  }),
875
875
  summary !== null && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("span", {
876
876
  className: ContextInjectionRow_module_css_default.sep,
@@ -925,15 +925,23 @@ window.__ModuleLoader__.load({
925
925
  * Localized elapsed-time label shared by running and settled turn chrome.
926
926
  * @param ms - Elapsed duration in milliseconds (negatives clamp to zero).
927
927
  * @param t - Translate seat supplying the duration templates.
928
- * @returns Display string in whole seconds.
928
+ * @returns Display string in whole seconds; minutes and seconds once the
929
+ * duration reaches a minute; hours, minutes, and seconds once it reaches an
930
+ * hour, with the smaller units zero-padded.
929
931
  */
930
932
  function formatRunDuration(ms, t) {
931
933
  const total = Math.max(0, Math.floor(ms / 1e3));
932
- const minutes = Math.floor(total / 60);
934
+ const hours = Math.floor(total / 3600);
935
+ const minutes = Math.floor(total / 60) % 60;
933
936
  const seconds = total % 60;
937
+ if (hours > 0) return t("duration.hours", {
938
+ hours,
939
+ minutes: pad2(minutes),
940
+ seconds: pad2(seconds)
941
+ });
934
942
  return minutes > 0 ? t("duration.minutes", {
935
943
  minutes,
936
- seconds: String(seconds).padStart(2, "0")
944
+ seconds: pad2(seconds)
937
945
  }) : t("duration.seconds", { seconds });
938
946
  }
939
947
  /**
@@ -1230,7 +1238,7 @@ window.__ModuleLoader__.load({
1230
1238
  });
1231
1239
  }
1232
1240
  /** Right-aligned bubble shared by user and steering rows. */
1233
- function UserStyleBubble({ content, renderMessageImages, actions, pending = false, echo = false, referenceLabels = [], skillNames = [], previewAttachments, t }) {
1241
+ function UserStyleBubble({ content, renderMessageImages, actions, pending = false, echo = false, referenceLabels = [], skillNames = [], previewAttachments, references, t }) {
1234
1242
  const { text, attachments: contentAttachments, rest } = contentParts(content);
1235
1243
  const attachments = previewAttachments ?? contentAttachments;
1236
1244
  const compactImages = attachments.length > 1;
@@ -1270,7 +1278,7 @@ window.__ModuleLoader__.load({
1270
1278
  }),
1271
1279
  showBubble && (0, react_jsx_runtime.jsxs)("div", {
1272
1280
  className: MessageItem_module_css_default.bubble,
1273
- children: [(0, _deepseek_ai_dsh_client_ui_primitives.projectUserText)(text, referenceLabels, skillNames), rest.map((block, i) => (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.JsonBlock, {
1281
+ children: [(0, _deepseek_ai_dsh_client_ui_primitives.projectUserText)(text, referenceLabels, skillNames, "skill", references), rest.map((block, i) => (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.JsonBlock, {
1274
1282
  label: t("message.extraBlock"),
1275
1283
  payload: block,
1276
1284
  truncatedLabel: truncated
@@ -1344,10 +1352,14 @@ window.__ModuleLoader__.load({
1344
1352
  });
1345
1353
  }
1346
1354
  /** User and admitted-steering keyed Chat renderer. */
1347
- const UserMessageNodeView = (0, react.memo)(function UserMessageNodeView({ node, renderMessageImages, t }) {
1355
+ const UserMessageNodeView = (0, react.memo)(function UserMessageNodeView({ node, renderMessageImages, openFile, openSkill, t }) {
1348
1356
  const data = node.data;
1349
1357
  return (0, react_jsx_runtime.jsx)(UserStyleBubble, {
1350
1358
  content: data.content,
1359
+ references: {
1360
+ openFile,
1361
+ openSkill
1362
+ },
1351
1363
  renderMessageImages,
1352
1364
  ...data.referenceLabels === void 0 ? {} : { referenceLabels: data.referenceLabels },
1353
1365
  ...data.skillNames === void 0 ? {} : { skillNames: data.skillNames },
@@ -1367,7 +1379,7 @@ window.__ModuleLoader__.load({
1367
1379
  return (0, react_jsx_runtime.jsx)(ContextInjectionRow, {
1368
1380
  content: data.content,
1369
1381
  source: data.source,
1370
- provenance: data.provenance,
1382
+ producer: data.producer,
1371
1383
  form: data.form,
1372
1384
  t
1373
1385
  });
@@ -1541,7 +1553,7 @@ window.__ModuleLoader__.load({
1541
1553
  return location?.kind === "turn" || location?.kind === "step" ? location.turn.turn : void 0;
1542
1554
  }
1543
1555
  /** Subscribe, apply Turn-process visibility, and dispatch one stable Context key. */
1544
- const ChatNodeSeat = (0, react.memo)(function ChatNodeSeat({ nodeKey, useChatNode, useChatNodeProcess, historyIncomplete, compactTranscript, cwd, openFile, inspectCall, forkAt, loadImage, renderMessageImages, fileMentions, useStore, actions, renderSlot, t }) {
1556
+ const ChatNodeSeat = (0, react.memo)(function ChatNodeSeat({ nodeKey, useChatNode, useChatNodeProcess, historyIncomplete, compactTranscript, cwd, openFile, openSkill, inspectCall, forkAt, loadImage, renderMessageImages, fileMentions, useStore, actions, renderSlot, t }) {
1545
1557
  const node = useChatNode(nodeKey);
1546
1558
  const routedNode = node;
1547
1559
  const turn = turnOf(routedNode);
@@ -1577,6 +1589,7 @@ window.__ModuleLoader__.load({
1577
1589
  const owner = (0, react.useMemo)(() => node === void 0 ? null : {
1578
1590
  cwd,
1579
1591
  openFile,
1592
+ openSkill,
1580
1593
  inspectCall,
1581
1594
  forkAt,
1582
1595
  loadImage,
@@ -1587,6 +1600,7 @@ window.__ModuleLoader__.load({
1587
1600
  node,
1588
1601
  cwd,
1589
1602
  openFile,
1603
+ openSkill,
1590
1604
  inspectCall,
1591
1605
  forkAt,
1592
1606
  loadImage,
@@ -2069,7 +2083,7 @@ window.__ModuleLoader__.load({
2069
2083
  * The chat view slot entry: pure component over the composed props; each
2070
2084
  * ordered business Node crosses the keyed renderer seat.
2071
2085
  */
2072
- function ChatView({ useSession, useChat, useChatNode, useChatNodeProcess, useSessions, useStore, actions, renderSlot, sessionId, openFile, loadOlder, loadThrough, loadImage, openView, chatScroll, forkAt, fileMentions, useTranscriptView, useProjection, t }) {
2086
+ function ChatView({ useSession, useChat, useChatNode, useChatNodeProcess, useSessions, useStore, actions, renderSlot, sessionId, openFile, openSkill, loadOlder, loadThrough, loadImage, openView, chatScroll, forkAt, fileMentions, useTranscriptView, useProjection, t }) {
2073
2087
  const order = useChat((s) => s.order);
2074
2088
  const nodeStore = useChat((s) => s.nodes);
2075
2089
  const turnNavigationItems = useChat((s) => s.navigation.items());
@@ -2542,6 +2556,7 @@ window.__ModuleLoader__.load({
2542
2556
  actions,
2543
2557
  cwd,
2544
2558
  openFile: requestOpenFile,
2559
+ openSkill,
2545
2560
  inspectCall,
2546
2561
  forkAt,
2547
2562
  loadImage,
@@ -2715,6 +2730,7 @@ window.__ModuleLoader__.load({
2715
2730
  "message.turnTime.ttft": "首 token 用时(TTFT)",
2716
2731
  "duration.seconds": "{seconds}秒",
2717
2732
  "duration.minutes": "{minutes}分{seconds}秒",
2733
+ "duration.hours": "{hours}小时{minutes}分{seconds}秒",
2718
2734
  "command.running": "执行中…",
2719
2735
  "command.failed": "指令失败",
2720
2736
  "command.done": "已完成",
@@ -2821,6 +2837,7 @@ window.__ModuleLoader__.load({
2821
2837
  "message.turnTime.ttft": "Time to first token (TTFT)",
2822
2838
  "duration.seconds": "{seconds}s",
2823
2839
  "duration.minutes": "{minutes}m {seconds}s",
2840
+ "duration.hours": "{hours}h {minutes}m {seconds}s",
2824
2841
  "command.running": "Running…",
2825
2842
  "command.failed": "Command failed",
2826
2843
  "command.done": "Completed",
@@ -2845,7 +2862,7 @@ window.__ModuleLoader__.load({
2845
2862
  var accessibility_module_css_default = { "visuallyHidden": "TTCZqG_visuallyHidden" };
2846
2863
  //#endregion
2847
2864
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-chat/src/client/chat/ReasoningRow.module.css.mjs
2848
- const css$8 = ".lcKema_root{flex-direction:column;display:flex}.lcKema_root:not([data-expanded]){contain:size layout;height:calc(24px + var(--dsh-content-font-delta,0px))}.lcKema_row{position:relative;overflow:hidden}.lcKema_root[data-state=running] .lcKema_row:after{content:\"\";inset-block:0;background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite lcKema_dsh-reasoning-row-sweep;position:absolute;left:0}@keyframes lcKema_dsh-reasoning-row-sweep{0%{left:-300px}90%,to{left:100%}}.lcKema_leading{flex-shrink:0}.lcKema_chevron{color:var(--dsw-alias-label-secondary)}.lcKema_title{font-weight:400}.lcKema_separator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.lcKema_summary{min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));white-space:nowrap;flex:auto;overflow:hidden}.lcKema_summaryText{text-overflow:ellipsis;display:block;overflow:hidden}.lcKema_summary[data-follow-end]{justify-content:flex-end;display:flex}.lcKema_summary[data-follow-end] .lcKema_summaryText{text-align:start;text-overflow:clip;flex:none;width:max-content;min-width:100%;overflow:visible}.lcKema_thinkBody{padding:4px 0 4px calc(22px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));white-space:pre-wrap;word-break:break-word}@media (prefers-reduced-motion:reduce){.lcKema_root[data-state=running] .lcKema_row:after{animation:none}}";
2865
+ const css$8 = ".lcKema_root{flex-direction:column;display:flex}.lcKema_root:not([data-expanded]){contain:size layout;height:calc(24px + var(--dsh-content-font-delta,0px))}.lcKema_row{position:relative;overflow:hidden}.lcKema_root[data-expanded] [data-open] [data-disclosure-row]{z-index:1;background:var(--dsw-alias-bg-base);position:sticky;top:0}.lcKema_root[data-state=running] .lcKema_row:after{content:\"\";inset-block:0;background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite lcKema_dsh-reasoning-row-sweep;position:absolute;left:0}@keyframes lcKema_dsh-reasoning-row-sweep{0%{left:-300px}90%,to{left:100%}}.lcKema_leading{flex-shrink:0}.lcKema_chevron{color:var(--dsw-alias-label-secondary)}.lcKema_title{font-weight:400}.lcKema_separator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.lcKema_summary{min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));white-space:nowrap;flex:auto;overflow:hidden}.lcKema_summaryText{text-overflow:ellipsis;display:block;overflow:hidden}.lcKema_summary[data-follow-end]{justify-content:flex-end;display:flex}.lcKema_summary[data-follow-end] .lcKema_summaryText{text-align:start;text-overflow:clip;flex:none;width:max-content;min-width:100%;overflow:visible}.lcKema_thinkBody{padding:4px 0 4px calc(22px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));white-space:pre-wrap;word-break:break-word}@media (prefers-reduced-motion:reduce){.lcKema_root[data-state=running] .lcKema_row:after{animation:none}}";
2849
2866
  const tagId$8 = "@deepseek-ai/dsh-client-ui-chat/ReasoningRow.module.css";
2850
2867
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$8) + "]") === null) {
2851
2868
  const tag = document.createElement("style");
@@ -2879,7 +2896,7 @@ window.__ModuleLoader__.load({
2879
2896
  return newline === -1 ? visible : visible.slice(newline + 1);
2880
2897
  }
2881
2898
  /**
2882
- * Render one assistant reasoning block as the Think disclosure row. The
2899
+ * Render one assistant reasoning block collapsed until the reader opens it. The
2883
2900
  * collapsed summary omits double-asterisk markers; expanded content preserves
2884
2901
  * the complete text.
2885
2902
  * @param props.text - complete or streaming reasoning text.
@@ -4200,7 +4217,7 @@ window.__ModuleLoader__.load({
4200
4217
  * @param source - Logged `user/message` source.
4201
4218
  * @returns Role and label rendered by Chat.
4202
4219
  */
4203
- function contextProvenance(source) {
4220
+ function contextProducer(source) {
4204
4221
  const record = asRecord(source);
4205
4222
  const kind = record === null ? null : readString(record, "kind");
4206
4223
  if (record === null || kind === null) return {
@@ -6061,7 +6078,7 @@ window.__ModuleLoader__.load({
6061
6078
  time: event.time,
6062
6079
  content: event.data.content,
6063
6080
  source: event.data.source,
6064
- provenance: contextProvenance(event.data.source),
6081
+ producer: contextProducer(event.data.source),
6065
6082
  form: contextForm(event.data.source)
6066
6083
  };
6067
6084
  return reader.previous("inbox-next-step")?.state.currentClaimed.has(String(event.data.id)) === true ? {
@@ -6347,6 +6364,7 @@ window.__ModuleLoader__.load({
6347
6364
  callTime: previous?.time ?? null,
6348
6365
  content: data.content ?? [],
6349
6366
  isError: data.isError === true,
6367
+ ...data.error === void 0 ? {} : { error: data.error },
6350
6368
  subCalls: []
6351
6369
  };
6352
6370
  }
@@ -8323,6 +8341,11 @@ window.__ModuleLoader__.load({
8323
8341
  else ctx.sidebarRight.openResource(url, { params: { line: options.line } });
8324
8342
  await Promise.resolve();
8325
8343
  },
8344
+ openSkill: (name) => {
8345
+ const scope = ctx.sessions.scope(sessionId);
8346
+ if (scope === void 0) return;
8347
+ ctx.get("inputTriggers")?.sessionOf(scope).openReference("skill", { ref: `/${name}` });
8348
+ },
8326
8349
  loadOlder: () => {
8327
8350
  session.loadOlder();
8328
8351
  },
@@ -11,6 +11,6 @@ interface ChatNodeSeatProps extends ChatNodeOwnerProps {
11
11
  readonly t: ChatViewSlotProps['t'];
12
12
  }
13
13
  /** Subscribe, apply Turn-process visibility, and dispatch one stable Context key. */
14
- export declare const ChatNodeSeat: import("react").MemoExoticComponent<({ nodeKey, useChatNode, useChatNodeProcess, historyIncomplete, compactTranscript, cwd, openFile, inspectCall, forkAt, loadImage, renderMessageImages, fileMentions, useStore, actions, renderSlot, t, }: ChatNodeSeatProps) => import("react").JSX.Element | null>;
14
+ export declare const ChatNodeSeat: import("react").MemoExoticComponent<({ nodeKey, useChatNode, useChatNodeProcess, historyIncomplete, compactTranscript, cwd, openFile, openSkill, inspectCall, forkAt, loadImage, renderMessageImages, fileMentions, useStore, actions, renderSlot, t, }: ChatNodeSeatProps) => import("react").JSX.Element | null>;
15
15
  export {};
16
16
  //# sourceMappingURL=ChatNodeSeat.d.ts.map
@@ -3,5 +3,5 @@ import type { ChatViewSlotProps } from '../contract/slots.ts';
3
3
  * The chat view slot entry: pure component over the composed props; each
4
4
  * ordered business Node crosses the keyed renderer seat.
5
5
  */
6
- export declare function ChatView({ useSession, useChat, useChatNode, useChatNodeProcess, useSessions, useStore, actions, renderSlot, sessionId, openFile, loadOlder, loadThrough, loadImage, openView, chatScroll, forkAt, fileMentions, useTranscriptView, useProjection, t, }: ChatViewSlotProps): import("react").JSX.Element;
6
+ export declare function ChatView({ useSession, useChat, useChatNode, useChatNodeProcess, useSessions, useStore, actions, renderSlot, sessionId, openFile, openSkill, loadOlder, loadThrough, loadImage, openView, chatScroll, forkAt, fileMentions, useTranscriptView, useProjection, t, }: ChatViewSlotProps): import("react").JSX.Element;
7
7
  //# sourceMappingURL=ChatView.d.ts.map
@@ -5,7 +5,7 @@ export interface ContextInjectionRowProps {
5
5
  content: ContextMessageNode['content'];
6
6
  source: ContextMessageNode['source'];
7
7
  /** Role and producer name projected from the durable source. */
8
- provenance: ContextMessageNode['provenance'];
8
+ producer: ContextMessageNode['producer'];
9
9
  /** Producer-declared information form; null renders the opaque body. */
10
10
  form: ContextMessageNode['form'];
11
11
  /** The owning view's locale seat, passed down as a plain prop. */
@@ -22,5 +22,5 @@ export interface ContextInjectionRowProps {
22
22
  * @param props - Durable content, its projected producer role/name and form, and the locale seat.
23
23
  * @returns A collapsed context row with a bounded, form-specific body.
24
24
  */
25
- export declare function ContextInjectionRow({ content, source, provenance, form, t }: ContextInjectionRowProps): import("react").JSX.Element;
25
+ export declare function ContextInjectionRow({ content, source, producer, form, t }: ContextInjectionRowProps): import("react").JSX.Element;
26
26
  //# sourceMappingURL=ContextInjectionRow.d.ts.map
@@ -26,7 +26,7 @@ export declare function PendingSubmissionBubble({ submission, renderMessageImage
26
26
  t: ChatViewSlotProps['t'];
27
27
  }): ReactNode;
28
28
  /** User and admitted-steering keyed Chat renderer. */
29
- export declare const UserMessageNodeView: import("react").MemoExoticComponent<({ node, renderMessageImages, t, }: ChatNodeViewProps<"user" | "steering">) => import("react").JSX.Element>;
29
+ export declare const UserMessageNodeView: import("react").MemoExoticComponent<({ node, renderMessageImages, openFile, openSkill, t, }: ChatNodeViewProps<"user" | "steering">) => import("react").JSX.Element>;
30
30
  /** Injected-context keyed Chat renderer. */
31
31
  export declare const ContextMessageNodeView: import("react").MemoExoticComponent<({ node, t }: ChatNodeViewProps<"context">) => import("react").JSX.Element>;
32
32
  /** Automatic compaction keyed Chat renderer. */
@@ -1,6 +1,6 @@
1
1
  import type { ChatViewSlotProps } from '../contract/slots.ts';
2
2
  /**
3
- * Render one assistant reasoning block as the Think disclosure row. The
3
+ * Render one assistant reasoning block collapsed until the reader opens it. The
4
4
  * collapsed summary omits double-asterisk markers; expanded content preserves
5
5
  * the complete text.
6
6
  * @param props.text - complete or streaming reasoning text.
@@ -2,7 +2,7 @@ import type { Translate } from '@deepseek-ai/dsh-client-ui-slots';
2
2
  /** The date-template share of the conversation dictionary the clock consumes. */
3
3
  export type ClockTranslate = Translate<'clock.md' | 'clock.ymd'>;
4
4
  /** The elapsed-duration share of the conversation dictionary. */
5
- export type RunDurationTranslate = Translate<'duration.seconds' | 'duration.minutes'>;
5
+ export type RunDurationTranslate = Translate<'duration.seconds' | 'duration.minutes' | 'duration.hours'>;
6
6
  /**
7
7
  * Local calendar-day epoch (ms at local midnight) for an instant.
8
8
  * @param ms - Unix epoch ms.
@@ -19,7 +19,9 @@ export declare function msUntilNextLocalMidnight(ms: number): number;
19
19
  * Localized elapsed-time label shared by running and settled turn chrome.
20
20
  * @param ms - Elapsed duration in milliseconds (negatives clamp to zero).
21
21
  * @param t - Translate seat supplying the duration templates.
22
- * @returns Display string in whole seconds.
22
+ * @returns Display string in whole seconds; minutes and seconds once the
23
+ * duration reaches a minute; hours, minutes, and seconds once it reaches an
24
+ * hour, with the smaller units zero-padded.
23
25
  */
24
26
  export declare function formatRunDuration(ms: number, t: RunDurationTranslate): string;
25
27
  /**
@@ -59,6 +59,8 @@ export interface ChatNodeTurnDataInjected {
59
59
  /** Stable owner currency delivered to a keyed Chat renderer. */
60
60
  export interface ChatNodeOwnerProps {
61
61
  cwd?: string | undefined;
62
+ /** Open the current source file of a skill referenced by a sent message. */
63
+ openSkill: (name: string) => void;
62
64
  openFile: (path: string, options?: OpenFileOptions) => void;
63
65
  inspectCall: (callId: ToolCallId) => void;
64
66
  forkAt: (seq: number) => void;
@@ -110,6 +112,8 @@ export interface ChatViewInjected {
110
112
  /** Resolve the stable Turn-process source for one Chat Node key. */
111
113
  chatNodeProcess: (key: string) => ChatNodeProcessSource;
112
114
  };
115
+ /** Open the current source file of a skill referenced by a sent message. */
116
+ openSkill: (name: string) => void;
113
117
  openFile: (path: string, options?: OpenFileOptions) => Promise<void>;
114
118
  loadOlder: () => void;
115
119
  /** Jump loader: page history back through seq; resolves when the window covers it. */
@@ -1,7 +1,7 @@
1
1
  import type { ConversationNode, ConversationTimelineSnapshot, PartialAssistant, RunningToolCall } from '@deepseek-ai/dsh-client-ui-conversation/client';
2
2
  import type { ChatConversationViewNode } from './chat-nodes.ts';
3
3
  import type { TurnProcessSpec } from './turn-process.ts';
4
- export type { AssistantBlock, AssistantMessageNode, AssistantProvenanceView, AssistantRequestConfig, AssistantTiming, CommandNode, CompactionSummaryNode, ContextMessageNode, ConversationNode, ModelRetryNode, PartialAssistant, RunningToolCall, SteeringMessageNode, TodoItem, ToolCallBlock, ToolResultNode, TurnErrorNode, TurnMaxTokensNode, UnknownSurfaceNode, UserMessageNode, } from '@deepseek-ai/dsh-client-ui-conversation/client';
4
+ export type { AssistantBlock, AssistantMessageNode, AssistantProviderMetadataView, AssistantRequestConfig, AssistantTiming, CommandNode, CompactionSummaryNode, ContextMessageNode, ConversationNode, ModelRetryNode, PartialAssistant, RunningToolCall, SteeringMessageNode, TodoItem, ToolCallBlock, ToolResultNode, TurnErrorNode, TurnMaxTokensNode, UnknownSurfaceNode, UserMessageNode, } from '@deepseek-ai/dsh-client-ui-conversation/client';
5
5
  /** Per-key observable used by one mounted Chat Node Seat. */
6
6
  export interface ChatNodeSource {
7
7
  /** @returns the current Node for this source's stable key. */
@@ -1,6 +1,6 @@
1
1
  /** Chat-owned conversion from durable Session events to Chat view data. */
2
2
  import type { ContentBlock, StreamChunk } from '@deepseek-ai/dsh-llm/types';
3
- import type { AssistantBlock, ContextProvenanceView, KnownContextForm } from '@deepseek-ai/dsh-client-ui-conversation/client';
3
+ import type { AssistantBlock, ContextProducerView, KnownContextForm } from '@deepseek-ai/dsh-client-ui-conversation/client';
4
4
  /**
5
5
  * Read the target-supported presentation form from a durable message source.
6
6
  * @param source - Logged `user/message` source.
@@ -12,7 +12,7 @@ export declare function contextForm(source: unknown): KnownContextForm | null;
12
12
  * @param source - Logged `user/message` source.
13
13
  * @returns Role and label rendered by Chat.
14
14
  */
15
- export declare function contextProvenance(source: unknown): ContextProvenanceView;
15
+ export declare function contextProducer(source: unknown): ContextProducerView;
16
16
  /**
17
17
  * Read distinct labels cited by a durable cross-session recall source.
18
18
  * @param source - Logged `user/message` source.
@@ -12,7 +12,7 @@ export type {} from './conversation-nodes/turn-error.ts';
12
12
  export type {} from './conversation-nodes/turn-max-tokens.ts';
13
13
  export type {} from './conversation-nodes/turn-process.ts';
14
14
  export type {} from './conversation-nodes/turn-tail.ts';
15
- export type { AssistantBlock, AssistantMessageNode, AssistantProvenanceView, AssistantRequestConfig, AssistantTiming, ChatLocationNodeIndex, ChatNodeProcessSource, ChatNodeSource, ChatNodeStore, ChatSnapshot, ChatTurnNavigationIndex, ChatTurnProcessPresentation, CommandNode, CompactionSummaryNode, ContextMessageNode, ConversationNode, LegacyConversationSlice, ModelRetryNode, PartialAssistant, RunningToolCall, SteeringMessageNode, ToolCallBlock, ToolResultNode, TurnErrorNode, TurnMaxTokensNode, TurnNavigationItem, UnknownSurfaceNode, UserMessageNode, } from './contract/snapshot.ts';
15
+ export type { AssistantBlock, AssistantMessageNode, AssistantProviderMetadataView, AssistantRequestConfig, AssistantTiming, ChatLocationNodeIndex, ChatNodeProcessSource, ChatNodeSource, ChatNodeStore, ChatSnapshot, ChatTurnNavigationIndex, ChatTurnProcessPresentation, CommandNode, CompactionSummaryNode, ContextMessageNode, ConversationNode, LegacyConversationSlice, ModelRetryNode, PartialAssistant, RunningToolCall, SteeringMessageNode, ToolCallBlock, ToolResultNode, TurnErrorNode, TurnMaxTokensNode, TurnNavigationItem, UnknownSurfaceNode, UserMessageNode, } from './contract/snapshot.ts';
16
16
  export type { AssistantChatData, ChatConversationViewNode, ChatNode, ChatNodeKind, FinalAssistantChatData, ManualCompactionChatData, RetryChatData, ToolChatData, TurnProcessChatData, TurnTailChatData, } from './contract/chat-nodes.ts';
17
17
  export type { ChatStoreState, ToolCallId, TurnProcessViewEntry } from './contract/store.ts';
18
18
  export type { TranscriptViewRowInjected, TranscriptViewRowProps } from './settings/TranscriptViewRow.tsx';
@@ -21,7 +21,7 @@ export type { AssistantActionOwnerProps, ChatFileMentions, ChatNodeOwnerProps, C
21
21
  export type { TurnProcessSpec, } from './contract/turn-process.ts';
22
22
  export type { ChatKey } from './locale.ts';
23
23
  export type { ConversationContext, ConversationContextOriginKind } from './model/conversation-context.ts';
24
- export type { ContextProvenanceView, ContextRole, KnownContextForm, } from '@deepseek-ai/dsh-client-ui-conversation/client';
24
+ export type { ContextProducerView, ContextRole, KnownContextForm, } from '@deepseek-ai/dsh-client-ui-conversation/client';
25
25
  export type { ConversationPromptSnapshot, RequestInspectionSnapshot, RequestPromptChange, RequestView, } from '@deepseek-ai/dsh-client-ui-conversation/client';
26
26
  export { isRunningTool, isSettledTool } from './contract/chat-nodes.ts';
27
27
  export { EMPTY_CHAT_SNAPSHOT } from './contract/snapshot.ts';
@@ -97,6 +97,7 @@ export declare const zh: {
97
97
  'message.turnTime.ttft': string;
98
98
  'duration.seconds': string;
99
99
  'duration.minutes': string;
100
+ 'duration.hours': string;
100
101
  'command.running': string;
101
102
  'command.failed': string;
102
103
  'command.done': string;
@@ -205,6 +206,7 @@ export declare const en: {
205
206
  'message.turnTime.ttft': string;
206
207
  'duration.seconds': string;
207
208
  'duration.minutes': string;
209
+ 'duration.hours': string;
208
210
  'command.running': string;
209
211
  'command.failed': string;
210
212
  'command.done': string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-ui-chat",
3
3
  "description": "Chat Conversation target, node definitions, renderers, and details surface",
4
- "version": "0.1.5-rc.2",
4
+ "version": "0.1.6-alpha.1",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -32,11 +32,12 @@
32
32
  "@deepseek-ai/dsh-api-workspace-controller",
33
33
  "@deepseek-ai/dsh-client-locale",
34
34
  "@deepseek-ai/dsh-client-ui-conversation",
35
+ "@deepseek-ai/dsh-client-ui-input-trigger",
35
36
  "@deepseek-ai/dsh-client-ui-layout",
36
37
  "@deepseek-ai/dsh-client-ui-renderer",
37
38
  "@deepseek-ai/dsh-client-ui-session",
38
- "@deepseek-ai/dsh-client-ui-sidebar-right",
39
39
  "@deepseek-ai/dsh-client-ui-settings",
40
+ "@deepseek-ai/dsh-client-ui-sidebar-right",
40
41
  "@deepseek-ai/dsh-client-ui-workspace"
41
42
  ],
42
43
  "platform": "web"
@@ -52,36 +53,37 @@
52
53
  "react": "^18.2.0",
53
54
  "react-dom": "^18.2.0",
54
55
  "@deepseek-ai/cordis": "^4.0.2",
55
- "@deepseek-ai/dsh-agent": "^0.1.5-rc.2",
56
- "@deepseek-ai/dsh-api-remotes": "^0.1.5-rc.2",
57
- "@deepseek-ai/dsh-api-session-controller": "^0.1.5-rc.2",
58
- "@deepseek-ai/dsh-api-workspace-controller": "^0.1.5-rc.2",
59
- "@deepseek-ai/dsh-attachment": "^0.1.5-rc.2",
60
- "@deepseek-ai/dsh-api-workspace-files": "^0.1.5-rc.2",
61
- "@deepseek-ai/dsh-client-locale": "^0.1.5-rc.2",
62
- "@deepseek-ai/dsh-client-store": "^0.1.5-rc.2",
63
- "@deepseek-ai/dsh-client-ui-approval": "^0.1.5-rc.2",
64
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.5-rc.2",
65
- "@deepseek-ai/dsh-client-ui-layout": "^0.1.5-rc.2",
66
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-rc.2",
67
- "@deepseek-ai/dsh-client-ui-renderer": "^0.1.5-rc.2",
68
- "@deepseek-ai/dsh-client-ui-session": "^0.1.5-rc.2",
69
- "@deepseek-ai/dsh-client-ui-settings": "^0.1.5-rc.2",
70
- "@deepseek-ai/dsh-client-ui-sidebar-documentpreview": "^0.1.5-rc.2",
71
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.5-rc.2",
72
- "@deepseek-ai/dsh-client-ui-workspace": "^0.1.5-rc.2",
73
- "@deepseek-ai/dsh-commands": "^0.1.5-rc.2",
74
- "@deepseek-ai/dsh-compaction": "^0.1.5-rc.2",
75
- "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
76
- "@deepseek-ai/dsh-llm-retry": "^0.1.5-rc.2",
77
- "@deepseek-ai/dsh-session": "^0.1.5-rc.2",
78
- "@deepseek-ai/dsh-session-stats": "^0.1.5-rc.2",
79
- "@deepseek-ai/dsh-session-turn-outline": "^0.1.5-rc.2",
80
- "@deepseek-ai/dsh-settings": "^0.1.5-rc.2",
81
- "@deepseek-ai/dsh-token-meter": "^0.1.5-rc.2",
82
- "@deepseek-ai/dsh-client-ui-sidebar-right": "^0.1.5-rc.2",
83
- "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
84
- "@deepseek-ai/dsh-util-workspace-path": "^0.1.5-rc.2"
56
+ "@deepseek-ai/dsh-agent": "^0.1.6-alpha.1",
57
+ "@deepseek-ai/dsh-api-remotes": "^0.1.6-alpha.1",
58
+ "@deepseek-ai/dsh-api-session-controller": "^0.1.6-alpha.1",
59
+ "@deepseek-ai/dsh-api-workspace-controller": "^0.1.6-alpha.1",
60
+ "@deepseek-ai/dsh-api-workspace-files": "^0.1.6-alpha.1",
61
+ "@deepseek-ai/dsh-attachment": "^0.1.6-alpha.1",
62
+ "@deepseek-ai/dsh-client-ui-approval": "^0.1.6-alpha.1",
63
+ "@deepseek-ai/dsh-client-store": "^0.1.6-alpha.1",
64
+ "@deepseek-ai/dsh-client-ui-conversation": "^0.1.6-alpha.1",
65
+ "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.6-alpha.1",
66
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.6-alpha.1",
67
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.6-alpha.1",
68
+ "@deepseek-ai/dsh-client-ui-layout": "^0.1.6-alpha.1",
69
+ "@deepseek-ai/dsh-client-ui-session": "^0.1.6-alpha.1",
70
+ "@deepseek-ai/dsh-client-ui-settings": "^0.1.6-alpha.1",
71
+ "@deepseek-ai/dsh-client-ui-sidebar-documentpreview": "^0.1.6-alpha.1",
72
+ "@deepseek-ai/dsh-client-ui-sidebar-right": "^0.1.6-alpha.1",
73
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.6-alpha.1",
74
+ "@deepseek-ai/dsh-client-ui-workspace": "^0.1.6-alpha.1",
75
+ "@deepseek-ai/dsh-commands": "^0.1.6-alpha.1",
76
+ "@deepseek-ai/dsh-compaction": "^0.1.6-alpha.1",
77
+ "@deepseek-ai/dsh-llm-retry": "^0.1.6-alpha.1",
78
+ "@deepseek-ai/dsh-llm": "^0.1.6-alpha.1",
79
+ "@deepseek-ai/dsh-session": "^0.1.6-alpha.1",
80
+ "@deepseek-ai/dsh-session-stats": "^0.1.6-alpha.1",
81
+ "@deepseek-ai/dsh-settings": "^0.1.6-alpha.1",
82
+ "@deepseek-ai/dsh-session-turn-outline": "^0.1.6-alpha.1",
83
+ "@deepseek-ai/dsh-token-meter": "^0.1.6-alpha.1",
84
+ "@deepseek-ai/dsh-util-workspace-path": "^0.1.6-alpha.1",
85
+ "@deepseek-ai/dsh-tools": "^0.1.6-alpha.1",
86
+ "@deepseek-ai/dsh-client-locale": "^0.1.6-alpha.1"
85
87
  },
86
88
  "dependencies": {
87
89
  "@deepseek-ai/schemastery": "^3.18.2"