@deepseek-ai/dsh-client-ui-subagent 0.1.6-alpha.2 → 0.1.7-alpha.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
@@ -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-subagent/README.md
5
- README.md: d0dadc79f552c28c5fea20a23a91c25a24e8ed61
6
- README.zh.md: 295206ace11baf67112db17b5bda10a52b80d9aa
5
+ README.md: b3dfb4a3aa56dbf240f4b76db410d45cc6ae5651
6
+ README.zh.md: a6ebd6da3c3caba2a3bd015da450b5a33ab79d67
package/README.md CHANGED
@@ -25,13 +25,13 @@ Use this package to browse every subagent conversation beneath a parent session,
25
25
  <a id="use-this-package"></a>
26
26
  ## Use this package
27
27
 
28
- The session header keeps the current session title as the lineage breadcrumb and, when the session has subagent descendants, appends a `/` count trigger before the header's action row; the trigger opens the descendant catalog, counts the complete subagent-only lineage, stops at ordinary forks, and shows ongoing activity when any counted descendant is running. Select any depth to open that child's conversation with its exact `{parentSessionId, childSessionId, mode}` address, or use the row's trailing arrow to open the same address in the right Sidebar, preferring a separate pane when room permits.
28
+ The session header keeps the current session title as the lineage breadcrumb; when the session's direct catalog has entries or a read has failed, the descendant-count trigger renders in the header actions band after the task list, with no breadcrumb separator. An absent catalog, an empty loading catalog, or a successfully loaded empty catalog hides the count trigger. The trigger opens that direct catalog, reports its total and running counts, and loads nested catalogs only when their rows expand. Select any depth to open that child's conversation with its exact `{parentSessionId, childSessionId, mode}` address, or use the row's trailing arrow to open the same address in the right Sidebar, preferring a separate pane when room permits.
29
29
 
30
- This package registers the `dsh-resource://subagentchat/session/<child>?parent=<parent>&mode=<mode>` resource and builtin Sidebar tab type. The resource refreshes the direct-parent catalog before it retains the child `SessionReference`, and releases the reference when the tab record closes. The tab renders the shared `conversation.content` Factory through `sidebar.chat.conversation`, fixes the local View to Chat, and omits the main Conversation header and width controls.
30
+ This package registers the `dsh-resource://subagentchat/session/<child>?parent=<parent>&mode=<mode>` resource and builtin Sidebar tab type. The resource retains the child `SessionReference` directly from its address without refreshing the parent catalog, and releases the reference when the tab record closes. The tab renders the shared `conversation.content` Factory through `sidebar.chat.conversation`, fixes the local View to Chat, and omits the main Conversation header and width controls.
31
31
 
32
32
  ### Browsing the tree
33
33
 
34
- Rows display mode plus `running`/`inactive` activity and an optional log-backed title; the trailing column stacks total durable provider usage above active-turn duration. Keyboard navigation works with ArrowRight/ArrowLeft to expand and collapse branches and ArrowUp/ArrowDown, Home, End, and Escape to navigate or close the tree. An unlabeled one-shot row falls back to its session id; corrupt, unsupported, or unavailable rows remain readable but disabled.
34
+ Rows display mode plus activity and an optional log-backed title; running uses the shared ongoing loader, an inactive child whose latest closed turn completed normally uses the shared success dot, and other inactive children use the shared idle dot. Every row reserves the same 14px status column, centering smaller dots so titles align with the loader state. The compact header trigger vertically centers its activity glyph and count with a 4px gap. The trailing column stacks total durable provider usage above active-turn duration. Keyboard navigation works with ArrowRight/ArrowLeft to expand and collapse branches and ArrowUp/ArrowDown, Home, End, and Escape to navigate or close the tree. An unlabeled one-shot row falls back to its session id. A row is a known leaf only after its own catalog loads empty.
35
35
 
36
36
  ### Continuing a conversation
37
37
 
@@ -53,16 +53,22 @@ The catalog and composer behavior are specified by the [Web subagent conversatio
53
53
 
54
54
  ### Catalog derivation
55
55
 
56
- The header lineage renderer reads `subagentsByParent` and session summaries through the standard `useSessions` hook. The compact tree remains direct-catalog authoritative: each healthy row's `hasChildren` hint determines disclosure before interaction, a catalog level reserves the disclosure column only when at least one healthy row is a branch, and expanding a branch immediately reserves one disabled loading row per known direct descendant before lazily replacing them with that child's authoritative catalog. Every visible branch is reported to the runtime so membership frames cause a debounced refresh only where the tree is being consumed.
56
+ The header lineage renderer reads `projectionsBySession` through the standard `useSessions` hook. The renderer selects `subagentCatalog` from each Session’s shared values for membership, disclosure, and counts; Activity prefers the unified UI status and falls back to Session summaries; summaries supply titles and usage. Expanding a row loads its initial catalog when needed. Live projection frames update every loaded level without menu subscriptions or repeated membership queries. A row remains expandable while its catalog is absent, loading, or failed, and becomes a known leaf after a ready empty catalog.
57
57
 
58
- ### Duration and tokens
58
+ Opening a catalog dropdown does not request its root catalog. Child-catalog expansion and failed-read retries call `refreshProjection`; shared projection-value changes update the display automatically.
59
59
 
60
- Token totals sum the four disjoint `tokenUsage` buckets. Duration sums completed `subagentTiming` turns, advances once per second only for an open turn on a running child, and freezes after the child becomes inactive; an interrupted open turn is bounded by its same-cut `active.through`, never by newer session metadata.
60
+ Breadcrumb addresses derive from the Provider-bound Session address and loaded parent catalogs, including never-selected ancestors.
61
+
62
+ ### Duration, completion, and tokens
63
+
64
+ Each visible catalog level advances its own clock while it contains a running child; collapsing the level or closing the menu releases that clock. Token totals sum the four disjoint `tokenUsage` buckets. The `subagentTiming` projection sums completed-turn duration and records whether the latest closed turn ended with `completed`; opening another turn clears that completion until its own `turn/end`. Duration advances once per second only for an open turn on a running child and freezes after the child becomes inactive; an interrupted open turn is bounded by its same-cut `active.through`, never by newer session metadata.
61
65
 
62
66
  ### Composer election
63
67
 
64
68
  One-shot children always elect a read-only composer. A continuable child elects one only when its exact parent is unavailable and the child is not running; otherwise the ordinary composer's Session routes prompts through `subagents/prompt`. This package never receives host context or calls a model-facing tool.
65
69
 
70
+ Unknown-mode catalog rows remain visible and clickable, using the child id when no label is available. Their composer is read-only until child history establishes a supported mode; a read failure is reported in the child conversation.
71
+
66
72
  </details>
67
73
 
68
74
  -----
@@ -104,7 +110,7 @@ Append-only. This package never edits earlier request tokens.
104
110
 
105
111
  These limits define what the catalog can show and what `@` references mean; they are current package constraints.
106
112
 
107
- - **The catalog has no durable outcome** — activity and timing do not distinguish completion, failure, or cancellation, and the UI exposes no Activation identity; stopping is limited to the composer's current-turn Stop for a running continuable child.
113
+ - **Non-completed inactive outcomes remain grouped** — the catalog distinguishes a latest normal completion from other inactive states, but does not distinguish failure, cancellation, refusal, token exhaustion, or a child with no closed turn; the UI exposes no Activation identity, and stopping is limited to the composer's current-turn Stop for a running continuable child.
108
114
  - **`@` references remain display-title text** — duplicate or renamed labels are ambiguous, so they intentionally do not acquire continuation semantics.
109
115
 
110
116
  <a id="dev-note"></a>
package/README.zh.md CHANGED
@@ -25,13 +25,13 @@ kind: "package-reference"
25
25
  <a id="use-this-package"></a>
26
26
  ## 使用本包
27
27
 
28
- 会话页头保留当前会话 title 作为谱系面包屑,并在会话存在 subagent 后代时,于页头操作行之前追加 `/` 数量触发器;触发器打开后代目录,统计仅含 subagent 的完整谱系、在普通 fork 处停止,并在任一计入统计的后代处于 `running` 时显示活动仍在进行。选择任意深度,即可用该子会话的确切 `{parentSessionId, childSessionId, mode}` 地址打开其对话;也可以使用行尾箭头在右侧 Sidebar 打开同一地址,并在空间允许时优先使用独立分栏。
28
+ 会话页头把当前会话标题作为谱系面包屑;当会话的直接目录有子项或读取失败时,后代数量触发器渲染在页头操作区、任务列表之后,不带任何面包屑分隔符。目录缺席、空目录加载中或成功加载为空时,均隐藏数量触发器。触发器打开该直接目录,报告总数与运行数,并且只在行展开时加载嵌套目录。选择任意深度,即可用该子会话的确切 `{parentSessionId, childSessionId, mode}` 地址打开其对话;也可以使用行尾箭头在右侧 Sidebar 打开同一地址,并在空间允许时优先使用独立分栏。
29
29
 
30
- 本包注册 `dsh-resource://subagentchat/session/<child>?parent=<parent>&mode=<mode>` 资源与 builtin Sidebar tab 类型。资源先刷新直接 parent 目录,再保留 child 的 `SessionReference`,并在 tab 记录关闭时释放 reference。tab 通过 `sidebar.chat.conversation` 渲染共享 `conversation.content` Factory,把局部 View 固定为 Chat,并省略主 Conversation 的 Header 与宽度控制。
30
+ 本包注册 `dsh-resource://subagentchat/session/<child>?parent=<parent>&mode=<mode>` 资源与 builtin Sidebar tab 类型。资源直接根据地址保留 child 的 `SessionReference`,不刷新 parent 目录,并在 tab 记录关闭时释放 reference。tab 通过 `sidebar.chat.conversation` 渲染共享 `conversation.content` Factory,把局部 View 固定为 Chat,并省略主 Conversation 的 Header 与宽度控制。
31
31
 
32
32
  ### 浏览目录
33
33
 
34
- 行显示 mode、`running`/`inactive` 活动状态与由日志支撑的可选 title;尾随列在上行显示提供方的持久化 token 用量总计,在下行显示活跃轮次耗时。键盘导航:ArrowRight/ArrowLeft 展开和折叠分支;ArrowUp/ArrowDown、Home、End 与 Escape 用于导航或关闭树。没有 label 的 one-shot 行回退到其会话 id;损坏、不受支持或不可用的行仍保持可读但禁用。
34
+ 行显示 mode、活动状态与由日志支撑的可选 title;running 使用共享 ongoing loading,最近一个已结束轮次正常完成的 inactive child 使用共享 success 绿点,其他 inactive child 使用共享 idle 灰点。每行都为状态图标预留相同的 14px 列宽,并将较小的圆点居中,使 title 与 loading 状态对齐。紧凑的页头触发器会垂直居中活动图标与数量,并保留 4px 水平间距。尾随列在上行显示提供方的持久化 token 用量总计,在下行显示活跃轮次耗时。键盘导航:ArrowRight/ArrowLeft 展开和折叠分支;ArrowUp/ArrowDown、Home、End 与 Escape 用于导航或关闭树。没有 label 的 one-shot 行回退到其会话 id。只有一行自身的目录加载为空后,它才是已知叶子。
35
35
 
36
36
  ### 续接对话
37
37
 
@@ -53,16 +53,22 @@ kind: "package-reference"
53
53
 
54
54
  ### 目录派生
55
55
 
56
- 页头谱系 renderer 通过标准 `useSessions` 钩子读取 `subagentsByParent` 与会话摘要。紧凑树仍以直接目录为权威依据:每个健康行的 `hasChildren` 提示在交互前决定是否显示展开控件;每层目录仅在其中至少一个健康行是分支时才预留展开列;展开分支时会立即为每个已知直接后代预留一行禁用的加载行,随后再用该 child 的权威目录懒加载结果替换。每个可见分支都会上报给运行时,使成员帧只在树正被消费的位置触发去抖动刷新。
56
+ 页头谱系 renderer 通过标准 `useSessions` 钩子读取 `projectionsBySession`。renderer 从每个 Session 的共享值中选择 `subagentCatalog`,用于成员关系、展开控件与数量;活动状态优先使用统一 UI status,缺少时使用 Session 摘要;摘要提供标题与用量。展开行会按需加载初始目录。实时 projection 帧更新所有已加载层级,无需菜单订阅或重复成员查询。行在目录缺席、加载中或失败时保持可展开,并在目录就绪且为空后成为已知叶子。
57
57
 
58
- ### 耗时与 token
58
+ 打开目录下拉菜单不会请求其根目录。展开子节点目录或重试失败读取时调用 `refreshProjection`;共享投影值的变化会自动更新显示。
59
59
 
60
- token 用量总计为四个互不重叠的 `tokenUsage` 桶之和。耗时会累加已完成的 `subagentTiming` 轮次,仅在运行中 child 存在未结束轮次时每秒递增一次,并在 child 变为 inactive 后冻结;被中断的未结束轮次以其同一切面的 `active.through` 为上界,绝不使用更新的会话元数据。
60
+ 面包屑地址从 Provider 所绑定的 Session 地址和已加载的 parent 目录推导,也包括从未选中过的祖先。
61
+
62
+ ### 耗时、完成状态与 token
63
+
64
+ 每个可见目录层在包含运行中 child 时独立推进时钟;折叠该层或关闭菜单会释放时钟。token 用量总计为四个互不重叠的 `tokenUsage` 桶之和。`subagentTiming` 投影会累加已结束轮次的耗时,并记录最近一个已结束轮次是否以 `completed` 结束;新轮次开始时会清除该完成状态,直到自身的 `turn/end` 到达。耗时仅在运行中 child 存在未结束轮次时每秒递增一次,并在 child 变为 inactive 后冻结;被中断的未结束轮次以其同一切面的 `active.through` 为上界,绝不使用更新的会话元数据。
61
65
 
62
66
  ### 编辑器选举
63
67
 
64
68
  one-shot child 始终选用只读编辑器。可继续 child 仅在其确切 parent 不可用且 child 未在运行时选用只读编辑器;否则普通编辑器的会话会经 `subagents/prompt` 路由提示词。本包绝不接收宿主上下文,也不调用面向模型的工具。
65
69
 
70
+ 模式未知的目录项仍可见、可点击,没有标签时显示子会话 id。读取子历史并确认受支持模式前,输入区保持只读;读取失败在该子会话中报告。
71
+
66
72
  </details>
67
73
 
68
74
  -----
@@ -104,7 +110,7 @@ one-shot child 始终选用只读编辑器。可继续 child 仅在其确切 par
104
110
 
105
111
  这些限制定义目录能显示什么、`@` 引用意味着什么;它们是当前包约束。
106
112
 
107
- - **目录没有持久化结果**:活动状态与计时无法区分完成、失败或取消,且 UI 不公开 Activation 身份;停止能力仅限编辑器上针对运行中可继续 child 的当前轮次 Stop。
113
+ - **非完成的 inactive 结果仍合并显示**:目录能区分最近一次正常完成与其他 inactive 状态,但不区分失败、取消、拒绝、token 耗尽或尚无已结束轮次的 child;UI 不公开 Activation 身份,停止能力仅限编辑器上针对运行中可继续 child 的当前轮次 Stop。
108
114
  - **`@` 引用仍是显示标题文本**:重复或改名后的 label 会有歧义,因此它们刻意不获得继续执行语义。
109
115
 
110
116
  <a id="dev-note"></a>
package/lib/client.js CHANGED
@@ -9,7 +9,7 @@ window.__ModuleLoader__.load({
9
9
  let react_dom = require("react-dom");
10
10
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
11
11
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-subagent/src/client/SubagentHeaderLineage.module.css.mjs
12
- const css$2 = ".ZKlsPq_root{align-items:center;gap:10px;min-width:0;display:inline-flex;position:relative}.ZKlsPq_switcherRoot{min-width:0;margin-left:6px}.ZKlsPq_trigger,.ZKlsPq_switcherTrigger{min-height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:6px;align-items:center;padding:3px 2px;font-size:12px;line-height:18px;display:inline-flex}.ZKlsPq_trigger{gap:4px}.ZKlsPq_switcherTrigger{min-width:0;max-width:244px;color:var(--dsw-alias-label-primary);gap:4px;font-weight:500}.ZKlsPq_ancestorSwitcherTrigger{color:var(--dsw-alias-label-tertiary);font-weight:400}.ZKlsPq_switcherTitle{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.ZKlsPq_switcherTrigger svg{flex:none}.ZKlsPq_separator{color:var(--dsw-alias-label-caption);font-size:14px;line-height:20px}.ZKlsPq_activitySlot{flex:none;width:10px;height:10px;display:inline-flex}.ZKlsPq_trigger:hover,.ZKlsPq_trigger:focus-visible{color:var(--dsw-alias-label-secondary)}.ZKlsPq_switcherTrigger:hover,.ZKlsPq_switcherTrigger:focus-visible{color:var(--dsw-alias-label-primary)}.ZKlsPq_ancestorSwitcherTrigger:hover,.ZKlsPq_ancestorSwitcherTrigger:focus-visible{color:var(--dsw-alias-label-tertiary)}.ZKlsPq_trigger svg,.ZKlsPq_switcherTrigger svg{transition:transform .12s}.ZKlsPq_triggerOpen{transform:rotate(180deg)}.ZKlsPq_menu{z-index:100;box-sizing:border-box;background:var(--dsw-specific-menu);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);width:336px;max-width:min(400px,100vw - 32px);max-height:min(560px,100vh - 140px);box-shadow:var(--dsw-elevation-prominent);border-radius:20px;flex-direction:column;padding:4px;display:flex;position:fixed;overflow:auto}.ZKlsPq_node{min-width:0;position:relative}.ZKlsPq_menu>.ZKlsPq_node{margin-left:-3px}.ZKlsPq_row{box-sizing:border-box;width:100%;min-height:50px;color:var(--dsw-alias-label-primary);text-align:left;cursor:pointer;background:0 0;border:0;border-radius:8px;outline:none;align-items:flex-start;gap:8px;padding:7px 8px 7px 11px;font-size:13px;line-height:18px;display:flex;position:relative}.ZKlsPq_row:hover>.ZKlsPq_clickarea,.ZKlsPq_row:focus-visible>.ZKlsPq_clickarea{background:var(--dsw-alias-interactive-bg-hover)}.ZKlsPq_clickarea{box-sizing:border-box;border-radius:8px;flex:1;align-self:stretch;align-items:flex-start;gap:8px;min-width:0;margin:-7px -8px;padding:7px 8px;display:flex}.ZKlsPq_row>[data-state],.ZKlsPq_clickarea>[data-state]{margin-top:4px}.ZKlsPq_disabled{color:var(--dsw-alias-label-dimmed);cursor:not-allowed}.ZKlsPq_disabled:hover{background:0 0}.ZKlsPq_loadingRow{cursor:default}.ZKlsPq_disclosure,.ZKlsPq_disclosureSpace{flex:none;width:14px;height:18px}.ZKlsPq_disclosure{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;justify-content:center;align-items:center;padding:0;transition:transform .12s;display:inline-flex}.ZKlsPq_disclosure:hover{color:var(--dsw-alias-label-primary)}.ZKlsPq_disclosureOpen{transform:rotate(90deg)}.ZKlsPq_content{flex-direction:column;flex:1;min-width:0;display:flex}.ZKlsPq_label,.ZKlsPq_summary{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ZKlsPq_label{color:inherit;font-weight:400}.ZKlsPq_currentLabel{font-weight:600}.ZKlsPq_summary,.ZKlsPq_metrics{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.ZKlsPq_metrics{font-variant-numeric:tabular-nums;text-align:right;white-space:nowrap;flex:none;grid-template-rows:18px 16px;display:grid}.ZKlsPq_metricToken{grid-row:1;line-height:18px}.ZKlsPq_metricDuration{grid-row:2}.ZKlsPq_sidebarButton{corner-shape:round;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:50%;flex:none;justify-content:center;align-items:center;margin:4px 0;padding:6px;display:inline-flex}.ZKlsPq_sidebarButton:hover,.ZKlsPq_sidebarButton:focus-visible{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.ZKlsPq_children{margin-left:18px;padding-left:4px;position:relative}.ZKlsPq_children:before,.ZKlsPq_children>.ZKlsPq_node:before{content:\"\";border-left:.5px solid var(--dsw-alias-border-l2);position:absolute;left:0}.ZKlsPq_children:before{height:26px;top:-26px}.ZKlsPq_children[aria-busy=true]:before{content:none}.ZKlsPq_children>.ZKlsPq_node:before{top:0;bottom:0;left:-4px}.ZKlsPq_children>.ZKlsPq_node:last-child:before{height:17px;bottom:auto}.ZKlsPq_children>.ZKlsPq_node>.ZKlsPq_row:before{content:\"\";border-top:.5px solid var(--dsw-alias-border-l2);width:14px;position:absolute;top:16px;left:-4px}.ZKlsPq_notice,.ZKlsPq_error{color:var(--dsw-alias-label-tertiary);padding:10px 12px;font-size:12px;line-height:18px}.ZKlsPq_error{color:var(--dsw-alias-state-error-primary);justify-content:space-between;align-items:center;gap:12px;display:flex}.ZKlsPq_refresh{color:inherit;cursor:pointer;background:0 0;border:0;border-radius:6px;flex:none;align-items:center;gap:4px;padding:4px 6px;display:inline-flex}.ZKlsPq_refresh:hover{background:var(--dsw-alias-interactive-bg-hover)}";
12
+ const css$2 = ".ZKlsPq_root{align-items:center;gap:10px;min-width:0;display:inline-flex;position:relative}.ZKlsPq_switcherRoot{min-width:0;margin-left:6px}.ZKlsPq_trigger,.ZKlsPq_switcherTrigger{min-height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:6px;align-items:center;padding:3px 2px;font-size:12px;line-height:18px;display:inline-flex}.ZKlsPq_trigger{gap:4px}.ZKlsPq_switcherTrigger{min-width:0;max-width:244px;color:var(--dsw-alias-label-primary);gap:4px;font-weight:500}.ZKlsPq_ancestorSwitcherTrigger{color:var(--dsw-alias-label-tertiary);font-weight:400}.ZKlsPq_switcherTitle{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.ZKlsPq_switcherTrigger svg{flex:none}.ZKlsPq_activitySlot{flex:none;justify-content:center;align-items:center;width:14px;height:14px;display:inline-flex}.ZKlsPq_trigger:hover,.ZKlsPq_trigger:focus-visible{color:var(--dsw-alias-label-secondary)}.ZKlsPq_switcherTrigger:hover,.ZKlsPq_switcherTrigger:focus-visible{color:var(--dsw-alias-label-primary)}.ZKlsPq_ancestorSwitcherTrigger:hover,.ZKlsPq_ancestorSwitcherTrigger:focus-visible{color:var(--dsw-alias-label-tertiary)}.ZKlsPq_trigger svg,.ZKlsPq_switcherTrigger svg{transition:transform .12s}.ZKlsPq_triggerOpen{transform:rotate(180deg)}.ZKlsPq_menu{z-index:100;box-sizing:border-box;background:var(--dsw-specific-menu);width:336px;max-width:min(400px,100vw - 32px);max-height:min(560px,100vh - 140px);backdrop-filter:var(--dsw-menu-backdrop-filter);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);box-shadow:var(--dsw-elevation-prominent);border-radius:16px;flex-direction:column;padding:3px;display:flex;position:fixed;overflow:auto}.ZKlsPq_node{min-width:0;position:relative}.ZKlsPq_menu>.ZKlsPq_node{margin-left:-2px}.ZKlsPq_row{box-sizing:border-box;width:100%;min-height:44px;color:var(--dsw-alias-label-primary);text-align:left;cursor:pointer;background:0 0;border:0;border-radius:7px;outline:none;align-items:flex-start;gap:6px;padding:6px 7px 6px 9px;font-size:12px;line-height:17px;display:flex;position:relative}.ZKlsPq_row:hover>.ZKlsPq_clickarea,.ZKlsPq_row:focus-visible>.ZKlsPq_clickarea{background:var(--dsw-alias-interactive-bg-hover)}.ZKlsPq_clickarea{box-sizing:border-box;border-radius:7px;flex:1;align-self:stretch;align-items:flex-start;gap:6px;min-width:0;margin:-6px -7px;padding:6px 7px;display:flex}.ZKlsPq_rowActivitySlot{flex:none;justify-content:center;align-items:center;width:14px;height:17px;display:inline-flex}.ZKlsPq_disclosure,.ZKlsPq_disclosureSpace{flex:none;width:14px;height:17px}.ZKlsPq_disclosure{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;justify-content:center;align-items:center;padding:0;transition:transform .12s;display:inline-flex}.ZKlsPq_disclosure svg{width:12px;height:12px}.ZKlsPq_disclosure:hover{color:var(--dsw-alias-label-primary)}.ZKlsPq_disclosureOpen{transform:rotate(90deg)}.ZKlsPq_content{flex-direction:column;flex:1;min-width:0;display:flex}.ZKlsPq_label,.ZKlsPq_summary{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ZKlsPq_label{color:inherit;font-weight:400}.ZKlsPq_currentLabel{font-weight:600}.ZKlsPq_summary,.ZKlsPq_metrics{color:var(--dsw-alias-label-tertiary);font-size:10px;line-height:15px}.ZKlsPq_metrics{font-variant-numeric:tabular-nums;text-align:right;white-space:nowrap;flex:none;grid-template-rows:17px 15px;display:grid}.ZKlsPq_metricToken{grid-row:1;line-height:17px}.ZKlsPq_metricDuration{grid-row:2}.ZKlsPq_sidebarButton{corner-shape:round;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:50%;flex:none;justify-content:center;align-items:center;margin:4px 0;padding:6px;display:inline-flex}.ZKlsPq_sidebarButton:hover,.ZKlsPq_sidebarButton:focus-visible{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.ZKlsPq_children{margin-left:16px;padding-left:3px;position:relative}.ZKlsPq_children:before,.ZKlsPq_children>.ZKlsPq_node:before{content:\"\";border-left:.5px solid var(--dsw-alias-border-l2);position:absolute;left:0}.ZKlsPq_children:before{height:23px;top:-23px}.ZKlsPq_children[aria-busy=true]:before{content:none}.ZKlsPq_children>.ZKlsPq_node:before{top:0;bottom:0;left:-3px}.ZKlsPq_children>.ZKlsPq_node:last-child:before{height:15px;bottom:auto}.ZKlsPq_children>.ZKlsPq_node>.ZKlsPq_row:before{content:\"\";border-top:.5px solid var(--dsw-alias-border-l2);width:12px;position:absolute;top:14px;left:-3px}.ZKlsPq_notice,.ZKlsPq_error{color:var(--dsw-alias-label-tertiary);padding:8px 10px;font-size:11px;line-height:16px}.ZKlsPq_error{color:var(--dsw-alias-state-error-primary);justify-content:space-between;align-items:center;gap:10px;display:flex}.ZKlsPq_refresh{color:inherit;cursor:pointer;background:0 0;border:0;border-radius:5px;flex:none;align-items:center;gap:3px;padding:3px 5px;display:inline-flex}.ZKlsPq_refresh svg{width:12px;height:12px}.ZKlsPq_refresh:hover{background:var(--dsw-alias-interactive-bg-hover)}";
13
13
  const tagId$2 = "@deepseek-ai/dsh-client-ui-subagent/SubagentHeaderLineage.module.css";
14
14
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
15
15
  const tag = document.createElement("style");
@@ -25,13 +25,11 @@ window.__ModuleLoader__.load({
25
25
  "clickarea": "ZKlsPq_clickarea",
26
26
  "content": "ZKlsPq_content",
27
27
  "currentLabel": "ZKlsPq_currentLabel",
28
- "disabled": "ZKlsPq_disabled",
29
28
  "disclosure": "ZKlsPq_disclosure",
30
29
  "disclosureOpen": "ZKlsPq_disclosureOpen",
31
30
  "disclosureSpace": "ZKlsPq_disclosureSpace",
32
31
  "error": "ZKlsPq_error",
33
32
  "label": "ZKlsPq_label",
34
- "loadingRow": "ZKlsPq_loadingRow",
35
33
  "menu": "ZKlsPq_menu",
36
34
  "metricDuration": "ZKlsPq_metricDuration",
37
35
  "metricToken": "ZKlsPq_metricToken",
@@ -41,7 +39,7 @@ window.__ModuleLoader__.load({
41
39
  "refresh": "ZKlsPq_refresh",
42
40
  "root": "ZKlsPq_root",
43
41
  "row": "ZKlsPq_row",
44
- "separator": "ZKlsPq_separator",
42
+ "rowActivitySlot": "ZKlsPq_rowActivitySlot",
45
43
  "sidebarButton": "ZKlsPq_sidebarButton",
46
44
  "summary": "ZKlsPq_summary",
47
45
  "switcherRoot": "ZKlsPq_switcherRoot",
@@ -51,44 +49,7 @@ window.__ModuleLoader__.load({
51
49
  "triggerOpen": "ZKlsPq_triggerOpen"
52
50
  };
53
51
  //#endregion
54
- //#region lib/types/client/subagent-lineage.js
55
- /** UI Subagent-owned projection of descendant counts from Session summaries. */
56
- /**
57
- * Index uninterrupted subagent descendants under each ancestor.
58
- * @param summaries - Session summaries keyed by id.
59
- * @returns descendant totals keyed by possible parent id.
60
- */
61
- function indexSubagentDescendants(summaries) {
62
- const indexed = /* @__PURE__ */ new Map();
63
- for (const descendant of Object.values(summaries)) {
64
- if (descendant.origin !== "subagent") continue;
65
- const seen = /* @__PURE__ */ new Set();
66
- let current = descendant;
67
- while (current?.origin === "subagent" && current.parentId !== void 0 && !seen.has(current.id)) {
68
- seen.add(current.id);
69
- const aggregate = indexed.get(current.parentId);
70
- if (aggregate === void 0) indexed.set(current.parentId, {
71
- count: 1,
72
- runningCount: descendant.running ? 1 : 0
73
- });
74
- else {
75
- aggregate.count += 1;
76
- if (descendant.running) aggregate.runningCount += 1;
77
- }
78
- current = summaries[current.parentId];
79
- }
80
- }
81
- return indexed;
82
- }
83
- //#endregion
84
52
  //#region lib/types/client/SubagentHeaderLineage.js
85
- function diagnosticReason(entry, t) {
86
- switch (entry.reason) {
87
- case "corrupt": return t("diagnostic.corrupt");
88
- case "unsupported": return t("diagnostic.unsupported");
89
- case "unavailable": return t("diagnostic.unavailable");
90
- }
91
- }
92
53
  function treeItems(root) {
93
54
  return root === null ? [] : Array.from(root.querySelectorAll("[role=\"treeitem\"]:not([aria-disabled=\"true\"])"));
94
55
  }
@@ -169,10 +130,6 @@ window.__ModuleLoader__.load({
169
130
  seconds: String(seconds).padStart(2, "0")
170
131
  });
171
132
  }
172
- const NO_DESCENDANTS = {
173
- count: 0,
174
- runningCount: 0
175
- };
176
133
  function SubagentSwitcherIcon() {
177
134
  return (0, react_jsx_runtime.jsxs)("svg", {
178
135
  width: "16",
@@ -191,95 +148,56 @@ window.__ModuleLoader__.load({
191
148
  })]
192
149
  });
193
150
  }
194
- /** Render the known direct-child shape while its authoritative catalog hydrates. */
195
- function CatalogLoadingRows({ parentSessionId, summaries, level, t }) {
196
- const children = Object.values(summaries).filter((summary) => summary.origin === "subagent" && summary.parentId === parentSessionId);
197
- if (children.length === 0) return (0, react_jsx_runtime.jsx)("div", {
151
+ /** Render catalog loading without inventing child membership. */
152
+ function CatalogLoadingRows({ t }) {
153
+ return (0, react_jsx_runtime.jsx)("div", {
198
154
  className: SubagentHeaderLineage_module_css_default.notice,
199
155
  children: t("loading.label")
200
156
  });
201
- return children.map((summary) => (0, react_jsx_runtime.jsx)("div", {
202
- className: SubagentHeaderLineage_module_css_default.node,
203
- children: (0, react_jsx_runtime.jsxs)("div", {
204
- role: "treeitem",
205
- "aria-disabled": "true",
206
- "aria-level": level,
207
- "aria-label": t("loading.aria"),
208
- className: `${SubagentHeaderLineage_module_css_default.row} ${SubagentHeaderLineage_module_css_default.disabled} ${SubagentHeaderLineage_module_css_default.loadingRow}`,
209
- children: [
210
- (0, react_jsx_runtime.jsx)("span", { className: SubagentHeaderLineage_module_css_default.disclosureSpace }),
211
- (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: summary.running ? "ongoing" : "done" }),
212
- (0, react_jsx_runtime.jsx)("span", {
213
- className: SubagentHeaderLineage_module_css_default.content,
214
- children: (0, react_jsx_runtime.jsx)("span", {
215
- className: SubagentHeaderLineage_module_css_default.label,
216
- children: t("loading.label")
217
- })
218
- })
219
- ]
220
- })
221
- }, summary.id));
157
+ }
158
+ /** A child becomes a known leaf only after its own authoritative catalog loads empty. */
159
+ function isKnownLeaf(catalog) {
160
+ return catalog?.state === "ready" && catalog.entries.length === 0;
222
161
  }
223
162
  /** Render one catalog level and recurse only through explicitly expanded rows. */
224
- function CatalogRows({ parentSessionId, currentSessionId, catalog, catalogs, summaries, expanded, level, now, openChild, openChildAside, refresh, toggleBranch, closeCatalog, t }) {
163
+ function CatalogRows({ parentSessionId, currentSessionId, catalog, catalogs, summaries, expanded, level, openChild, openChildAside, refreshProjection, toggleBranch, closeCatalog, t }) {
164
+ const [now, setNow] = (0, react.useState)(() => Date.now());
165
+ const running = catalog.entries.some((entry) => entry.activity === "running");
166
+ (0, react.useEffect)(() => {
167
+ if (!running) return;
168
+ const timer = setInterval(() => {
169
+ setNow(Date.now());
170
+ }, 1e3);
171
+ return () => {
172
+ clearInterval(timer);
173
+ };
174
+ }, [running]);
225
175
  const emptyLoading = catalog.state === "loading" && catalog.entries.length === 0;
226
- const reserveDisclosure = catalog.entries.some((entry) => entry.kind === "child" && entry.hasChildren);
176
+ const reserveDisclosure = catalog.entries.some((entry) => !isKnownLeaf(catalogs[entry.id]));
227
177
  return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
228
- emptyLoading && (0, react_jsx_runtime.jsx)(CatalogLoadingRows, {
229
- parentSessionId,
230
- summaries,
231
- level,
232
- t
233
- }),
178
+ emptyLoading && (0, react_jsx_runtime.jsx)(CatalogLoadingRows, { t }),
234
179
  catalog.state === "error" && (0, react_jsx_runtime.jsxs)("div", {
235
180
  className: SubagentHeaderLineage_module_css_default.error,
236
181
  children: [(0, react_jsx_runtime.jsx)("span", { children: catalog.error?.message ?? t("load.error") }), (0, react_jsx_runtime.jsxs)("button", {
237
182
  type: "button",
238
183
  className: SubagentHeaderLineage_module_css_default.refresh,
239
184
  onClick: () => {
240
- refresh(parentSessionId);
185
+ refreshProjection(parentSessionId);
241
186
  },
242
- children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline14, {}), t("retry")]
187
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutlineRegular, { size: 14 }), t("retry")]
243
188
  })]
244
189
  }),
245
190
  catalog.entries.map((entry) => {
246
- if (entry.kind === "diagnostic") {
247
- const reason = diagnosticReason(entry, t);
248
- return (0, react_jsx_runtime.jsx)("div", {
249
- className: SubagentHeaderLineage_module_css_default.node,
250
- children: (0, react_jsx_runtime.jsxs)("div", {
251
- role: "treeitem",
252
- "aria-disabled": "true",
253
- "aria-level": level,
254
- "aria-label": `${entry.id} ${reason}`,
255
- className: `${SubagentHeaderLineage_module_css_default.row} ${SubagentHeaderLineage_module_css_default.disabled}`,
256
- title: reason,
257
- children: [
258
- reserveDisclosure && (0, react_jsx_runtime.jsx)("span", { className: SubagentHeaderLineage_module_css_default.disclosureSpace }),
259
- (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "error" }),
260
- (0, react_jsx_runtime.jsxs)("span", {
261
- className: SubagentHeaderLineage_module_css_default.content,
262
- children: [(0, react_jsx_runtime.jsx)("span", {
263
- className: SubagentHeaderLineage_module_css_default.label,
264
- children: entry.id
265
- }), (0, react_jsx_runtime.jsx)("span", {
266
- className: SubagentHeaderLineage_module_css_default.summary,
267
- children: reason
268
- })]
269
- })
270
- ]
271
- })
272
- }, entry.id);
273
- }
274
191
  const childCatalog = catalogs[entry.id];
275
192
  const isCurrent = entry.id === currentSessionId;
276
193
  const isExpanded = expanded.has(entry.id);
277
- const knownLeaf = !entry.hasChildren;
194
+ const knownLeaf = isKnownLeaf(childCatalog);
278
195
  const childLoading = childCatalog === void 0 || childCatalog.state === "loading" && childCatalog.entries.length === 0;
279
196
  const summary = summaries[entry.id];
280
197
  const label = entry.label ?? entry.id;
281
- const mode = entry.mode === "one-shot" ? t("mode.oneShot") : t("mode.continuable");
282
- const activity = entry.activity === "running" ? t("activity.running") : t("activity.inactive");
198
+ const mode = entry.mode === "unknown" ? t("mode.unknown") : entry.mode === "one-shot" ? t("mode.oneShot") : t("mode.continuable");
199
+ const completed = entry.activity === "inactive" && summary?.projectionValues?.subagentTiming?.lastTurnCompleted === true;
200
+ const activity = entry.activity === "running" ? t("activity.running") : completed ? t("activity.completed") : t("activity.inactive");
283
201
  const secondary = [
284
202
  summary?.title,
285
203
  mode,
@@ -349,11 +267,14 @@ window.__ModuleLoader__.load({
349
267
  className: `${SubagentHeaderLineage_module_css_default.disclosure} ${isExpanded ? SubagentHeaderLineage_module_css_default.disclosureOpen : ""}`,
350
268
  "aria-label": t(isExpanded ? "branch.collapse" : "branch.expand", { label }),
351
269
  onClick: toggle,
352
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {})
270
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineRegular, {})
353
271
  }), (0, react_jsx_runtime.jsxs)("div", {
354
272
  className: SubagentHeaderLineage_module_css_default.clickarea,
355
273
  children: [
356
- (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: entry.activity === "running" ? "ongoing" : "done" }),
274
+ (0, react_jsx_runtime.jsx)("span", {
275
+ className: SubagentHeaderLineage_module_css_default.rowActivitySlot,
276
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: entry.activity === "running" ? "ongoing" : completed ? "done" : "idle" })
277
+ }),
357
278
  (0, react_jsx_runtime.jsxs)("span", {
358
279
  className: SubagentHeaderLineage_module_css_default.content,
359
280
  children: [(0, react_jsx_runtime.jsx)("span", {
@@ -384,7 +305,7 @@ window.__ModuleLoader__.load({
384
305
  onKeyDown: (event) => {
385
306
  event.stopPropagation();
386
307
  },
387
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {})
308
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineRegular, {})
388
309
  })
389
310
  ]
390
311
  })]
@@ -392,12 +313,7 @@ window.__ModuleLoader__.load({
392
313
  role: "group",
393
314
  className: SubagentHeaderLineage_module_css_default.children,
394
315
  "aria-busy": childLoading || void 0,
395
- children: childCatalog === void 0 ? (0, react_jsx_runtime.jsx)(CatalogLoadingRows, {
396
- parentSessionId: entry.id,
397
- summaries,
398
- level: level + 1,
399
- t
400
- }) : (0, react_jsx_runtime.jsx)(CatalogRows, {
316
+ children: childCatalog === void 0 ? (0, react_jsx_runtime.jsx)(CatalogLoadingRows, { t }) : (0, react_jsx_runtime.jsx)(CatalogRows, {
401
317
  parentSessionId: entry.id,
402
318
  currentSessionId,
403
319
  catalog: childCatalog,
@@ -405,10 +321,9 @@ window.__ModuleLoader__.load({
405
321
  summaries,
406
322
  expanded,
407
323
  level: level + 1,
408
- now,
409
324
  openChild,
410
325
  openChildAside,
411
- refresh,
326
+ refreshProjection,
412
327
  toggleBranch,
413
328
  closeCatalog,
414
329
  t
@@ -429,46 +344,44 @@ window.__ModuleLoader__.load({
429
344
  };
430
345
  }
431
346
  /** One trigger-plus-tree dropdown over the catalog rooted at `rootSessionId`. */
432
- function CatalogDropdown({ rootSessionId, currentSessionId, displayTitle, openTitle, variant, separator = false, useSessions, openChild, openChildAside, refresh, setCatalogOpen, t }) {
347
+ function CatalogDropdown({ rootSessionId, currentSessionId, displayTitle, openTitle, variant, useSessions, useSessionStatus, openChild, openChildAside, refreshProjection, t }) {
433
348
  const ancestorSwitcher = variant === "switcher" && openTitle !== void 0;
434
- const catalogs = useSessions((state) => state.subagentsByParent);
349
+ const projections = useSessions((state) => state.projectionsBySession);
435
350
  const summaries = useSessions((state) => state.byId);
351
+ const statuses = useSessionStatus((value) => value);
352
+ const catalogs = (0, react.useMemo)(() => Object.fromEntries(Object.entries(projections).map(([id, snapshot]) => [id, {
353
+ state: snapshot.state === "idle" ? snapshot.values.subagentCatalog === void 0 ? "loading" : "ready" : snapshot.state,
354
+ error: snapshot.error,
355
+ entries: (snapshot.values.subagentCatalog ?? []).map((entry) => ({
356
+ ...entry,
357
+ activity: (statuses.get(entry.id)?.running ?? summaries[entry.id]?.running) === true ? "running" : "inactive"
358
+ }))
359
+ }])), [
360
+ projections,
361
+ summaries,
362
+ statuses
363
+ ]);
436
364
  const catalog = catalogs[rootSessionId];
437
365
  const [open, setOpen] = (0, react.useState)(false);
438
366
  const [menuPosition, setMenuPosition] = (0, react.useState)();
439
- const [now, setNow] = (0, react.useState)(() => Date.now());
440
367
  const [expanded, setExpanded] = (0, react.useState)(() => /* @__PURE__ */ new Set());
441
368
  const rootRef = (0, react.useRef)(null);
442
369
  const triggerRef = (0, react.useRef)(null);
443
370
  const menuRef = (0, react.useRef)(null);
444
371
  const hoverOpenTimer = (0, react.useRef)(void 0);
445
372
  const hoverCloseTimer = (0, react.useRef)(void 0);
446
- const observedCatalogs = (0, react.useRef)(/* @__PURE__ */ new Set());
447
- const setCatalogOpenRef = (0, react.useRef)(setCatalogOpen);
448
- setCatalogOpenRef.current = setCatalogOpen;
449
- const currentEntry = currentSessionId === void 0 ? void 0 : catalog?.entries.find((entry) => entry.kind === "child" && entry.id === currentSessionId);
450
- const switcherDisplayTitle = currentEntry?.kind === "child" ? currentEntry.label ?? currentEntry.id : displayTitle;
451
- const healthy = catalog?.entries.filter((entry) => entry.kind === "child") ?? [];
452
- const descendants = (0, react.useMemo)(() => indexSubagentDescendants(summaries).get(rootSessionId) ?? NO_DESCENDANTS, [rootSessionId, summaries]);
453
- const descendantCount = Math.max(healthy.length, descendants.count);
454
- const totalCountKey = descendantCount === 1 ? "count.total.one" : "count.total.other";
455
- const runningCountKey = descendants.runningCount === 1 ? "count.running.one" : "count.running.other";
456
- const presentedCatalog = (descendants.count > 0 || variant === "switcher") && (catalog === void 0 || catalog.state === "ready" && catalog.entries.length === 0) ? {
373
+ const currentEntry = currentSessionId === void 0 ? void 0 : catalog?.entries.find((entry) => entry.id === currentSessionId);
374
+ const switcherDisplayTitle = currentEntry !== void 0 ? currentEntry.label ?? currentEntry.id : displayTitle;
375
+ const directChildren = catalog?.entries ?? [];
376
+ const directCount = directChildren.length;
377
+ const runningCount = directChildren.filter((entry) => entry.activity === "running").length;
378
+ const totalCountKey = directCount === 1 ? "count.total.one" : "count.total.other";
379
+ const runningCountKey = runningCount === 1 ? "count.running.one" : "count.running.other";
380
+ const presentedCatalog = catalog ?? (variant === "switcher" ? {
457
381
  entries: [],
458
- parentAvailable: catalog?.parentAvailable ?? false,
459
382
  state: "loading",
460
383
  error: null
461
- } : catalog;
462
- const observeCatalog = (parentSessionId, next) => {
463
- if (next) observedCatalogs.current.add(parentSessionId);
464
- else observedCatalogs.current.delete(parentSessionId);
465
- setCatalogOpen(parentSessionId, next);
466
- };
467
- const closeAllCatalogs = () => {
468
- for (const parentSessionId of observedCatalogs.current) setCatalogOpen(parentSessionId, false);
469
- observedCatalogs.current.clear();
470
- setExpanded(/* @__PURE__ */ new Set());
471
- };
384
+ } : void 0);
472
385
  const cancelHoverClose = () => {
473
386
  if (hoverCloseTimer.current === void 0) return;
474
387
  clearTimeout(hoverCloseTimer.current);
@@ -488,12 +401,10 @@ window.__ModuleLoader__.load({
488
401
  if (trigger === null) return;
489
402
  setOpen(true);
490
403
  setMenuPosition(catalogMenuPosition(trigger));
491
- setNow(Date.now());
492
- observeCatalog(rootSessionId, true);
493
404
  } else {
494
405
  setOpen(false);
495
406
  setMenuPosition(void 0);
496
- closeAllCatalogs();
407
+ setExpanded(/* @__PURE__ */ new Set());
497
408
  }
498
409
  if (restoreFocus) queueMicrotask(() => {
499
410
  triggerRef.current?.focus();
@@ -522,10 +433,9 @@ window.__ModuleLoader__.load({
522
433
  if (closing.has(parentSessionId) || !expanded.has(parentSessionId)) return;
523
434
  closing.add(parentSessionId);
524
435
  const branch = catalogs[parentSessionId];
525
- for (const entry of branch?.entries ?? []) if (entry.kind === "child") visit(entry.id);
436
+ for (const entry of branch?.entries ?? []) visit(entry.id);
526
437
  };
527
438
  visit(root);
528
- for (const parentSessionId of closing) observeCatalog(parentSessionId, false);
529
439
  setExpanded((current) => new Set([...current].filter((id) => !closing.has(id))));
530
440
  };
531
441
  const toggleBranch = (childSessionId) => {
@@ -534,7 +444,7 @@ window.__ModuleLoader__.load({
534
444
  return;
535
445
  }
536
446
  setExpanded((current) => new Set(current).add(childSessionId));
537
- observeCatalog(childSessionId, true);
447
+ refreshProjection(childSessionId);
538
448
  };
539
449
  (0, react.useEffect)(() => {
540
450
  if (!open) return;
@@ -561,29 +471,18 @@ window.__ModuleLoader__.load({
561
471
  document.removeEventListener("scroll", placeMenu, true);
562
472
  };
563
473
  }, [open]);
564
- (0, react.useEffect)(() => {
565
- if (!open || descendants.runningCount === 0) return;
566
- const timer = setInterval(() => {
567
- setNow(Date.now());
568
- }, 1e3);
569
- return () => {
570
- clearInterval(timer);
571
- };
572
- }, [open, descendants.runningCount]);
573
474
  (0, react.useEffect)(() => () => {
574
475
  cancelHoverOpen();
575
476
  cancelHoverClose();
576
- for (const parentSessionId of observedCatalogs.current) setCatalogOpenRef.current(parentSessionId, false);
577
- observedCatalogs.current.clear();
578
477
  }, []);
579
- const visible = presentedCatalog !== void 0 && (variant === "switcher" || presentedCatalog.state === "error" || presentedCatalog.entries.length > 0 || descendantCount > 0);
478
+ const visible = presentedCatalog !== void 0 && (variant === "switcher" || presentedCatalog.state === "error" || presentedCatalog.entries.length > 0);
580
479
  (0, react.useEffect)(() => {
581
480
  if (visible) return;
582
481
  cancelHoverOpen();
583
482
  cancelHoverClose();
584
483
  if (!open) return;
585
484
  setOpen(false);
586
- closeAllCatalogs();
485
+ setExpanded(/* @__PURE__ */ new Set());
587
486
  }, [visible, open]);
588
487
  if (!visible) return null;
589
488
  const focusAt = (index) => {
@@ -617,96 +516,105 @@ window.__ModuleLoader__.load({
617
516
  onKeyDown: navigate,
618
517
  onMouseEnter: scheduleHoverOpen,
619
518
  onMouseLeave: scheduleHoverClose,
620
- children: [
621
- separator && (0, react_jsx_runtime.jsx)("span", {
622
- className: SubagentHeaderLineage_module_css_default.separator,
623
- children: "/"
624
- }),
625
- (0, react_jsx_runtime.jsxs)("button", {
626
- ref: triggerRef,
627
- type: "button",
628
- className: variant === "switcher" ? `${SubagentHeaderLineage_module_css_default.switcherTrigger} ${ancestorSwitcher ? SubagentHeaderLineage_module_css_default.ancestorSwitcherTrigger : ""}` : SubagentHeaderLineage_module_css_default.trigger,
629
- "aria-haspopup": "tree",
630
- "aria-expanded": open,
631
- "aria-label": variant === "switcher" ? t("switcher.aria", { title: switcherDisplayTitle }) : t(descendants.runningCount > 0 ? runningCountKey : totalCountKey, { count: descendants.runningCount > 0 ? descendants.runningCount : descendantCount }),
632
- onClick: openTitle === void 0 ? void 0 : () => {
633
- cancelHoverOpen();
634
- if (open) changeOpen(false);
635
- openTitle();
636
- },
637
- onKeyDown: (event) => {
638
- if (event.key !== "ArrowDown") return;
639
- event.preventDefault();
640
- if (!open) changeOpen(true);
641
- queueMicrotask(() => {
642
- focusAt(0);
643
- });
519
+ children: [(0, react_jsx_runtime.jsxs)("button", {
520
+ ref: triggerRef,
521
+ type: "button",
522
+ className: variant === "switcher" ? `${SubagentHeaderLineage_module_css_default.switcherTrigger} ${ancestorSwitcher ? SubagentHeaderLineage_module_css_default.ancestorSwitcherTrigger : ""}` : SubagentHeaderLineage_module_css_default.trigger,
523
+ "aria-haspopup": "tree",
524
+ "aria-expanded": open,
525
+ "aria-label": variant === "switcher" ? t("switcher.aria", { title: switcherDisplayTitle }) : t(runningCount > 0 ? runningCountKey : totalCountKey, { count: runningCount > 0 ? runningCount : directCount }),
526
+ onClick: openTitle === void 0 ? void 0 : () => {
527
+ cancelHoverOpen();
528
+ if (open) changeOpen(false);
529
+ openTitle();
530
+ },
531
+ onKeyDown: (event) => {
532
+ if (event.key !== "ArrowDown") return;
533
+ event.preventDefault();
534
+ if (!open) changeOpen(true);
535
+ queueMicrotask(() => {
536
+ focusAt(0);
537
+ });
538
+ },
539
+ children: [variant === "switcher" ? (0, react_jsx_runtime.jsx)("span", {
540
+ className: SubagentHeaderLineage_module_css_default.switcherTitle,
541
+ children: switcherDisplayTitle
542
+ }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [runningCount > 0 && (0, react_jsx_runtime.jsx)("span", {
543
+ className: SubagentHeaderLineage_module_css_default.activitySlot,
544
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "ongoing" })
545
+ }), (0, react_jsx_runtime.jsx)("span", {
546
+ className: SubagentHeaderLineage_module_css_default.count,
547
+ children: t(totalCountKey, { count: directCount })
548
+ })] }), variant === "switcher" ? (0, react_jsx_runtime.jsx)(SubagentSwitcherIcon, {}) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: open ? SubagentHeaderLineage_module_css_default.triggerOpen : void 0 })]
549
+ }), open && (0, react_dom.createPortal)((0, react_jsx_runtime.jsx)("div", {
550
+ ref: menuRef,
551
+ className: SubagentHeaderLineage_module_css_default.menu,
552
+ style: menuPosition,
553
+ role: "tree",
554
+ "aria-label": t("tree.aria"),
555
+ onMouseEnter: cancelHoverClose,
556
+ onMouseLeave: scheduleHoverClose,
557
+ children: (0, react_jsx_runtime.jsx)(CatalogRows, {
558
+ parentSessionId: rootSessionId,
559
+ currentSessionId,
560
+ catalog: presentedCatalog,
561
+ catalogs,
562
+ summaries,
563
+ expanded,
564
+ level: 1,
565
+ openChild,
566
+ openChildAside,
567
+ refreshProjection,
568
+ toggleBranch,
569
+ closeCatalog: () => {
570
+ changeOpen(false);
644
571
  },
645
- children: [variant === "switcher" ? (0, react_jsx_runtime.jsx)("span", {
646
- className: SubagentHeaderLineage_module_css_default.switcherTitle,
647
- children: switcherDisplayTitle
648
- }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [descendants.runningCount > 0 && (0, react_jsx_runtime.jsx)("span", {
649
- className: SubagentHeaderLineage_module_css_default.activitySlot,
650
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "ongoing" })
651
- }), (0, react_jsx_runtime.jsx)("span", {
652
- className: SubagentHeaderLineage_module_css_default.count,
653
- children: t(totalCountKey, { count: descendantCount })
654
- })] }), variant === "switcher" ? (0, react_jsx_runtime.jsx)(SubagentSwitcherIcon, {}) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: open ? SubagentHeaderLineage_module_css_default.triggerOpen : void 0 })]
655
- }),
656
- open && (0, react_dom.createPortal)((0, react_jsx_runtime.jsx)("div", {
657
- ref: menuRef,
658
- className: SubagentHeaderLineage_module_css_default.menu,
659
- style: menuPosition,
660
- role: "tree",
661
- "aria-label": t("tree.aria"),
662
- onMouseEnter: cancelHoverClose,
663
- onMouseLeave: scheduleHoverClose,
664
- children: (0, react_jsx_runtime.jsx)(CatalogRows, {
665
- parentSessionId: rootSessionId,
666
- currentSessionId,
667
- catalog: presentedCatalog,
668
- catalogs,
669
- summaries,
670
- expanded,
671
- level: 1,
672
- now,
673
- openChild,
674
- openChildAside,
675
- refresh,
676
- toggleBranch,
677
- closeCatalog: () => {
678
- changeOpen(false);
679
- },
680
- t
681
- })
682
- }), document.body)
683
- ]
572
+ t
573
+ })
574
+ }), document.body)]
684
575
  });
685
576
  }
686
577
  /**
578
+ * Session-header catalog action for root sessions: the descendant count and
579
+ * its dropdown, ordered after the task list. Child sessions render nothing
580
+ * here — their breadcrumb switcher in the lineage slot owns the same
581
+ * navigation.
582
+ * @param props - Session standard props plus the catalog actions and translator.
583
+ * @returns The count dropdown, or null on a child session.
584
+ */
585
+ function SubagentCatalogAction({ sessionId, useSessions, useSessionStatus, openChild, openChildAside, refreshProjection, t }) {
586
+ if (useSessions((state) => state.byId[sessionId]?.origin === "subagent")) return null;
587
+ return (0, react_jsx_runtime.jsx)(CatalogDropdown, {
588
+ rootSessionId: sessionId,
589
+ variant: "count",
590
+ useSessions,
591
+ useSessionStatus,
592
+ openChild,
593
+ openChildAside,
594
+ refreshProjection,
595
+ t
596
+ }, sessionId);
597
+ }
598
+ /**
687
599
  * Render one breadcrumb title together with its subagent navigation.
688
600
  * @param props - Breadcrumb title, session standard props, and catalog actions.
689
- * @returns An ordinary-title descendant count, or a title-and-chevron sibling switcher.
601
+ * @returns A title-and-chevron sibling switcher, or nothing on a root session.
690
602
  */
691
- function SubagentHeaderLineage({ lineageSessionId, displayTitle, openTitle, useSessions, openChild, openChildAside, refresh, setCatalogOpen, t }) {
603
+ function SubagentHeaderLineage({ lineageSessionId, displayTitle, openTitle, useSessions, useSession, useSessionStatus, openChild, openChildAside, refreshProjection, t }) {
604
+ const address = useSession((session) => session.subagent?.address);
692
605
  const parentId = useSessions((state) => {
693
- const summary = state.byId[lineageSessionId];
694
- return summary?.origin === "subagent" ? summary.parentId : void 0;
606
+ if (address?.childSessionId === lineageSessionId) return address.parentSessionId;
607
+ for (const [parentId, snapshot] of Object.entries(state.projectionsBySession)) if (snapshot.values.subagentCatalog?.some((entry) => entry.id === lineageSessionId)) return parentId;
695
608
  });
696
609
  const shared = {
697
610
  useSessions,
611
+ useSessionStatus,
698
612
  openChild,
699
613
  openChildAside,
700
- refresh,
701
- setCatalogOpen,
614
+ refreshProjection,
702
615
  t
703
616
  };
704
- if (parentId === void 0) return (0, react_jsx_runtime.jsx)(CatalogDropdown, {
705
- rootSessionId: lineageSessionId,
706
- variant: "count",
707
- separator: true,
708
- ...shared
709
- }, lineageSessionId);
617
+ if (parentId === void 0) return null;
710
618
  return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(CatalogDropdown, {
711
619
  rootSessionId: parentId,
712
620
  currentSessionId: lineageSessionId,
@@ -744,7 +652,7 @@ window.__ModuleLoader__.load({
744
652
  return (0, react_jsx_runtime.jsxs)("div", {
745
653
  className: SubagentReadOnlyComposer_module_css_default.frame,
746
654
  role: "status",
747
- children: [(0, react_jsx_runtime.jsx)("strong", { children: t(oneShot ? "readonly.oneShot.title" : "readonly.title") }), (0, react_jsx_runtime.jsx)("span", { children: t(oneShot ? "readonly.oneShot.body" : "readonly.body") })]
655
+ children: [(0, react_jsx_runtime.jsx)("strong", { children: t(oneShot ? "readonly.oneShot.title" : "readonly.title") }), (0, react_jsx_runtime.jsx)("span", { children: t(matched.reason === "unknown" ? "readonly.unknown.body" : oneShot ? "readonly.oneShot.body" : "readonly.body") })]
748
656
  });
749
657
  }
750
658
  //#endregion
@@ -794,7 +702,7 @@ window.__ModuleLoader__.load({
794
702
  if (parts.length !== 2 || parts[0] !== "session") return void 0;
795
703
  const parentSessionId = url.searchParams.get("parent");
796
704
  const mode = url.searchParams.get("mode");
797
- if (parentSessionId === null || parentSessionId === "" || mode !== "one-shot" && mode !== "continuable") return;
705
+ if (parentSessionId === null || parentSessionId === "" || mode !== "one-shot" && mode !== "continuable" && mode !== "unknown") return;
798
706
  try {
799
707
  return {
800
708
  parentSessionId,
@@ -823,8 +731,6 @@ window.__ModuleLoader__.load({
823
731
  const address = parseSubagentChatAddress(resourceAddress);
824
732
  if (address === void 0) throw new Error(`ui-subagent: invalid chat resource address "${resourceAddress}"`);
825
733
  if (isAbortRequested(signal)) return;
826
- await sessions.refreshSubagents(address.parentSessionId);
827
- if (isAbortRequested(signal)) return;
828
734
  const reference = sessions.retain(address, {
829
735
  source: "sidebarChat",
830
736
  signal
@@ -910,9 +816,6 @@ window.__ModuleLoader__.load({
910
816
  const NS = "subagent";
911
817
  /** Simplified Chinese dictionary (the key-set source of truth). */
912
818
  const zh = {
913
- "diagnostic.corrupt": "会话记录损坏",
914
- "diagnostic.unsupported": "子代理记录版本不受支持",
915
- "diagnostic.unavailable": "会话记录暂不可用",
916
819
  "duration.seconds": "{seconds}秒",
917
820
  "duration.minutes": "{minutes}分{seconds}秒",
918
821
  "duration.hours": "{hours}小时{minutes}分{seconds}秒",
@@ -928,12 +831,14 @@ window.__ModuleLoader__.load({
928
831
  "tokens.million": "{value}M",
929
832
  "tokens.total": "{value} tok",
930
833
  "loading.label": "正在加载子代理…",
931
- "loading.aria": "正在加载子代理",
932
834
  "load.error": "无法加载子代理",
933
835
  "retry": "重试",
934
836
  "mode.oneShot": "一次性",
935
837
  "mode.continuable": "可继续",
838
+ "mode.unknown": "模式未知",
839
+ "readonly.unknown.body": "读取子会话后才能确定是否可继续。",
936
840
  "activity.running": "正在运行",
841
+ "activity.completed": "已完成",
937
842
  "activity.inactive": "当前未运行",
938
843
  "branch.collapse": "收起 {label} 的下级子代理",
939
844
  "branch.expand": "展开 {label} 的下级子代理",
@@ -952,9 +857,6 @@ window.__ModuleLoader__.load({
952
857
  };
953
858
  /** English dictionary, key-identical to the Chinese source of truth. */
954
859
  const en = {
955
- "diagnostic.corrupt": "corrupted session record",
956
- "diagnostic.unsupported": "unsupported subagent record version",
957
- "diagnostic.unavailable": "session record temporarily unavailable",
958
860
  "duration.seconds": "{seconds}s",
959
861
  "duration.minutes": "{minutes}m {seconds}s",
960
862
  "duration.hours": "{hours}h {minutes}m {seconds}s",
@@ -970,12 +872,14 @@ window.__ModuleLoader__.load({
970
872
  "tokens.million": "{value}M",
971
873
  "tokens.total": "{value} tok",
972
874
  "loading.label": "Loading subagents…",
973
- "loading.aria": "Loading subagents",
974
875
  "load.error": "Unable to load subagents",
975
876
  "retry": "Retry",
976
877
  "mode.oneShot": "one-shot",
977
878
  "mode.continuable": "continuable",
879
+ "mode.unknown": "unknown mode",
880
+ "readonly.unknown.body": "Read the child session to determine whether it can be continued.",
978
881
  "activity.running": "running",
882
+ "activity.completed": "completed",
979
883
  "activity.inactive": "not running",
980
884
  "branch.collapse": "Collapse {label} descendants",
981
885
  "branch.expand": "Expand {label} descendants",
@@ -1006,6 +910,7 @@ window.__ModuleLoader__.load({
1006
910
  function selectReadOnlySubagent(owner) {
1007
911
  const subagent = owner.session?.subagent;
1008
912
  if (subagent === void 0 || subagent === null) return null;
913
+ if (subagent.address.mode === "unknown") return { reason: "unknown" };
1009
914
  if (subagent.address.mode === "one-shot") return { reason: "one-shot" };
1010
915
  if (subagent.parentAvailable !== false) return null;
1011
916
  return owner.session?.running === true ? null : { reason: "parent-unavailable" };
@@ -1022,7 +927,6 @@ window.__ModuleLoader__.load({
1022
927
  ctx.inject(["resources", "sidebarRightTabs"], (scope) => {
1023
928
  registerSidebarChat(scope, ctx.locale.bind(NS));
1024
929
  });
1025
- const sessions = ctx.sessions;
1026
930
  const catalogActions = (_parentSessionId) => ({
1027
931
  openChild(address) {
1028
932
  ctx.uiWorkspace.openSession(address);
@@ -1033,11 +937,8 @@ window.__ModuleLoader__.load({
1033
937
  preferNewPane: true
1034
938
  });
1035
939
  },
1036
- refresh(parentSessionId) {
1037
- sessions.refreshSubagents(parentSessionId);
1038
- },
1039
- setCatalogOpen(parentSessionId, open) {
1040
- sessions.setSubagentCatalogOpen(parentSessionId, open);
940
+ refreshProjection(parentSessionId) {
941
+ ctx.sessions.refreshProjections(parentSessionId);
1041
942
  }
1042
943
  });
1043
944
  ctx.slots.inject("conversation.session.header.lineage", () => ctx.slots.register({
@@ -1045,6 +946,13 @@ window.__ModuleLoader__.load({
1045
946
  locale: NS,
1046
947
  inject: catalogActions
1047
948
  }, SubagentHeaderLineage));
949
+ ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
950
+ name: "conversation.session.header.actions",
951
+ id: "subagent-catalog",
952
+ order: 30,
953
+ locale: NS,
954
+ inject: catalogActions
955
+ }, SubagentCatalogAction));
1048
956
  ctx.slots.inject("conversation.composer", () => ctx.slots.register({
1049
957
  name: "conversation.composer",
1050
958
  priority: -10,
@@ -6,15 +6,25 @@ import { NS } from './locales.ts';
6
6
  export interface SubagentCatalogInjected {
7
7
  openChild: (address: SubagentAddress) => void;
8
8
  openChildAside: (address: SubagentAddress) => void;
9
- refresh: (parentSessionId: SessionId) => void;
10
- setCatalogOpen: (parentSessionId: SessionId, open: boolean) => void;
9
+ refreshProjection: (parentSessionId: SessionId) => void;
11
10
  }
12
11
  /** Full props for the session-header lineage renderer. */
13
12
  export type SubagentHeaderLineageProps = PropsRuntime<'conversation.session.header.lineage'> & SubagentCatalogInjected & PropsLocale<typeof NS>;
13
+ /** Full props for the root-session catalog entry in the header actions band. */
14
+ export type SubagentCatalogActionProps = PropsRuntime<'conversation.session.header.actions'> & SubagentCatalogInjected & PropsLocale<typeof NS>;
15
+ /**
16
+ * Session-header catalog action for root sessions: the descendant count and
17
+ * its dropdown, ordered after the task list. Child sessions render nothing
18
+ * here — their breadcrumb switcher in the lineage slot owns the same
19
+ * navigation.
20
+ * @param props - Session standard props plus the catalog actions and translator.
21
+ * @returns The count dropdown, or null on a child session.
22
+ */
23
+ export declare function SubagentCatalogAction({ sessionId, useSessions, useSessionStatus, openChild, openChildAside, refreshProjection, t, }: SubagentCatalogActionProps): import("react").JSX.Element | null;
14
24
  /**
15
25
  * Render one breadcrumb title together with its subagent navigation.
16
26
  * @param props - Breadcrumb title, session standard props, and catalog actions.
17
- * @returns An ordinary-title descendant count, or a title-and-chevron sibling switcher.
27
+ * @returns A title-and-chevron sibling switcher, or nothing on a root session.
18
28
  */
19
- export declare function SubagentHeaderLineage({ lineageSessionId, displayTitle, openTitle, useSessions, openChild, openChildAside, refresh, setCatalogOpen, t, }: SubagentHeaderLineageProps): import("react").JSX.Element;
29
+ export declare function SubagentHeaderLineage({ lineageSessionId, displayTitle, openTitle, useSessions, useSession, useSessionStatus, openChild, openChildAside, refreshProjection, t, }: SubagentHeaderLineageProps): import("react").JSX.Element | null;
20
30
  //# sourceMappingURL=SubagentHeaderLineage.d.ts.map
@@ -2,7 +2,7 @@ import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots
2
2
  import { NS } from './locales.ts';
3
3
  /** Why a catalog-addressed conversation cannot accept human input. */
4
4
  export interface SubagentReadOnlyMatch {
5
- reason: 'one-shot' | 'parent-unavailable';
5
+ reason: 'one-shot' | 'parent-unavailable' | 'unknown';
6
6
  }
7
7
  /** Full chain props after the read-only subagent selector accepts the owner currency. */
8
8
  export type SubagentReadOnlyComposerProps = PropsRuntime<'conversation.composer'> & {
@@ -7,7 +7,7 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
7
7
  'subagent': SubagentKey;
8
8
  }
9
9
  }
10
- export type { SubagentCatalogInjected, SubagentHeaderLineageProps, } from './SubagentHeaderLineage.tsx';
10
+ export type { SubagentCatalogActionProps, SubagentCatalogInjected, SubagentHeaderLineageProps, } from './SubagentHeaderLineage.tsx';
11
11
  export type { SubagentReadOnlyComposerProps, SubagentReadOnlyMatch, } from './SubagentReadOnlyComposer.tsx';
12
12
  /** Required services for subagent presentation and navigation. */
13
13
  export declare const inject: string[];
@@ -3,9 +3,6 @@
3
3
  export declare const NS = "subagent";
4
4
  /** Simplified Chinese dictionary (the key-set source of truth). */
5
5
  export declare const zh: {
6
- readonly 'diagnostic.corrupt': "会话记录损坏";
7
- readonly 'diagnostic.unsupported': "子代理记录版本不受支持";
8
- readonly 'diagnostic.unavailable': "会话记录暂不可用";
9
6
  readonly 'duration.seconds': "{seconds}秒";
10
7
  readonly 'duration.minutes': "{minutes}分{seconds}秒";
11
8
  readonly 'duration.hours': "{hours}小时{minutes}分{seconds}秒";
@@ -21,12 +18,14 @@ export declare const zh: {
21
18
  readonly 'tokens.million': "{value}M";
22
19
  readonly 'tokens.total': "{value} tok";
23
20
  readonly 'loading.label': "正在加载子代理…";
24
- readonly 'loading.aria': "正在加载子代理";
25
21
  readonly 'load.error': "无法加载子代理";
26
22
  readonly retry: "重试";
27
23
  readonly 'mode.oneShot': "一次性";
28
24
  readonly 'mode.continuable': "可继续";
25
+ readonly 'mode.unknown': "模式未知";
26
+ readonly 'readonly.unknown.body': "读取子会话后才能确定是否可继续。";
29
27
  readonly 'activity.running': "正在运行";
28
+ readonly 'activity.completed': "已完成";
30
29
  readonly 'activity.inactive': "当前未运行";
31
30
  readonly 'branch.collapse': "收起 {label} 的下级子代理";
32
31
  readonly 'branch.expand': "展开 {label} 的下级子代理";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-ui-subagent",
3
3
  "description": "Subagent conversation catalog, continuation routing UI, and '@' reference source",
4
- "version": "0.1.6-alpha.2",
4
+ "version": "0.1.7-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -43,31 +43,31 @@
43
43
  },
44
44
  "license": "MIT",
45
45
  "peerDependencies": {
46
- "@deepseek-ai/cordis": "^4.0.2"
46
+ "@deepseek-ai/cordis": "~4.0.4"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/react": "~18.3.1",
50
50
  "@types/react-dom": "~18.3.0",
51
51
  "react": "^18.2.0",
52
52
  "react-dom": "^18.2.0",
53
- "@deepseek-ai/dsh-client-resources": "^0.1.6-alpha.2",
54
- "@deepseek-ai/dsh-client-test-runtime": "^0.1.6-alpha.2",
55
- "@deepseek-ai/dsh-client-locale": "^0.1.6-alpha.2",
56
- "@deepseek-ai/dsh-client-ui-chat": "^0.1.6-alpha.2",
57
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.6-alpha.2",
58
- "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.6-alpha.2",
59
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.6-alpha.2",
60
- "@deepseek-ai/dsh-subagent": "^0.1.6-alpha.2",
61
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.6-alpha.2",
62
- "@deepseek-ai/dsh-token-meter": "^0.1.6-alpha.2",
63
- "@deepseek-ai/cordis": "^4.0.2",
64
- "@deepseek-ai/dsh-client-connection": "^0.1.6-alpha.2",
65
- "@deepseek-ai/dsh-session": "^0.1.6-alpha.2",
66
- "@deepseek-ai/dsh-client-ui-renderer": "^0.1.6-alpha.2",
67
- "@deepseek-ai/dsh-client-ui-sidebar-right": "^0.1.6-alpha.2",
68
- "@deepseek-ai/dsh-client-ui-session": "^0.1.6-alpha.2",
69
- "@deepseek-ai/dsh-client-ui-workspace": "^0.1.6-alpha.2",
70
- "@deepseek-ai/dsh-api-session-controller": "^0.1.6-alpha.2"
53
+ "@deepseek-ai/dsh-client-locale": "0.1.7-alpha.2",
54
+ "@deepseek-ai/dsh-client-resources": "0.1.7-alpha.2",
55
+ "@deepseek-ai/dsh-client-test-runtime": "0.1.7-alpha.2",
56
+ "@deepseek-ai/dsh-client-ui-chat": "0.1.7-alpha.2",
57
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.7-alpha.2",
58
+ "@deepseek-ai/dsh-client-ui-input-trigger": "0.1.7-alpha.2",
59
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.7-alpha.2",
60
+ "@deepseek-ai/dsh-token-meter": "0.1.7-alpha.2",
61
+ "@deepseek-ai/dsh-subagent": "0.1.7-alpha.2",
62
+ "@deepseek-ai/cordis": "~4.0.4",
63
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-alpha.2",
64
+ "@deepseek-ai/dsh-client-connection": "0.1.7-alpha.2",
65
+ "@deepseek-ai/dsh-session": "0.1.7-alpha.2",
66
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-alpha.2",
67
+ "@deepseek-ai/dsh-client-ui-sidebar-right": "0.1.7-alpha.2",
68
+ "@deepseek-ai/dsh-client-ui-session": "0.1.7-alpha.2",
69
+ "@deepseek-ai/dsh-client-ui-workspace": "0.1.7-alpha.2",
70
+ "@deepseek-ai/dsh-api-session-controller": "0.1.7-alpha.2"
71
71
  },
72
72
  "files": [
73
73
  "lib/index.js",
@@ -1,21 +0,0 @@
1
- /** UI Subagent-owned projection of descendant counts from Session summaries. */
2
- import type { SessionId } from '@deepseek-ai/dsh-session/types';
3
- interface LineageEntry {
4
- readonly id: SessionId;
5
- readonly parentId?: SessionId;
6
- readonly origin?: 'subagent';
7
- readonly running: boolean;
8
- }
9
- /** Descendant counts for one possible parent Session. */
10
- export interface SubagentDescendantSummary {
11
- readonly count: number;
12
- readonly runningCount: number;
13
- }
14
- /**
15
- * Index uninterrupted subagent descendants under each ancestor.
16
- * @param summaries - Session summaries keyed by id.
17
- * @returns descendant totals keyed by possible parent id.
18
- */
19
- export declare function indexSubagentDescendants(summaries: Readonly<Record<SessionId, LineageEntry>>): ReadonlyMap<SessionId, SubagentDescendantSummary>;
20
- export {};
21
- //# sourceMappingURL=subagent-lineage.d.ts.map