@x1a0f3n9/dsh-client-ui-skill 0.1.5-rc.4 → 0.1.7-rc.2

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
@@ -1,6 +1,58 @@
1
- # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
2
- # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
- # after editing either side, bring the other along and re-record with:
1
+ # Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
2
+ # section, a hash of its English and Chinese blocks outside code blocks and generated regions.
3
+ # After editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/client/ui-skill/README.md
5
- README.md: a1e9e7047f102f2610160905727450833b540082
6
- README.zh.md: d7669b11fc7249c857e20f3c52f93b8bfd214281
5
+ /:
6
+ en: 490d60d7bec05d21
7
+ zh: 72a1300893d68f31
8
+ /x1a0f3n9-dsh-client-ui-skill:
9
+ en: 49786b8c5dd64237
10
+ zh: 0debecde1d8ff41e
11
+ /x1a0f3n9-dsh-client-ui-skill/summary:
12
+ en: fad7bff8d3371dfc
13
+ zh: c546189c87d6fbf2
14
+ /x1a0f3n9-dsh-client-ui-skill/table-of-contents:
15
+ en: d152484eb41ac6b4
16
+ zh: 09388d293f9be9cb
17
+ /x1a0f3n9-dsh-client-ui-skill/use-this-package:
18
+ en: 2f17d0875048ef3c
19
+ zh: 6878ee4c75f2b2cf
20
+ /x1a0f3n9-dsh-client-ui-skill/use-this-package/what-the-source-offers:
21
+ en: 2ba1a6158c85b46e
22
+ zh: 9ab58ceef8743849
23
+ /x1a0f3n9-dsh-client-ui-skill/use-this-package/the-skill-tool-row:
24
+ en: 52c7aee8faf26795
25
+ zh: f68e2f17cc7e369a
26
+ /x1a0f3n9-dsh-client-ui-skill/understand-the-implementation:
27
+ en: df2a0ee9d2638f41
28
+ zh: 3b4af7e505e990ca
29
+ /x1a0f3n9-dsh-client-ui-skill/understand-the-implementation/candidate-flow:
30
+ en: 1a02a85859f851c7
31
+ zh: 03bd48b83c4a287c
32
+ /x1a0f3n9-dsh-client-ui-skill/understand-the-implementation/registration:
33
+ en: 1965ad3169b7fd97
34
+ zh: efc23c44ad1d2765
35
+ /x1a0f3n9-dsh-client-ui-skill/further-exploration:
36
+ en: 54198f095d0cc569
37
+ zh: 4eba4413e159967b
38
+ /x1a0f3n9-dsh-client-ui-skill/model-experience:
39
+ en: 215e7ba838619b7b
40
+ zh: a311da3843709f90
41
+ /x1a0f3n9-dsh-client-ui-skill/model-experience/user-explicit-skill-invocation:
42
+ en: ae1928252b0ea55c
43
+ zh: 6c78cb51c6805a2d
44
+ /x1a0f3n9-dsh-client-ui-skill/model-experience/user-explicit-skill-invocation/what-the-model-sees:
45
+ en: 02313760445799a2
46
+ zh: 46007ed9e9f35b44
47
+ /x1a0f3n9-dsh-client-ui-skill/model-experience/user-explicit-skill-invocation/token-effect:
48
+ en: cb759321f8c62a96
49
+ zh: 6d479501856d9cd6
50
+ /x1a0f3n9-dsh-client-ui-skill/model-experience/user-explicit-skill-invocation/kv-cache-effect:
51
+ en: da53c649077dad7e
52
+ zh: 845f77793f8e10a2
53
+ /x1a0f3n9-dsh-client-ui-skill/known-limitations-and-deferred-work:
54
+ en: aed53b17a91d4b02
55
+ zh: fac571e9228e69c5
56
+ /x1a0f3n9-dsh-client-ui-skill/known-limitations-and-deferred-work/dev-note:
57
+ en: f3cb9f98b665c2f9
58
+ zh: 2275c60173ce961b
package/README.md CHANGED
@@ -33,7 +33,9 @@ Ordinary-session candidates come from the `skills/list` Remote; the host serves
33
33
 
34
34
  ### The skill tool row
35
35
 
36
- A collapsed row renders the skill glyph, `Skill` title, and requested skill name; running calls carry the transcript shimmer, failures replace the name with the first error line, and interrupted calls use the warning state. A settled row expands into a bounded `Instructions` card containing the exact durable tool output, with the standard trajectory `Inspect` affordance when available. The row derives its name, lifecycle, and body only from the frozen call/result slice supplied by ui-tool, never from the current catalog, so replay stays stable when installed skills or their descriptions change.
36
+ The `preparing` stage shows only the skill icon and title, with no requested skill name or expansion. The `start` and `result` stages use the recorded arguments and output described below; preparation does not consult the installed catalog.
37
+
38
+ A collapsed row renders the skill glyph, `Skill` title, and requested skill name on the same secondary font-size axis, line height, row height, and glyph scaling as ordinary Tool rows. Every lifecycle state retains the ordinary skill glyph; running calls carry the transcript shimmer, while failures replace the name with the first error line and interruptions retain their explicit status text. A settled row expands into a bounded `Instructions` card containing the exact durable tool output, with the standard trajectory `Inspect` affordance when available; this expanded card keeps its own typography. The row derives its name, lifecycle, and body only from the frozen call/result slice supplied by ui-tool, never from the current catalog, so replay stays stable when installed skills or their descriptions change.
37
39
 
38
40
  Hovering over `/name` highlights the entire reference. Clicking a known skill opens its provider-supplied `SKILL.md` path in the right Sidebar while keeping the token editable. An uncached click shares the per-Session catalog fetch and opens when it completes, retaining the clicked Session address. Preset changes, connection resets, and plugin disposal cancel pending previews; a later click fetches the current catalog again. Skills without a file path remain invocable but have no file preview.
39
41
 
@@ -51,6 +53,8 @@ The source implements no adjudication hooks and no reference codec: the pick lan
51
53
 
52
54
  Catalogs cache per ordinary session with a single-flight fetch; the scope-birth `warm` hook prewarms the session's entry, the forwarded `agent-preset/selected` owner event drops that one session's entry (the catalog belongs to the preset, and a blank session may switch after the warm), and `connection/reset` clears everything. Catalog-addressed continuable children resolve no skill candidates locally because the existing skill RPC requires an attached session; viewing their persisted history must not activate them. The list RPC rides the plugin's root-context connection captured at registration; draft chip visuals derive from the `lexicon` scan.
53
55
 
56
+ Each catalog fetch requires an existing retained Client Session and waits for its initial history open to succeed before sending `skills/list`. A temporary `skillCatalog` reference holds that Session until the fetch settles. An unretained Session or a failed open rejects without sending the RPC; preset invalidation, connection reset, and plugin disposal also cancel a pending history wait.
57
+
54
58
  ### Registration
55
59
 
56
60
  The `/client` exports are the plugin body (`apply`/`inject`) only; the source object is internal to the registration effect. The tool row registers the `skill` wire name in ui-tool's keyed `tool.call.toolview` slot.
package/README.zh.md CHANGED
@@ -33,7 +33,9 @@ kind: "package-reference"
33
33
 
34
34
  ### skill 工具行
35
35
 
36
- 收起的行显示 skill 图标、`Skill` 标题与请求加载的 skill 名称;运行中的调用带有 transcript(文本记录)的扫光效果,失败时用错误首行替换名称,中断的调用使用警告状态。已结算的行展开为一个尺寸受限的 `Instructions` 卡片,其中原样呈现持久化的工具输出;可用时还会提供标准轨迹的 `Inspect` 入口。该行的名称、生命周期与正文只派生自 ui-tool 提供的冻结调用/结果切片,绝不读取当前目录,因此即使已安装的 skill 或其描述发生变化,回放仍保持稳定。
36
+ `preparing` 阶段只显示技能图标与标题,不显示请求加载的技能名称,也不能展开。`start` 和 `result` 阶段使用下述记录参数与输出;准备阶段不查询已安装目录。
37
+
38
+ 收起的行显示 skill 图标、`Skill` 标题与请求加载的 skill 名称,并与普通工具行使用相同的 secondary 字号轴、行高、行高度和图标缩放。所有生命周期状态都保留普通 skill 图标;运行中的调用带有 transcript(文本记录)的扫光效果,失败时以错误首行替换名称,中断则保留明确状态文本。已结算的行展开为一个尺寸受限的 `Instructions` 卡片,其中原样呈现持久化的工具输出;可用时还会提供标准轨迹的 `Inspect` 入口,展开卡片保留自身排版。该行的名称、生命周期与正文只派生自 ui-tool 提供的冻结调用/结果切片,绝不读取当前目录,因此即使已安装的 skill 或其描述发生变化,回放仍保持稳定。
37
39
 
38
40
  鼠标移入 `/name` 时,背景覆盖整个引用。点击已知 skill 会在右侧栏打开提供方给出的 `SKILL.md` 路径,同时保留文本的可编辑性。缓存未就绪时,点击复用该 Session 的目录请求,在完成后按点击时的 Session 地址打开预览。切换预设、重置连接和插件释放会取消待处理的预览;后续点击重新获取当前目录。没有文件路径的 skill 仍可调用,但没有文件预览。
39
41
 
@@ -51,6 +53,8 @@ source 不实现任何裁决钩子,也没有引用 codec:pick 落下字面
51
53
 
52
54
  目录按普通会话缓存,拉取走 single-flight;scope 创建时的 `warm` 钩子预热该会话的缓存项,转发的 owner 事件 `agent-preset/selected` 丢弃该会话这一项(目录属于 preset,而空会话可能在预热之后才切换),`connection/reset` 清空全部缓存。由目录寻址的可继续 subagent 在客户端解析为没有 skill 候选,因为现有 skill RPC 要求会话已挂载;查看其持久化历史不得激活它。列表 RPC 使用插件注册时捕获的根上下文连接;草稿 chip 视觉由 `lexicon` 扫描派生。
53
55
 
56
+ 每次目录拉取都要求客户端已持有该会话,并等待首次历史打开成功后才发送 `skills/list`。临时的 `skillCatalog` 引用持续持有会话,直到拉取结束。未被持有的会话或打开失败会直接拒绝,不发送 RPC;预设失效、连接重置和插件释放也会取消正在等待的历史打开。
57
+
54
58
  ### 注册
55
59
 
56
60
  `/client` 导出接口只有插件主体(`apply`/`inject`);source 对象是注册 effect 的内部实现。工具行把 `skill` wire 名称注册进 ui-tool 的 keyed `tool.call.toolview` slot。
package/lib/client.js CHANGED
@@ -66,7 +66,7 @@ window.__ModuleLoader__.load({
66
66
  }
67
67
  //#endregion
68
68
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-skill/src/client/SkillRow.module.css.mjs
69
- const css = ".iWrAna_card{flex-direction:column;display:flex}.iWrAna_row{align-items:center;min-width:0;height:24px;display:flex;position:relative;overflow:hidden}.iWrAna_row[data-expandable]{cursor:pointer}.iWrAna_card[data-state=running] .iWrAna_row:after{content:\"\";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 iWrAna_dsh-skill-row-sweep;position:absolute;inset:0 auto 0 0}@keyframes iWrAna_dsh-skill-row-sweep{0%{left:-300px}90%,to{left:100%}}.iWrAna_leading{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;margin-right:6px;display:inline-flex;position:relative}.iWrAna_chevron{color:var(--dsw-alias-label-secondary)}.iWrAna_iconIdle{opacity:1;transition:opacity .1s;display:inline-flex}.iWrAna_chevronHover{opacity:0;margin:auto;transition:opacity .1s;position:absolute;inset:0}.iWrAna_row:hover .iWrAna_iconIdle{opacity:0}.iWrAna_row:hover .iWrAna_chevronHover{opacity:1}.iWrAna_title{color:var(--dsw-alias-label-secondary);flex:none;font-size:14px;line-height:24px}.iWrAna_separator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.iWrAna_summary{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-tertiary);flex:auto;font-size:14px;line-height:24px;overflow:hidden}.iWrAna_errorSummary{color:var(--dsw-alias-state-error-primary)}.iWrAna_bodyWrap{flex-direction:column;display:flex}.iWrAna_instructionsCard{border:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-markdown-code-block);border-radius:12px;flex-direction:column;max-height:260px;margin:4px 0 4px 4px;display:flex;overflow:hidden}.iWrAna_instructionsHeader{border-bottom:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block-banner);color:var(--dsw-alias-label-caption);text-transform:uppercase;letter-spacing:.04em;flex:none;padding:8px 12px;font-size:11px;font-weight:500;line-height:16px}.iWrAna_instructions{white-space:pre-wrap;overflow-wrap:anywhere;min-height:0;font:var(--dsw-font-markdown-code-block-small);color:var(--dsw-alias-label-secondary);margin:0;padding:10px 12px 12px;overflow:auto}.iWrAna_instructions[data-error]{color:var(--dsw-alias-state-error-primary)}.iWrAna_instructions::-webkit-scrollbar-thumb{background-clip:padding-box;border:2px solid #0000;border-radius:6px}.iWrAna_instructions::-webkit-scrollbar-track{margin:6px 0}.iWrAna_inspectButton{border:.5px solid var(--dsw-alias-border-l4);corner-shape:round;background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-secondary);cursor:pointer;opacity:0;border-radius:999px;align-self:flex-start;align-items:center;gap:4px;margin:4px 0 2px 4px;padding:2px 8px;font-size:11px;line-height:16px;transition:opacity .1s;display:inline-flex}.iWrAna_card:hover .iWrAna_inspectButton,.iWrAna_inspectButton:focus-visible{opacity:1}.iWrAna_inspectButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.iWrAna_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}@media (prefers-reduced-motion:reduce){.iWrAna_card[data-state=running] .iWrAna_row:after{animation:none;display:none}.iWrAna_iconIdle,.iWrAna_chevronHover,.iWrAna_inspectButton{transition:none}}";
69
+ const css = ".iWrAna_card{flex-direction:column;display:flex}.iWrAna_row{height:calc(24px + var(--dsh-content-font-delta,0px));align-items:center;min-width:0;display:flex;position:relative;overflow:hidden}.iWrAna_row[data-expandable]{cursor:pointer}.iWrAna_card[data-state=running] .iWrAna_row:after,.iWrAna_card[data-state=preparing] .iWrAna_row:after{content:\"\";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 iWrAna_dsh-skill-row-sweep;position:absolute;inset:0 auto 0 0}@keyframes iWrAna_dsh-skill-row-sweep{0%{left:-300px}90%,to{left:100%}}.iWrAna_leading{width:calc(16px + var(--dsh-content-font-delta,0px));height:calc(16px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;margin-right:6px;display:inline-flex;position:relative}.iWrAna_leading svg{width:calc(14px + var(--dsh-content-font-delta,0px));height:calc(14px + var(--dsh-content-font-delta,0px))}.iWrAna_chevron{color:var(--dsw-alias-label-secondary)}.iWrAna_iconIdle{opacity:1;transition:opacity .1s;display:inline-flex}.iWrAna_chevronHover{opacity:0;margin:auto;transition:opacity .1s;position:absolute;inset:0}.iWrAna_row:hover .iWrAna_iconIdle{opacity:0}.iWrAna_row:hover .iWrAna_chevronHover{opacity:1}.iWrAna_title{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-secondary);flex:none}.iWrAna_separator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.iWrAna_summary{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);flex:auto;overflow:hidden}.iWrAna_errorSummary{color:var(--dsw-alias-state-error-primary)}.iWrAna_stoppedSummary{color:var(--dsw-alias-state-warn-label)}.iWrAna_bodyWrap{flex-direction:column;display:flex}.iWrAna_instructionsCard{border:.5px solid var(--dsw-alias-border-l1);border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-markdown-code-block);flex-direction:column;max-height:260px;margin:4px 0 4px 4px;display:flex;overflow:hidden}.iWrAna_instructionsHeader{border-bottom:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block-banner);color:var(--dsw-alias-label-caption);text-transform:uppercase;letter-spacing:.04em;flex:none;padding:8px 12px;font-size:11px;font-weight:500;line-height:16px}.iWrAna_instructions{white-space:pre-wrap;overflow-wrap:anywhere;min-height:0;font:var(--dsw-font-markdown-code-block-small);color:var(--dsw-alias-label-secondary);margin:0;padding:10px 12px 12px;overflow:auto}.iWrAna_instructions[data-error]{color:var(--dsw-alias-state-error-primary)}.iWrAna_instructions::-webkit-scrollbar-thumb{border-radius:var(--dsw-radius-sm);background-clip:padding-box;border:2px solid #0000}.iWrAna_instructions::-webkit-scrollbar-track{margin:6px 0}.iWrAna_inspectButton{border:.5px solid var(--dsw-alias-border-l4);corner-shape:round;background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-secondary);cursor:pointer;opacity:0;border-radius:999px;align-self:flex-start;align-items:center;gap:4px;margin:4px 0 2px 4px;padding:2px 8px;font-size:11px;line-height:16px;transition:opacity .1s;display:inline-flex}.iWrAna_card:hover .iWrAna_inspectButton,.iWrAna_inspectButton:focus-visible{opacity:1}.iWrAna_inspectButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.iWrAna_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}@media (prefers-reduced-motion:reduce){.iWrAna_card[data-state=running] .iWrAna_row:after{animation:none;display:none}.iWrAna_iconIdle,.iWrAna_chevronHover,.iWrAna_inspectButton{transition:none}}";
70
70
  const tagId = "@x1a0f3n9/dsh-client-ui-skill/SkillRow.module.css";
71
71
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
72
72
  const tag = document.createElement("style");
@@ -90,6 +90,7 @@ window.__ModuleLoader__.load({
90
90
  "leading": "iWrAna_leading",
91
91
  "row": "iWrAna_row",
92
92
  "separator": "iWrAna_separator",
93
+ "stoppedSummary": "iWrAna_stoppedSummary",
93
94
  "summary": "iWrAna_summary",
94
95
  "title": "iWrAna_title",
95
96
  "visuallyHidden": "iWrAna_visuallyHidden"
@@ -134,30 +135,21 @@ window.__ModuleLoader__.load({
134
135
  state
135
136
  };
136
137
  }
137
- /** State substitution for the collapsed leading slot. */
138
- function leadingFor(state) {
139
- switch (state) {
140
- case "error": return (0, react_jsx_runtime.jsx)(_x1a0f3n9_dsh_client_ui_primitives.StateDot, { state: "error" });
141
- case "stopped": return (0, react_jsx_runtime.jsx)(_x1a0f3n9_dsh_client_ui_primitives.StateDot, { state: "warning" });
142
- default: return (0, react_jsx_runtime.jsx)(_x1a0f3n9_dsh_client_ui_primitives.IconSkillOutline16, { size: 14 });
143
- }
144
- }
145
138
  /** Leading disclosure slot: state icon at rest, chevron on hover or while open. */
146
- function disclosureLeading(state, open, expandable) {
147
- if (open) return (0, react_jsx_runtime.jsx)(_x1a0f3n9_dsh_client_ui_primitives.IconChevronDownOutline14, { className: SkillRow_module_css_default.chevron });
148
- const icon = leadingFor(state);
139
+ function disclosureLeading(open, expandable) {
140
+ if (open) return (0, react_jsx_runtime.jsx)(_x1a0f3n9_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: SkillRow_module_css_default.chevron });
141
+ const icon = (0, react_jsx_runtime.jsx)(_x1a0f3n9_dsh_client_ui_primitives.IconSkillOutlineRegular, { size: 14 });
149
142
  if (!expandable) return icon;
150
143
  return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("span", {
151
144
  className: SkillRow_module_css_default.iconIdle,
152
145
  children: icon
153
- }), (0, react_jsx_runtime.jsx)(_x1a0f3n9_dsh_client_ui_primitives.IconChevronDownOutline14, { className: `${SkillRow_module_css_default.chevron} ${SkillRow_module_css_default.chevronHover}` })] });
146
+ }), (0, react_jsx_runtime.jsx)(_x1a0f3n9_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: `${SkillRow_module_css_default.chevron} ${SkillRow_module_css_default.chevronHover}` })] });
154
147
  }
155
- /** Visually hidden state copy for the colour-only lifecycle cues. */
148
+ /** Visually hidden state copy for the color-only running sweep and error tone. */
156
149
  function stateStatus(state, t) {
157
150
  switch (state) {
158
151
  case "running": return t("row.running");
159
152
  case "error": return t("row.failed");
160
- case "stopped": return t("row.stopped");
161
153
  default: return null;
162
154
  }
163
155
  }
@@ -166,13 +158,38 @@ window.__ModuleLoader__.load({
166
158
  * @param props - keyed toolview payload plus the skill locale seat.
167
159
  * @returns the dedicated skill row.
168
160
  */
169
- function SkillRow({ block, inspect, t }) {
161
+ function SkillRow(props) {
162
+ if (props.phase === "preparing") return (0, react_jsx_runtime.jsx)("div", {
163
+ className: SkillRow_module_css_default.card,
164
+ "data-tool": "skill",
165
+ "data-state": "preparing",
166
+ children: (0, react_jsx_runtime.jsxs)("div", {
167
+ className: SkillRow_module_css_default.row,
168
+ children: [
169
+ (0, react_jsx_runtime.jsx)("span", {
170
+ className: SkillRow_module_css_default.leading,
171
+ children: (0, react_jsx_runtime.jsx)(_x1a0f3n9_dsh_client_ui_primitives.IconSkillOutlineRegular, { size: 14 })
172
+ }),
173
+ (0, react_jsx_runtime.jsx)("span", {
174
+ className: SkillRow_module_css_default.visuallyHidden,
175
+ children: props.t("row.preparing")
176
+ }),
177
+ (0, react_jsx_runtime.jsx)("span", {
178
+ className: SkillRow_module_css_default.title,
179
+ children: props.t("row.title")
180
+ })
181
+ ]
182
+ })
183
+ });
184
+ return (0, react_jsx_runtime.jsx)(StartedSkillRow, { ...props });
185
+ }
186
+ function StartedSkillRow({ block, inspect, t }) {
170
187
  const model = skillRowModel(block);
171
188
  const [expanded, setExpanded] = (0, react.useState)(false);
172
189
  const expandable = model.output !== null;
173
190
  const open = expanded && expandable;
174
191
  const status = stateStatus(model.state, t);
175
- const summary = model.errorSummary ?? model.name;
192
+ const summary = model.state === "stopped" ? t("row.stopped") : model.errorSummary ?? model.name;
176
193
  const toggleExpand = () => {
177
194
  setExpanded((value) => !value);
178
195
  };
@@ -188,7 +205,7 @@ window.__ModuleLoader__.load({
188
205
  onClick: toggleExpand,
189
206
  onKeyDown: toggleFromKeyboard
190
207
  } : {};
191
- const leading = disclosureLeading(model.state, open, expandable);
208
+ const leading = disclosureLeading(open, expandable);
192
209
  return (0, react_jsx_runtime.jsxs)("div", {
193
210
  className: SkillRow_module_css_default.card,
194
211
  "data-tool": "skill",
@@ -215,7 +232,7 @@ window.__ModuleLoader__.load({
215
232
  "aria-hidden": true
216
233
  }),
217
234
  (0, react_jsx_runtime.jsx)("span", {
218
- className: model.errorSummary === null ? SkillRow_module_css_default.summary : `${SkillRow_module_css_default.summary} ${SkillRow_module_css_default.errorSummary}`,
235
+ className: `${SkillRow_module_css_default.summary}${model.state === "error" ? ` ${SkillRow_module_css_default.errorSummary}` : model.state === "stopped" ? ` ${SkillRow_module_css_default.stoppedSummary}` : ""}`,
219
236
  children: summary
220
237
  })
221
238
  ]
@@ -236,7 +253,7 @@ window.__ModuleLoader__.load({
236
253
  type: "button",
237
254
  className: SkillRow_module_css_default.inspectButton,
238
255
  onClick: inspect,
239
- children: [(0, react_jsx_runtime.jsx)(_x1a0f3n9_dsh_client_ui_primitives.IconInspectOutline12, {}), t("row.inspect")]
256
+ children: [(0, react_jsx_runtime.jsx)(_x1a0f3n9_dsh_client_ui_primitives.IconInspectOutlineRegular, {}), t("row.inspect")]
240
257
  }) : null]
241
258
  }) : null]
242
259
  });
@@ -248,8 +265,9 @@ window.__ModuleLoader__.load({
248
265
  const NS = "skill";
249
266
  /** Simplified Chinese dictionary (the key-set source of truth). */
250
267
  const zh = {
251
- "row.title": "Skill",
268
+ "row.title": "加载技能",
252
269
  "row.running": "正在加载 skill",
270
+ "row.preparing": "准备加载技能",
253
271
  "row.failed": "skill 加载失败",
254
272
  "row.stopped": "skill 加载已中止",
255
273
  "row.instructions": "说明",
@@ -260,6 +278,7 @@ window.__ModuleLoader__.load({
260
278
  const en = {
261
279
  "row.title": "Skill",
262
280
  "row.running": "Loading skill",
281
+ "row.preparing": "Preparing to load a skill",
263
282
  "row.failed": "Skill load failed",
264
283
  "row.stopped": "Skill load stopped",
265
284
  "row.instructions": "Instructions",
@@ -308,10 +327,19 @@ window.__ModuleLoader__.load({
308
327
  if (existing !== void 0) return existing;
309
328
  const abort = new AbortController();
310
329
  const promise = (async () => {
311
- const result = await skills.list({ sessionId }, abort.signal);
312
- abort.signal.throwIfAborted();
313
- if (!result.ok) throw new Error(`skills/list failed: ${result.error.code}: ${result.error.message}`);
314
- return result.value.skills;
330
+ if (sessions.binding(sessionId) === void 0) throw new Error(`skill catalog requires a retained session "${sessionId}"`);
331
+ return sessions.using(sessionId, {
332
+ source: "skillCatalog",
333
+ signal: abort.signal
334
+ }, async (reference) => {
335
+ abort.signal.throwIfAborted();
336
+ const state = reference.binding.session.getSnapshot();
337
+ if (state.openState !== "open") throw state.openError ?? /* @__PURE__ */ new Error(`session "${sessionId}" is not open`);
338
+ const result = await skills.list({ sessionId }, abort.signal);
339
+ abort.signal.throwIfAborted();
340
+ if (!result.ok) throw new Error(`skills/list failed: ${result.error.code}: ${result.error.message}`);
341
+ return result.value.skills;
342
+ });
315
343
  })();
316
344
  const entry = {
317
345
  promise,
@@ -6,6 +6,6 @@ type SkillRowProps = ToolCallViewProps & PropsLocale<'skill'>;
6
6
  * @param props - keyed toolview payload plus the skill locale seat.
7
7
  * @returns the dedicated skill row.
8
8
  */
9
- export declare function SkillRow({ block, inspect, t }: SkillRowProps): import("react").JSX.Element;
9
+ export declare function SkillRow(props: SkillRowProps): import("react").JSX.Element;
10
10
  export {};
11
11
  //# sourceMappingURL=SkillRow.d.ts.map
@@ -1,5 +1,11 @@
1
1
  import type { Context as ClientContext } from '@deepseek-ai/cordis';
2
2
  import { type SkillKey } from './locales.ts';
3
+ declare module '@x1a0f3n9/dsh-api-session-controller/client' {
4
+ interface SessionReferenceSourceMap {
5
+ /** A skill-catalog fetch waiting for initial history and its RPC result. */
6
+ skillCatalog: unknown;
7
+ }
8
+ }
3
9
  declare module '@x1a0f3n9/dsh-client-ui-slots' {
4
10
  interface LocaleNamespaceMap {
5
11
  /** The dedicated skill tool row's copy. */
@@ -5,6 +5,7 @@ export declare const NS = "skill";
5
5
  export declare const zh: {
6
6
  'row.title': string;
7
7
  'row.running': string;
8
+ 'row.preparing': string;
8
9
  'row.failed': string;
9
10
  'row.stopped': string;
10
11
  'row.instructions': string;
@@ -17,6 +18,7 @@ export type SkillKey = keyof typeof zh;
17
18
  export declare const en: {
18
19
  'row.title': string;
19
20
  'row.running': string;
21
+ 'row.preparing': string;
20
22
  'row.failed': string;
21
23
  'row.stopped': string;
22
24
  'row.instructions': string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@x1a0f3n9/dsh-client-ui-skill",
3
3
  "description": "Web skill references and the dedicated skill tool row",
4
- "version": "0.1.5-rc.4",
4
+ "version": "0.1.7-rc.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -41,27 +41,27 @@
41
41
  },
42
42
  "license": "MIT",
43
43
  "peerDependencies": {
44
- "@deepseek-ai/cordis": "^4.0.2"
44
+ "@deepseek-ai/cordis": "~4.0.4"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@testing-library/react": "^16.1.0",
48
48
  "@types/react": "~18.3.1",
49
49
  "react": "^18.2.0",
50
50
  "react-dom": "^18.2.0",
51
- "@x1a0f3n9/dsh-api-remotes": "^0.1.5-rc.4",
52
- "@x1a0f3n9/dsh-api-session-controller": "^0.1.5-rc.4",
53
- "@x1a0f3n9/dsh-client-connection": "^0.1.5-rc.4",
54
- "@x1a0f3n9/dsh-client-locale": "^0.1.5-rc.4",
55
- "@x1a0f3n9/dsh-client-test-runtime": "^0.1.5-rc.4",
56
- "@x1a0f3n9/dsh-client-ui-primitives": "^0.1.5-rc.4",
57
- "@x1a0f3n9/dsh-client-ui-input-trigger": "^0.1.5-rc.4",
58
- "@x1a0f3n9/dsh-client-ui-renderer": "^0.1.5-rc.4",
59
- "@x1a0f3n9/dsh-client-ui-slots": "^0.1.5-rc.4",
60
- "@x1a0f3n9/dsh-client-ui-tool": "^0.1.5-rc.4",
61
- "@x1a0f3n9/dsh-session": "^0.1.5-rc.4",
62
- "@deepseek-ai/cordis": "^4.0.2",
63
- "@x1a0f3n9/dsh-client-ui-sidebar-right": "^0.1.5-rc.4",
64
- "@x1a0f3n9/dsh-util-workspace-path": "^0.1.5-rc.4"
51
+ "@x1a0f3n9/dsh-api-remotes": "0.1.7-rc.2",
52
+ "@x1a0f3n9/dsh-api-session-controller": "0.1.7-rc.2",
53
+ "@x1a0f3n9/dsh-client-connection": "0.1.7-rc.2",
54
+ "@x1a0f3n9/dsh-client-locale": "0.1.7-rc.2",
55
+ "@x1a0f3n9/dsh-client-test-runtime": "0.1.7-rc.2",
56
+ "@x1a0f3n9/dsh-client-ui-primitives": "0.1.7-rc.2",
57
+ "@x1a0f3n9/dsh-client-ui-input-trigger": "0.1.7-rc.2",
58
+ "@x1a0f3n9/dsh-client-ui-renderer": "0.1.7-rc.2",
59
+ "@x1a0f3n9/dsh-client-ui-slots": "0.1.7-rc.2",
60
+ "@x1a0f3n9/dsh-client-ui-tool": "0.1.7-rc.2",
61
+ "@x1a0f3n9/dsh-session": "0.1.7-rc.2",
62
+ "@deepseek-ai/cordis": "~4.0.4",
63
+ "@x1a0f3n9/dsh-client-ui-sidebar-right": "0.1.7-rc.2",
64
+ "@x1a0f3n9/dsh-util-workspace-path": "0.1.7-rc.2"
65
65
  },
66
66
  "files": [
67
67
  "lib/index.js",