@deepseek-ai/dsh-client-ui-subagent 0.1.6-alpha.1 → 0.1.7-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -9,13 +9,13 @@ 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$1 = ".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_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)}";
13
- const tagId$1 = "@deepseek-ai/dsh-client-ui-subagent/SubagentHeaderLineage.module.css";
14
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
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
+ const tagId$2 = "@deepseek-ai/dsh-client-ui-subagent/SubagentHeaderLineage.module.css";
14
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
15
15
  const tag = document.createElement("style");
16
16
  tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-subagent";
17
- tag.dataset.pluginCss = tagId$1;
18
- tag.textContent = css$1;
17
+ tag.dataset.pluginCss = tagId$2;
18
+ tag.textContent = css$2;
19
19
  document.head.appendChild(tag);
20
20
  }
21
21
  var SubagentHeaderLineage_module_css_default = {
@@ -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,8 @@ 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",
43
+ "sidebarButton": "ZKlsPq_sidebarButton",
45
44
  "summary": "ZKlsPq_summary",
46
45
  "switcherRoot": "ZKlsPq_switcherRoot",
47
46
  "switcherTitle": "ZKlsPq_switcherTitle",
@@ -50,44 +49,7 @@ window.__ModuleLoader__.load({
50
49
  "triggerOpen": "ZKlsPq_triggerOpen"
51
50
  };
52
51
  //#endregion
53
- //#region lib/types/client/subagent-lineage.js
54
- /** UI Subagent-owned projection of descendant counts from Session summaries. */
55
- /**
56
- * Index uninterrupted subagent descendants under each ancestor.
57
- * @param summaries - Session summaries keyed by id.
58
- * @returns descendant totals keyed by possible parent id.
59
- */
60
- function indexSubagentDescendants(summaries) {
61
- const indexed = /* @__PURE__ */ new Map();
62
- for (const descendant of Object.values(summaries)) {
63
- if (descendant.origin !== "subagent") continue;
64
- const seen = /* @__PURE__ */ new Set();
65
- let current = descendant;
66
- while (current?.origin === "subagent" && current.parentId !== void 0 && !seen.has(current.id)) {
67
- seen.add(current.id);
68
- const aggregate = indexed.get(current.parentId);
69
- if (aggregate === void 0) indexed.set(current.parentId, {
70
- count: 1,
71
- runningCount: descendant.running ? 1 : 0
72
- });
73
- else {
74
- aggregate.count += 1;
75
- if (descendant.running) aggregate.runningCount += 1;
76
- }
77
- current = summaries[current.parentId];
78
- }
79
- }
80
- return indexed;
81
- }
82
- //#endregion
83
52
  //#region lib/types/client/SubagentHeaderLineage.js
84
- function diagnosticReason(entry, t) {
85
- switch (entry.reason) {
86
- case "corrupt": return t("diagnostic.corrupt");
87
- case "unsupported": return t("diagnostic.unsupported");
88
- case "unavailable": return t("diagnostic.unavailable");
89
- }
90
- }
91
53
  function treeItems(root) {
92
54
  return root === null ? [] : Array.from(root.querySelectorAll("[role=\"treeitem\"]:not([aria-disabled=\"true\"])"));
93
55
  }
@@ -168,10 +130,6 @@ window.__ModuleLoader__.load({
168
130
  seconds: String(seconds).padStart(2, "0")
169
131
  });
170
132
  }
171
- const NO_DESCENDANTS = {
172
- count: 0,
173
- runningCount: 0
174
- };
175
133
  function SubagentSwitcherIcon() {
176
134
  return (0, react_jsx_runtime.jsxs)("svg", {
177
135
  width: "16",
@@ -190,95 +148,56 @@ window.__ModuleLoader__.load({
190
148
  })]
191
149
  });
192
150
  }
193
- /** Render the known direct-child shape while its authoritative catalog hydrates. */
194
- function CatalogLoadingRows({ parentSessionId, summaries, level, t }) {
195
- const children = Object.values(summaries).filter((summary) => summary.origin === "subagent" && summary.parentId === parentSessionId);
196
- 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", {
197
154
  className: SubagentHeaderLineage_module_css_default.notice,
198
155
  children: t("loading.label")
199
156
  });
200
- return children.map((summary) => (0, react_jsx_runtime.jsx)("div", {
201
- className: SubagentHeaderLineage_module_css_default.node,
202
- children: (0, react_jsx_runtime.jsxs)("div", {
203
- role: "treeitem",
204
- "aria-disabled": "true",
205
- "aria-level": level,
206
- "aria-label": t("loading.aria"),
207
- className: `${SubagentHeaderLineage_module_css_default.row} ${SubagentHeaderLineage_module_css_default.disabled} ${SubagentHeaderLineage_module_css_default.loadingRow}`,
208
- children: [
209
- (0, react_jsx_runtime.jsx)("span", { className: SubagentHeaderLineage_module_css_default.disclosureSpace }),
210
- (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: summary.running ? "ongoing" : "done" }),
211
- (0, react_jsx_runtime.jsx)("span", {
212
- className: SubagentHeaderLineage_module_css_default.content,
213
- children: (0, react_jsx_runtime.jsx)("span", {
214
- className: SubagentHeaderLineage_module_css_default.label,
215
- children: t("loading.label")
216
- })
217
- })
218
- ]
219
- })
220
- }, 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;
221
161
  }
222
162
  /** Render one catalog level and recurse only through explicitly expanded rows. */
223
- function CatalogRows({ parentSessionId, currentSessionId, catalog, catalogs, summaries, expanded, level, now, openChild, 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]);
224
175
  const emptyLoading = catalog.state === "loading" && catalog.entries.length === 0;
225
- const reserveDisclosure = catalog.entries.some((entry) => entry.kind === "child" && entry.hasChildren);
176
+ const reserveDisclosure = catalog.entries.some((entry) => !isKnownLeaf(catalogs[entry.id]));
226
177
  return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
227
- emptyLoading && (0, react_jsx_runtime.jsx)(CatalogLoadingRows, {
228
- parentSessionId,
229
- summaries,
230
- level,
231
- t
232
- }),
178
+ emptyLoading && (0, react_jsx_runtime.jsx)(CatalogLoadingRows, { t }),
233
179
  catalog.state === "error" && (0, react_jsx_runtime.jsxs)("div", {
234
180
  className: SubagentHeaderLineage_module_css_default.error,
235
181
  children: [(0, react_jsx_runtime.jsx)("span", { children: catalog.error?.message ?? t("load.error") }), (0, react_jsx_runtime.jsxs)("button", {
236
182
  type: "button",
237
183
  className: SubagentHeaderLineage_module_css_default.refresh,
238
184
  onClick: () => {
239
- refresh(parentSessionId);
185
+ refreshProjection(parentSessionId);
240
186
  },
241
- 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")]
242
188
  })]
243
189
  }),
244
190
  catalog.entries.map((entry) => {
245
- if (entry.kind === "diagnostic") {
246
- const reason = diagnosticReason(entry, t);
247
- return (0, react_jsx_runtime.jsx)("div", {
248
- className: SubagentHeaderLineage_module_css_default.node,
249
- children: (0, react_jsx_runtime.jsxs)("div", {
250
- role: "treeitem",
251
- "aria-disabled": "true",
252
- "aria-level": level,
253
- "aria-label": `${entry.id} ${reason}`,
254
- className: `${SubagentHeaderLineage_module_css_default.row} ${SubagentHeaderLineage_module_css_default.disabled}`,
255
- title: reason,
256
- children: [
257
- reserveDisclosure && (0, react_jsx_runtime.jsx)("span", { className: SubagentHeaderLineage_module_css_default.disclosureSpace }),
258
- (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "error" }),
259
- (0, react_jsx_runtime.jsxs)("span", {
260
- className: SubagentHeaderLineage_module_css_default.content,
261
- children: [(0, react_jsx_runtime.jsx)("span", {
262
- className: SubagentHeaderLineage_module_css_default.label,
263
- children: entry.id
264
- }), (0, react_jsx_runtime.jsx)("span", {
265
- className: SubagentHeaderLineage_module_css_default.summary,
266
- children: reason
267
- })]
268
- })
269
- ]
270
- })
271
- }, entry.id);
272
- }
273
191
  const childCatalog = catalogs[entry.id];
274
192
  const isCurrent = entry.id === currentSessionId;
275
193
  const isExpanded = expanded.has(entry.id);
276
- const knownLeaf = !entry.hasChildren;
194
+ const knownLeaf = isKnownLeaf(childCatalog);
277
195
  const childLoading = childCatalog === void 0 || childCatalog.state === "loading" && childCatalog.entries.length === 0;
278
196
  const summary = summaries[entry.id];
279
197
  const label = entry.label ?? entry.id;
280
- const mode = entry.mode === "one-shot" ? t("mode.oneShot") : t("mode.continuable");
281
- 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");
282
201
  const secondary = [
283
202
  summary?.title,
284
203
  mode,
@@ -300,6 +219,16 @@ window.__ModuleLoader__.load({
300
219
  });
301
220
  closeCatalog();
302
221
  };
222
+ const openAside = (event) => {
223
+ event.preventDefault();
224
+ event.stopPropagation();
225
+ openChildAside({
226
+ parentSessionId,
227
+ childSessionId: entry.id,
228
+ mode: entry.mode
229
+ });
230
+ closeCatalog();
231
+ };
303
232
  const handleKey = (event) => {
304
233
  if (event.key === "Enter" || event.key === " ") {
305
234
  event.preventDefault();
@@ -338,11 +267,14 @@ window.__ModuleLoader__.load({
338
267
  className: `${SubagentHeaderLineage_module_css_default.disclosure} ${isExpanded ? SubagentHeaderLineage_module_css_default.disclosureOpen : ""}`,
339
268
  "aria-label": t(isExpanded ? "branch.collapse" : "branch.expand", { label }),
340
269
  onClick: toggle,
341
- 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, {})
342
271
  }), (0, react_jsx_runtime.jsxs)("div", {
343
272
  className: SubagentHeaderLineage_module_css_default.clickarea,
344
273
  children: [
345
- (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
+ }),
346
278
  (0, react_jsx_runtime.jsxs)("span", {
347
279
  className: SubagentHeaderLineage_module_css_default.content,
348
280
  children: [(0, react_jsx_runtime.jsx)("span", {
@@ -363,6 +295,17 @@ window.__ModuleLoader__.load({
363
295
  title: t("duration.exactTitle", { duration: durationMetric.exact }),
364
296
  children: durationMetric.compact
365
297
  })]
298
+ }),
299
+ !isCurrent && (0, react_jsx_runtime.jsx)("button", {
300
+ type: "button",
301
+ className: SubagentHeaderLineage_module_css_default.sidebarButton,
302
+ "aria-label": t("open.sidebar", { label }),
303
+ title: t("open.sidebar", { label }),
304
+ onClick: openAside,
305
+ onKeyDown: (event) => {
306
+ event.stopPropagation();
307
+ },
308
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineRegular, {})
366
309
  })
367
310
  ]
368
311
  })]
@@ -370,12 +313,7 @@ window.__ModuleLoader__.load({
370
313
  role: "group",
371
314
  className: SubagentHeaderLineage_module_css_default.children,
372
315
  "aria-busy": childLoading || void 0,
373
- children: childCatalog === void 0 ? (0, react_jsx_runtime.jsx)(CatalogLoadingRows, {
374
- parentSessionId: entry.id,
375
- summaries,
376
- level: level + 1,
377
- t
378
- }) : (0, react_jsx_runtime.jsx)(CatalogRows, {
316
+ children: childCatalog === void 0 ? (0, react_jsx_runtime.jsx)(CatalogLoadingRows, { t }) : (0, react_jsx_runtime.jsx)(CatalogRows, {
379
317
  parentSessionId: entry.id,
380
318
  currentSessionId,
381
319
  catalog: childCatalog,
@@ -383,9 +321,9 @@ window.__ModuleLoader__.load({
383
321
  summaries,
384
322
  expanded,
385
323
  level: level + 1,
386
- now,
387
324
  openChild,
388
- refresh,
325
+ openChildAside,
326
+ refreshProjection,
389
327
  toggleBranch,
390
328
  closeCatalog,
391
329
  t
@@ -406,46 +344,44 @@ window.__ModuleLoader__.load({
406
344
  };
407
345
  }
408
346
  /** One trigger-plus-tree dropdown over the catalog rooted at `rootSessionId`. */
409
- function CatalogDropdown({ rootSessionId, currentSessionId, displayTitle, openTitle, variant, separator = false, useSessions, openChild, refresh, setCatalogOpen, t }) {
347
+ function CatalogDropdown({ rootSessionId, currentSessionId, displayTitle, openTitle, variant, useSessions, useSessionStatus, openChild, openChildAside, refreshProjection, t }) {
410
348
  const ancestorSwitcher = variant === "switcher" && openTitle !== void 0;
411
- const catalogs = useSessions((state) => state.subagentsByParent);
349
+ const projections = useSessions((state) => state.projectionsBySession);
412
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
+ ]);
413
364
  const catalog = catalogs[rootSessionId];
414
365
  const [open, setOpen] = (0, react.useState)(false);
415
366
  const [menuPosition, setMenuPosition] = (0, react.useState)();
416
- const [now, setNow] = (0, react.useState)(() => Date.now());
417
367
  const [expanded, setExpanded] = (0, react.useState)(() => /* @__PURE__ */ new Set());
418
368
  const rootRef = (0, react.useRef)(null);
419
369
  const triggerRef = (0, react.useRef)(null);
420
370
  const menuRef = (0, react.useRef)(null);
421
371
  const hoverOpenTimer = (0, react.useRef)(void 0);
422
372
  const hoverCloseTimer = (0, react.useRef)(void 0);
423
- const observedCatalogs = (0, react.useRef)(/* @__PURE__ */ new Set());
424
- const setCatalogOpenRef = (0, react.useRef)(setCatalogOpen);
425
- setCatalogOpenRef.current = setCatalogOpen;
426
- const currentEntry = currentSessionId === void 0 ? void 0 : catalog?.entries.find((entry) => entry.kind === "child" && entry.id === currentSessionId);
427
- const switcherDisplayTitle = currentEntry?.kind === "child" ? currentEntry.label ?? currentEntry.id : displayTitle;
428
- const healthy = catalog?.entries.filter((entry) => entry.kind === "child") ?? [];
429
- const descendants = (0, react.useMemo)(() => indexSubagentDescendants(summaries).get(rootSessionId) ?? NO_DESCENDANTS, [rootSessionId, summaries]);
430
- const descendantCount = Math.max(healthy.length, descendants.count);
431
- const totalCountKey = descendantCount === 1 ? "count.total.one" : "count.total.other";
432
- const runningCountKey = descendants.runningCount === 1 ? "count.running.one" : "count.running.other";
433
- 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" ? {
434
381
  entries: [],
435
- parentAvailable: catalog?.parentAvailable ?? false,
436
382
  state: "loading",
437
383
  error: null
438
- } : catalog;
439
- const observeCatalog = (parentSessionId, next) => {
440
- if (next) observedCatalogs.current.add(parentSessionId);
441
- else observedCatalogs.current.delete(parentSessionId);
442
- setCatalogOpen(parentSessionId, next);
443
- };
444
- const closeAllCatalogs = () => {
445
- for (const parentSessionId of observedCatalogs.current) setCatalogOpen(parentSessionId, false);
446
- observedCatalogs.current.clear();
447
- setExpanded(/* @__PURE__ */ new Set());
448
- };
384
+ } : void 0);
449
385
  const cancelHoverClose = () => {
450
386
  if (hoverCloseTimer.current === void 0) return;
451
387
  clearTimeout(hoverCloseTimer.current);
@@ -465,12 +401,10 @@ window.__ModuleLoader__.load({
465
401
  if (trigger === null) return;
466
402
  setOpen(true);
467
403
  setMenuPosition(catalogMenuPosition(trigger));
468
- setNow(Date.now());
469
- observeCatalog(rootSessionId, true);
470
404
  } else {
471
405
  setOpen(false);
472
406
  setMenuPosition(void 0);
473
- closeAllCatalogs();
407
+ setExpanded(/* @__PURE__ */ new Set());
474
408
  }
475
409
  if (restoreFocus) queueMicrotask(() => {
476
410
  triggerRef.current?.focus();
@@ -499,10 +433,9 @@ window.__ModuleLoader__.load({
499
433
  if (closing.has(parentSessionId) || !expanded.has(parentSessionId)) return;
500
434
  closing.add(parentSessionId);
501
435
  const branch = catalogs[parentSessionId];
502
- for (const entry of branch?.entries ?? []) if (entry.kind === "child") visit(entry.id);
436
+ for (const entry of branch?.entries ?? []) visit(entry.id);
503
437
  };
504
438
  visit(root);
505
- for (const parentSessionId of closing) observeCatalog(parentSessionId, false);
506
439
  setExpanded((current) => new Set([...current].filter((id) => !closing.has(id))));
507
440
  };
508
441
  const toggleBranch = (childSessionId) => {
@@ -511,7 +444,7 @@ window.__ModuleLoader__.load({
511
444
  return;
512
445
  }
513
446
  setExpanded((current) => new Set(current).add(childSessionId));
514
- observeCatalog(childSessionId, true);
447
+ refreshProjection(childSessionId);
515
448
  };
516
449
  (0, react.useEffect)(() => {
517
450
  if (!open) return;
@@ -538,29 +471,18 @@ window.__ModuleLoader__.load({
538
471
  document.removeEventListener("scroll", placeMenu, true);
539
472
  };
540
473
  }, [open]);
541
- (0, react.useEffect)(() => {
542
- if (!open || descendants.runningCount === 0) return;
543
- const timer = setInterval(() => {
544
- setNow(Date.now());
545
- }, 1e3);
546
- return () => {
547
- clearInterval(timer);
548
- };
549
- }, [open, descendants.runningCount]);
550
474
  (0, react.useEffect)(() => () => {
551
475
  cancelHoverOpen();
552
476
  cancelHoverClose();
553
- for (const parentSessionId of observedCatalogs.current) setCatalogOpenRef.current(parentSessionId, false);
554
- observedCatalogs.current.clear();
555
477
  }, []);
556
- 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);
557
479
  (0, react.useEffect)(() => {
558
480
  if (visible) return;
559
481
  cancelHoverOpen();
560
482
  cancelHoverClose();
561
483
  if (!open) return;
562
484
  setOpen(false);
563
- closeAllCatalogs();
485
+ setExpanded(/* @__PURE__ */ new Set());
564
486
  }, [visible, open]);
565
487
  if (!visible) return null;
566
488
  const focusAt = (index) => {
@@ -594,94 +516,105 @@ window.__ModuleLoader__.load({
594
516
  onKeyDown: navigate,
595
517
  onMouseEnter: scheduleHoverOpen,
596
518
  onMouseLeave: scheduleHoverClose,
597
- children: [
598
- separator && (0, react_jsx_runtime.jsx)("span", {
599
- className: SubagentHeaderLineage_module_css_default.separator,
600
- children: "/"
601
- }),
602
- (0, react_jsx_runtime.jsxs)("button", {
603
- ref: triggerRef,
604
- type: "button",
605
- className: variant === "switcher" ? `${SubagentHeaderLineage_module_css_default.switcherTrigger} ${ancestorSwitcher ? SubagentHeaderLineage_module_css_default.ancestorSwitcherTrigger : ""}` : SubagentHeaderLineage_module_css_default.trigger,
606
- "aria-haspopup": "tree",
607
- "aria-expanded": open,
608
- "aria-label": variant === "switcher" ? t("switcher.aria", { title: switcherDisplayTitle }) : t(descendants.runningCount > 0 ? runningCountKey : totalCountKey, { count: descendants.runningCount > 0 ? descendants.runningCount : descendantCount }),
609
- onClick: openTitle === void 0 ? void 0 : () => {
610
- cancelHoverOpen();
611
- if (open) changeOpen(false);
612
- openTitle();
613
- },
614
- onKeyDown: (event) => {
615
- if (event.key !== "ArrowDown") return;
616
- event.preventDefault();
617
- if (!open) changeOpen(true);
618
- queueMicrotask(() => {
619
- focusAt(0);
620
- });
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);
621
571
  },
622
- children: [variant === "switcher" ? (0, react_jsx_runtime.jsx)("span", {
623
- className: SubagentHeaderLineage_module_css_default.switcherTitle,
624
- children: switcherDisplayTitle
625
- }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [descendants.runningCount > 0 && (0, react_jsx_runtime.jsx)("span", {
626
- className: SubagentHeaderLineage_module_css_default.activitySlot,
627
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "ongoing" })
628
- }), (0, react_jsx_runtime.jsx)("span", {
629
- className: SubagentHeaderLineage_module_css_default.count,
630
- children: t(totalCountKey, { count: descendantCount })
631
- })] }), 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 })]
632
- }),
633
- open && (0, react_dom.createPortal)((0, react_jsx_runtime.jsx)("div", {
634
- ref: menuRef,
635
- className: SubagentHeaderLineage_module_css_default.menu,
636
- style: menuPosition,
637
- role: "tree",
638
- "aria-label": t("tree.aria"),
639
- onMouseEnter: cancelHoverClose,
640
- onMouseLeave: scheduleHoverClose,
641
- children: (0, react_jsx_runtime.jsx)(CatalogRows, {
642
- parentSessionId: rootSessionId,
643
- currentSessionId,
644
- catalog: presentedCatalog,
645
- catalogs,
646
- summaries,
647
- expanded,
648
- level: 1,
649
- now,
650
- openChild,
651
- refresh,
652
- toggleBranch,
653
- closeCatalog: () => {
654
- changeOpen(false);
655
- },
656
- t
657
- })
658
- }), document.body)
659
- ]
572
+ t
573
+ })
574
+ }), document.body)]
660
575
  });
661
576
  }
662
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
+ /**
663
599
  * Render one breadcrumb title together with its subagent navigation.
664
600
  * @param props - Breadcrumb title, session standard props, and catalog actions.
665
- * @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.
666
602
  */
667
- function SubagentHeaderLineage({ lineageSessionId, displayTitle, openTitle, useSessions, openChild, refresh, setCatalogOpen, t }) {
603
+ function SubagentHeaderLineage({ lineageSessionId, displayTitle, openTitle, useSessions, useSession, useSessionStatus, openChild, openChildAside, refreshProjection, t }) {
604
+ const address = useSession((session) => session.subagent?.address);
668
605
  const parentId = useSessions((state) => {
669
- const summary = state.byId[lineageSessionId];
670
- 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;
671
608
  });
672
609
  const shared = {
673
610
  useSessions,
611
+ useSessionStatus,
674
612
  openChild,
675
- refresh,
676
- setCatalogOpen,
613
+ openChildAside,
614
+ refreshProjection,
677
615
  t
678
616
  };
679
- if (parentId === void 0) return (0, react_jsx_runtime.jsx)(CatalogDropdown, {
680
- rootSessionId: lineageSessionId,
681
- variant: "count",
682
- separator: true,
683
- ...shared
684
- }, lineageSessionId);
617
+ if (parentId === void 0) return null;
685
618
  return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(CatalogDropdown, {
686
619
  rootSessionId: parentId,
687
620
  currentSessionId: lineageSessionId,
@@ -697,13 +630,13 @@ window.__ModuleLoader__.load({
697
630
  }
698
631
  //#endregion
699
632
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-subagent/src/client/SubagentReadOnlyComposer.module.css.mjs
700
- const css = ".XJ7liG_frame{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1);min-height:54px;color:var(--dsw-alias-label-tertiary);border-radius:14px;justify-content:center;align-items:center;gap:8px;margin:0 24px 20px;padding:10px 16px;font-size:13px;line-height:20px;display:flex}.XJ7liG_frame strong{color:var(--dsw-alias-label-primary);font-weight:510}";
701
- const tagId = "@deepseek-ai/dsh-client-ui-subagent/SubagentReadOnlyComposer.module.css";
702
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
633
+ const css$1 = ".XJ7liG_frame{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1);min-height:54px;color:var(--dsw-alias-label-tertiary);border-radius:14px;justify-content:center;align-items:center;gap:8px;margin:0 24px 20px;padding:10px 16px;font-size:13px;line-height:20px;display:flex}.XJ7liG_frame strong{color:var(--dsw-alias-label-primary);font-weight:510}";
634
+ const tagId$1 = "@deepseek-ai/dsh-client-ui-subagent/SubagentReadOnlyComposer.module.css";
635
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
703
636
  const tag = document.createElement("style");
704
637
  tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-subagent";
705
- tag.dataset.pluginCss = tagId;
706
- tag.textContent = css;
638
+ tag.dataset.pluginCss = tagId$1;
639
+ tag.textContent = css$1;
707
640
  document.head.appendChild(tag);
708
641
  }
709
642
  var SubagentReadOnlyComposer_module_css_default = { "frame": "XJ7liG_frame" };
@@ -719,9 +652,163 @@ window.__ModuleLoader__.load({
719
652
  return (0, react_jsx_runtime.jsxs)("div", {
720
653
  className: SubagentReadOnlyComposer_module_css_default.frame,
721
654
  role: "status",
722
- 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") })]
656
+ });
657
+ }
658
+ //#endregion
659
+ //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-subagent/src/client/sidebar-chat/SidebarChat.module.css.mjs
660
+ const css = ".olTFqa_root{width:100%;min-width:0;height:100%;min-height:0;display:flex}";
661
+ const tagId = "@deepseek-ai/dsh-client-ui-subagent/SidebarChat.module.css";
662
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
663
+ const tag = document.createElement("style");
664
+ tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-subagent";
665
+ tag.dataset.pluginCss = tagId;
666
+ tag.textContent = css;
667
+ document.head.appendChild(tag);
668
+ }
669
+ var SidebarChat_module_css_default = { "root": "olTFqa_root" };
670
+ //#endregion
671
+ //#region lib/types/client/sidebar-chat/index.js
672
+ /** Stable implementation identity for the Sidebar tab body. */
673
+ const SUBAGENT_CHAT_ID = "@deepseek-ai/dsh-client-ui-subagent";
674
+ /** Resource-address prefix for an embedded Session chat. */
675
+ const SUBAGENT_CHAT_ADDRESS = "dsh-resource://subagentchat/session/";
676
+ /**
677
+ * Address one subagent Session together with the routing facts needed to restore it.
678
+ * @param address - durable direct-parent subagent address.
679
+ * @returns canonical Sidebar resource address.
680
+ */
681
+ function subagentChatAddress(address) {
682
+ const query = new URLSearchParams({
683
+ parent: address.parentSessionId,
684
+ mode: address.mode
685
+ });
686
+ return `${SUBAGENT_CHAT_ADDRESS}${encodeURIComponent(address.childSessionId)}?${query}`;
687
+ }
688
+ /**
689
+ * Parse one canonical Sidebar chat resource address.
690
+ * @param value - possible chat resource address.
691
+ * @returns the encoded direct-parent address, or undefined for another or malformed resource.
692
+ */
693
+ function parseSubagentChatAddress(value) {
694
+ let url;
695
+ try {
696
+ url = new URL(value);
697
+ } catch (_invalidUrl) {
698
+ return;
699
+ }
700
+ if (url.protocol !== "dsh-resource:" || url.hostname.toLowerCase() !== "subagentchat") return void 0;
701
+ const parts = url.pathname.split("/").filter(Boolean);
702
+ if (parts.length !== 2 || parts[0] !== "session") return void 0;
703
+ const parentSessionId = url.searchParams.get("parent");
704
+ const mode = url.searchParams.get("mode");
705
+ if (parentSessionId === null || parentSessionId === "" || mode !== "one-shot" && mode !== "continuable" && mode !== "unknown") return;
706
+ try {
707
+ return {
708
+ parentSessionId,
709
+ childSessionId: decodeURIComponent(parts[1]),
710
+ mode
711
+ };
712
+ } catch (_invalidEncoding) {
713
+ return;
714
+ }
715
+ }
716
+ function waitForAbort(signal) {
717
+ if (signal.aborted) return Promise.resolve();
718
+ return new Promise((resolve) => {
719
+ signal.addEventListener("abort", () => {
720
+ resolve();
721
+ }, { once: true });
722
+ });
723
+ }
724
+ function isAbortRequested(signal) {
725
+ return signal.aborted;
726
+ }
727
+ function subagentChatResourceProvider(sessions) {
728
+ return {
729
+ protocol: "subagentchat",
730
+ async *open(resourceAddress, { signal }) {
731
+ const address = parseSubagentChatAddress(resourceAddress);
732
+ if (address === void 0) throw new Error(`ui-subagent: invalid chat resource address "${resourceAddress}"`);
733
+ if (isAbortRequested(signal)) return;
734
+ const reference = sessions.retain(address, {
735
+ source: "sidebarChat",
736
+ signal
737
+ });
738
+ try {
739
+ yield {
740
+ ok: true,
741
+ value: {
742
+ address,
743
+ reference
744
+ }
745
+ };
746
+ await waitForAbort(signal);
747
+ } finally {
748
+ reference.release();
749
+ }
750
+ }
751
+ };
752
+ }
753
+ /** Fixed Chat selection used by an embedded Conversation occurrence. */
754
+ function FixedChatConversationView(props) {
755
+ return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: props.renderSlot("conversation.session", { view: "chat" }) });
756
+ }
757
+ /** Render the shared Conversation content for one explicitly provided child Session. */
758
+ function ConversationSlotPanel({ sessionId, useSession, useConversation, useSessions, renderFactorySlot }) {
759
+ const session = useSession((value) => value);
760
+ const shellPhase = useConversation((value) => value).activeTargets.size > 0 || !session.blank && !session.awaitingFirstTurn || session.running ? "active" : session.promptAttempted ? "engaging" : "blank";
761
+ const summaryBlank = useSessions((state) => state.byId[sessionId]?.blank);
762
+ const parentAvailabilityPending = session.subagent?.address.mode === "continuable" && session.subagent.parentAvailable === void 0;
763
+ const settling = shellPhase === "blank" && session.openState === "loading" && summaryBlank !== true || parentAvailabilityPending;
764
+ const hero = shellPhase === "blank" && (session.openState === "open" || summaryBlank === true);
765
+ return renderFactorySlot("conversation.content", {
766
+ variant: "embedded",
767
+ phase: settling ? "settling" : hero ? "hero" : "active",
768
+ hero
769
+ }, { slots: { views: FixedChatConversationView } });
770
+ }
771
+ /** Bind a chat resource's child reference around its Conversation slot. */
772
+ function SidebarChatTab({ useResource, useTabInfo, SessionProvider, renderSlot }) {
773
+ const { tab } = useTabInfo();
774
+ const resource = useResource(tab.contentId);
775
+ return (0, react_jsx_runtime.jsx)("div", {
776
+ className: SidebarChat_module_css_default.root,
777
+ "data-sidebar-chat": "",
778
+ children: resource.value === void 0 ? null : (0, react_jsx_runtime.jsx)(SessionProvider, {
779
+ session: resource.value.reference,
780
+ children: renderSlot("sidebar.chat.conversation", {})
781
+ })
723
782
  });
724
783
  }
784
+ /**
785
+ * Register the chat resource owner and its right-Sidebar presentation.
786
+ * @param ctx - Client root carrying Sessions, resources, Slots, and Sidebar registries.
787
+ * @param t - Chat namespace translator used for fallback tab titles.
788
+ */
789
+ function registerSidebarChat(ctx, t) {
790
+ ctx.effect(() => ctx.resources.register(subagentChatResourceProvider(ctx.sessions)), "ui-subagent: Sidebar chat resources");
791
+ ctx.effect(() => ctx.sidebarRightTabs.register({
792
+ id: SUBAGENT_CHAT_ID,
793
+ kind: "subagentchat",
794
+ patterns: [`${SUBAGENT_CHAT_ADDRESS}**`],
795
+ priority: "builtin",
796
+ canOpen: (address) => parseSubagentChatAddress(address) !== void 0,
797
+ title: (address) => {
798
+ const child = parseSubagentChatAddress(address)?.childSessionId;
799
+ return child === void 0 ? t("sidebar.chat") : ctx.sessions.list.getSnapshot().byId[child]?.projectionValues?.subagent?.label ?? child;
800
+ }
801
+ }), "ui-subagent: Sidebar chat type");
802
+ ctx.effect(() => ctx.slots.inject("sidebar.right.pane.tab", () => ctx.slots.register({
803
+ name: "sidebar.right.pane.tab",
804
+ key: SUBAGENT_CHAT_ID,
805
+ children: { "sidebar.chat.conversation": {
806
+ kind: "single",
807
+ scope: "session"
808
+ } }
809
+ }, SidebarChatTab)), "ui-subagent: Sidebar chat body");
810
+ ctx.effect(() => ctx.slots.inject("sidebar.chat.conversation", () => ctx.slots.register({ name: "sidebar.chat.conversation" }, ConversationSlotPanel)), "ui-subagent: Sidebar Conversation");
811
+ }
725
812
  //#endregion
726
813
  //#region lib/types/client/locales.js
727
814
  /** `subagent` namespace dictionaries. */
@@ -729,9 +816,6 @@ window.__ModuleLoader__.load({
729
816
  const NS = "subagent";
730
817
  /** Simplified Chinese dictionary (the key-set source of truth). */
731
818
  const zh = {
732
- "diagnostic.corrupt": "会话记录损坏",
733
- "diagnostic.unsupported": "子代理记录版本不受支持",
734
- "diagnostic.unavailable": "会话记录暂不可用",
735
819
  "duration.seconds": "{seconds}秒",
736
820
  "duration.minutes": "{minutes}分{seconds}秒",
737
821
  "duration.hours": "{hours}小时{minutes}分{seconds}秒",
@@ -747,12 +831,14 @@ window.__ModuleLoader__.load({
747
831
  "tokens.million": "{value}M",
748
832
  "tokens.total": "{value} tok",
749
833
  "loading.label": "正在加载子代理…",
750
- "loading.aria": "正在加载子代理",
751
834
  "load.error": "无法加载子代理",
752
835
  "retry": "重试",
753
836
  "mode.oneShot": "一次性",
754
837
  "mode.continuable": "可继续",
838
+ "mode.unknown": "模式未知",
839
+ "readonly.unknown.body": "读取子会话后才能确定是否可继续。",
755
840
  "activity.running": "正在运行",
841
+ "activity.completed": "已完成",
756
842
  "activity.inactive": "当前未运行",
757
843
  "branch.collapse": "收起 {label} 的下级子代理",
758
844
  "branch.expand": "展开 {label} 的下级子代理",
@@ -762,6 +848,8 @@ window.__ModuleLoader__.load({
762
848
  "count.running.other": "{count} 个子代理,正在运行",
763
849
  "switcher.aria": "切换子代理:{title}",
764
850
  "tree.aria": "子代理会话",
851
+ "open.sidebar": "在侧边栏打开 {label}",
852
+ "sidebar.chat": "聊天",
765
853
  "readonly.oneShot.title": "一次性子代理记录",
766
854
  "readonly.title": "此子代理暂时只读",
767
855
  "readonly.oneShot.body": "一次性任务不支持后续消息,可在这里查看完整执行记录。",
@@ -769,9 +857,6 @@ window.__ModuleLoader__.load({
769
857
  };
770
858
  /** English dictionary, key-identical to the Chinese source of truth. */
771
859
  const en = {
772
- "diagnostic.corrupt": "corrupted session record",
773
- "diagnostic.unsupported": "unsupported subagent record version",
774
- "diagnostic.unavailable": "session record temporarily unavailable",
775
860
  "duration.seconds": "{seconds}s",
776
861
  "duration.minutes": "{minutes}m {seconds}s",
777
862
  "duration.hours": "{hours}h {minutes}m {seconds}s",
@@ -787,12 +872,14 @@ window.__ModuleLoader__.load({
787
872
  "tokens.million": "{value}M",
788
873
  "tokens.total": "{value} tok",
789
874
  "loading.label": "Loading subagents…",
790
- "loading.aria": "Loading subagents",
791
875
  "load.error": "Unable to load subagents",
792
876
  "retry": "Retry",
793
877
  "mode.oneShot": "one-shot",
794
878
  "mode.continuable": "continuable",
879
+ "mode.unknown": "unknown mode",
880
+ "readonly.unknown.body": "Read the child session to determine whether it can be continued.",
795
881
  "activity.running": "running",
882
+ "activity.completed": "completed",
796
883
  "activity.inactive": "not running",
797
884
  "branch.collapse": "Collapse {label} descendants",
798
885
  "branch.expand": "Expand {label} descendants",
@@ -802,6 +889,8 @@ window.__ModuleLoader__.load({
802
889
  "count.running.other": "{count} subagents running",
803
890
  "switcher.aria": "Switch subagent: {title}",
804
891
  "tree.aria": "Subagent sessions",
892
+ "open.sidebar": "Open {label} in sidebar",
893
+ "sidebar.chat": "Chat",
805
894
  "readonly.oneShot.title": "One-shot subagent record",
806
895
  "readonly.title": "This subagent is read-only for now",
807
896
  "readonly.oneShot.body": "One-shot tasks do not accept follow-ups; review the full execution record here.",
@@ -809,16 +898,19 @@ window.__ModuleLoader__.load({
809
898
  };
810
899
  //#endregion
811
900
  //#region lib/types/client/index.js
812
- /** Required services for conversation slots and session navigation. */
901
+ /** Required services for subagent presentation and navigation. */
813
902
  const inject = [
814
903
  "sessions",
904
+ "uiWorkspace",
815
905
  "slots",
816
- "locale"
906
+ "locale",
907
+ "sidebarRight"
817
908
  ];
818
909
  /** Claim the composer for one-shot history or an unavailable continuation owner. */
819
910
  function selectReadOnlySubagent(owner) {
820
911
  const subagent = owner.session?.subagent;
821
912
  if (subagent === void 0 || subagent === null) return null;
913
+ if (subagent.address.mode === "unknown") return { reason: "unknown" };
822
914
  if (subagent.address.mode === "one-shot") return { reason: "one-shot" };
823
915
  if (subagent.parentAvailable !== false) return null;
824
916
  return owner.session?.running === true ? null : { reason: "parent-unavailable" };
@@ -832,16 +924,21 @@ window.__ModuleLoader__.load({
832
924
  zh,
833
925
  en
834
926
  }), "ui-subagent: dictionaries");
835
- const sessions = ctx.sessions;
927
+ ctx.inject(["resources", "sidebarRightTabs"], (scope) => {
928
+ registerSidebarChat(scope, ctx.locale.bind(NS));
929
+ });
836
930
  const catalogActions = (_parentSessionId) => ({
837
931
  openChild(address) {
838
- sessions.openSubagent(address);
932
+ ctx.uiWorkspace.openSession(address);
839
933
  },
840
- refresh(parentSessionId) {
841
- sessions.refreshSubagents(parentSessionId);
934
+ openChildAside(address) {
935
+ ctx.sidebarRight.openResource(subagentChatAddress(address), {
936
+ kind: "subagentchat",
937
+ preferNewPane: true
938
+ });
842
939
  },
843
- setCatalogOpen(parentSessionId, open) {
844
- sessions.setSubagentCatalogOpen(parentSessionId, open);
940
+ refreshProjection(parentSessionId) {
941
+ ctx.sessions.refreshProjections(parentSessionId);
845
942
  }
846
943
  });
847
944
  ctx.slots.inject("conversation.session.header.lineage", () => ctx.slots.register({
@@ -849,6 +946,13 @@ window.__ModuleLoader__.load({
849
946
  locale: NS,
850
947
  inject: catalogActions
851
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));
852
956
  ctx.slots.inject("conversation.composer", () => ctx.slots.register({
853
957
  name: "conversation.composer",
854
958
  priority: -10,