@deepseek-ai/dsh-client-ui-conversation 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.
Files changed (33) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +20 -6
  3. package/README.zh.md +20 -6
  4. package/lib/client.js +1374 -370
  5. package/lib/index.js +9 -8
  6. package/lib/types/client/contract/conversation.d.ts +19 -0
  7. package/lib/types/client/contract/groups.d.ts +116 -0
  8. package/lib/types/client/contract/input.d.ts +9 -0
  9. package/lib/types/client/contract/records.d.ts +3 -7
  10. package/lib/types/client/contract/slots.d.ts +51 -17
  11. package/lib/types/client/conversation/assembler.d.ts +16 -1
  12. package/lib/types/client/conversation/assembly.d.ts +3 -0
  13. package/lib/types/client/conversation/group-registry.d.ts +30 -0
  14. package/lib/types/client/conversation/group-store.d.ts +29 -0
  15. package/lib/types/client/conversation/location-index.d.ts +6 -0
  16. package/lib/types/client/index.d.ts +3 -1
  17. package/lib/types/client/input/editor/claim-decor.d.ts +2 -2
  18. package/lib/types/client/input/editor/keymap.d.ts +6 -2
  19. package/lib/types/client/input/editor/runtime.d.ts +13 -0
  20. package/lib/types/client/input/editor/view-binding.d.ts +1 -1
  21. package/lib/types/client/input/facade.d.ts +7 -0
  22. package/lib/types/client/input/submission-policy.d.ts +6 -6
  23. package/lib/types/client/locales.d.ts +384 -4
  24. package/lib/types/client/queue/QueueDock.d.ts +1 -1
  25. package/lib/types/client/service.d.ts +6 -0
  26. package/lib/types/client/skeleton/ConversationHeader.d.ts +8 -0
  27. package/lib/types/client/skeleton/ConversationSession.d.ts +1 -1
  28. package/lib/types/client/skeleton/DefaultConversationViews.d.ts +1 -1
  29. package/lib/types/client/skeleton/control-row-layout.d.ts +10 -0
  30. package/lib/types/client/view-selection.d.ts +4 -0
  31. package/lib/types/index.d.ts +16 -5
  32. package/lib/types/submission-settings.d.ts +9 -1
  33. package/package.json +35 -34
package/lib/client.js CHANGED
@@ -34,7 +34,7 @@ window.__ModuleLoader__.load({
34
34
  let react = require("react");
35
35
  react = __toESM(react, 1);
36
36
  let react_dom = require("react-dom");
37
- //#region ../../../vendor/cosmokit/src/misc.ts
37
+ //#region ../../../vendor/cosmokit/lib/index.js
38
38
  /** Return true when a value is `null` or `undefined`. */
39
39
  function isNullable(value) {
40
40
  return value === null || value === void 0;
@@ -58,8 +58,43 @@ window.__ModuleLoader__.load({
58
58
  for (const key of keys) if (forced || source[key] !== void 0) result[key] = source[key];
59
59
  return result;
60
60
  }
61
- //#endregion
62
- //#region ../../../vendor/cosmokit/src/types.ts
61
+ /** Shared config references used by schema validators and plugin runtimes. */
62
+ const write = Symbol.for("cosmokit.volatile.write");
63
+ function snapshot(value, ancestors = /* @__PURE__ */ new Set()) {
64
+ if (typeof value === "function") throw new TypeError("volatile config cannot contain functions");
65
+ if (value === null || typeof value !== "object") return value;
66
+ if (ancestors.has(value)) throw new TypeError("volatile config cannot contain cycles");
67
+ ancestors.add(value);
68
+ try {
69
+ if (Array.isArray(value)) return Object.freeze(value.map((item) => snapshot(item, ancestors)));
70
+ if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) throw new TypeError("volatile config objects must be plain objects or arrays");
71
+ return Object.freeze(Object.fromEntries(Object.entries(value).map(([key, item]) => [key, snapshot(item, ancestors)])));
72
+ } finally {
73
+ ancestors.delete(value);
74
+ }
75
+ }
76
+ /**
77
+ * Create a detached reference containing an immutable copy of the supplied data.
78
+ * @param value - validated config data; class instances and functions are unsupported.
79
+ * @returns a reference whose value is updated only by its owning runtime.
80
+ */
81
+ function createVolatile(value) {
82
+ let current = snapshot(value);
83
+ return Object.freeze({
84
+ get: () => current,
85
+ [write]: (value) => {
86
+ current = value;
87
+ }
88
+ });
89
+ }
90
+ /**
91
+ * Identify references across ESM/CJS copies of the shared library.
92
+ * @param value - a parsed config value.
93
+ * @returns whether the value implements the shared reference protocol.
94
+ */
95
+ function isVolatile(value) {
96
+ return typeof value === "object" && value !== null && write in value;
97
+ }
63
98
  /** Test values using `instanceof` with a `toStringTag` fallback. */
64
99
  function is$1(type, value) {
65
100
  if (arguments.length === 1) return (value) => is$1(type, value);
@@ -71,15 +106,16 @@ window.__ModuleLoader__.load({
71
106
  function isArrayBufferSource(value) {
72
107
  return isArrayBufferLike(value) || ArrayBuffer.isView(value);
73
108
  }
74
- let Binary;
75
- (function(_Binary) {
76
- _Binary.is = isArrayBufferLike;
77
- _Binary.isSource = isArrayBufferSource;
109
+ /** Binary source detection and base64/hex conversion helpers. */
110
+ var Binary;
111
+ (function(Binary) {
112
+ Binary.is = isArrayBufferLike;
113
+ Binary.isSource = isArrayBufferSource;
78
114
  function fromSource(source) {
79
115
  if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength);
80
116
  else return source;
81
117
  }
82
- _Binary.fromSource = fromSource;
118
+ Binary.fromSource = fromSource;
83
119
  function toBase64(source) {
84
120
  source = fromSource(source);
85
121
  if (typeof Buffer !== "undefined") return Buffer.from(source).toString("base64");
@@ -88,18 +124,18 @@ window.__ModuleLoader__.load({
88
124
  for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);
89
125
  return btoa(binary);
90
126
  }
91
- _Binary.toBase64 = toBase64;
127
+ Binary.toBase64 = toBase64;
92
128
  function fromBase64(source) {
93
129
  if (typeof Buffer !== "undefined") return fromSource(Buffer.from(source, "base64"));
94
130
  return Uint8Array.from(atob(source), (c) => c.charCodeAt(0));
95
131
  }
96
- _Binary.fromBase64 = fromBase64;
132
+ Binary.fromBase64 = fromBase64;
97
133
  function toHex(source) {
98
134
  source = fromSource(source);
99
135
  if (typeof Buffer !== "undefined") return Buffer.from(source).toString("hex");
100
136
  return Array.from(new Uint8Array(source), (byte) => byte.toString(16).padStart(2, "0")).join("");
101
137
  }
102
- _Binary.toHex = toHex;
138
+ Binary.toHex = toHex;
103
139
  function fromHex(source) {
104
140
  if (typeof Buffer !== "undefined") return fromSource(Buffer.from(source, "hex"));
105
141
  const hex = source.length % 2 === 0 ? source : source.slice(0, source.length - 1);
@@ -107,7 +143,7 @@ window.__ModuleLoader__.load({
107
143
  for (let i = 0; i < hex.length; i += 2) buffer.push(parseInt(`${hex[i]}${hex[i + 1]}`, 16));
108
144
  return Uint8Array.from(buffer).buffer;
109
145
  }
110
- _Binary.fromHex = fromHex;
146
+ Binary.fromHex = fromHex;
111
147
  })(Binary || (Binary = {}));
112
148
  Binary.fromBase64;
113
149
  Binary.toBase64;
@@ -139,58 +175,78 @@ window.__ModuleLoader__.load({
139
175
  }
140
176
  return result;
141
177
  }
142
- /** Deeply compare arrays, dates, regexps, buffers, and plain object fields. */
178
+ /**
179
+ * Compare values recursively, treating two volatile references as equal regardless of value.
180
+ * Strict comparison distinguishes null/undefined, treats opaque objects by identity,
181
+ * compares URLs by normalized href, treats array holes as undefined, and considers distinct cyclic structures unequal.
182
+ * @param a - first value.
183
+ * @param b - second value.
184
+ * @param strict - whether to require strict data equality outside volatile references.
185
+ * @returns whether the values compare equal.
186
+ */
143
187
  function deepEqual(a, b, strict) {
144
- if (a === b) return true;
145
- if (!strict && isNullable(a) && isNullable(b)) return true;
146
- if (typeof a !== typeof b) return false;
147
- if (typeof a !== "object") return false;
148
- if (!a || !b) return false;
149
- function check(test, then) {
150
- return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : void 0;
151
- }
152
- return check(Array.isArray, (a, b) => a.length === b.length && a.every((item, index) => deepEqual(item, b[index]))) ?? check(is$1("Date"), (a, b) => a.valueOf() === b.valueOf()) ?? check(is$1("RegExp"), (a, b) => a.source === b.source && a.flags === b.flags) ?? check(isArrayBufferLike, (a, b) => {
153
- if (a.byteLength !== b.byteLength) return false;
154
- const viewA = new Uint8Array(a);
155
- const viewB = new Uint8Array(b);
156
- for (let i = 0; i < viewA.length; i++) if (viewA[i] !== viewB[i]) return false;
157
- return true;
158
- }) ?? Object.keys({
159
- ...a,
160
- ...b
161
- }).every((key) => deepEqual(a[key], b[key], strict));
188
+ const ancestors = /* @__PURE__ */ new Set();
189
+ function compare(a, b) {
190
+ if (a === b) return true;
191
+ if (isVolatile(a) || isVolatile(b)) return isVolatile(a) && isVolatile(b);
192
+ if (!strict && isNullable(a) && isNullable(b)) return true;
193
+ if (typeof a !== typeof b || typeof a !== "object" || !a || !b) return false;
194
+ if (ancestors.has(a)) return false;
195
+ function check(test, then) {
196
+ return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : void 0;
197
+ }
198
+ ancestors.add(a);
199
+ try {
200
+ return check(Array.isArray, (a, b) => {
201
+ if (a.length !== b.length) return false;
202
+ for (let index = 0; index < a.length; index++) if (!compare(a[index], b[index])) return false;
203
+ return true;
204
+ }) ?? check(is$1("Date"), (a, b) => a.valueOf() === b.valueOf()) ?? check(is$1("URL"), (a, b) => a.href === b.href) ?? check(is$1("RegExp"), (a, b) => a.source === b.source && a.flags === b.flags) ?? check(isArrayBufferLike, (a, b) => {
205
+ if (a.byteLength !== b.byteLength) return false;
206
+ const viewA = new Uint8Array(a);
207
+ const viewB = new Uint8Array(b);
208
+ for (let i = 0; i < viewA.length; i++) if (viewA[i] !== viewB[i]) return false;
209
+ return true;
210
+ }) ?? ((!strict || [a, b].every((value) => Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null)) && Object.keys({
211
+ ...a,
212
+ ...b
213
+ }).every((key) => compare(a[key], b[key])));
214
+ } finally {
215
+ ancestors.delete(a);
216
+ }
217
+ }
218
+ return compare(a, b);
162
219
  }
163
- //#endregion
164
- //#region ../../../vendor/cosmokit/src/time.ts
165
- let Time;
166
- (function(_Time) {
167
- _Time.millisecond = 1;
168
- const second = _Time.second = 1e3;
169
- const minute = _Time.minute = second * 60;
170
- const hour = _Time.hour = minute * 60;
171
- const day = _Time.day = hour * 24;
172
- const week = _Time.week = day * 7;
220
+ /** Time constants plus parsing and formatting helpers. */
221
+ var Time;
222
+ (function(Time) {
223
+ Time.millisecond = 1;
224
+ Time.second = 1e3;
225
+ Time.minute = Time.second * 60;
226
+ Time.hour = Time.minute * 60;
227
+ Time.day = Time.hour * 24;
228
+ Time.week = Time.day * 7;
173
229
  let timezoneOffset = (/* @__PURE__ */ new Date()).getTimezoneOffset();
174
230
  function setTimezoneOffset(offset) {
175
231
  timezoneOffset = offset;
176
232
  }
177
- _Time.setTimezoneOffset = setTimezoneOffset;
233
+ Time.setTimezoneOffset = setTimezoneOffset;
178
234
  function getTimezoneOffset() {
179
235
  return timezoneOffset;
180
236
  }
181
- _Time.getTimezoneOffset = getTimezoneOffset;
237
+ Time.getTimezoneOffset = getTimezoneOffset;
182
238
  function getDateNumber(date = /* @__PURE__ */ new Date(), offset) {
183
239
  if (typeof date === "number") date = new Date(date);
184
240
  if (offset === void 0) offset = timezoneOffset;
185
- return Math.floor((date.valueOf() / minute - offset) / 1440);
241
+ return Math.floor((date.valueOf() / Time.minute - offset) / 1440);
186
242
  }
187
- _Time.getDateNumber = getDateNumber;
243
+ Time.getDateNumber = getDateNumber;
188
244
  function fromDateNumber(value, offset) {
189
- const date = new Date(value * day);
245
+ const date = new Date(value * Time.day);
190
246
  if (offset === void 0) offset = timezoneOffset;
191
- return new Date(+date + offset * minute);
247
+ return new Date(+date + offset * Time.minute);
192
248
  }
193
- _Time.fromDateNumber = fromDateNumber;
249
+ Time.fromDateNumber = fromDateNumber;
194
250
  const numeric = /\d+(?:\.\d+)?/.source;
195
251
  const timeRegExp = new RegExp(`^${[
196
252
  "w(?:eek(?:s)?)?",
@@ -202,9 +258,9 @@ window.__ModuleLoader__.load({
202
258
  function parseTime(source) {
203
259
  const capture = timeRegExp.exec(source);
204
260
  if (!capture) return 0;
205
- return (parseFloat(capture[1]) * week || 0) + (parseFloat(capture[2]) * day || 0) + (parseFloat(capture[3]) * hour || 0) + (parseFloat(capture[4]) * minute || 0) + (parseFloat(capture[5]) * second || 0);
261
+ return (parseFloat(capture[1]) * Time.week || 0) + (parseFloat(capture[2]) * Time.day || 0) + (parseFloat(capture[3]) * Time.hour || 0) + (parseFloat(capture[4]) * Time.minute || 0) + (parseFloat(capture[5]) * Time.second || 0);
206
262
  }
207
- _Time.parseTime = parseTime;
263
+ Time.parseTime = parseTime;
208
264
  function parseDate(date) {
209
265
  const parsed = parseTime(date);
210
266
  if (parsed) date = Date.now() + parsed;
@@ -212,27 +268,27 @@ window.__ModuleLoader__.load({
212
268
  else if (/^\d{1,2}-\d{1,2}-\d{1,2}(:\d{1,2}){1,2}$/.test(date)) date = `${(/* @__PURE__ */ new Date()).getFullYear()}-${date}`;
213
269
  return date ? new Date(date) : /* @__PURE__ */ new Date();
214
270
  }
215
- _Time.parseDate = parseDate;
271
+ Time.parseDate = parseDate;
216
272
  function format(ms) {
217
273
  const abs = Math.abs(ms);
218
- if (abs >= day - hour / 2) return Math.round(ms / day) + "d";
219
- else if (abs >= hour - minute / 2) return Math.round(ms / hour) + "h";
220
- else if (abs >= minute - second / 2) return Math.round(ms / minute) + "m";
221
- else if (abs >= second) return Math.round(ms / second) + "s";
274
+ if (abs >= Time.day - Time.hour / 2) return Math.round(ms / Time.day) + "d";
275
+ else if (abs >= Time.hour - Time.minute / 2) return Math.round(ms / Time.hour) + "h";
276
+ else if (abs >= Time.minute - Time.second / 2) return Math.round(ms / Time.minute) + "m";
277
+ else if (abs >= Time.second) return Math.round(ms / Time.second) + "s";
222
278
  return ms + "ms";
223
279
  }
224
- _Time.format = format;
280
+ Time.format = format;
225
281
  function toDigits(source, length = 2) {
226
282
  return source.toString().padStart(length, "0");
227
283
  }
228
- _Time.toDigits = toDigits;
284
+ Time.toDigits = toDigits;
229
285
  function template(template, time = /* @__PURE__ */ new Date()) {
230
286
  return template.replace("yyyy", time.getFullYear().toString()).replace("yy", time.getFullYear().toString().slice(2)).replace("MM", toDigits(time.getMonth() + 1)).replace("dd", toDigits(time.getDate())).replace("hh", toDigits(time.getHours())).replace("mm", toDigits(time.getMinutes())).replace("ss", toDigits(time.getSeconds())).replace("SSS", toDigits(time.getMilliseconds(), 3));
231
287
  }
232
- _Time.template = template;
288
+ Time.template = template;
233
289
  })(Time || (Time = {}));
234
290
  //#endregion
235
- //#region ../../../vendor/schemastery/src/index.ts
291
+ //#region ../../../vendor/schemastery/lib/index.mjs
236
292
  const kSchema = Symbol.for("schemastery");
237
293
  const kValidationError = Symbol.for("ValidationError");
238
294
  globalThis.__schemastery_index__ ??= 0;
@@ -408,6 +464,7 @@ window.__ModuleLoader__.load({
408
464
  return schema;
409
465
  };
410
466
  Schema.prototype.simplify = function simplify(value) {
467
+ if (isVolatile(value)) value = value.get();
411
468
  if (deepEqual(value, this.meta.default, this.type === "dict")) return null;
412
469
  if (isNullable(value)) return value;
413
470
  if (this.type === "object" || this.type === "dict") {
@@ -464,12 +521,49 @@ window.__ModuleLoader__.load({
464
521
  };
465
522
  return schema;
466
523
  } });
524
+ Schema.prototype.volatile = function volatile() {
525
+ if (this.meta.volatile) throw new TypeError("volatile schema is already wrapped");
526
+ return this.extra("volatile", true);
527
+ };
467
528
  const resolvers = {};
529
+ const checkedVolatile = Symbol("checked-volatile-schema");
530
+ function validateVolatileSchema(schema, path = [], blocked = false, seen = /* @__PURE__ */ new Map()) {
531
+ const states = seen.get(schema) ?? /* @__PURE__ */ new Set();
532
+ if (states.has(blocked)) return;
533
+ states.add(blocked);
534
+ seen.set(schema, states);
535
+ if (schema.meta?.volatile && blocked) throw new ValidationError("volatile fields require a fixed object path without an enclosing volatile field", { path });
536
+ const nested = blocked || !!schema.meta?.volatile;
537
+ if (schema.dict) for (const [key, child] of Object.entries(schema.dict)) validateVolatileSchema(child, [...path, key], nested, seen);
538
+ if (schema.sKey) validateVolatileSchema(schema.sKey, [...path, "<key>"], true, seen);
539
+ if (schema.inner && (schema.type !== "lazy" || schema.inner[kSchema])) validateVolatileSchema(schema.inner, [...path, "*"], true, seen);
540
+ if (schema.list) for (let index = 0; index < schema.list.length; index++) validateVolatileSchema(schema.list[index], [...path, String(index)], true, seen);
541
+ }
468
542
  Schema.extend = function extend(type, resolve) {
469
543
  resolvers[type] = resolve;
470
544
  };
471
545
  Schema.resolve = function resolve(data, schema, options = {}, strict = false) {
472
546
  if (!schema) return [data];
547
+ if (!options[checkedVolatile]) {
548
+ validateVolatileSchema(schema, options.path);
549
+ options = {
550
+ ...options,
551
+ [checkedVolatile]: true
552
+ };
553
+ }
554
+ if (schema.meta?.volatile) {
555
+ const inner = Schema(schema);
556
+ inner.meta = {
557
+ ...schema.meta,
558
+ volatile: false
559
+ };
560
+ const [value, adapted] = Schema.resolve(data, inner, options, strict);
561
+ try {
562
+ return [createVolatile(value), adapted];
563
+ } catch (error) {
564
+ throw new ValidationError(error instanceof Error ? error.message : String(error), options);
565
+ }
566
+ }
473
567
  if (options.ignore?.(data, schema)) return [data];
474
568
  if (isNullable(data) && schema.type !== "lazy") {
475
569
  if (schema.meta.required) throw new ValidationError(`missing required value`, options);
@@ -572,6 +666,7 @@ window.__ModuleLoader__.load({
572
666
  ...schema.meta,
573
667
  ...schema.inner.meta
574
668
  };
669
+ validateVolatileSchema(schema.inner, options.path, true);
575
670
  }
576
671
  return Schema.resolve(data, schema.inner, options, strict);
577
672
  });
@@ -671,7 +766,7 @@ window.__ModuleLoader__.load({
671
766
  } catch (e) {
672
767
  if (!options?.autofix) throw e;
673
768
  delete data[key];
674
- return schema.meta.default;
769
+ return schema.meta.volatile ? createVolatile(schema.meta.default) : schema.meta.default;
675
770
  }
676
771
  }
677
772
  Schema.extend("array", (data, { inner, meta }, options) => {
@@ -826,7 +921,18 @@ window.__ModuleLoader__.load({
826
921
  "preserve"
827
922
  ], ({ inner }, isInner) => inner.toString(isInner));
828
923
  //#endregion
829
- //#region ../../util/values/src/index.ts
924
+ //#region ../../util/values/lib/index.js
925
+ /** Duplicate-install-safe JSON and immutable-value helpers. @module @deepseek-ai/dsh-util-values */
926
+ /**
927
+ * Mark an unreachable closed-union branch.
928
+ * @param value - impossible value; an unhandled typed variant fails at the call site.
929
+ * @param context - optional switch-site label included in the failure message.
930
+ * @returns never; a runtime value that escaped its type always throws.
931
+ */
932
+ function assertNever$1(value, context) {
933
+ const rendered = JSON.stringify(value) ?? String(value);
934
+ throw new Error(`unreachable variant${context ? ` in ${context}` : ""}: ${rendered}`);
935
+ }
830
936
  /**
831
937
  * Weak-key lookup with a strongly retained iterable set of associated values.
832
938
  *
@@ -923,10 +1029,11 @@ window.__ModuleLoader__.load({
923
1029
  };
924
1030
  }
925
1031
  //#endregion
926
- //#region ../../core/session/src/surface.ts
1032
+ //#region ../../core/session/lib/types/surface.js
927
1033
  /** Runtime counterpart of the message-producing event union. */
928
1034
  const SURFACE_EVENT_TYPES = new Set([
929
1035
  "system/message",
1036
+ "developer/message",
930
1037
  "user/message",
931
1038
  "assistant/message",
932
1039
  "tool/result"
@@ -1016,6 +1123,173 @@ window.__ModuleLoader__.load({
1016
1123
  return `${kind.length}:${kind}${id}`;
1017
1124
  }
1018
1125
  //#endregion
1126
+ //#region lib/types/client/conversation/group-store.js
1127
+ /** Keyed group publication and incremental validation of rendering positions. */
1128
+ function sameNodeReference(left, right) {
1129
+ return left.key === right.key && left.groupPart === right.groupPart;
1130
+ }
1131
+ function sameEntry(left, right) {
1132
+ return left.kind === right.kind && left.key === right.key && (left.kind === "group" || right.kind === "node" && left.groupPart === right.groupPart);
1133
+ }
1134
+ function reuseReferences(previous, next, equal) {
1135
+ return previous === next || previous.length === next.length && previous.every((value, index) => equal(value, next[index])) ? previous : next;
1136
+ }
1137
+ /** Validates a complete batch before installing its group and root-list changes. */
1138
+ var ConversationGroupStore = class {
1139
+ root = [];
1140
+ rootGroups = /* @__PURE__ */ new Set();
1141
+ groups = /* @__PURE__ */ new Map();
1142
+ placements = /* @__PURE__ */ new Map();
1143
+ sources = /* @__PURE__ */ new Map();
1144
+ dirty = /* @__PURE__ */ new Set();
1145
+ /** @returns the identity-stable ordered root references. */
1146
+ get entries() {
1147
+ return this.root;
1148
+ }
1149
+ groupSource(key) {
1150
+ let source = this.sources.get(key);
1151
+ if (source === void 0) {
1152
+ const publication = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(this.groups.get(key));
1153
+ source = {
1154
+ publication,
1155
+ observable: {
1156
+ getSnapshot: () => this.groups.get(key),
1157
+ subscribe: (listener) => publication.subscribe(listener)
1158
+ }
1159
+ };
1160
+ this.sources.set(key, source);
1161
+ }
1162
+ return source.observable;
1163
+ }
1164
+ /**
1165
+ * Install one validated update without notifying readers.
1166
+ * @param update - root replacement and complete or incremental group records.
1167
+ * @param readNode - synchronous reader of the current target Nodes.
1168
+ */
1169
+ prepareAndInstall(update, readNode) {
1170
+ const nextRoot = update.entries === void 0 ? this.root : reuseReferences(this.root, update.entries, sameEntry);
1171
+ const nextRootGroups = nextRoot === this.root ? this.rootGroups : this.collectRootGroups(nextRoot);
1172
+ const { upserts, removes } = this.collectChanges(update);
1173
+ const replaceReferences = update.groups.kind === "replace";
1174
+ if (this.groups.size - removes.size + [...upserts.keys()].filter((key) => !this.groups.has(key)).length !== nextRootGroups.size) throw new Error("conversation group records and root references must correspond one-to-one");
1175
+ for (const key of removes) if (nextRootGroups.has(key)) throw new Error(`conversation group "${key}" is still referenced`);
1176
+ for (const key of upserts.keys()) if (!nextRootGroups.has(key)) throw new Error(`conversation group "${key}" has no root reference`);
1177
+ if (nextRootGroups !== this.rootGroups) {
1178
+ for (const key of nextRootGroups) if (!upserts.has(key) && !this.groups.has(key)) throw new Error(`conversation root references missing group "${key}"`);
1179
+ }
1180
+ const affectedParts = /* @__PURE__ */ new Map();
1181
+ const partsOf = (key) => {
1182
+ let parts = affectedParts.get(key);
1183
+ if (parts === void 0) {
1184
+ parts = new Set(this.placements.get(key));
1185
+ affectedParts.set(key, parts);
1186
+ }
1187
+ return parts;
1188
+ };
1189
+ const removeReference = (reference) => {
1190
+ partsOf(reference.key).delete(reference.groupPart);
1191
+ };
1192
+ const addReference = (reference) => {
1193
+ if (readNode(reference.key) === void 0) throw new Error(`conversation group references missing Node "${reference.key}"`);
1194
+ const parts = partsOf(reference.key);
1195
+ if (parts.has(reference.groupPart) || reference.groupPart === void 0 && parts.size > 0 || parts.has(void 0)) throw new Error(`conversation Node "${reference.key}" has overlapping rendering positions`);
1196
+ parts.add(reference.groupPart);
1197
+ };
1198
+ if (replaceReferences || nextRoot !== this.root) {
1199
+ for (const entry of this.root) if (entry.kind === "node") removeReference(entry);
1200
+ }
1201
+ for (const key of removes) for (const member of this.groups.get(key).members) removeReference(member);
1202
+ for (const [key, next] of upserts) {
1203
+ const previous = this.groups.get(key);
1204
+ if (previous !== void 0 && (replaceReferences || previous.members !== next.members)) for (const member of previous.members) removeReference(member);
1205
+ }
1206
+ if (replaceReferences || nextRoot !== this.root) {
1207
+ for (const entry of nextRoot) if (entry.kind === "node") addReference(entry);
1208
+ }
1209
+ for (const [key, next] of upserts) if (replaceReferences || this.groups.get(key)?.members !== next.members) for (const member of next.members) addReference(member);
1210
+ for (const [key, parts] of affectedParts) if (parts.size === 0) this.placements.delete(key);
1211
+ else this.placements.set(key, parts);
1212
+ for (const key of removes) {
1213
+ this.groups.delete(key);
1214
+ this.dirty.add(key);
1215
+ }
1216
+ for (const [key, next] of upserts) {
1217
+ if (this.groups.get(key) === next) continue;
1218
+ this.groups.set(key, next);
1219
+ this.dirty.add(key);
1220
+ }
1221
+ this.root = nextRoot;
1222
+ this.rootGroups = nextRootGroups;
1223
+ }
1224
+ /** Publish changed group sources after all related target data has been installed. */
1225
+ publish() {
1226
+ const keys = [...this.dirty];
1227
+ this.dirty.clear();
1228
+ for (const key of keys) this.sources.get(key)?.publication.set(this.groups.get(key));
1229
+ }
1230
+ /** Remove grouping without deleting its source Nodes; publication remains deferred. */
1231
+ clear() {
1232
+ this.prepareAndInstall(
1233
+ {
1234
+ entries: [],
1235
+ groups: {
1236
+ kind: "replace",
1237
+ snapshots: []
1238
+ }
1239
+ },
1240
+ /* v8 ignore next -- an empty replacement never reads a Node reference. */
1241
+ () => void 0
1242
+ );
1243
+ }
1244
+ collectRootGroups(entries) {
1245
+ const keys = /* @__PURE__ */ new Set();
1246
+ for (const entry of entries) {
1247
+ if (entry.kind !== "group") continue;
1248
+ if (keys.has(entry.key)) throw new Error(`conversation group "${entry.key}" has duplicate root references`);
1249
+ keys.add(entry.key);
1250
+ }
1251
+ return keys;
1252
+ }
1253
+ collectChanges(update) {
1254
+ const upserts = /* @__PURE__ */ new Map();
1255
+ const removes = /* @__PURE__ */ new Set();
1256
+ const add = (snapshot) => {
1257
+ if (upserts.has(snapshot.key)) throw new Error(`conversation group "${snapshot.key}" has duplicate upserts`);
1258
+ const previous = this.groups.get(snapshot.key);
1259
+ if (previous === void 0) {
1260
+ upserts.set(snapshot.key, snapshot);
1261
+ return;
1262
+ }
1263
+ const members = reuseReferences(previous.members, snapshot.members, sameNodeReference);
1264
+ upserts.set(snapshot.key, previous.data === snapshot.data && previous.members === members ? previous : {
1265
+ ...snapshot,
1266
+ members
1267
+ });
1268
+ };
1269
+ switch (update.groups.kind) {
1270
+ case "replace":
1271
+ for (const snapshot of update.groups.snapshots) add(snapshot);
1272
+ for (const key of this.groups.keys()) if (!upserts.has(key)) removes.add(key);
1273
+ break;
1274
+ case "apply":
1275
+ for (const snapshot of update.groups.upserts) add(snapshot);
1276
+ for (const key of update.groups.removes) {
1277
+ if (removes.has(key)) throw new Error(`conversation group "${key}" has duplicate removals`);
1278
+ if (!this.groups.has(key)) throw new Error(`conversation group "${key}" cannot be removed because it is absent`);
1279
+ if (upserts.has(key)) throw new Error(`conversation group "${key}" cannot be upserted and removed together`);
1280
+ removes.add(key);
1281
+ }
1282
+ break;
1283
+ /* v8 ignore next 2 -- closed update union; TypeScript rejects other operation tags. */
1284
+ default: assertNever$1(update.groups);
1285
+ }
1286
+ return {
1287
+ upserts,
1288
+ removes
1289
+ };
1290
+ }
1291
+ };
1292
+ //#endregion
1019
1293
  //#region lib/types/client/conversation/location-index.js
1020
1294
  var MutableLocationDataSource = class {
1021
1295
  store;
@@ -1139,6 +1413,7 @@ window.__ModuleLoader__.load({
1139
1413
  turnDataStores = /* @__PURE__ */ new Map();
1140
1414
  stepDataStores = /* @__PURE__ */ new Map();
1141
1415
  dirtyDataStores = /* @__PURE__ */ new Set();
1416
+ changedTurns = /* @__PURE__ */ new Set();
1142
1417
  currentTurn;
1143
1418
  currentStep;
1144
1419
  /**
@@ -1149,6 +1424,15 @@ window.__ModuleLoader__.load({
1149
1424
  return this.timeline;
1150
1425
  }
1151
1426
  /**
1427
+ * Drain the Turn changes accumulated for one assembly flush.
1428
+ * @returns Turn identities changed since the preceding drain.
1429
+ */
1430
+ takeChangedTurns() {
1431
+ const turns = [...this.changedTurns];
1432
+ this.changedTurns.clear();
1433
+ return turns;
1434
+ }
1435
+ /**
1152
1436
  * Replace all Definition-owned Location values while preserving reader identities.
1153
1437
  * @param entries - complete current set of Definition-owned Location values.
1154
1438
  * @returns whether any published Location data changed.
@@ -1311,6 +1595,7 @@ window.__ModuleLoader__.load({
1311
1595
  break;
1312
1596
  }
1313
1597
  }
1598
+ for (const turn of new Set([...previousTurns.keys(), ...nextTurns.keys()])) if (previousTurns.get(turn) !== nextTurns.get(turn)) this.changedTurns.add(turn);
1314
1599
  this.timeline = sameMap && turnOrder === this.timeline.turnOrder ? this.timeline : {
1315
1600
  turnOrder,
1316
1601
  turns: nextTurns
@@ -1390,6 +1675,7 @@ window.__ModuleLoader__.load({
1390
1675
  turnOrder,
1391
1676
  turns
1392
1677
  };
1678
+ if (turn !== previousTurn) this.changedTurns.add(turnNumber);
1393
1679
  const changed = /* @__PURE__ */ new Set();
1394
1680
  for (const seq of this.seqsByTurn.get(turnNumber) ?? []) {
1395
1681
  const previous = this.locations.get(seq);
@@ -1469,17 +1755,20 @@ window.__ModuleLoader__.load({
1469
1755
  return this.mutableStepData(stepDataKey(turn, step));
1470
1756
  }
1471
1757
  mutableTurnData(turn) {
1472
- const current = this.turnDataStores.get(turn) ?? this.createDataStore();
1758
+ const current = this.turnDataStores.get(turn) ?? this.createDataStore(turn);
1473
1759
  this.turnDataStores.set(turn, current);
1474
1760
  return current;
1475
1761
  }
1476
1762
  mutableStepData(key) {
1477
- const current = this.stepDataStores.get(key) ?? this.createDataStore();
1763
+ const current = this.stepDataStores.get(key) ?? this.createDataStore(Number(key.slice(0, key.indexOf(":"))));
1478
1764
  this.stepDataStores.set(key, current);
1479
1765
  return current;
1480
1766
  }
1481
- createDataStore() {
1482
- return new MutableLocationDataStore((store) => this.dirtyDataStores.add(store));
1767
+ createDataStore(turn) {
1768
+ return new MutableLocationDataStore((store) => {
1769
+ this.dirtyDataStores.add(store);
1770
+ this.changedTurns.add(turn);
1771
+ });
1483
1772
  }
1484
1773
  storeFor(data) {
1485
1774
  return data.kind === "turn" ? this.mutableTurnData(data.turn) : this.mutableStepData(stepDataKey(data.turn, requireStep(data)));
@@ -1586,6 +1875,10 @@ window.__ModuleLoader__.load({
1586
1875
  location
1587
1876
  };
1588
1877
  }
1878
+ const NO_GROUPS = {
1879
+ entries: () => [],
1880
+ forTarget: () => void 0
1881
+ };
1589
1882
  /**
1590
1883
  * Session-owned incremental engine that assembles business Contexts from a
1591
1884
  * contiguous Event window and materializes registered view snapshots.
@@ -1593,6 +1886,7 @@ window.__ModuleLoader__.load({
1593
1886
  var ConversationNodeAssembler = class {
1594
1887
  eventDefinitions;
1595
1888
  viewDefinitions;
1889
+ groupDefinitions;
1596
1890
  contexts = /* @__PURE__ */ new Map();
1597
1891
  contextsByKind = /* @__PURE__ */ new Map();
1598
1892
  contextsBySeq = /* @__PURE__ */ new Map();
@@ -1604,6 +1898,8 @@ window.__ModuleLoader__.load({
1604
1898
  revised = /* @__PURE__ */ new Set();
1605
1899
  dependents = /* @__PURE__ */ new Map();
1606
1900
  views = /* @__PURE__ */ new Map();
1901
+ groups = /* @__PURE__ */ new Map();
1902
+ pendingGroupStores = /* @__PURE__ */ new Set();
1607
1903
  activeTargets = /* @__PURE__ */ new Set();
1608
1904
  hasMore = false;
1609
1905
  replacePending = true;
@@ -1611,10 +1907,12 @@ window.__ModuleLoader__.load({
1611
1907
  /**
1612
1908
  * @param eventDefinitions - live Event Definition registry.
1613
1909
  * @param viewDefinitions - live view builder registry.
1910
+ * @param groupDefinitions - optional registered grouping rules, independent of presentation modes.
1614
1911
  */
1615
- constructor(eventDefinitions, viewDefinitions) {
1912
+ constructor(eventDefinitions, viewDefinitions, groupDefinitions = NO_GROUPS) {
1616
1913
  this.eventDefinitions = eventDefinitions;
1617
1914
  this.viewDefinitions = viewDefinitions;
1915
+ this.groupDefinitions = groupDefinitions;
1618
1916
  this.resetViewBuilders();
1619
1917
  }
1620
1918
  /**
@@ -1744,46 +2042,37 @@ window.__ModuleLoader__.load({
1744
2042
  if (!this.replacePending && this.dirty.size === 0 && !this.timelineDirty) return false;
1745
2043
  if (this.replacePending) {
1746
2044
  this.replaceLocationData();
1747
- let published = false;
2045
+ const updated = [];
2046
+ const changedTurns = this.locationIndex.takeChangedTurns();
1748
2047
  for (const target of this.activeTargets) {
1749
2048
  const view = this.views.get(target);
1750
2049
  if (view === void 0) continue;
1751
- const builder = view.builder ?? view.definition.create();
1752
- view.builder = builder;
1753
- view.snapshot = builder.replace({
1754
- nodes: this.buildTargetNodes(target, this.contextsByTarget.get(target)),
1755
- timeline: this.locationIndex.snapshot()
1756
- });
1757
- published = true;
2050
+ this.updateView(view, true, this.buildTargetNodes(target, this.contextsByTarget.get(target)), changedTurns);
2051
+ updated.push(view);
1758
2052
  }
1759
- this.locationIndex.publishData();
1760
2053
  this.replacePending = false;
1761
2054
  this.dirty.clear();
1762
2055
  this.dirtyByTarget.clear();
1763
2056
  this.timelineDirty = false;
1764
- return published;
2057
+ return this.publishViews(updated);
1765
2058
  }
1766
- let published = false;
2059
+ const updated = [];
1767
2060
  if (this.applyDirtyLocationData()) this.timelineDirty = true;
2061
+ const changedTurns = this.locationIndex.takeChangedTurns();
1768
2062
  const timelineDirty = this.timelineDirty;
1769
2063
  for (const target of this.activeTargets) {
1770
2064
  const view = this.views.get(target);
1771
2065
  if (view === void 0) continue;
1772
- const builder = view.builder;
1773
- if (builder === void 0) continue;
2066
+ if (view.builder === void 0) continue;
1774
2067
  const upserts = this.buildTargetUpserts(target, this.dirtyByTarget.get(target));
1775
2068
  if (upserts.length === 0 && !timelineDirty) continue;
1776
- view.snapshot = builder.apply({
1777
- upserts,
1778
- timeline: this.locationIndex.snapshot()
1779
- });
1780
- published = true;
2069
+ this.updateView(view, false, upserts, changedTurns);
2070
+ updated.push(view);
1781
2071
  }
1782
- this.locationIndex.publishData();
1783
2072
  this.dirty.clear();
1784
2073
  this.dirtyByTarget.clear();
1785
2074
  this.timelineDirty = false;
1786
- return published;
2075
+ return this.publishViews(updated);
1787
2076
  }
1788
2077
  /**
1789
2078
  * Add one target to the monotonic active set and materialize its current snapshot.
@@ -1798,6 +2087,7 @@ window.__ModuleLoader__.load({
1798
2087
  this.activeTargets.add(target);
1799
2088
  if (view === void 0) return published;
1800
2089
  this.replaceView(view);
2090
+ this.publishViews([view]);
1801
2091
  return true;
1802
2092
  }
1803
2093
  /**
@@ -1811,6 +2101,9 @@ window.__ModuleLoader__.load({
1811
2101
  get(target) {
1812
2102
  return this.snapshot(target);
1813
2103
  }
2104
+ grouped(target) {
2105
+ return this.groups.get(target)?.store;
2106
+ }
1814
2107
  /**
1815
2108
  * Read targets whose owners classify their latest snapshot as visible activity.
1816
2109
  * @returns target ids contributing visible activity.
@@ -2137,12 +2430,51 @@ window.__ModuleLoader__.load({
2137
2430
  return node;
2138
2431
  }
2139
2432
  replaceView(view) {
2433
+ this.updateView(view, true, this.buildTargetNodes(view.target, this.contextsByTarget.get(view.target)), []);
2434
+ }
2435
+ updateView(view, replacing, nodes, changedTurns) {
2140
2436
  const builder = view.builder ?? view.definition.create();
2437
+ const definition = view.groupDefinition;
2438
+ if (definition !== void 0 && builder.groupInput === void 0) throw new Error(`conversation group target "${view.target}" requires builder.groupInput()`);
2141
2439
  view.builder = builder;
2142
- view.snapshot = builder.replace({
2143
- nodes: this.buildTargetNodes(view.target, this.contextsByTarget.get(view.target)),
2144
- timeline: this.locationIndex.snapshot()
2440
+ const timeline = this.locationIndex.snapshot();
2441
+ const snapshot = replacing ? builder.replace({
2442
+ nodes,
2443
+ timeline,
2444
+ changedTurns
2445
+ }) : builder.apply({
2446
+ upserts: nodes,
2447
+ timeline,
2448
+ changedTurns
2145
2449
  });
2450
+ if (definition !== void 0 && builder.groupInput !== void 0) {
2451
+ let context = this.groups.get(view.target);
2452
+ const initial = context === void 0;
2453
+ if (context === void 0) context = {
2454
+ definition,
2455
+ state: definition.create(),
2456
+ store: new ConversationGroupStore()
2457
+ };
2458
+ const input = builder.groupInput();
2459
+ context.state = definition.update(context, input);
2460
+ const change = definition.buildGroups(context);
2461
+ if ((initial || input.kind === "replace") && (change === null || change.entries === void 0 || change.groups.kind !== "replace")) throw new Error(`conversation group target "${view.target}" requires complete grouping for replacement input`);
2462
+ if (change !== null) {
2463
+ context.store.prepareAndInstall(change, input.readNode);
2464
+ this.pendingGroupStores.add(context.store);
2465
+ }
2466
+ this.groups.set(view.target, context);
2467
+ }
2468
+ view.snapshot = snapshot;
2469
+ }
2470
+ publishViews(updated) {
2471
+ const changed = updated.length > 0 || this.pendingGroupStores.size > 0;
2472
+ const stores = [...this.pendingGroupStores];
2473
+ this.pendingGroupStores.clear();
2474
+ for (const view of updated) view.builder?.publish?.();
2475
+ for (const store of stores) store.publish();
2476
+ this.locationIndex.publishData();
2477
+ return changed;
2146
2478
  }
2147
2479
  buildTargetNodes(target, contexts) {
2148
2480
  const nodes = [];
@@ -2208,11 +2540,19 @@ window.__ModuleLoader__.load({
2208
2540
  return changed;
2209
2541
  }
2210
2542
  resetViewBuilders() {
2543
+ const definitions = this.viewDefinitions.entries();
2544
+ const targets = new Set(definitions.map((definition) => definition.target));
2545
+ for (const [target, group] of this.groups) if (!targets.has(target) || this.groupDefinitions.forTarget(target) !== group.definition) {
2546
+ group.store.clear();
2547
+ this.pendingGroupStores.add(group.store);
2548
+ this.groups.delete(target);
2549
+ }
2211
2550
  this.views.clear();
2212
- for (const definition of this.viewDefinitions.entries()) {
2551
+ for (const definition of definitions) {
2213
2552
  const view = {
2214
2553
  target: definition.target,
2215
2554
  definition,
2555
+ groupDefinition: this.groupDefinitions.forTarget(definition.target),
2216
2556
  isActive: definition.isActive === void 0 ? void 0 : (snapshot) => definition.isActive?.(snapshot) === true,
2217
2557
  builder: void 0,
2218
2558
  snapshot: void 0
@@ -2337,7 +2677,17 @@ window.__ModuleLoader__.load({
2337
2677
  if (definition.target === void 0 !== (definition.buildViewNode === void 0)) throw new Error(`conversation Definition "${definition.kind}" must declare target and buildViewNode together`);
2338
2678
  }
2339
2679
  //#endregion
2340
- //#region ../../util/crypto/src/index.ts
2680
+ //#region ../../util/crypto/lib/index.js
2681
+ /**
2682
+ * UUID minting that works in every JavaScript context this repository ships
2683
+ * to. `crypto.randomUUID` is a secure-context Web API — a page or worker
2684
+ * served over plain HTTP on a LAN address has no such method — while
2685
+ * `crypto.getRandomValues` is unrestricted everywhere (browsers, workers,
2686
+ * Node ≥ 19). One implementation here replaces per-caller polyfills; the
2687
+ * `no-restricted-properties` lint rule points `crypto.randomUUID` callers at
2688
+ * this module.
2689
+ * @module @deepseek-ai/dsh-util-crypto
2690
+ */
2341
2691
  /**
2342
2692
  * Encode bytes as canonical base64 without overflowing function argument limits.
2343
2693
  * @param data - Bytes to encode.
@@ -2522,6 +2872,37 @@ window.__ModuleLoader__.load({
2522
2872
  }
2523
2873
  };
2524
2874
  //#endregion
2875
+ //#region lib/types/client/conversation/group-registry.js
2876
+ /** One Group Definition per target; registration never instantiates its Builder. */
2877
+ var ConversationGroupRegistry = class extends ConversationDefinitionRegistry {
2878
+ views;
2879
+ /**
2880
+ * @param ctx - owning plugin context.
2881
+ * @param views - registered target Builder definitions.
2882
+ */
2883
+ constructor(ctx, views) {
2884
+ super(ctx);
2885
+ this.views = views;
2886
+ }
2887
+ /**
2888
+ * Register grouping rules for an existing target.
2889
+ * @param definition - business State and grouping output for the declared target data.
2890
+ * @returns the effect-owned, idempotent registration disposer.
2891
+ */
2892
+ register(definition) {
2893
+ if (!this.views.entries().some((view) => view.target === definition.target)) throw new Error(`conversation group target "${definition.target}" is not registered`);
2894
+ return this.registerDefinition(definition.target, definition, `conversation group target "${definition.target}" is already registered`, `uiConversation.groups.register(${JSON.stringify(definition.target)})`);
2895
+ }
2896
+ /**
2897
+ * Find the grouping rules registered for one target.
2898
+ * @param target - View target.
2899
+ * @returns its grouping Definition, when registered.
2900
+ */
2901
+ forTarget(target) {
2902
+ return this.definitions.get(target);
2903
+ }
2904
+ };
2905
+ //#endregion
2525
2906
  //#region lib/types/client/conversation/assembly.js
2526
2907
  /** Per-Session target-neutral Conversation assembly. */
2527
2908
  var BoundConversation = class {
@@ -2634,6 +3015,8 @@ window.__ModuleLoader__.load({
2634
3015
  events;
2635
3016
  /** Registry of target View definitions. */
2636
3017
  views;
3018
+ /** Business grouping rules over already materialized target Nodes. */
3019
+ groups;
2637
3020
  bindings = new WeakMapWithValues();
2638
3021
  images;
2639
3022
  /**
@@ -2645,6 +3028,7 @@ window.__ModuleLoader__.load({
2645
3028
  this.sessions = sessions;
2646
3029
  this.events = new ConversationEventRegistry(ctx);
2647
3030
  this.views = new ConversationViewRegistry(ctx);
3031
+ this.groups = new ConversationGroupRegistry(ctx, this.views);
2648
3032
  this.images = new HistoricalImageCache(ctx, sessions);
2649
3033
  const rebuild = () => {
2650
3034
  for (const record of this.bindings.values) record.binding.rebuild();
@@ -2661,7 +3045,9 @@ window.__ModuleLoader__.load({
2661
3045
  ctx.effect(() => {
2662
3046
  const disposeEvents = this.events.subscribe(scheduleRebuild);
2663
3047
  const disposeViews = this.views.subscribe(scheduleRebuild);
3048
+ const disposeGroups = this.groups.subscribe(scheduleRebuild);
2664
3049
  return () => {
3050
+ disposeGroups();
2665
3051
  disposeViews();
2666
3052
  disposeEvents();
2667
3053
  for (const record of [...this.bindings.values]) this.drop(record, true);
@@ -2680,7 +3066,7 @@ window.__ModuleLoader__.load({
2680
3066
  if (this.sessions.binding(sessionId) !== owner) throw new Error(`uiConversation.binding: inactive session "${sessionId}"`);
2681
3067
  const current = this.bindings.get(owner);
2682
3068
  if (current !== void 0) return current.binding;
2683
- const binding = new BoundConversation(owner.eventSource, new ConversationNodeAssembler(this.events, this.views));
3069
+ const binding = new BoundConversation(owner.eventSource, new ConversationNodeAssembler(this.events, this.views, this.groups));
2684
3070
  const record = {
2685
3071
  source: owner,
2686
3072
  binding,
@@ -2811,6 +3197,48 @@ window.__ModuleLoader__.load({
2811
3197
  }
2812
3198
  }
2813
3199
  //#endregion
3200
+ //#region ../../context/file-reference/lib/types/grammar.js
3201
+ /**
3202
+ * Format a selected path as prompt text. Whitespace uses the quoted
3203
+ * `@"path"` grammar; a quoted directory keeps that quote open after its
3204
+ * trailing slash so completion can descend another level.
3205
+ * @param candidate - selected file or directory.
3206
+ * @param preserveQuote - retain an explicitly opened quote even when unnecessary.
3207
+ * @returns the insertion value, or `undefined` for a path the editor grammar cannot represent safely.
3208
+ */
3209
+ function formatFileMention(candidate, preserveQuote) {
3210
+ const path = candidate.kind === "directory" ? `${candidate.path}/` : candidate.path;
3211
+ if (/[\u0000-\u001f\u007f-\u009f"]/u.test(path)) return void 0;
3212
+ if (!(preserveQuote || /\s/u.test(path))) return `@${path}`;
3213
+ if (candidate.kind === "directory") return `@"${path}`;
3214
+ return `@"${path}"`;
3215
+ }
3216
+ //#endregion
3217
+ //#region ../../util/workspace-path/lib/index.js
3218
+ /**
3219
+ * Read the final non-empty segment of a Workspace path for display.
3220
+ * Workspace-label surfaces use this helper instead of deriving another basename.
3221
+ * @param path - Workspace directory path using POSIX or Windows separators.
3222
+ * @returns the final segment, or an empty string for a separator-only path.
3223
+ */
3224
+ function workspaceTitleOf(path) {
3225
+ const trimmed = path.replace(/[/\\]+$/, "");
3226
+ const separator = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
3227
+ return trimmed.slice(separator + 1);
3228
+ }
3229
+ /**
3230
+ * Strip the workspace root from a workspace-rooted absolute path (display only).
3231
+ * @param text - the path to shorten.
3232
+ * @param cwd - session workspace root; absent or empty leaves the path unchanged.
3233
+ * @returns the path relative to the workspace root, or unchanged when it is not rooted there.
3234
+ */
3235
+ function relativizeToCwd(text, cwd) {
3236
+ if (cwd === void 0 || cwd === "") return text;
3237
+ const root = cwd.replace(/[/\\]+$/, "");
3238
+ if (text.startsWith(`${root}/`) || text.startsWith(`${root}\\`)) return text.slice(root.length + 1);
3239
+ return text;
3240
+ }
3241
+ //#endregion
2814
3242
  //#region lib/types/client/service.js
2815
3243
  /**
2816
3244
  * Scope-addressed conversation send, cancel, and history orchestration.
@@ -3287,7 +3715,11 @@ window.__ModuleLoader__.load({
3287
3715
  default: throw new UnsupportedImageMediaTypeError(value);
3288
3716
  }
3289
3717
  }
3290
- /** Whether a browser-declared MIME selects the image draft path (all other files upload verbatim). */
3718
+ /**
3719
+ * Whether a browser-declared MIME selects the image draft path (all other files upload verbatim).
3720
+ * @param value - the browser's declared MIME type.
3721
+ * @returns whether the file is an accepted raster image.
3722
+ */
3291
3723
  function isImageMediaType(value) {
3292
3724
  return value === "image/png" || value === "image/jpeg" || value === "image/webp" || value === "image/gif";
3293
3725
  }
@@ -11924,7 +12356,7 @@ window.__ModuleLoader__.load({
11924
12356
  className: ReferenceChip_module_css_default.marker,
11925
12357
  "aria-hidden": true,
11926
12358
  children: "@"
11927
- }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.ReferenceIcon, {
12359
+ }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.ReferenceIconRegular, {
11928
12360
  kind: appearance,
11929
12361
  size: 14,
11930
12362
  className: ReferenceChip_module_css_default.icon
@@ -12350,8 +12782,8 @@ window.__ModuleLoader__.load({
12350
12782
  }
12351
12783
  //#endregion
12352
12784
  //#region lib/types/client/input/editor/claim-decor.js
12353
- /** Inline style carried by the claim-token node (the old backdrop's hlToken color). */
12354
- const TOKEN_STYLE = "color: var(--dsw-alias-state-warn-label)";
12785
+ /** Inline style carried by the claim-token node. */
12786
+ const TOKEN_STYLE = "color: var(--dsw-alias-state-business-primary)";
12355
12787
  /** The document's first text leaf, or null (empty document / leading chip). */
12356
12788
  function firstTextLeaf() {
12357
12789
  const block = nl().getFirstChild();
@@ -12842,6 +13274,20 @@ window.__ModuleLoader__.load({
12842
13274
  return applied;
12843
13275
  }
12844
13276
  /**
13277
+ * Insert an asynchronous text result as one independent undo operation.
13278
+ * @param span - owner-validated insertion range.
13279
+ * @param text - text sanitized with the same rules as paste.
13280
+ * @returns whether the range mapped and the edit applied.
13281
+ */
13282
+ insertAsyncText(span, text) {
13283
+ let applied = false;
13284
+ const clean = text.replace(REFERENCE_PLACEHOLDER_RE, "");
13285
+ this.applyEdit(() => {
13286
+ applied = $replaceDetectSpanWithText(span, clean);
13287
+ }, Co);
13288
+ return applied;
13289
+ }
13290
+ /**
12845
13291
  * Insert a reference chip with the existing trailing-space rule.
12846
13292
  * @param span - detect-coordinate range.
12847
13293
  * @param ref - reference fields.
@@ -12855,6 +13301,27 @@ window.__ModuleLoader__.load({
12855
13301
  });
12856
13302
  return applied;
12857
13303
  }
13304
+ /**
13305
+ * Insert an ordered file-reference batch after the live selection without deleting it.
13306
+ * @param references - validated references in source order.
13307
+ * @returns whether the live insertion position accepted the batch.
13308
+ */
13309
+ insertFileReferences(references) {
13310
+ if (references.length === 0) return true;
13311
+ let applied = false;
13312
+ this.applyEdit(() => {
13313
+ const projection = $projectComposer((key) => this.occurrenceIdOf(key));
13314
+ const at = projection.selection?.end ?? projection.detectText.length;
13315
+ const before = projection.detectText.slice(0, at);
13316
+ const nodes = references.flatMap((ref) => [$createReferenceChipNode(ref), Go(" ")]);
13317
+ if (before !== "" && !/\s$/u.test(before)) nodes.unshift(Go(" "));
13318
+ applied = $replaceDetectSpanWithNodes({
13319
+ start: at,
13320
+ end: at
13321
+ }, nodes);
13322
+ }, Co);
13323
+ return applied;
13324
+ }
12858
13325
  /** Refresh claim-token decoration after the model's claim changes. */
12859
13326
  refreshClaimDecoration() {
12860
13327
  refreshClaimDecoration(this.editor);
@@ -12967,6 +13434,15 @@ window.__ModuleLoader__.load({
12967
13434
  }
12968
13435
  /** The public provide-channel action face (one stable identity per session). */
12969
13436
  actions = {
13437
+ captureInsertion: () => ({
13438
+ ...this.caretSpan(),
13439
+ draftRev: this.rev
13440
+ }),
13441
+ insertText: (text, span) => {
13442
+ if (this.snapshot.phase === "adjudicating" || this.snapshot.phase === "submitting" || this.disposed) return false;
13443
+ if (span.draftRev !== this.rev) return false;
13444
+ return this.draftEditor.insertAsyncText(span, text);
13445
+ },
12970
13446
  setDraft: (text) => {
12971
13447
  this.setDraft(text);
12972
13448
  },
@@ -13058,6 +13534,19 @@ window.__ModuleLoader__.load({
13058
13534
  return true;
13059
13535
  }
13060
13536
  /**
13537
+ * Add validated file references and attachment ids while admission is editable.
13538
+ * @param references - reference chips in source order.
13539
+ * @param ids - newly allocated attachment ids.
13540
+ * @returns false when admission is locked or the editor refuses the insertion.
13541
+ */
13542
+ addFiles(references, ids) {
13543
+ if (this.snapshot.phase === "adjudicating" || this.snapshot.phase === "submitting") return false;
13544
+ if (!this.draftEditor.insertFileReferences(references)) return false;
13545
+ this.attachmentIds = [...this.attachmentIds, ...ids];
13546
+ this.publish();
13547
+ return true;
13548
+ }
13549
+ /**
13061
13550
  * Remove one attachment id from this draft. Busy admission phases refuse, like
13062
13551
  * {@link addAttachments}: a removal landing while a command submit serializes
13063
13552
  * would otherwise vanish from the rail yet still ride the in-flight send.
@@ -13808,7 +14297,9 @@ window.__ModuleLoader__.load({
13808
14297
  const BUSY_ENTER_BEHAVIORS = ["queue", "steer"];
13809
14298
  /** Default preserves Enter-as-Queue for running conversations. */
13810
14299
  const DEFAULT_BUSY_ENTER_BEHAVIOR = "queue";
13811
- Schema.object({ [BUSY_ENTER_FIELD]: Schema.union([...BUSY_ENTER_BEHAVIORS]).default(DEFAULT_BUSY_ENTER_BEHAVIOR) });
14300
+ /** Durable conversation schema; also the wire envelope the browser scope validates against. */
14301
+ const ConversationSettingsFields = { [BUSY_ENTER_FIELD]: Schema.union([...BUSY_ENTER_BEHAVIORS]).default(DEFAULT_BUSY_ENTER_BEHAVIOR) };
14302
+ Schema.object(ConversationSettingsFields);
13812
14303
  //#endregion
13813
14304
  //#region lib/types/client/input/submission-policy.js
13814
14305
  /**
@@ -13841,22 +14332,24 @@ window.__ModuleLoader__.load({
13841
14332
  var ComposerSubmissionPolicy = class {
13842
14333
  /** Reactive preference source for the composer bar and the Settings row. */
13843
14334
  busyEnter = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(DEFAULT_BUSY_ENTER_BEHAVIOR);
14335
+ unsubscribe;
13844
14336
  host;
13845
14337
  /**
13846
- * @param host - durable preference scope owned by the providing plugin;
13847
- * absent compositions stay process-local. The adoption subscription shares
13848
- * the scope's plugin lifetime — a disposed scope never publishes again, so
13849
- * the policy needs no release hook.
14338
+ * @param host Shared configuration form; omitted keeps the browser-local default.
13850
14339
  */
13851
14340
  constructor(host) {
13852
14341
  this.host = host;
13853
14342
  if (host !== void 0) {
13854
- host.subscribe(() => {
14343
+ this.unsubscribe = host.subscribe(() => {
13855
14344
  this.adopt(host);
13856
14345
  });
13857
14346
  this.adopt(host);
13858
14347
  }
13859
14348
  }
14349
+ /** Release the preference subscription. */
14350
+ dispose() {
14351
+ this.unsubscribe?.();
14352
+ }
13860
14353
  /**
13861
14354
  * Change the busy-state submission behavior; the live value publishes
13862
14355
  * before the durable write starts.
@@ -13908,6 +14401,9 @@ window.__ModuleLoader__.load({
13908
14401
  "attachment.dropTitle": "文件或图片拖动到此处即可添加",
13909
14402
  "attachment.dropDesc": "图片限制:最多 {count} 张,每张 {size}",
13910
14403
  "attachment.dropBlocked": "当前无法添加文件或图片",
14404
+ "attachment.directoryDesktopOnly": "只有桌面端支持添加文件夹,浏览器里请添加单个文件",
14405
+ "attachment.pathUnavailable": "无法获取文件夹路径,请重新拖入",
14406
+ "attachment.pathUnsupported": "路径含有无法引用的字符,请改名后再试",
13911
14407
  "image.pending": "待发送图片",
13912
14408
  "image.openOriginal": "查看原图",
13913
14409
  "image.openOriginalLabel": "{label},点击查看原图",
@@ -13952,7 +14448,196 @@ window.__ModuleLoader__.load({
13952
14448
  "todo.progress.done": "{done} 已完成",
13953
14449
  "todo.progress.active": "{active} 进行中",
13954
14450
  "todo.progress.pending": "{pending} 待处理",
14451
+ "todo.status.completed": "已完成",
14452
+ "todo.status.inProgress": "进行中",
14453
+ "todo.status.pending": "待处理",
13955
14454
  "todo.rowTitle": "更新任务清单",
14455
+ "tool.title.createGoal": "创建目标",
14456
+ "tool.title.getGoal": "查看目标",
14457
+ "tool.title.updateGoal": "更新目标",
14458
+ "tool.title.createSchedule": "创建定时任务",
14459
+ "tool.title.listSchedules": "查看定时任务",
14460
+ "tool.title.deleteSchedule": "删除定时任务",
14461
+ "detail.state": "状态",
14462
+ "detail.todo.completed": "已完成",
14463
+ "detail.todo.in_progress": "进行中",
14464
+ "detail.todo.pending": "待处理",
14465
+ "detail.todo.empty": "任务清单为空",
14466
+ "todo.diff.initial": "首次记录",
14467
+ "todo.diff.compare": "与上次清单相比",
14468
+ "todo.diff.unavailable": "旧清单不可用",
14469
+ "todo.diff.noChanges": "清单没有变化",
14470
+ "todo.diff.added": "新增 {count}",
14471
+ "todo.diff.updated": "更新 {count}",
14472
+ "todo.diff.removed": "移除 {count}",
14473
+ "todo.diff.unchanged": "{count} 项未变化",
14474
+ "todo.diff.addedItem": "新增",
14475
+ "todo.diff.updatedItem": "状态变化",
14476
+ "todo.diff.movedItem": "顺序调整",
14477
+ "todo.diff.removedItem": "移除",
14478
+ "detail.goal.empty": "没有目标",
14479
+ "detail.goal.active": "进行中",
14480
+ "detail.goal.disarmed": "等待继续",
14481
+ "detail.goal.paused": "已暂停",
14482
+ "detail.goal.blocked": "受阻",
14483
+ "detail.goal.complete": "已完成",
14484
+ "detail.goal.rounds": "执行轮次",
14485
+ "detail.goal.reason": "受阻原因",
14486
+ "detail.days": "{count} 天",
14487
+ "detail.hours": "{count} 小时",
14488
+ "detail.minutes": "{count} 分钟",
14489
+ "detail.seconds": "{count} 秒",
14490
+ "detail.schedule.once": "单次",
14491
+ "detail.schedule.every": "每 {interval}",
14492
+ "detail.schedule.when": "计划时间",
14493
+ "detail.schedule.frequency": "重复",
14494
+ "detail.schedule.scheduled": "等待触发",
14495
+ "detail.schedule.overdue": "已到期,等待会话恢复",
14496
+ "detail.schedule.empty": "没有定时任务",
14497
+ "detail.schedule.deleted": "已删除",
14498
+ "detail.schedule.count": "{count} 个定时任务",
14499
+ "tool.title.inspectProviders": "检查提供方",
14500
+ "tool.title.queryRuntime": "查询运行时",
14501
+ "tool.title.inspectPlugins": "检查动态插件",
14502
+ "tool.title.workflow": "运行工作流",
14503
+ "tool.title.ralph": "运行 Ralph",
14504
+ "tool.title.readEvent": "读取事件",
14505
+ "tool.title.searchEvents": "搜索事件",
14506
+ "tool.title.traceEvent": "追踪事件",
14507
+ "tool.title.searchSessions": "搜索会话",
14508
+ "tool.title.traceSession": "追踪会话",
14509
+ "tool.title.listModels": "查看可用模型",
14510
+ "tool.title.subagent": "委派任务",
14511
+ "tool.title.listAgents": "查看代理",
14512
+ "tool.title.sendMessage": "发送消息",
14513
+ "tool.title.interruptAgent": "中断代理",
14514
+ "tool.title.listJobs": "查看后台任务",
14515
+ "tool.title.readJob": "读取任务输出",
14516
+ "tool.title.killJob": "取消后台任务",
14517
+ "tool.title.openTerminal": "创建终端",
14518
+ "tool.title.readTerminal": "读取终端",
14519
+ "tool.title.listTerminals": "查看终端",
14520
+ "tool.title.signalTerminal": "发送终端信号",
14521
+ "tool.title.closeTerminal": "关闭终端",
14522
+ "tool.title.lsp": "查询代码符号",
14523
+ "tool.title.findDefinition": "查找定义",
14524
+ "tool.title.findReferences": "查找引用",
14525
+ "tool.title.findImplementation": "查找实现",
14526
+ "tool.title.hoverSymbol": "查看符号信息",
14527
+ "tool.title.spawnTeammate": "创建队友",
14528
+ "tool.title.createTeamTask": "创建团队任务",
14529
+ "tool.title.getTeamTask": "读取团队任务",
14530
+ "tool.title.updateTeamTask": "更新团队任务",
14531
+ "tool.title.listTeamTasks": "查看团队任务",
14532
+ "tool.title.waitAgent": "等待队友",
14533
+ "detail.recordedResult": "调用结果",
14534
+ "detail.empty": "暂无结果",
14535
+ "detail.none": "无",
14536
+ "detail.yes": "是",
14537
+ "detail.no": "否",
14538
+ "detail.moreInInspect": "另有 {count} 项,可在「查看」中读取",
14539
+ "detail.status.running": "运行中",
14540
+ "detail.status.idle": "空闲",
14541
+ "detail.status.ready": "就绪",
14542
+ "detail.status.inactive": "未运行",
14543
+ "detail.status.provisioning": "准备中",
14544
+ "detail.status.failed": "失败",
14545
+ "detail.status.completed": "已完成",
14546
+ "detail.status.deleted": "已删除",
14547
+ "detail.status.killed": "已取消",
14548
+ "detail.status.accepted": "已接收",
14549
+ "detail.status.queued": "已入队",
14550
+ "detail.status.exited": "已退出",
14551
+ "detail.field.id": "ID",
14552
+ "detail.field.revision": "版本",
14553
+ "detail.field.platform": "平台",
14554
+ "detail.field.provider": "提供方",
14555
+ "detail.field.model": "模型",
14556
+ "detail.field.role": "角色",
14557
+ "detail.field.context": "上下文",
14558
+ "detail.field.owner": "负责人",
14559
+ "detail.field.ready": "可开始",
14560
+ "detail.field.dependencies": "前置任务",
14561
+ "detail.field.writeScopes": "文件范围",
14562
+ "detail.field.warnings": "提示",
14563
+ "detail.field.diagnostics": "诊断",
14564
+ "detail.field.methods": "方法",
14565
+ "detail.field.inputSchema": "输入 Schema",
14566
+ "detail.field.outputSchema": "输出 Schema",
14567
+ "detail.field.currentPackage": "当前包",
14568
+ "detail.field.nextPackage": "待运行的包",
14569
+ "detail.field.latestRun": "最近运行",
14570
+ "detail.field.packages": "版本包",
14571
+ "detail.field.registrations": "注册项",
14572
+ "detail.field.props": "属性",
14573
+ "detail.field.data": "数据",
14574
+ "detail.field.source": "来源",
14575
+ "detail.field.content": "内容",
14576
+ "detail.field.message": "消息",
14577
+ "detail.field.messageId": "消息 ID",
14578
+ "detail.field.root": "根节点",
14579
+ "detail.field.pid": "进程 ID",
14580
+ "detail.field.type": "类型",
14581
+ "detail.field.time": "时间",
14582
+ "detail.field.seq": "事件序号",
14583
+ "detail.field.turn": "轮次",
14584
+ "detail.field.step": "步骤",
14585
+ "detail.field.callId": "调用 ID",
14586
+ "detail.field.agents": "启动代理数",
14587
+ "detail.field.result": "结果",
14588
+ "detail.field.parent": "父级",
14589
+ "detail.field.depth": "层级",
14590
+ "detail.field.exitCode": "退出码",
14591
+ "detail.field.signal": "信号",
14592
+ "detail.field.previousStatus": "中断前状态",
14593
+ "detail.field.agent": "代理 ID",
14594
+ "detail.field.job": "任务 ID",
14595
+ "detail.field.task": "任务内容",
14596
+ "detail.field.processGroup": "进程组",
14597
+ "detail.field.availability": "可用状态",
14598
+ "detail.field.bestMatch": "最相关事件",
14599
+ "detail.field.target": "目标事件",
14600
+ "detail.field.surface": "记录状态",
14601
+ "detail.agents.count": "{count} 个代理",
14602
+ "detail.jobs.count": "{count} 个后台任务",
14603
+ "detail.terminals.count": "{count} 个终端",
14604
+ "detail.tasks.count": "{count} 个团队任务",
14605
+ "detail.tasks.nextPage": "后面还有任务;下一页位置为 {cursor}",
14606
+ "detail.locations.count": "{count} 个位置",
14607
+ "detail.location": "第 {line} 行,第 {column} 列",
14608
+ "detail.receipt.delivered": "消息已送达",
14609
+ "detail.receipt.interrupt": "已请求中断",
14610
+ "detail.receipt.started": "已启动",
14611
+ "detail.receipt.cancel": "已请求取消",
14612
+ "detail.receipt.alreadyFinished": "任务已结束",
14613
+ "detail.receipt.signal": "信号已发送",
14614
+ "detail.receipt.closed": "已关闭",
14615
+ "detail.receipt.closing": "关闭中",
14616
+ "detail.wait.noProgress": "没有正在运行的队友",
14617
+ "detail.wait.title": "队友状态",
14618
+ "detail.wait.timeout": "等待超时",
14619
+ "detail.wait.changed": "检测到变化",
14620
+ "detail.agent.reply": "代理回复",
14621
+ "detail.models.title": "可用模型",
14622
+ "detail.output.lines": "第 {begin}–{end} 行,共 {total} 行",
14623
+ "detail.output.truncated": "输出已截断",
14624
+ "detail.providers.count": "{count} 个检查提供方",
14625
+ "detail.plugins.count": "{count} 个动态插件",
14626
+ "detail.workflow.script": "工作流脚本",
14627
+ "detail.ralph.reportedComplete": "代理报告完成",
14628
+ "detail.ralph.reportedBlocker": "代理报告受阻",
14629
+ "detail.ralph.limit": "已达到轮次上限",
14630
+ "detail.report.nextSteps": "待完成事项",
14631
+ "detail.trace.replacedBy": "被替换为",
14632
+ "detail.trace.replacementChain": "替换链",
14633
+ "detail.trace.replaces": "替换的事件",
14634
+ "detail.trace.sources": "引用来源",
14635
+ "detail.trace.derived": "派生事件",
14636
+ "detail.trace.ancestors": "祖先会话",
14637
+ "detail.trace.descendants": "后代会话",
14638
+ "detail.matches.count": "{count} 条匹配",
14639
+ "detail.matches.capped": "已达到结果上限,可缩小搜索范围",
14640
+ "detail.event.neighbors": "前后事件",
13956
14641
  "todo.completed": "{done}/{total} 已完成",
13957
14642
  "command.attachmentsUnsupported": "/{command} 不接受附件,请先移除附件",
13958
14643
  "ask.rowTitle": "提问",
@@ -13974,7 +14659,7 @@ window.__ModuleLoader__.load({
13974
14659
  "row.inspect": "查看",
13975
14660
  "tool.title.search": "搜索",
13976
14661
  "tool.title.read": "读取",
13977
- "tool.title.bash": "Bash",
14662
+ "tool.title.bash": "运行命令",
13978
14663
  "tool.title.write": "写入",
13979
14664
  "tool.title.edit": "编辑",
13980
14665
  "tool.title.code": "代码",
@@ -13983,17 +14668,15 @@ window.__ModuleLoader__.load({
13983
14668
  "tool.title.runCordis": "运行 Cordis 插件",
13984
14669
  "tool.title.stopCordis": "停止 Cordis 插件",
13985
14670
  "tool.title.removeCordis": "移除 Cordis 插件",
13986
- "tool.title.pwsh": "Pwsh",
14671
+ "tool.title.pwsh": "运行命令",
13987
14672
  "tool.title.readImage": "读取图片",
13988
- "tool.title.grep": "Grep",
13989
- "tool.title.glob": "Glob",
14673
+ "tool.title.grep": "搜索文件内容",
14674
+ "tool.title.glob": "查找文件",
13990
14675
  "tool.title.webSearch": "网页搜索",
13991
14676
  "tool.title.webFetch": "网页获取",
13992
14677
  "tool.autoReviewRejected": "Auto review 已拒绝",
13993
14678
  "tool.autoReviewNotExecuted": "工具未执行。原因:{reason}",
13994
14679
  "tool.autoReviewReasonFallback": "Auto review 未授权此次操作",
13995
- "diff.files.one": "{count} 个文件",
13996
- "diff.files.other": "{count} 个文件",
13997
14680
  "diff.collapseAria": "收起差异",
13998
14681
  "diff.expandAria": "展开其余 {count} 行差异",
13999
14682
  "diff.expandRest": "… 其余 {count} 行",
@@ -14066,6 +14749,9 @@ window.__ModuleLoader__.load({
14066
14749
  "attachment.dropTitle": "Drag files or images here to add them",
14067
14750
  "attachment.dropDesc": "Image limit: up to {count} images, {size} each",
14068
14751
  "attachment.dropBlocked": "Files and images cannot be added right now",
14752
+ "attachment.directoryDesktopOnly": "Folders can only be added in the desktop app; add individual files in the browser",
14753
+ "attachment.pathUnavailable": "Could not obtain the folder path; drag it in again",
14754
+ "attachment.pathUnsupported": "The path contains characters a reference cannot carry; rename it and try again",
14069
14755
  "image.pending": "Pending images",
14070
14756
  "image.openOriginal": "View original",
14071
14757
  "image.openOriginalLabel": "{label}, click to view original",
@@ -14110,7 +14796,196 @@ window.__ModuleLoader__.load({
14110
14796
  "todo.progress.done": "{done} completed",
14111
14797
  "todo.progress.active": "{active} in progress",
14112
14798
  "todo.progress.pending": "{pending} pending",
14799
+ "todo.status.completed": "Completed",
14800
+ "todo.status.inProgress": "In progress",
14801
+ "todo.status.pending": "Pending",
14113
14802
  "todo.rowTitle": "Update to-do list",
14803
+ "tool.title.createGoal": "Create goal",
14804
+ "tool.title.getGoal": "View goal",
14805
+ "tool.title.updateGoal": "Update goal",
14806
+ "tool.title.createSchedule": "Create reminder",
14807
+ "tool.title.listSchedules": "List reminders",
14808
+ "tool.title.deleteSchedule": "Delete reminder",
14809
+ "detail.state": "Status",
14810
+ "detail.todo.completed": "Completed",
14811
+ "detail.todo.in_progress": "In progress",
14812
+ "detail.todo.pending": "Pending",
14813
+ "detail.todo.empty": "The to-do list is empty",
14814
+ "todo.diff.initial": "Initial list",
14815
+ "todo.diff.compare": "Changes since the previous list",
14816
+ "todo.diff.unavailable": "Previous list unavailable",
14817
+ "todo.diff.noChanges": "No changes to the list",
14818
+ "todo.diff.added": "{count} added",
14819
+ "todo.diff.updated": "{count} updated",
14820
+ "todo.diff.removed": "{count} removed",
14821
+ "todo.diff.unchanged": "{count} unchanged",
14822
+ "todo.diff.addedItem": "Added",
14823
+ "todo.diff.updatedItem": "Status changed",
14824
+ "todo.diff.movedItem": "Reordered",
14825
+ "todo.diff.removedItem": "Removed",
14826
+ "detail.goal.empty": "No goal",
14827
+ "detail.goal.active": "Active",
14828
+ "detail.goal.disarmed": "Awaiting continuation",
14829
+ "detail.goal.paused": "Paused",
14830
+ "detail.goal.blocked": "Blocked",
14831
+ "detail.goal.complete": "Completed",
14832
+ "detail.goal.rounds": "Rounds",
14833
+ "detail.goal.reason": "Blocker",
14834
+ "detail.days": "{count} d",
14835
+ "detail.hours": "{count} h",
14836
+ "detail.minutes": "{count} min",
14837
+ "detail.seconds": "{count} s",
14838
+ "detail.schedule.once": "Once",
14839
+ "detail.schedule.every": "Every {interval}",
14840
+ "detail.schedule.when": "Scheduled for",
14841
+ "detail.schedule.frequency": "Repeat",
14842
+ "detail.schedule.scheduled": "Scheduled",
14843
+ "detail.schedule.overdue": "Overdue, awaiting session resume",
14844
+ "detail.schedule.empty": "No reminders",
14845
+ "detail.schedule.deleted": "Deleted",
14846
+ "detail.schedule.count": "{count} reminders",
14847
+ "tool.title.inspectProviders": "Inspect providers",
14848
+ "tool.title.queryRuntime": "Query runtime",
14849
+ "tool.title.inspectPlugins": "Inspect plugins",
14850
+ "tool.title.workflow": "Run workflow",
14851
+ "tool.title.ralph": "Run Ralph",
14852
+ "tool.title.readEvent": "Read event",
14853
+ "tool.title.searchEvents": "Search events",
14854
+ "tool.title.traceEvent": "Trace event",
14855
+ "tool.title.searchSessions": "Search sessions",
14856
+ "tool.title.traceSession": "Trace session",
14857
+ "tool.title.listModels": "List models",
14858
+ "tool.title.subagent": "Delegate task",
14859
+ "tool.title.listAgents": "List agents",
14860
+ "tool.title.sendMessage": "Send message",
14861
+ "tool.title.interruptAgent": "Interrupt agent",
14862
+ "tool.title.listJobs": "List background jobs",
14863
+ "tool.title.readJob": "Read job output",
14864
+ "tool.title.killJob": "Cancel background job",
14865
+ "tool.title.openTerminal": "Open terminal",
14866
+ "tool.title.readTerminal": "Read terminal",
14867
+ "tool.title.listTerminals": "List terminals",
14868
+ "tool.title.signalTerminal": "Signal terminal",
14869
+ "tool.title.closeTerminal": "Close terminal",
14870
+ "tool.title.lsp": "Query code symbols",
14871
+ "tool.title.findDefinition": "Find definition",
14872
+ "tool.title.findReferences": "Find references",
14873
+ "tool.title.findImplementation": "Find implementation",
14874
+ "tool.title.hoverSymbol": "Inspect symbol",
14875
+ "tool.title.spawnTeammate": "Create teammate",
14876
+ "tool.title.createTeamTask": "Create team task",
14877
+ "tool.title.getTeamTask": "Read team task",
14878
+ "tool.title.updateTeamTask": "Update team task",
14879
+ "tool.title.listTeamTasks": "List team tasks",
14880
+ "tool.title.waitAgent": "Wait for teammates",
14881
+ "detail.recordedResult": "Recorded result",
14882
+ "detail.empty": "No results",
14883
+ "detail.none": "None",
14884
+ "detail.yes": "Yes",
14885
+ "detail.no": "No",
14886
+ "detail.moreInInspect": "{count} more items available in Inspect",
14887
+ "detail.status.running": "Running",
14888
+ "detail.status.idle": "Idle",
14889
+ "detail.status.ready": "Ready",
14890
+ "detail.status.inactive": "Inactive",
14891
+ "detail.status.provisioning": "Provisioning",
14892
+ "detail.status.failed": "Failed",
14893
+ "detail.status.completed": "Completed",
14894
+ "detail.status.deleted": "Deleted",
14895
+ "detail.status.killed": "Cancelled",
14896
+ "detail.status.accepted": "Accepted",
14897
+ "detail.status.queued": "Queued",
14898
+ "detail.status.exited": "Exited",
14899
+ "detail.field.id": "ID",
14900
+ "detail.field.revision": "Revision",
14901
+ "detail.field.platform": "Platform",
14902
+ "detail.field.provider": "Provider",
14903
+ "detail.field.model": "Model",
14904
+ "detail.field.role": "Role",
14905
+ "detail.field.context": "Context",
14906
+ "detail.field.owner": "Owner",
14907
+ "detail.field.ready": "Ready",
14908
+ "detail.field.dependencies": "Dependencies",
14909
+ "detail.field.writeScopes": "Write scopes",
14910
+ "detail.field.warnings": "Warnings",
14911
+ "detail.field.diagnostics": "Diagnostics",
14912
+ "detail.field.methods": "Methods",
14913
+ "detail.field.inputSchema": "Input schema",
14914
+ "detail.field.outputSchema": "Output schema",
14915
+ "detail.field.currentPackage": "Current package",
14916
+ "detail.field.nextPackage": "Next package",
14917
+ "detail.field.latestRun": "Latest run",
14918
+ "detail.field.packages": "Packages",
14919
+ "detail.field.registrations": "Registrations",
14920
+ "detail.field.props": "Props",
14921
+ "detail.field.data": "Data",
14922
+ "detail.field.source": "Source",
14923
+ "detail.field.content": "Content",
14924
+ "detail.field.message": "Message",
14925
+ "detail.field.messageId": "Message ID",
14926
+ "detail.field.root": "Root",
14927
+ "detail.field.pid": "Process ID",
14928
+ "detail.field.type": "Type",
14929
+ "detail.field.time": "Time",
14930
+ "detail.field.seq": "Event sequence",
14931
+ "detail.field.turn": "Turn",
14932
+ "detail.field.step": "Step",
14933
+ "detail.field.callId": "Call ID",
14934
+ "detail.field.agents": "Agents started",
14935
+ "detail.field.result": "Result",
14936
+ "detail.field.parent": "Parent",
14937
+ "detail.field.depth": "Depth",
14938
+ "detail.field.exitCode": "Exit code",
14939
+ "detail.field.signal": "Signal",
14940
+ "detail.field.previousStatus": "Previous status",
14941
+ "detail.field.agent": "Agent ID",
14942
+ "detail.field.job": "Job ID",
14943
+ "detail.field.task": "Task",
14944
+ "detail.field.processGroup": "Process group",
14945
+ "detail.field.availability": "Availability",
14946
+ "detail.field.bestMatch": "Best match",
14947
+ "detail.field.target": "Target event",
14948
+ "detail.field.surface": "Record status",
14949
+ "detail.agents.count": "{count} agents",
14950
+ "detail.jobs.count": "{count} background jobs",
14951
+ "detail.terminals.count": "{count} terminals",
14952
+ "detail.tasks.count": "{count} team tasks",
14953
+ "detail.tasks.nextPage": "More tasks available; next cursor is {cursor}",
14954
+ "detail.locations.count": "{count} locations",
14955
+ "detail.location": "Line {line}, column {column}",
14956
+ "detail.receipt.delivered": "Message delivered",
14957
+ "detail.receipt.interrupt": "Interrupt requested",
14958
+ "detail.receipt.started": "Started",
14959
+ "detail.receipt.cancel": "Cancellation requested",
14960
+ "detail.receipt.alreadyFinished": "Already finished",
14961
+ "detail.receipt.signal": "Signal delivered",
14962
+ "detail.receipt.closed": "Closed",
14963
+ "detail.receipt.closing": "Closing",
14964
+ "detail.wait.noProgress": "No active teammates",
14965
+ "detail.wait.title": "Teammate activity",
14966
+ "detail.wait.timeout": "Wait timed out",
14967
+ "detail.wait.changed": "Change detected",
14968
+ "detail.agent.reply": "Agent response",
14969
+ "detail.models.title": "Available models",
14970
+ "detail.output.lines": "Lines {begin}–{end} of {total}",
14971
+ "detail.output.truncated": "Output truncated",
14972
+ "detail.providers.count": "{count} inspect providers",
14973
+ "detail.plugins.count": "{count} dynamic plugins",
14974
+ "detail.workflow.script": "Workflow script",
14975
+ "detail.ralph.reportedComplete": "Worker reported completion",
14976
+ "detail.ralph.reportedBlocker": "Worker reported a blocker",
14977
+ "detail.ralph.limit": "Round limit reached",
14978
+ "detail.report.nextSteps": "Remaining work",
14979
+ "detail.trace.replacedBy": "Replaced by",
14980
+ "detail.trace.replacementChain": "Replacement chain",
14981
+ "detail.trace.replaces": "Replaced events",
14982
+ "detail.trace.sources": "Source events",
14983
+ "detail.trace.derived": "Derived events",
14984
+ "detail.trace.ancestors": "Ancestor sessions",
14985
+ "detail.trace.descendants": "Descendant sessions",
14986
+ "detail.matches.count": "{count} matches",
14987
+ "detail.matches.capped": "Result limit reached; narrow the search for more",
14988
+ "detail.event.neighbors": "Surrounding events",
14114
14989
  "todo.completed": "{done}/{total} completed",
14115
14990
  "command.attachmentsUnsupported": "/{command} does not accept attachments; remove them first",
14116
14991
  "ask.rowTitle": "Ask question",
@@ -14150,8 +15025,6 @@ window.__ModuleLoader__.load({
14150
15025
  "tool.autoReviewRejected": "Rejected by Auto review",
14151
15026
  "tool.autoReviewNotExecuted": "Tool was not executed. Reason: {reason}",
14152
15027
  "tool.autoReviewReasonFallback": "Auto review did not authorize this action",
14153
- "diff.files.one": "{count} file",
14154
- "diff.files.other": "{count} files",
14155
15028
  "diff.collapseAria": "Collapse diff",
14156
15029
  "diff.expandAria": "Expand {count} more diff lines",
14157
15030
  "diff.expandRest": "… {count} more lines",
@@ -14202,7 +15075,7 @@ window.__ModuleLoader__.load({
14202
15075
  };
14203
15076
  //#endregion
14204
15077
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-conversation/src/client/queue/QueueDock.module.css.mjs
14205
- const css$6 = "._7yHdaG_dock{box-sizing:border-box;width:calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));max-width:calc(var(--dsh-composer-card-max-width) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));margin:0 auto calc(0px - var(--dsh-composer-stack-gap) - 3px);padding:0 var(--dsh-composer-dock-inset);flex:none}._7yHdaG_panel{background:var(--dsw-specific-tip);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px 12px 0 0;width:100%;padding:2px 0;position:relative;overflow:hidden}._7yHdaG_panel:after{border:.5px solid var(--dsw-alias-border-l1);border-radius:inherit;content:\"\";pointer-events:none;border-bottom:none;position:absolute;inset:0}._7yHdaG_header{box-sizing:border-box;width:100%;height:36px;color:var(--dsw-alias-label-primary);text-align:left;cursor:pointer;background:0 0;border:none;border-radius:8px;align-items:center;gap:10px;padding:4px 12px;display:flex}._7yHdaG_header:focus-visible{outline:2px solid var(--dsw-alias-label-tertiary);outline-offset:-2px}._7yHdaG_header:disabled{cursor:default}._7yHdaG_lead{color:var(--dsw-alias-label-tertiary);flex:none;place-items:center;display:grid}._7yHdaG_count{min-width:0;font-family:Inter, var(--dsw-font-family);flex:auto;font-size:13px;font-weight:500;line-height:24px}._7yHdaG_chevron{width:14px;height:14px;color:var(--dsw-alias-label-tertiary);flex:none;place-items:center;display:grid}._7yHdaG_list{max-height:180px;margin:0;padding:0;list-style:none;overflow-y:auto}._7yHdaG_row{box-sizing:border-box;border-radius:8px;align-items:center;gap:10px;width:100%;height:36px;padding:4px 5px 4px 12px;display:flex}._7yHdaG_row+._7yHdaG_row{box-shadow:inset 0 1px 0 var(--dsw-alias-border-l1)}._7yHdaG_attachments{flex:none;gap:4px;min-width:0;max-width:55%;display:flex;overflow:hidden}._7yHdaG_pendingRow ._7yHdaG_attachments{flex-shrink:1}._7yHdaG_file{border:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);box-sizing:border-box;border-radius:6px;flex:0 180px;align-items:center;gap:4px;min-width:74px;height:24px;padding:0 6px;display:inline-flex;overflow:hidden}._7yHdaG_fileIcon{flex:none;width:16px;height:16px;display:inline-flex}._7yHdaG_fileName{min-width:0;color:var(--dsw-alias-label-primary-dimmed);font:var(--dsw-font-xs-13);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}._7yHdaG_fileSize{color:var(--dsw-alias-label-tertiary);white-space:nowrap;flex:none;font-size:10px}._7yHdaG_thumb{border:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);object-fit:cover;border-radius:4px;width:24px;height:24px}._7yHdaG_preview,._7yHdaG_editor{min-width:0;font:var(--dsw-font-xs-13);font-family:Inter, var(--dsw-font-family);flex:auto}._7yHdaG_preview{color:var(--dsw-alias-label-primary-dimmed);text-overflow:ellipsis;white-space:nowrap;word-break:break-word;overflow:hidden}._7yHdaG_editor{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-base);height:28px;color:var(--dsw-alias-label-primary);border-radius:6px;outline:none;padding:0 8px}._7yHdaG_editor:focus{border-color:var(--dsw-alias-state-business-primary)}._7yHdaG_actions{flex:none;align-items:center;gap:10px;display:flex}._7yHdaG_status{color:var(--dsw-alias-label-tertiary);font:var(--dsw-font-xs-13);white-space:nowrap;flex:none}._7yHdaG_action{corner-shape:round;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:999px;flex:none;place-items:center;padding:0;display:grid}._7yHdaG_action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}._7yHdaG_action:focus-visible{outline:2px solid var(--dsw-alias-label-tertiary);outline-offset:-2px}._7yHdaG_action:disabled{cursor:default;opacity:.45}";
15078
+ const css$6 = "._7yHdaG_dock{box-sizing:border-box;width:calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));max-width:calc(var(--dsh-composer-card-max-width) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));margin:0 auto calc(0px - var(--dsh-composer-stack-gap) - 3px);padding:0 var(--dsh-composer-dock-inset);flex:none}._7yHdaG_panel{isolation:isolate;--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px 12px 0 0;width:100%;padding:2px 0;position:relative;overflow:hidden}._7yHdaG_panel:before{z-index:-1;border-radius:inherit;background:var(--dsw-specific-menu);backdrop-filter:var(--dsw-menu-backdrop-filter);content:\"\";pointer-events:none;position:absolute;inset:0}._7yHdaG_panel:after{border:.5px solid var(--dsw-alias-border-l1);border-radius:inherit;content:\"\";pointer-events:none;border-bottom:none;position:absolute;inset:0}._7yHdaG_header{box-sizing:border-box;width:100%;height:36px;color:var(--dsw-alias-label-primary);text-align:left;cursor:pointer;background:0 0;border:none;border-radius:8px;align-items:center;gap:10px;padding:4px 12px;display:flex}._7yHdaG_header:focus-visible{outline:2px solid var(--dsw-alias-label-tertiary);outline-offset:-2px}._7yHdaG_header:disabled{cursor:default}._7yHdaG_lead{color:var(--dsw-alias-label-tertiary);flex:none;place-items:center;display:grid}._7yHdaG_count{min-width:0;font-family:Inter, var(--dsw-font-family);flex:auto;font-size:13px;font-weight:500;line-height:24px}._7yHdaG_chevron{width:14px;height:14px;color:var(--dsw-alias-label-tertiary);flex:none;place-items:center;display:grid}._7yHdaG_list{max-height:180px;margin:0;padding:0;list-style:none;overflow-y:auto}._7yHdaG_row{box-sizing:border-box;border-radius:8px;align-items:center;gap:10px;width:100%;min-height:36px;padding:4px 5px 4px 12px;display:flex}._7yHdaG_row+._7yHdaG_row{box-shadow:inset 0 1px 0 var(--dsw-alias-border-l1)}._7yHdaG_attachments{flex:none;gap:4px;min-width:0;max-width:55%;display:flex;overflow:hidden}._7yHdaG_pendingRow ._7yHdaG_attachments{flex-shrink:1}._7yHdaG_file{border:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);box-sizing:border-box;border-radius:6px;flex:0 180px;align-items:center;gap:4px;min-width:74px;height:24px;padding:0 6px;display:inline-flex;overflow:hidden}._7yHdaG_fileIcon{flex:none;width:16px;height:16px;display:inline-flex}._7yHdaG_fileName{min-width:0;color:var(--dsw-alias-label-primary-dimmed);font:var(--dsw-font-xs-13);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}._7yHdaG_fileSize{color:var(--dsw-alias-label-tertiary);white-space:nowrap;flex:none;font-size:10px}._7yHdaG_thumb{border:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);object-fit:cover;border-radius:4px;width:24px;height:24px}._7yHdaG_preview,._7yHdaG_editor{min-width:0;font:var(--dsw-font-xs-13);font-family:Inter, var(--dsw-font-family);flex:auto}._7yHdaG_preview{color:var(--dsw-alias-label-primary-dimmed);text-overflow:ellipsis;white-space:nowrap;word-break:break-word;overflow:hidden}._7yHdaG_editor{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-base);min-height:28px;max-height:127px;color:var(--dsw-alias-label-primary);resize:none;border-radius:6px;outline:none;padding:3px 8px;overflow-y:auto}._7yHdaG_editor:focus{border-color:var(--dsw-alias-state-business-primary)}._7yHdaG_actions{flex:none;align-items:center;gap:10px;display:flex}._7yHdaG_status{color:var(--dsw-alias-label-tertiary);font:var(--dsw-font-xs-13);white-space:nowrap;flex:none}._7yHdaG_action{corner-shape:round;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:999px;flex:none;place-items:center;padding:0;display:grid}._7yHdaG_action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}._7yHdaG_action:focus-visible{outline:2px solid var(--dsw-alias-label-tertiary);outline-offset:-2px}._7yHdaG_action:disabled{cursor:default;opacity:.45}";
14206
15079
  const tagId$6 = "@deepseek-ai/dsh-client-ui-conversation/QueueDock.module.css";
14207
15080
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$6) + "]") === null) {
14208
15081
  const tag = document.createElement("style");
@@ -14321,13 +15194,55 @@ window.__ModuleLoader__.load({
14321
15194
  });
14322
15195
  }
14323
15196
  /**
15197
+ * Inline editor for one queued row. A textarea rather than an input: HTML
15198
+ * strips newlines from single-line input values, so editing a multi-line
15199
+ * queued message through one rewrites it as a single line. It grows with its
15200
+ * content up to the CSS cap, then scrolls. Enter saves, Shift+Enter breaks the
15201
+ * line, Escape cancels.
15202
+ */
15203
+ function QueueEditor({ text, label, onChange, onSave, onCancel }) {
15204
+ const ref = (0, react.useRef)(null);
15205
+ (0, react.useLayoutEffect)(() => {
15206
+ const node = ref.current;
15207
+ /* v8 ignore next -- the ref is attached before layout effects run. */
15208
+ if (node === null) return;
15209
+ node.style.height = "auto";
15210
+ node.style.height = `${node.scrollHeight + node.offsetHeight - node.clientHeight}px`;
15211
+ }, [text]);
15212
+ return (0, react_jsx_runtime.jsx)("textarea", {
15213
+ ref,
15214
+ autoFocus: true,
15215
+ rows: 1,
15216
+ className: QueueDock_module_css_default.editor,
15217
+ "aria-label": label,
15218
+ value: text,
15219
+ onChange: (event) => {
15220
+ onChange(event.currentTarget.value);
15221
+ },
15222
+ onKeyDown: (event) => {
15223
+ if (event.key === "Escape") {
15224
+ onCancel();
15225
+ return;
15226
+ }
15227
+ if (event.key !== "Enter" || event.shiftKey || event.nativeEvent.isComposing) return;
15228
+ event.preventDefault();
15229
+ onSave();
15230
+ }
15231
+ });
15232
+ }
15233
+ /**
14324
15234
  * Queue strip: one item renders directly; multiple items default to a
14325
- * collapsible count header; an empty queue renders nothing. Local submissions
15235
+ * collapsible count header; an empty queue renders nothing. Local queued submissions
14326
15236
  * show sending status and disabled actions until their Host queue rows arrive.
14327
15237
  */
14328
15238
  function QueueDock({ useSession, useProjection, updateQueue, notify, loadImage, t }) {
14329
- const queue = useProjection("inbox")?.["next-turn"] ?? EMPTY_QUEUE;
15239
+ const inbox = useProjection("inbox");
14330
15240
  const pendingSubmissions = useSession((s) => s.pendingSubmissions);
15241
+ const queue = (0, react.useMemo)(() => {
15242
+ const rows = inbox?.["next-turn"] ?? EMPTY_QUEUE;
15243
+ const inChat = new Set(pendingSubmissions.filter((item) => item.placement === "transcript").map((item) => item.requestId));
15244
+ return inChat.size === 0 ? rows : rows.filter(({ source }) => source.kind !== "user" || !("rpcId" in source) || !inChat.has(source.rpcId));
15245
+ }, [inbox, pendingSubmissions]);
14331
15246
  const pendingQueue = (0, react.useMemo)(() => {
14332
15247
  const admitted = new Set(queue.flatMap(({ source }) => source.kind === "user" && "rpcId" in source ? [source.rpcId] : []));
14333
15248
  return pendingSubmissions.filter((submission) => submission.placement === "queued" && !admitted.has(submission.requestId));
@@ -14393,7 +15308,7 @@ window.__ModuleLoader__.load({
14393
15308
  (0, react_jsx_runtime.jsx)("span", {
14394
15309
  className: QueueDock_module_css_default.lead,
14395
15310
  "aria-hidden": true,
14396
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconQueueOutline14, {})
15311
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconQueueOutlineRegular, {})
14397
15312
  }),
14398
15313
  (0, react_jsx_runtime.jsx)("span", {
14399
15314
  className: QueueDock_module_css_default.count,
@@ -14407,7 +15322,7 @@ window.__ModuleLoader__.load({
14407
15322
  (0, react_jsx_runtime.jsx)("span", {
14408
15323
  className: QueueDock_module_css_default.chevron,
14409
15324
  "aria-hidden": true,
14410
- children: expanded ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {}) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, {})
15325
+ children: expanded ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {}) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutlineRegular, {})
14411
15326
  })
14412
15327
  ]
14413
15328
  }), (0, react_jsx_runtime.jsxs)("ul", {
@@ -14423,28 +15338,22 @@ window.__ModuleLoader__.load({
14423
15338
  rowCount === 1 && (0, react_jsx_runtime.jsx)("span", {
14424
15339
  className: QueueDock_module_css_default.lead,
14425
15340
  "aria-hidden": true,
14426
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconQueueOutline14, {})
15341
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconQueueOutlineRegular, {})
14427
15342
  }),
14428
- editing?.id === row.id ? (0, react_jsx_runtime.jsx)("input", {
14429
- autoFocus: true,
14430
- className: QueueDock_module_css_default.editor,
14431
- "aria-label": t("queue.edit"),
14432
- value: editing.text,
14433
- onChange: (event) => {
15343
+ editing?.id === row.id ? (0, react_jsx_runtime.jsx)(QueueEditor, {
15344
+ text: editing.text,
15345
+ label: t("queue.edit"),
15346
+ onChange: (text) => {
14434
15347
  setEditing({
14435
15348
  id: row.id,
14436
- text: event.currentTarget.value
15349
+ text
14437
15350
  });
14438
15351
  },
14439
- onKeyDown: (event) => {
14440
- if (event.key === "Escape") {
14441
- setEditing(null);
14442
- return;
14443
- }
14444
- if (event.key === "Enter" && !event.nativeEvent.isComposing) {
14445
- event.preventDefault();
14446
- saveEdit();
14447
- }
15352
+ onSave: () => {
15353
+ saveEdit();
15354
+ },
15355
+ onCancel: () => {
15356
+ setEditing(null);
14448
15357
  }
14449
15358
  }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [attachments.length > 0 && (0, react_jsx_runtime.jsx)("span", {
14450
15359
  className: QueueDock_module_css_default.attachments,
@@ -14474,7 +15383,7 @@ window.__ModuleLoader__.load({
14474
15383
  onClick: () => {
14475
15384
  saveEdit();
14476
15385
  },
14477
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutline16, { size: 14 })
15386
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular, { size: 14 })
14478
15387
  })
14479
15388
  }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
14480
15389
  label: t("queue.cancelEdit"),
@@ -14488,7 +15397,7 @@ window.__ModuleLoader__.load({
14488
15397
  onClick: () => {
14489
15398
  setEditing(null);
14490
15399
  },
14491
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
15400
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutlineRegular, { size: 14 })
14492
15401
  })
14493
15402
  })] }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
14494
15403
  (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
@@ -14508,7 +15417,7 @@ window.__ModuleLoader__.load({
14508
15417
  text
14509
15418
  });
14510
15419
  },
14511
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, { size: 14 })
15420
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutlineRegular, { size: 14 })
14512
15421
  })
14513
15422
  }),
14514
15423
  (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
@@ -14523,7 +15432,7 @@ window.__ModuleLoader__.load({
14523
15432
  onClick: () => {
14524
15433
  applyAction(row.id, { kind: "remove" }, t("queue.removeFailed"));
14525
15434
  },
14526
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 14 })
15435
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineRegular, { size: 14 })
14527
15436
  })
14528
15437
  }),
14529
15438
  (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
@@ -14540,7 +15449,7 @@ window.__ModuleLoader__.load({
14540
15449
  onClick: () => {
14541
15450
  applyAction(row.id, { kind: "steer" }, t("queue.steerFailed"));
14542
15451
  },
14543
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSendOutline14, {})
15452
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSendOutlineRegular, {})
14544
15453
  })
14545
15454
  })
14546
15455
  ] })
@@ -14555,7 +15464,7 @@ window.__ModuleLoader__.load({
14555
15464
  rowCount === 1 && (0, react_jsx_runtime.jsx)("span", {
14556
15465
  className: QueueDock_module_css_default.lead,
14557
15466
  "aria-hidden": true,
14558
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconQueueOutline14, {})
15467
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconQueueOutlineRegular, {})
14559
15468
  }),
14560
15469
  submission.attachments.length > 0 && (0, react_jsx_runtime.jsx)("span", {
14561
15470
  className: QueueDock_module_css_default.attachments,
@@ -14586,7 +15495,7 @@ window.__ModuleLoader__.load({
14586
15495
  "aria-label": t("queue.edit"),
14587
15496
  title: t("queue.sending"),
14588
15497
  disabled: true,
14589
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, { size: 14 })
15498
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutlineRegular, { size: 14 })
14590
15499
  }),
14591
15500
  (0, react_jsx_runtime.jsx)("button", {
14592
15501
  type: "button",
@@ -14594,7 +15503,7 @@ window.__ModuleLoader__.load({
14594
15503
  "aria-label": t("queue.remove"),
14595
15504
  title: t("queue.sending"),
14596
15505
  disabled: true,
14597
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 14 })
15506
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineRegular, { size: 14 })
14598
15507
  }),
14599
15508
  (0, react_jsx_runtime.jsx)("button", {
14600
15509
  type: "button",
@@ -14602,7 +15511,7 @@ window.__ModuleLoader__.load({
14602
15511
  "aria-label": t("queue.steer"),
14603
15512
  title: t("queue.sending"),
14604
15513
  disabled: true,
14605
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSendOutline14, {})
15514
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSendOutlineRegular, {})
14606
15515
  })
14607
15516
  ]
14608
15517
  })
@@ -14717,7 +15626,7 @@ window.__ModuleLoader__.load({
14717
15626
  onClick: () => {
14718
15627
  setOpen((value) => !value);
14719
15628
  },
14720
- children: [t(selectedLabel), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: EnterBehaviorRow_module_css_default.chevron })]
15629
+ children: [t(selectedLabel), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: EnterBehaviorRow_module_css_default.chevron })]
14721
15630
  })
14722
15631
  })]
14723
15632
  });
@@ -14726,7 +15635,10 @@ window.__ModuleLoader__.load({
14726
15635
  //#region lib/types/client/contract/snapshot.js
14727
15636
  /** Empty Conversation value used before a Session binding is available. */
14728
15637
  const EMPTY_CONVERSATION_SNAPSHOT = {
14729
- views: { get: () => void 0 },
15638
+ views: {
15639
+ get: () => void 0,
15640
+ grouped: () => void 0
15641
+ },
14730
15642
  activeTargets: /* @__PURE__ */ new Set()
14731
15643
  };
14732
15644
  /**
@@ -14740,7 +15652,7 @@ window.__ModuleLoader__.load({
14740
15652
  }
14741
15653
  //#endregion
14742
15654
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css.mjs
14743
- const css$4 = ".wSkVaW_root{background:var(--dsw-alias-bg-base);flex-direction:column;min-width:0;height:100%;display:flex;position:relative}.wSkVaW_header{box-sizing:border-box;border-bottom:.5px solid var(--dsw-alias-border-l3);flex:none;min-height:76px;padding:10px 28px 0 20px}.wSkVaW_headerBlank{border-bottom:none;min-height:0}.wSkVaW_headerBlank .wSkVaW_headerCorner{margin-left:auto}[data-platform=darwin] .wSkVaW_titleRow{-webkit-app-region:drag}[data-platform=darwin] .wSkVaW_titleRow button,[data-platform=darwin] .wSkVaW_titleRow a,[data-platform=darwin] .wSkVaW_headerLeading,[data-platform=darwin] .wSkVaW_headerActions,[data-platform=darwin] .wSkVaW_headerUtilities,[data-platform=darwin] .wSkVaW_headerCorner{-webkit-app-region:no-drag}.wSkVaW_titleRow{align-items:center;gap:0;min-height:30px;display:flex}.wSkVaW_titleCluster{flex:1;align-items:center;gap:10px;min-width:0;display:flex}.wSkVaW_headerLeading{flex:none;align-items:center;gap:8px;display:flex}.wSkVaW_headerLeading:empty{display:none}.wSkVaW_crumbs{white-space:nowrap;align-items:center;gap:4px;min-width:0;display:flex;overflow:hidden}.wSkVaW_crumbSeg{align-items:center;gap:4px;min-width:0;display:inline-flex}.wSkVaW_crumbSep{color:var(--dsw-alias-label-caption);font-size:14px;line-height:20px}.wSkVaW_crumb{max-width:220px;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:12px;padding:4px 8px;font-size:14px;line-height:20px;overflow:hidden}.wSkVaW_crumbSubagent{font-size:12px;line-height:18px}.wSkVaW_crumb:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.wSkVaW_crumbCurrent{color:var(--dsw-alias-label-primary);cursor:default;font-weight:500}.wSkVaW_headerActions{flex:none;align-items:center;gap:8px;display:flex}.wSkVaW_headerUtilities{flex:none;align-items:center;gap:8px;margin-left:20px;display:flex}.wSkVaW_headerUtilities:empty{display:none}.wSkVaW_headerCorner{flex:none;align-items:center;margin-left:8px;margin-right:-16px;display:flex}.wSkVaW_headerCorner:empty{display:none}.wSkVaW_tabs{z-index:1;gap:36px;margin-top:10px;padding-left:8px;display:flex;position:relative}.wSkVaW_tab{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;padding:0 0 9px;font-size:13px;font-weight:500;line-height:16px;position:relative}.wSkVaW_tab:after{content:\"\";background:0 0;border-radius:2px;height:2px;position:absolute;bottom:-1px;left:0;right:0}.wSkVaW_tabActive{color:var(--dsw-alias-state-business-primary)}.wSkVaW_tabActive:after{background:var(--dsw-alias-state-business-primary)}.wSkVaW_viewArea{flex-direction:column;flex:1;min-height:0;display:flex}.wSkVaW_widthHandle{z-index:0;width:min(10px, calc((100% - var(--dsh-chat-content-width)) / 2 - 24px - 24px));cursor:col-resize;position:absolute;top:0;bottom:0}.wSkVaW_widthHandle[data-side=left]{right:calc(50% + var(--dsh-chat-content-width) / 2 + 24px)}.wSkVaW_widthHandle[data-side=right]{left:calc(50% + var(--dsh-chat-content-width) / 2 + 24px)}.wSkVaW_widthHandle:after{content:\"\";background:linear-gradient(to bottom, transparent calc(var(--dsh-width-handle-pointer-y,50%) - 36px), var(--dsw-alias-scrollbar-bg-l1) calc(var(--dsh-width-handle-pointer-y,50%) - 8px), var(--dsw-alias-scrollbar-bg-l1) calc(var(--dsh-width-handle-pointer-y,50%) + 8px), transparent calc(var(--dsh-width-handle-pointer-y,50%) + 36px));opacity:0;pointer-events:none;border-radius:2px;width:2px;position:absolute;top:0;bottom:0}.wSkVaW_widthHandle[data-side=left]:after{right:4px}.wSkVaW_widthHandle[data-side=right]:after{left:4px}.wSkVaW_widthHandle:hover:after,.wSkVaW_widthHandle[data-dragging]:after{opacity:1}.wSkVaW_widthHandle[data-dragging]{z-index:8}.wSkVaW_root:has([data-conversation-composer-overlay]) .wSkVaW_widthHandle{display:none}.wSkVaW_composerStack{--dsh-composer-stack-gap:6px;gap:var(--dsh-composer-stack-gap);flex-direction:column;display:flex}.wSkVaW_composerSeat{--dsh-composer-text-max-height:336px;flex-direction:column;flex:none;display:flex}.wSkVaW_root[data-phase=active]{overflow:hidden}.wSkVaW_root[data-phase=active] .wSkVaW_header{flex:none}.wSkVaW_body{--dsh-chat-content-width:var(--dsh-chat-user-width,clamp(680px, calc(var(--dsh-conversation-column-width,0px) * .64), 920px));--dsh-composer-card-max-width:calc(var(--dsh-chat-content-width) + 32px);--dsh-composer-side-clearance:16px;--dsh-composer-dock-inset:8px;flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.wSkVaW_embeddedBody{--dsh-chat-content-width:min(calc(100% - 32px), 920px);--dsh-composer-card-max-width:min(calc(100% - 16px), 952px);--dsh-composer-side-clearance:8px;--dsh-composer-dock-inset:8px;overflow:hidden}.wSkVaW_scrollBody{scrollbar-gutter:stable;flex-direction:column;flex:1;min-height:0;margin-right:2px;display:flex;overflow-y:auto}.wSkVaW_scrollBody::-webkit-scrollbar-track{margin:2px}.wSkVaW_root[data-phase=active] .wSkVaW_viewArea,.wSkVaW_embeddedBody[data-content-phase=active] .wSkVaW_viewArea{flex:1 0 auto;min-height:auto}.wSkVaW_root[data-phase=active] .wSkVaW_composerSeat,.wSkVaW_embeddedBody[data-content-phase=active] .wSkVaW_composerSeat{z-index:7;background:linear-gradient(180deg, color-mix(in srgb, var(--dsw-alias-bg-base) 0%, transparent) 0px, var(--dsw-alias-bg-base) 36px);position:sticky;bottom:0}.wSkVaW_root[data-phase=active] .wSkVaW_composerSeat:has([data-trigger-menu]){z-index:9}.wSkVaW_scrollBody:has([data-conversation-composer-overlay]){scrollbar-gutter:auto;position:relative;overflow:hidden auto}.wSkVaW_scrollBody:has([data-conversation-composer-overlay])>[data-slot=conversation\\.session]>.wSkVaW_viewArea{flex:1 1 0;min-height:0;overflow:hidden}.wSkVaW_scrollBody:has([data-conversation-composer-overlay])>.wSkVaW_composerSeat{right:var(--dsh-scrollbar-width);position:absolute;bottom:0;left:0}.wSkVaW_composerHero{width:min(calc(var(--dsh-composer-card-max-width) + 2 * var(--dsh-composer-side-clearance)), 100%);z-index:1;align-self:center;gap:8px;padding-bottom:32px}.wSkVaW_heroWorkspaceRow{align-items:center;gap:2px;min-width:0;margin-top:4px;padding:0 16px 0 20px;display:flex}.wSkVaW_root[data-phase=hero] .wSkVaW_scrollBody,.wSkVaW_embeddedBody[data-content-phase=hero] .wSkVaW_scrollBody{justify-content:center;overflow-y:auto}.wSkVaW_root[data-phase=settling] .wSkVaW_composerSeat,.wSkVaW_embeddedBody[data-content-phase=settling] .wSkVaW_composerSeat{visibility:hidden}";
15655
+ const css$4 = ".wSkVaW_root{background:var(--dsw-alias-bg-base);flex-direction:column;min-width:0;height:100%;display:flex;position:relative}.wSkVaW_header{box-sizing:border-box;border-bottom:.5px solid var(--dsw-alias-border-l3);flex:none;grid-template-columns:auto minmax(0,1fr);min-height:76px;padding:10px 28px 0 20px;display:grid}.wSkVaW_header:where(:not(:has(.wSkVaW_tabs))){min-height:0;padding-bottom:10px}.wSkVaW_headerBlank{border-bottom:none;min-height:0;padding-bottom:0}.wSkVaW_headerBlank .wSkVaW_headerCorner{margin-left:auto}html:not([data-platform=darwin]) .wSkVaW_headerSessionless{padding-top:0}html:not([data-platform=darwin]) .wSkVaW_headerSessionless .wSkVaW_titleRow{min-height:0}[data-platform=darwin] .wSkVaW_headerLeading,[data-platform=darwin] .wSkVaW_headerActions,[data-platform=darwin] .wSkVaW_headerUtilities,[data-platform=darwin] .wSkVaW_headerCorner{-webkit-app-region:no-drag}.wSkVaW_titleRow{min-height:30px;grid-column:2;align-items:center;gap:0;padding-inline-start:max(0px, calc(var(--dsh-frame-leading-clearance,0px) - 20px));display:flex}.wSkVaW_titleCluster{flex:1;align-items:center;gap:10px;min-width:0;display:flex}.wSkVaW_headerLeading{flex:none;grid-area:1/1;align-items:center;gap:8px;display:flex}.wSkVaW_crumbs{white-space:nowrap;align-items:center;gap:4px;min-width:0;display:flex;overflow:hidden}.wSkVaW_crumbSeg{align-items:center;gap:4px;min-width:0;display:inline-flex}.wSkVaW_crumbSep{color:var(--dsw-alias-label-caption);font-size:14px;line-height:20px}.wSkVaW_crumb{max-width:220px;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:12px;padding:4px 8px;font-size:14px;line-height:20px;display:inline-block;overflow:hidden}.wSkVaW_crumbSubagent{font-size:12px;line-height:18px}button.wSkVaW_crumb:hover{background:var(--dsw-alias-interactive-bg-hover)}.wSkVaW_crumbCurrent{color:var(--dsw-alias-label-primary);cursor:default;font-weight:500}.wSkVaW_headerActions{flex:none;align-items:center;gap:8px;display:flex}.wSkVaW_headerUtilities{flex:none;align-items:center;gap:8px;margin-left:20px;display:flex}.wSkVaW_headerUtilities:empty{display:none}.wSkVaW_headerCorner{flex:none;align-items:center;margin-left:8px;margin-right:-16px;display:flex}.wSkVaW_headerCorner:empty{display:none}.wSkVaW_tabs{z-index:1;grid-column:1/-1;gap:36px;margin-top:10px;padding-left:8px;display:flex;position:relative}.wSkVaW_tab{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;padding:0 0 9px;font-size:13px;font-weight:500;line-height:16px;position:relative}.wSkVaW_tab:after{content:\"\";background:0 0;border-radius:2px;height:2px;position:absolute;bottom:-1px;left:0;right:0}.wSkVaW_tabActive{color:var(--dsw-alias-state-business-primary)}.wSkVaW_tabActive:after{background:var(--dsw-alias-state-business-primary)}.wSkVaW_viewArea{flex-direction:column;flex:1;min-height:0;display:flex}.wSkVaW_widthHandle{z-index:0;width:min(10px, calc((100% - var(--dsh-chat-content-width)) / 2 - 24px - 24px));cursor:col-resize;position:absolute;top:0;bottom:0}.wSkVaW_widthHandle[data-side=left]{right:calc(50% + var(--dsh-chat-content-width) / 2 + 24px)}.wSkVaW_widthHandle[data-side=right]{left:calc(50% + var(--dsh-chat-content-width) / 2 + 24px)}.wSkVaW_widthHandle:after{content:\"\";background:linear-gradient(to bottom, transparent calc(var(--dsh-width-handle-pointer-y,50%) - 36px), var(--dsw-alias-scrollbar-bg-l1) calc(var(--dsh-width-handle-pointer-y,50%) - 8px), var(--dsw-alias-scrollbar-bg-l1) calc(var(--dsh-width-handle-pointer-y,50%) + 8px), transparent calc(var(--dsh-width-handle-pointer-y,50%) + 36px));opacity:0;pointer-events:none;border-radius:2px;width:2px;position:absolute;top:0;bottom:0}.wSkVaW_widthHandle[data-side=left]:after{right:4px}.wSkVaW_widthHandle[data-side=right]:after{left:4px}.wSkVaW_widthHandle:hover:after,.wSkVaW_widthHandle[data-dragging]:after{opacity:1}.wSkVaW_widthHandle[data-dragging]{z-index:8}.wSkVaW_root:has([data-conversation-composer-overlay]) .wSkVaW_widthHandle{display:none}.wSkVaW_composerStack{--dsh-composer-stack-gap:6px;gap:var(--dsh-composer-stack-gap);flex-direction:column;display:flex}.wSkVaW_composerSeat{--dsh-composer-text-max-height:336px;flex-direction:column;flex:none;display:flex}.wSkVaW_root[data-phase=active]{overflow:hidden}.wSkVaW_root[data-phase=active] .wSkVaW_header{flex:none}.wSkVaW_body{--dsh-chat-content-width:var(--dsh-chat-user-width,clamp(680px, calc(var(--dsh-conversation-column-width,0px) * .64), 920px));--dsh-composer-card-max-width:calc(var(--dsh-chat-content-width) + 32px);--dsh-composer-side-clearance:16px;--dsh-composer-dock-inset:8px;flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.wSkVaW_embeddedBody{--dsh-chat-content-width:min(calc(100% - 32px), 920px);--dsh-composer-card-max-width:min(calc(100% - 16px), 952px);--dsh-composer-side-clearance:8px;--dsh-composer-dock-inset:8px;overflow:hidden}.wSkVaW_scrollBody{scrollbar-gutter:stable;flex-direction:column;flex:1;min-height:0;margin-right:2px;display:flex;overflow-y:auto}.wSkVaW_scrollBody::-webkit-scrollbar-track{margin:2px}.wSkVaW_root[data-phase=active] .wSkVaW_viewArea,.wSkVaW_embeddedBody[data-content-phase=active] .wSkVaW_viewArea{flex:1 0 auto;min-height:auto}.wSkVaW_root[data-phase=active] .wSkVaW_composerSeat,.wSkVaW_embeddedBody[data-content-phase=active] .wSkVaW_composerSeat{z-index:7;background:linear-gradient(180deg, color-mix(in srgb, var(--dsw-alias-bg-base) 0%, transparent) 0px, var(--dsw-alias-bg-base) 36px);position:sticky;bottom:0}.wSkVaW_root[data-phase=active] .wSkVaW_composerSeat:has([data-trigger-menu]){z-index:9}.wSkVaW_scrollBody:has([data-conversation-composer-overlay]){scrollbar-gutter:auto;position:relative;overflow:hidden auto}.wSkVaW_scrollBody:has([data-conversation-composer-overlay])>[data-slot=conversation\\.session]>.wSkVaW_viewArea{flex:1 1 0;min-height:0;overflow:hidden}.wSkVaW_scrollBody:has([data-conversation-composer-overlay])>.wSkVaW_composerSeat{right:var(--dsh-scrollbar-width);position:absolute;bottom:0;left:0}.wSkVaW_composerHero{width:min(calc(var(--dsh-composer-card-max-width) + 2 * var(--dsh-composer-side-clearance)), 100%);z-index:1;align-self:center;gap:8px;padding-bottom:32px}.wSkVaW_heroWorkspaceRow{align-items:center;gap:2px;min-width:0;margin-top:4px;padding:0 16px 0 20px;display:flex}.wSkVaW_root[data-phase=hero] .wSkVaW_scrollBody,.wSkVaW_embeddedBody[data-content-phase=hero] .wSkVaW_scrollBody{justify-content:center;overflow-y:auto}.wSkVaW_root[data-phase=settling] .wSkVaW_composerSeat,.wSkVaW_embeddedBody[data-content-phase=settling] .wSkVaW_composerSeat{visibility:hidden}";
14744
15656
  const tagId$4 = "@deepseek-ai/dsh-client-ui-conversation/ConversationRoot.module.css";
14745
15657
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
14746
15658
  const tag = document.createElement("style");
@@ -14766,6 +15678,7 @@ window.__ModuleLoader__.load({
14766
15678
  "headerBlank": "wSkVaW_headerBlank",
14767
15679
  "headerCorner": "wSkVaW_headerCorner",
14768
15680
  "headerLeading": "wSkVaW_headerLeading",
15681
+ "headerSessionless": "wSkVaW_headerSessionless",
14769
15682
  "headerUtilities": "wSkVaW_headerUtilities",
14770
15683
  "heroWorkspaceRow": "wSkVaW_heroWorkspaceRow",
14771
15684
  "root": "wSkVaW_root",
@@ -14813,7 +15726,7 @@ window.__ModuleLoader__.load({
14813
15726
  }
14814
15727
  /** One pointer-captured transcript width handle. */
14815
15728
  function WidthHandle(props) {
14816
- const [dragging, setDragging] = (0, react.useState)(false);
15729
+ const dragging = (0, react.useRef)(false);
14817
15730
  const base = (0, react.useRef)(0);
14818
15731
  const origin = (0, react.useRef)(0);
14819
15732
  const latest = (0, react.useRef)(0);
@@ -14838,12 +15751,14 @@ window.__ModuleLoader__.load({
14838
15751
  origin.current = event.clientX;
14839
15752
  latest.current = event.clientX;
14840
15753
  base.current = callbacks.current.onStart();
14841
- setDragging(true);
15754
+ dragging.current = true;
15755
+ event.currentTarget.toggleAttribute("data-dragging", true);
14842
15756
  }, []);
14843
15757
  const onPointerMove = (0, react.useCallback)((event) => {
15758
+ if (!dragging.current) return;
15759
+ if (!event.currentTarget.hasPointerCapture(event.pointerId)) return;
14844
15760
  const box = event.currentTarget.getBoundingClientRect();
14845
15761
  event.currentTarget.style.setProperty("--dsh-width-handle-pointer-y", `${event.clientY - box.top}px`);
14846
- if (!event.currentTarget.hasPointerCapture(event.pointerId)) return;
14847
15762
  latest.current = event.clientX;
14848
15763
  frame.current ??= requestAnimationFrame(() => {
14849
15764
  frame.current = null;
@@ -14851,17 +15766,21 @@ window.__ModuleLoader__.load({
14851
15766
  });
14852
15767
  }, []);
14853
15768
  const onPointerUp = (0, react.useCallback)((event) => {
15769
+ if (!dragging.current) return;
14854
15770
  if (!event.currentTarget.hasPointerCapture(event.pointerId)) return;
15771
+ dragging.current = false;
15772
+ event.currentTarget.toggleAttribute("data-dragging", false);
14855
15773
  event.currentTarget.releasePointerCapture(event.pointerId);
14856
15774
  cancelFrame();
14857
15775
  latest.current = event.clientX;
14858
15776
  if (latest.current !== origin.current) callbacks.current.onCommit(outwardWidth());
14859
- setDragging(false);
14860
15777
  callbacks.current.onEnd();
14861
15778
  }, []);
14862
- const onPointerCancel = (0, react.useCallback)(() => {
15779
+ const onPointerCancel = (0, react.useCallback)((event) => {
15780
+ if (!dragging.current) return;
15781
+ dragging.current = false;
15782
+ event.currentTarget.toggleAttribute("data-dragging", false);
14863
15783
  cancelFrame();
14864
- setDragging(false);
14865
15784
  callbacks.current.onEnd();
14866
15785
  }, []);
14867
15786
  const onWheel = (0, react.useCallback)((event) => {
@@ -14878,7 +15797,6 @@ window.__ModuleLoader__.load({
14878
15797
  className: ConversationRoot_module_css_default.widthHandle,
14879
15798
  "data-side": props.side,
14880
15799
  "data-width-handle": props.side,
14881
- "data-dragging": dragging || void 0,
14882
15800
  onPointerDown,
14883
15801
  onPointerMove,
14884
15802
  onPointerUp,
@@ -14957,7 +15875,7 @@ window.__ModuleLoader__.load({
14957
15875
  return (0, react_jsx_runtime.jsxs)("div", {
14958
15876
  className: ConversationRoot_module_css_default.root,
14959
15877
  "data-phase": phase,
14960
- children: [sessionId === void 0 ? null : renderSlot("conversation.session.header", {}), renderFactorySlot("conversation.content", {
15878
+ children: [renderSlot("conversation.header", {}), renderFactorySlot("conversation.content", {
14961
15879
  variant: "main",
14962
15880
  phase,
14963
15881
  hero
@@ -14970,19 +15888,6 @@ window.__ModuleLoader__.load({
14970
15888
  return (0, react_jsx_runtime.jsx)(ConversationMainPanel, { ...props });
14971
15889
  }
14972
15890
  //#endregion
14973
- //#region ../../util/workspace-path/src/index.ts
14974
- /**
14975
- * Read the final non-empty segment of a Workspace path for display.
14976
- * Workspace-label surfaces use this helper instead of deriving another basename.
14977
- * @param path - Workspace directory path using POSIX or Windows separators.
14978
- * @returns the final segment, or an empty string for a separator-only path.
14979
- */
14980
- function workspaceTitleOf(path) {
14981
- const trimmed = path.replace(/[/\\]+$/, "");
14982
- const separator = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
14983
- return trimmed.slice(separator + 1);
14984
- }
14985
- //#endregion
14986
15891
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-conversation/src/client/skeleton/HeroShell.module.css.mjs
14987
15892
  const css$3 = ".pXSMma_root{justify-content:center;align-items:center;min-width:0;height:100%;padding:0 24px;display:flex}.pXSMma_stack{width:100%;max-width:var(--dsh-composer-card-max-width);flex-direction:column;align-items:stretch;gap:12px;display:flex;overflow:visible}.pXSMma_headline{color:var(--dsw-alias-label-primary);flex-wrap:wrap;justify-content:center;align-items:center;gap:12px 10px;font-size:26px;font-weight:500;line-height:32px;display:flex}.pXSMma_titleGroup{flex-wrap:wrap;justify-content:center;align-items:center;gap:4px 7px;min-width:0;display:flex}.pXSMma_previewBadge{border:.5px solid var(--dsw-alias-interactive-bg-hover);background:var(--dsw-alias-state-business-tertiary);color:var(--dsw-alias-label-primary-bluish);font-family:var(--ds-font-family-code);white-space:nowrap;border-radius:24px;align-self:flex-start;margin-top:2px;padding:1px 7px 0;font-size:12px;font-weight:500;line-height:18px}.pXSMma_fishHitbox{flex:none;justify-content:center;align-items:center;display:inline-flex}.pXSMma_fish{transform-origin:50% 60%;color:var(--dsw-alias-label-primary);display:block;overflow:visible}@keyframes pXSMma_hero-fish-swim{0%,to{transform:none}35%{transform:rotate(-4deg)translate(-.4px,-.9px)}70%{transform:rotate(1.6deg)translate(.3px,.2px)}}@media (hover:hover) and (prefers-reduced-motion:no-preference){.pXSMma_fishHitbox:hover .pXSMma_fish{animation:1.6s ease-in-out infinite pXSMma_hero-fish-swim}}.pXSMma_body{flex-direction:column;gap:12px;min-width:0;display:flex;position:relative;overflow:visible}.pXSMma_body>*{z-index:1;position:relative}.pXSMma_body>.pXSMma_workspaceRow{z-index:10;align-items:center;min-width:0;padding-left:8px;display:flex}.pXSMma_workspace{max-width:min(100%,360px);min-height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:16px;align-items:center;gap:4px;padding:0 8px;font-size:13px;font-weight:500;line-height:20px;display:inline-flex}.pXSMma_workspace:not(:disabled):hover,.pXSMma_workspace[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover)}.pXSMma_workspace:disabled{cursor:default}.pXSMma_folder{color:var(--dsw-alias-label-primary);flex:none}.pXSMma_workspaceLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.pXSMma_chevron{color:var(--dsw-alias-label-caption);flex:none}.pXSMma_modalInput{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);width:100%;height:44px;color:var(--dsw-alias-label-primary);background:0 0;border-radius:22px;outline:none;padding:7px 14px;font-size:14px;font-weight:400;line-height:22px}.pXSMma_modalInput::placeholder{color:var(--dsw-alias-label-caption)}.pXSMma_modalInput:disabled{color:var(--dsw-alias-label-dimmed)}.pXSMma_modalAction{min-width:72px}.pXSMma_modalError{color:var(--dsw-alias-state-error-primary);margin-top:8px;font-size:12px;line-height:18px}";
14988
15893
  const tagId$3 = "@deepseek-ai/dsh-client-ui-conversation/HeroShell.module.css";
@@ -15045,10 +15950,10 @@ window.__ModuleLoader__.load({
15045
15950
  "aria-expanded": menuOpen,
15046
15951
  onClick,
15047
15952
  children: [
15048
- label === void 0 ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderClose16, {
15953
+ label === void 0 ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderCloseRegular, {
15049
15954
  className: HeroShell_module_css_default.folder,
15050
15955
  size: 16
15051
- }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpen16, {
15956
+ }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpenRegular, {
15052
15957
  className: HeroShell_module_css_default.folder,
15053
15958
  size: 16
15054
15959
  }),
@@ -15056,7 +15961,7 @@ window.__ModuleLoader__.load({
15056
15961
  className: HeroShell_module_css_default.workspaceLabel,
15057
15962
  children: label ?? t("hero.chooseWorkspace")
15058
15963
  }),
15059
- (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {
15964
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {
15060
15965
  className: HeroShell_module_css_default.chevron,
15061
15966
  size: 12
15062
15967
  })
@@ -15289,8 +16194,26 @@ window.__ModuleLoader__.load({
15289
16194
  return renderSlot("main.conversation", {});
15290
16195
  }
15291
16196
  //#endregion
15292
- //#region lib/types/client/view-selection.js
15293
- const DEFAULT_VIEW_ID = "chat";
16197
+ //#region lib/types/client/skeleton/ConversationHeader.js
16198
+ /** Resident conversation navigation and Session-specific header content. */
16199
+ /**
16200
+ * Keeps global navigation available before a Session exists.
16201
+ * @param props - Optional Session sources and authorized header slots.
16202
+ * @returns The persistent header with any selected Session's title and views.
16203
+ */
16204
+ function ConversationHeader({ sessionId, useSession, useConversation, renderSlot }) {
16205
+ const session = useSession((s) => s);
16206
+ const conversation = useConversation((s) => s);
16207
+ const blank = session === void 0 || conversation === void 0 || session.blank && conversationPhase(session, conversation) === "blank";
16208
+ return (0, react_jsx_runtime.jsxs)("header", {
16209
+ className: clsx(ConversationRoot_module_css_default.header, blank && ConversationRoot_module_css_default.headerBlank, sessionId === void 0 && ConversationRoot_module_css_default.headerSessionless),
16210
+ children: [(0, react_jsx_runtime.jsx)("div", {
16211
+ className: ConversationRoot_module_css_default.headerLeading,
16212
+ "data-conversation-header-leading": "",
16213
+ children: renderSlot("conversation.header.leading", {})
16214
+ }), sessionId === void 0 ? (0, react_jsx_runtime.jsx)("div", { className: ConversationRoot_module_css_default.titleRow }) : renderSlot("conversation.session.header", { hideChrome: blank })]
16215
+ });
16216
+ }
15294
16217
  /**
15295
16218
  * Resolve a preferred registered View, then Chat, without choosing another View.
15296
16219
  * @param tabs - currently registered Views.
@@ -15298,7 +16221,7 @@ window.__ModuleLoader__.load({
15298
16221
  * @returns the selected View, Chat fallback, or undefined when neither is registered.
15299
16222
  */
15300
16223
  function resolveActiveView(tabs, selectedId) {
15301
- return (selectedId === null ? void 0 : tabs.find((view) => view.id === selectedId)) ?? tabs.find((view) => view.id === DEFAULT_VIEW_ID);
16224
+ return (selectedId === null ? void 0 : tabs.find((view) => view.id === selectedId)) ?? tabs.find((view) => view.id === "chat");
15302
16225
  }
15303
16226
  //#endregion
15304
16227
  //#region lib/types/client/skeleton/DefaultConversationViews.js
@@ -15308,8 +16231,10 @@ window.__ModuleLoader__.load({
15308
16231
  * @param props - Strict Session input/store, view ledger, and render shares.
15309
16232
  * @returns the active view area, or null while the Session remains blank.
15310
16233
  */
15311
- function DefaultConversationViews({ view, useSession, useConversation, useConversationViews, useInput, inputActions, useStore, actions, renderSlot, bindDraftMirror, openView }) {
15312
- const active = resolveActiveView(useConversationViews((value) => value), useStore((s) => s.view));
16234
+ function DefaultConversationViews({ view, useSession, useConversation, useConversationViews, useInput, inputActions, useStore, actions, renderSlot, bindDraftMirror, openView, useInspectCall }) {
16235
+ const tabs = useConversationViews((value) => value);
16236
+ const inspectCall = useInspectCall((value) => value);
16237
+ const active = resolveActiveView(tabs, useStore((s) => s.view));
15313
16238
  const session = useSession((s) => s);
15314
16239
  const conversation = useConversation((s) => s);
15315
16240
  const inputState = useInput((s) => s);
@@ -15327,6 +16252,7 @@ window.__ModuleLoader__.load({
15327
16252
  return (0, react_jsx_runtime.jsx)("div", {
15328
16253
  className: ConversationRoot_module_css_default.viewArea,
15329
16254
  children: viewId !== void 0 && renderSlot("conversation.view", {
16255
+ inspectCall,
15330
16256
  viewRequest,
15331
16257
  openView,
15332
16258
  completeViewRequest: actions.completeViewRequest
@@ -15366,87 +16292,77 @@ window.__ModuleLoader__.load({
15366
16292
  * @param props - Strict Session store, view ledger, navigation, render, and locale shares.
15367
16293
  * @returns Session navigation controls, with title and tabs after conversation starts.
15368
16294
  */
15369
- function ConversationSessionHeader({ sessionId, useSession, useSessions, useConversation, useConversationViews, useStore, renderSlot, open, selectView, t }) {
16295
+ function ConversationSessionHeader({ sessionId, hideChrome, useSessions, useConversationViews, useStore, renderSlot, open, selectView, t }) {
15370
16296
  const tabs = useConversationViews((value) => value);
15371
16297
  const active = resolveActiveView(tabs, useStore((s) => s.view));
15372
16298
  const ancestry = useSessions((s) => deriveAncestry(s, sessionId), equalBreadcrumbs);
15373
- const session = useSession((s) => s);
15374
- const conversation = useConversation((s) => s);
15375
- const hideChrome = session.blank && conversationPhase(session, conversation) === "blank";
15376
- return (0, react_jsx_runtime.jsxs)("header", {
15377
- className: clsx(ConversationRoot_module_css_default.header, hideChrome && ConversationRoot_module_css_default.headerBlank),
15378
- children: [(0, react_jsx_runtime.jsxs)("div", {
15379
- className: ConversationRoot_module_css_default.titleRow,
15380
- children: [
15381
- (0, react_jsx_runtime.jsx)("div", {
15382
- className: ConversationRoot_module_css_default.headerLeading,
15383
- "data-conversation-header-leading": "",
15384
- children: renderSlot("conversation.session.header.leading", {})
15385
- }),
15386
- !hideChrome && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
15387
- className: ConversationRoot_module_css_default.titleCluster,
15388
- children: [(0, react_jsx_runtime.jsxs)("nav", {
15389
- className: ConversationRoot_module_css_default.crumbs,
15390
- "aria-label": t("session.hierarchy"),
15391
- children: [ancestry.map((summary, index) => {
15392
- const last = index === ancestry.length - 1;
15393
- const title = (0, react_jsx_runtime.jsx)("button", {
15394
- type: "button",
15395
- className: clsx(ConversationRoot_module_css_default.crumb, summary.subagent && ConversationRoot_module_css_default.crumbSubagent, last && ConversationRoot_module_css_default.crumbCurrent),
15396
- disabled: last,
15397
- onClick: () => {
15398
- open(summary.id);
15399
- },
15400
- children: summary.displayTitle
15401
- });
15402
- const lineage = last || summary.subagent;
15403
- const lineageOwner = {
15404
- lineageSessionId: summary.id,
15405
- displayTitle: summary.displayTitle,
15406
- ...last ? {} : { openTitle: () => {
15407
- open(summary.id);
15408
- } }
15409
- };
15410
- return (0, react_jsx_runtime.jsxs)("span", {
15411
- className: ConversationRoot_module_css_default.crumbSeg,
15412
- children: [index > 0 && (0, react_jsx_runtime.jsx)("span", {
15413
- className: ConversationRoot_module_css_default.crumbSep,
15414
- children: "/"
15415
- }), lineage ? summary.subagent ? renderSlot("conversation.session.header.lineage", lineageOwner, { fallback: title }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [title, renderSlot("conversation.session.header.lineage", lineageOwner, { fallback: null })] }) : title]
15416
- }, summary.id);
15417
- }), ancestry.length === 0 && (0, react_jsx_runtime.jsx)("span", {
15418
- className: ConversationRoot_module_css_default.crumbCurrent,
15419
- children: sessionId
15420
- })]
15421
- }), (0, react_jsx_runtime.jsx)("div", {
15422
- className: ConversationRoot_module_css_default.headerActions,
15423
- children: renderSlot("conversation.session.header.actions", {})
15424
- })]
15425
- }), (0, react_jsx_runtime.jsx)("div", {
15426
- className: ConversationRoot_module_css_default.headerUtilities,
15427
- children: renderSlot("conversation.session.header.utilities", {})
15428
- })] }),
15429
- (0, react_jsx_runtime.jsx)("div", {
15430
- className: ConversationRoot_module_css_default.headerCorner,
15431
- "data-conversation-header-corner": "",
15432
- children: renderSlot("conversation.session.header.corner", {})
15433
- })
15434
- ]
15435
- }), !hideChrome && tabs.length > 1 && (0, react_jsx_runtime.jsx)("div", {
15436
- className: ConversationRoot_module_css_default.tabs,
15437
- role: "tablist",
15438
- children: tabs.map((viewTab) => (0, react_jsx_runtime.jsx)("button", {
15439
- type: "button",
15440
- role: "tab",
15441
- "aria-selected": viewTab.id === active?.id,
15442
- className: clsx(ConversationRoot_module_css_default.tab, viewTab.id === active?.id && ConversationRoot_module_css_default.tabActive),
15443
- onClick: () => {
15444
- selectView(viewTab.id);
15445
- },
15446
- children: viewTab.label
15447
- }, viewTab.id))
16299
+ const showTabs = !hideChrome && tabs.length > 1;
16300
+ return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
16301
+ className: ConversationRoot_module_css_default.titleRow,
16302
+ children: [!hideChrome && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
16303
+ className: ConversationRoot_module_css_default.titleCluster,
16304
+ children: [(0, react_jsx_runtime.jsxs)("nav", {
16305
+ className: ConversationRoot_module_css_default.crumbs,
16306
+ "aria-label": t("session.hierarchy"),
16307
+ children: [ancestry.map((summary, index) => {
16308
+ const last = index === ancestry.length - 1;
16309
+ const title = last ? (0, react_jsx_runtime.jsx)("span", {
16310
+ className: clsx(ConversationRoot_module_css_default.crumb, summary.subagent && ConversationRoot_module_css_default.crumbSubagent, ConversationRoot_module_css_default.crumbCurrent),
16311
+ children: summary.displayTitle
16312
+ }) : (0, react_jsx_runtime.jsx)("button", {
16313
+ type: "button",
16314
+ className: clsx(ConversationRoot_module_css_default.crumb, summary.subagent && ConversationRoot_module_css_default.crumbSubagent),
16315
+ onClick: () => {
16316
+ open(summary.id);
16317
+ },
16318
+ children: summary.displayTitle
16319
+ });
16320
+ const lineage = last || summary.subagent;
16321
+ const lineageOwner = {
16322
+ lineageSessionId: summary.id,
16323
+ displayTitle: summary.displayTitle,
16324
+ ...last ? {} : { openTitle: () => {
16325
+ open(summary.id);
16326
+ } }
16327
+ };
16328
+ return (0, react_jsx_runtime.jsxs)("span", {
16329
+ className: ConversationRoot_module_css_default.crumbSeg,
16330
+ children: [index > 0 && (0, react_jsx_runtime.jsx)("span", {
16331
+ className: ConversationRoot_module_css_default.crumbSep,
16332
+ children: "/"
16333
+ }), lineage ? summary.subagent ? renderSlot("conversation.session.header.lineage", lineageOwner, { fallback: title }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [title, renderSlot("conversation.session.header.lineage", lineageOwner, { fallback: null })] }) : title]
16334
+ }, summary.id);
16335
+ }), ancestry.length === 0 && (0, react_jsx_runtime.jsx)("span", {
16336
+ className: ConversationRoot_module_css_default.crumbCurrent,
16337
+ children: sessionId
16338
+ })]
16339
+ }), (0, react_jsx_runtime.jsx)("div", {
16340
+ className: ConversationRoot_module_css_default.headerActions,
16341
+ children: renderSlot("conversation.session.header.actions", {})
16342
+ })]
16343
+ }), (0, react_jsx_runtime.jsx)("div", {
16344
+ className: ConversationRoot_module_css_default.headerUtilities,
16345
+ children: renderSlot("conversation.session.header.utilities", {})
16346
+ })] }), (0, react_jsx_runtime.jsx)("div", {
16347
+ className: ConversationRoot_module_css_default.headerCorner,
16348
+ "data-conversation-header-corner": "",
16349
+ children: renderSlot("conversation.session.header.corner", {})
15448
16350
  })]
15449
- });
16351
+ }), showTabs && (0, react_jsx_runtime.jsx)("div", {
16352
+ className: ConversationRoot_module_css_default.tabs,
16353
+ role: "tablist",
16354
+ "data-conversation-tabs": "",
16355
+ children: tabs.map((viewTab) => (0, react_jsx_runtime.jsx)("button", {
16356
+ type: "button",
16357
+ role: "tab",
16358
+ "aria-selected": viewTab.id === active?.id,
16359
+ className: clsx(ConversationRoot_module_css_default.tab, viewTab.id === active?.id && ConversationRoot_module_css_default.tabActive),
16360
+ onClick: () => {
16361
+ selectView(viewTab.id);
16362
+ },
16363
+ children: viewTab.label
16364
+ }, viewTab.id))
16365
+ })] });
15450
16366
  }
15451
16367
  /**
15452
16368
  * Renders the active Session view inside the resident scrollport and keeps
@@ -15639,8 +16555,16 @@ window.__ModuleLoader__.load({
15639
16555
  }, 4), editor.registerCommand(Je$2, (event) => {
15640
16556
  const clipboardData = event.clipboardData ?? null;
15641
16557
  if (clipboardData === null) return false;
15642
- const files = Array.from(clipboardData.items).filter((item) => item.kind === "file").map((item) => item.getAsFile()).filter((file) => file !== null);
15643
- if (files.length > 0) handlers.intakeFiles(files);
16558
+ const files = [];
16559
+ const directories = /* @__PURE__ */ new Set();
16560
+ for (const item of clipboardData.items) {
16561
+ if (item.kind !== "file") continue;
16562
+ const file = item.getAsFile();
16563
+ if (file === null) continue;
16564
+ files.push(file);
16565
+ if (typeof item.webkitGetAsEntry === "function" && item.webkitGetAsEntry()?.isDirectory === true) directories.add(file);
16566
+ }
16567
+ if (files.length > 0) handlers.intakeFiles(files, directories.size === 0 ? void 0 : directories);
15644
16568
  const text = clipboardData.getData("text/plain");
15645
16569
  if (text === "") {
15646
16570
  if (files.length === 0) return false;
@@ -15752,8 +16676,8 @@ window.__ModuleLoader__.load({
15752
16676
  }
15753
16677
  keyboard.submit(resolveSubmitMode(g.busyEnter, g.running, accelerated ? "accelerated" : "enter", g.steeringAvailable));
15754
16678
  },
15755
- intakeFiles: (files) => {
15756
- gate.current.intakeFiles(files);
16679
+ intakeFiles: (files, directories) => {
16680
+ gate.current.intakeFiles(files, directories);
15757
16681
  },
15758
16682
  pasteText: (text) => {
15759
16683
  if (gate.current.machineBusy || gate.current.locked) return;
@@ -15834,7 +16758,7 @@ window.__ModuleLoader__.load({
15834
16758
  }
15835
16759
  //#endregion
15836
16760
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-conversation/src/client/skeleton/ContextMeter.module.css.mjs
15837
- const css$2 = ".JObwrW_root{flex:none;display:inline-flex}.JObwrW_trigger{color:var(--dsw-alias-label-tertiary);font-family:inherit;font-size:var(--dsh-content-font-size-secondary,13px);font-variant-numeric:tabular-nums;line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:24px;flex:none;align-items:center;gap:6px;padding:1px 8px;display:inline-flex}.JObwrW_trigger:hover,.JObwrW_trigger[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.JObwrW_track{fill:none;stroke:var(--dsw-alias-border-l3);stroke-width:2px}.JObwrW_fill{fill:none;stroke:var(--dsw-alias-label-tertiary);stroke-width:2px;stroke-linecap:round}.JObwrW_panel{z-index:1100;box-sizing:border-box;background:var(--dsw-specific-menu);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);width:min(264px,100vw - 24px);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-secondary);cursor:default;border:0;border-radius:12px;padding:12px;font-size:12px;line-height:20px;position:fixed}.JObwrW_header{align-items:center;gap:6px;display:flex}.JObwrW_figures{font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-primary);margin-left:auto;font-weight:500}.JObwrW_percent{color:var(--dsw-alias-label-primary);font-weight:500}.JObwrW_headline{color:var(--dsw-alias-label-tertiary)}.JObwrW_headline:empty{display:none}.JObwrW_bar{corner-shape:round;background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;gap:1px;height:4px;margin:10px 0 12px;display:flex;overflow:hidden}.JObwrW_segment{background:var(--meter-tint,var(--dsw-alias-label-tertiary));border-radius:1px;flex:none;min-width:2px;height:100%}.JObwrW_swatch{background:var(--meter-tint);vertical-align:baseline;border-radius:2px;width:8px;height:8px;margin-right:6px;display:inline-block}.JObwrW_colorSystem{--meter-tint:var(--dsw-static-neutral-bluish-400)}.JObwrW_colorTools{--meter-tint:#a78bfa}.JObwrW_colorMessages{--meter-tint:var(--dsw-static-blue-450)}.JObwrW_rows{margin:6px 0 0}.JObwrW_row{justify-content:space-between;align-items:center;gap:12px;padding:2px 0;display:flex}.JObwrW_row dt{color:var(--dsw-alias-label-secondary)}.JObwrW_row dd{font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-primary);margin:0}";
16761
+ const css$2 = ".JObwrW_root{flex:none;display:inline-flex}.JObwrW_trigger{color:var(--dsw-alias-label-tertiary);font-family:inherit;font-size:var(--dsh-content-font-size-secondary,13px);font-variant-numeric:tabular-nums;line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:24px;flex:none;align-items:center;gap:6px;padding:1px 8px;display:inline-flex}.JObwrW_trigger:hover,.JObwrW_trigger[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.JObwrW_track{fill:none;stroke:var(--dsw-alias-border-l3);stroke-width:2px}.JObwrW_fill{fill:none;stroke:var(--dsw-alias-label-tertiary);stroke-width:2px;stroke-linecap:round}.JObwrW_panel{z-index:1100;box-sizing:border-box;background:var(--dsw-specific-menu);width:min(264px,100vw - 24px);backdrop-filter:var(--dsw-menu-backdrop-filter);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-secondary);cursor:default;border:0;border-radius:12px;padding:12px;font-size:12px;line-height:20px;position:fixed}.JObwrW_header{align-items:center;gap:6px;display:flex}.JObwrW_figures{font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-primary);margin-left:auto;font-weight:500}.JObwrW_percent{color:var(--dsw-alias-label-primary);font-weight:500}.JObwrW_headline{color:var(--dsw-alias-label-tertiary)}.JObwrW_headline:empty{display:none}.JObwrW_bar{corner-shape:round;background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;gap:1px;height:4px;margin:10px 0 12px;display:flex;overflow:hidden}.JObwrW_segment{background:var(--meter-tint,var(--dsw-alias-label-tertiary));border-radius:1px;flex:none;min-width:2px;height:100%}.JObwrW_swatch{background:var(--meter-tint);vertical-align:baseline;border-radius:2px;width:8px;height:8px;margin-right:6px;display:inline-block}.JObwrW_colorSystem{--meter-tint:var(--dsw-static-neutral-bluish-400)}.JObwrW_colorTools{--meter-tint:#a78bfa}.JObwrW_colorMessages{--meter-tint:var(--dsw-static-blue-450)}.JObwrW_rows{margin:6px 0 0}.JObwrW_row{justify-content:space-between;align-items:center;gap:12px;padding:2px 0;display:flex}.JObwrW_row dt{color:var(--dsw-alias-label-secondary)}.JObwrW_row dd{font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-primary);margin:0}";
15838
16762
  const tagId$2 = "@deepseek-ai/dsh-client-ui-conversation/ContextMeter.module.css";
15839
16763
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
15840
16764
  const tag = document.createElement("style");
@@ -16043,8 +16967,47 @@ window.__ModuleLoader__.load({
16043
16967
  });
16044
16968
  }
16045
16969
  //#endregion
16970
+ //#region lib/types/client/skeleton/control-row-layout.js
16971
+ /** Content-sized model collapse for the composer's two control groups. */
16972
+ /**
16973
+ * Collapse the model text only when the expanded controls cannot share a line.
16974
+ * The model seat consumes the row's inherited display variables; wrapping remains
16975
+ * available when even the icon cannot fit. Each notification is measured synchronously.
16976
+ * @param row - Composer control row with its leading and trailing groups.
16977
+ * @returns Disconnect the layout observers and font listener.
16978
+ */
16979
+ function observeControlRow(row) {
16980
+ const measure = () => {
16981
+ row.removeAttribute("data-model-compact");
16982
+ const style = getComputedStyle(row);
16983
+ const available = row.getBoundingClientRect().width - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight);
16984
+ const widths = Array.from(row.children, (child) => child.getBoundingClientRect().width).filter((width) => width > 0);
16985
+ const needed = widths.reduce((sum, width) => sum + width, 0) + Math.max(0, widths.length - 1) * parseFloat(style.columnGap);
16986
+ row.toggleAttribute("data-model-compact", needed > available);
16987
+ };
16988
+ const resize = new ResizeObserver(measure);
16989
+ resize.observe(row);
16990
+ for (const child of row.children) resize.observe(child);
16991
+ const mutation = new MutationObserver(measure);
16992
+ mutation.observe(row, {
16993
+ subtree: true,
16994
+ childList: true,
16995
+ characterData: true,
16996
+ attributes: true,
16997
+ attributeFilter: ["hidden"]
16998
+ });
16999
+ const fonts = document.fonts;
17000
+ fonts.addEventListener("loadingdone", measure);
17001
+ measure();
17002
+ return () => {
17003
+ resize.disconnect();
17004
+ mutation.disconnect();
17005
+ fonts.removeEventListener("loadingdone", measure);
17006
+ };
17007
+ }
17008
+ //#endregion
16046
17009
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-conversation/src/client/skeleton/InputBar.module.css.mjs
16047
- const css$1 = ".uV2eYG_root{padding:0 var(--dsh-composer-side-clearance) 4px;flex-direction:column;align-items:center;display:flex}.uV2eYG_dock{justify-content:center;align-items:center;gap:12px;max-width:100%;padding-top:4px;display:flex}.uV2eYG_hero .uV2eYG_dock:empty{display:none}.uV2eYG_hero{padding:0 var(--dsh-composer-side-clearance)}.uV2eYG_notice{width:100%;max-width:var(--dsh-composer-card-max-width);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);border-radius:8px;margin-bottom:6px;padding:4px 8px;font-size:12px;line-height:18px}.uV2eYG_card{box-sizing:border-box;width:100%;max-width:var(--dsh-composer-card-max-width);--dsw-elevation-stroke-color:var(--dsw-alias-border-l2);background:var(--dsw-specific-input-major);box-shadow:var(--dsw-elevation-soft);font-size:var(--dsh-content-font-size,14px);line-height:calc(24px + var(--dsh-content-font-delta,0px));--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border:0;border-radius:22px;flex-direction:column;gap:12px;padding-top:8px;display:flex;position:relative}.uV2eYG_cardWorkspaceTrigger{--dsw-elevation-stroke-color:transparent;cursor:pointer}.uV2eYG_cardWorkspaceTrigger:after{content:\"\";background:var(--dsw-alias-border-l4);pointer-events:none;border-radius:22px;transition:background-color .1s;position:absolute;inset:-1px;-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='none' rx='22' ry='22' stroke='black' stroke-width='2' stroke-dasharray='4 4'/%3E%3C/svg%3E\");mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='none' rx='22' ry='22' stroke='black' stroke-width='2' stroke-dasharray='4 4'/%3E%3C/svg%3E\")}.uV2eYG_cardWorkspaceTrigger :disabled{pointer-events:none}.uV2eYG_cardWorkspaceTrigger:hover:after{background:var(--dsw-alias-state-business-primary)}.uV2eYG_accessory{align-items:center;gap:8px;padding:10px 12px 0;display:flex}.uV2eYG_overlayAnchor{height:0;position:absolute;inset:0 0 auto}.uV2eYG_scroll{max-height:var(--dsh-composer-text-max-height);margin-right:4px;overflow-y:auto}.uV2eYG_scroll::-webkit-scrollbar-track{margin-top:8px}.uV2eYG_grow{position:relative}.uV2eYG_pending{corner-shape:round;background:var(--dsw-alias-state-business-primary);border-radius:50%;width:8px;height:8px;animation:1s ease-in-out infinite alternate uV2eYG_input-pending}@keyframes uV2eYG_input-pending{0%{opacity:.35}to{opacity:1}}.uV2eYG_input{box-sizing:border-box;min-height:36px;font-family:var(--dsw-font-family);font-size:inherit;line-height:inherit;white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere;color:var(--dsw-alias-label-primary);caret-color:var(--dsw-alias-state-business-primary);outline:none;padding:4px 8px 0 14px}.uV2eYG_input p{margin:0}.uV2eYG_input p:last-child:after{content:var(--dsh-composer-hint);color:var(--dsw-alias-label-caption)}.uV2eYG_input[data-composer-composing] p:last-child:after{content:none}.uV2eYG_input[data-composer-composing]+.uV2eYG_placeholder{visibility:hidden}.uV2eYG_placeholder{color:var(--dsw-alias-label-caption);white-space:nowrap;text-overflow:ellipsis;pointer-events:none;user-select:none;position:absolute;inset:4px 8px auto 14px;overflow:hidden}.uV2eYG_inputDisabled{color:var(--dsw-alias-label-tertiary);cursor:not-allowed}.uV2eYG_input[aria-haspopup=menu]{cursor:pointer}.uV2eYG_hero .uV2eYG_input{min-height:52px}.uV2eYG_hero .uV2eYG_placeholder{white-space:normal;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box}.uV2eYG_row{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;min-width:0;padding:2px 8px 6px;display:flex;container-type:inline-size}.uV2eYG_tools,.uV2eYG_modes,.uV2eYG_trailing{align-items:center;min-width:0;display:flex}.uV2eYG_tools,.uV2eYG_modes{gap:12px}.uV2eYG_trailing{flex:none;gap:12px;margin-left:auto}.uV2eYG_add{corner-shape:round;background:var(--dsw-specific-selector);width:28px;height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:999px;flex:none;place-items:center;display:grid}.uV2eYG_add:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.uV2eYG_add:disabled{opacity:.5;cursor:default}.uV2eYG_select{max-width:220px;height:28px;color:var(--dsw-alias-label-secondary);white-space:nowrap;cursor:pointer;appearance:none;background-color:#0000;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");background-position:right 4px center;background-repeat:no-repeat;background-size:12px 12px;border:none;border-radius:8px;outline:none;padding:0 20px 0 8px;font-size:13px;font-weight:500;line-height:20px}.uV2eYG_select:hover:not(:disabled){background-color:var(--dsw-alias-interactive-bg-hover)}.uV2eYG_select:disabled{opacity:.5;cursor:default}.uV2eYG_primary{corner-shape:round;background:var(--dsw-alias-button-info-fill);color:#fff;cursor:pointer;border:none;border-radius:999px;flex:none;place-items:center;width:34px;height:34px;transition:background-color .1s;display:grid;transform:translateY(-2px)}.uV2eYG_primary:hover:not(:disabled){background:var(--dsw-alias-button-info-hover)}.uV2eYG_primary:disabled{opacity:.4;cursor:default}.uV2eYG_retry{color:inherit;cursor:pointer;background:0 0;border:1px solid;border-radius:4px;margin-left:8px;padding:1px 8px;font-size:12px}";
17010
+ const css$1 = ".uV2eYG_root{padding:0 var(--dsh-composer-side-clearance) 4px;flex-direction:column;align-items:center;display:flex}.uV2eYG_dock{justify-content:center;align-items:center;gap:12px;max-width:100%;padding-top:4px;display:flex}.uV2eYG_hero .uV2eYG_dock:empty{display:none}.uV2eYG_hero{padding:0 var(--dsh-composer-side-clearance)}.uV2eYG_notice{width:100%;max-width:var(--dsh-composer-card-max-width);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);border-radius:8px;margin-bottom:6px;padding:4px 8px;font-size:12px;line-height:18px}.uV2eYG_card{box-sizing:border-box;width:100%;max-width:var(--dsh-composer-card-max-width);--dsw-elevation-stroke-color:var(--dsw-alias-border-l2);background:var(--dsw-specific-input-major);box-shadow:var(--dsw-elevation-soft);font-size:var(--dsh-content-font-size,14px);line-height:calc(24px + var(--dsh-content-font-delta,0px));--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border:0;border-radius:22px;flex-direction:column;gap:12px;padding-top:8px;display:flex;position:relative}.uV2eYG_cardWorkspaceTrigger{--dsw-elevation-stroke-color:transparent;cursor:pointer}.uV2eYG_cardWorkspaceTrigger:after{content:\"\";box-sizing:border-box;color:var(--dsw-alias-border-l4);pointer-events:none;border:1px dashed;border-radius:22px;transition:color .1s;position:absolute;inset:0}.uV2eYG_cardWorkspaceTrigger :disabled{pointer-events:none}.uV2eYG_cardWorkspaceTrigger:hover:after{color:var(--dsw-alias-state-business-primary)}.uV2eYG_accessory{align-items:center;gap:8px;padding:10px 12px 0;display:flex}.uV2eYG_overlayAnchor{height:0;position:absolute;inset:0 0 auto}.uV2eYG_scroll{max-height:var(--dsh-composer-text-max-height);margin-right:4px;overflow-y:auto}.uV2eYG_scroll::-webkit-scrollbar-track{margin-top:8px}.uV2eYG_grow{position:relative}.uV2eYG_pending{corner-shape:round;background:var(--dsw-alias-state-business-primary);border-radius:50%;width:8px;height:8px;animation:1s ease-in-out infinite alternate uV2eYG_input-pending}@keyframes uV2eYG_input-pending{0%{opacity:.35}to{opacity:1}}.uV2eYG_input{box-sizing:border-box;min-height:36px;font-family:var(--dsw-font-family);font-size:inherit;line-height:inherit;white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere;color:var(--dsw-alias-label-primary);caret-color:var(--dsw-alias-state-business-primary);outline:none;padding:4px 8px 0 14px}.uV2eYG_input p{margin:0}.uV2eYG_input p:last-child:after{content:var(--dsh-composer-hint);color:var(--dsw-alias-label-caption)}.uV2eYG_input[data-composer-composing] p:last-child:after{content:none}.uV2eYG_input[data-composer-composing]+.uV2eYG_placeholder{visibility:hidden}.uV2eYG_placeholder{color:var(--dsw-alias-label-caption);white-space:nowrap;text-overflow:ellipsis;pointer-events:none;user-select:none;position:absolute;inset:4px 8px auto 14px;overflow:hidden}.uV2eYG_inputDisabled{color:var(--dsw-alias-label-tertiary);cursor:not-allowed}.uV2eYG_input[aria-haspopup=menu]{cursor:pointer}.uV2eYG_hero .uV2eYG_input{min-height:52px}.uV2eYG_hero .uV2eYG_placeholder{white-space:normal;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box}.uV2eYG_row{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;min-width:0;padding:2px 8px 6px;display:flex;container-type:inline-size}.uV2eYG_row[data-model-compact]{--dsh-composer-model-text-display:none;--dsh-composer-model-icon-display:block}.uV2eYG_tools,.uV2eYG_modes,.uV2eYG_trailing{align-items:center;min-width:0;display:flex}.uV2eYG_tools,.uV2eYG_modes{gap:12px}.uV2eYG_trailing{flex:none;gap:12px;margin-left:auto}@container (width<=560px){.uV2eYG_tools,.uV2eYG_modes,.uV2eYG_trailing{gap:8px}}.uV2eYG_add{corner-shape:round;background:var(--dsw-specific-selector);width:28px;height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:999px;flex:none;place-items:center;display:grid}.uV2eYG_add:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.uV2eYG_add:disabled{opacity:.5;cursor:default}.uV2eYG_select{max-width:220px;height:28px;color:var(--dsw-alias-label-secondary);white-space:nowrap;cursor:pointer;appearance:none;background-color:#0000;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");background-position:right 4px center;background-repeat:no-repeat;background-size:12px 12px;border:none;border-radius:8px;outline:none;padding:0 20px 0 8px;font-size:13px;font-weight:500;line-height:20px}.uV2eYG_select:hover:not(:disabled){background-color:var(--dsw-alias-interactive-bg-hover)}.uV2eYG_select:disabled{opacity:.5;cursor:default}.uV2eYG_primary{corner-shape:round;background:var(--dsw-alias-button-info-fill);color:#fff;cursor:pointer;border:none;border-radius:999px;flex:none;place-items:center;width:34px;height:34px;transition:background-color .1s;display:grid;transform:translateY(-2px)}.uV2eYG_primary:hover:not(:disabled){background:var(--dsw-alias-button-info-hover)}.uV2eYG_primary:disabled{opacity:.4;cursor:default}.uV2eYG_retry{color:inherit;cursor:pointer;background:0 0;border:1px solid;border-radius:4px;margin-left:8px;padding:1px 8px;font-size:12px}.uV2eYG_standardControls{align-items:center;gap:12px;min-width:0;display:flex}.uV2eYG_tools[hidden],.uV2eYG_standardControls[hidden]{display:none}.uV2eYG_trailingActive{flex:1;margin-left:0}.uV2eYG_activity{flex:none;align-items:center;display:flex}.uV2eYG_activity:empty{display:none}.uV2eYG_activityExpanded{flex:1;min-width:0}";
16048
17011
  const tagId$1 = "@deepseek-ai/dsh-client-ui-conversation/InputBar.module.css";
16049
17012
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
16050
17013
  const tag = document.createElement("style");
@@ -16055,6 +17018,8 @@ window.__ModuleLoader__.load({
16055
17018
  }
16056
17019
  var InputBar_module_css_default = {
16057
17020
  "accessory": "uV2eYG_accessory",
17021
+ "activity": "uV2eYG_activity",
17022
+ "activityExpanded": "uV2eYG_activityExpanded",
16058
17023
  "add": "uV2eYG_add",
16059
17024
  "card": "uV2eYG_card",
16060
17025
  "cardWorkspaceTrigger": "uV2eYG_cardWorkspaceTrigger",
@@ -16075,8 +17040,10 @@ window.__ModuleLoader__.load({
16075
17040
  "row": "uV2eYG_row",
16076
17041
  "scroll": "uV2eYG_scroll",
16077
17042
  "select": "uV2eYG_select",
17043
+ "standardControls": "uV2eYG_standardControls",
16078
17044
  "tools": "uV2eYG_tools",
16079
- "trailing": "uV2eYG_trailing"
17045
+ "trailing": "uV2eYG_trailing",
17046
+ "trailingActive": "uV2eYG_trailingActive"
16080
17047
  };
16081
17048
  //#endregion
16082
17049
  //#region lib/types/client/skeleton/InputBar.js
@@ -16099,6 +17066,10 @@ window.__ModuleLoader__.load({
16099
17066
  const notice = useNotices((s) => s);
16100
17067
  const busyEnter = useBusyEnter((s) => s);
16101
17068
  const commandMenuOpen = useMenuLauncher((source) => source === "command");
17069
+ const [activity, setActivity] = (0, react.useState)(false);
17070
+ (0, react.useEffect)(() => {
17071
+ setActivity(false);
17072
+ }, [sessionId]);
16102
17073
  const promptError = useSession((s) => s.promptError) ?? null;
16103
17074
  const running = useSession((s) => s.running) ?? false;
16104
17075
  const subagent = useSession((s) => s.subagent) ?? null;
@@ -16142,6 +17113,12 @@ window.__ModuleLoader__.load({
16142
17113
  (0, react.useEffect)(() => {
16143
17114
  if (notice?.level === "error") showToast(notice.text);
16144
17115
  }, [notice, showToast]);
17116
+ const rowRef = (0, react.useRef)(null);
17117
+ (0, react.useLayoutEffect)(() => {
17118
+ const row = rowRef.current;
17119
+ if (row === null) return;
17120
+ return observeControlRow(row);
17121
+ }, []);
16145
17122
  const cardRef = (0, react.useRef)(null);
16146
17123
  const scrollRef = (0, react.useRef)(null);
16147
17124
  const continuable = subagent?.address.mode === "continuable";
@@ -16181,7 +17158,7 @@ window.__ModuleLoader__.load({
16181
17158
  (0, react.useEffect)(() => {
16182
17159
  return installDraftWheel(scrollRef);
16183
17160
  }, []);
16184
- const intakeFiles = (0, react.useCallback)((files) => {
17161
+ const intakeFiles = (0, react.useCallback)((files, directories) => {
16185
17162
  if (subagent !== null || addFiles === void 0 || files.length === 0) return;
16186
17163
  const rejected = (() => {
16187
17164
  if (imageLimits !== void 0) {
@@ -16192,7 +17169,7 @@ window.__ModuleLoader__.load({
16192
17169
  if (images.some((file) => file.size > imageLimits.maxImageBytes)) return t("image.fileTooLarge", { size: imageSizeText(imageLimits.maxImageBytes) });
16193
17170
  if (imageAttachments.reduce((sum, attachment) => sum + attachment.file.size, 0) + images.reduce((sum, file) => sum + file.size, 0) > imageLimits.maxMessageImageBytes) return t("image.totalTooLarge", { size: imageSizeText(imageLimits.maxMessageImageBytes) });
16194
17171
  }
16195
- return addFiles(files);
17172
+ return addFiles(files, directories);
16196
17173
  })();
16197
17174
  if (rejected !== null) showToast(rejected);
16198
17175
  }, [
@@ -16289,7 +17266,7 @@ window.__ModuleLoader__.load({
16289
17266
  children: [
16290
17267
  toast !== null && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
16291
17268
  text: toast.text,
16292
- icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutline16, {}),
17269
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutlineRegular, {}),
16293
17270
  anchor: cardRef.current,
16294
17271
  onDone: dismissToast
16295
17272
  }, toast.seq),
@@ -16347,9 +17324,11 @@ window.__ModuleLoader__.load({
16347
17324
  showPlaceholder: draft === "" && attachments.length === 0 && !claimActive
16348
17325
  }),
16349
17326
  (0, react_jsx_runtime.jsxs)("div", {
17327
+ ref: rowRef,
16350
17328
  className: InputBar_module_css_default.row,
16351
17329
  children: [(0, react_jsx_runtime.jsxs)("div", {
16352
17330
  className: InputBar_module_css_default.tools,
17331
+ hidden: activity,
16353
17332
  children: [
16354
17333
  (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
16355
17334
  label: t("input.commands"),
@@ -16364,7 +17343,7 @@ window.__ModuleLoader__.load({
16364
17343
  disabled: locked || toggleCommandMenu === void 0,
16365
17344
  onMouseDown: keepFocus,
16366
17345
  onClick: onToggleCommandMenu,
16367
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 })
17346
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineMedium, { size: 14 })
16368
17347
  })
16369
17348
  }),
16370
17349
  (0, react_jsx_runtime.jsx)("input", {
@@ -16382,10 +17361,20 @@ window.__ModuleLoader__.load({
16382
17361
  input === void 0 || sessionId === void 0 ? null : renderSlot("conversation.input.left", {})
16383
17362
  ]
16384
17363
  }), (0, react_jsx_runtime.jsxs)("div", {
16385
- className: InputBar_module_css_default.trailing,
17364
+ className: clsx(InputBar_module_css_default.trailing, activity && InputBar_module_css_default.trailingActive),
16386
17365
  children: [
16387
- input === void 0 || sessionId === void 0 ? null : renderSlot("conversation.input.right", {}),
16388
- sessionId === void 0 ? null : renderSlot("conversation.input.model", { locked: modelSeatLocked }),
17366
+ (0, react_jsx_runtime.jsxs)("div", {
17367
+ className: InputBar_module_css_default.standardControls,
17368
+ hidden: activity,
17369
+ children: [input === void 0 || sessionId === void 0 ? null : renderSlot("conversation.input.right", {}), sessionId === void 0 ? null : renderSlot("conversation.input.model", { locked: modelSeatLocked })]
17370
+ }),
17371
+ input === void 0 || sessionId === void 0 ? null : (0, react_jsx_runtime.jsx)("div", {
17372
+ className: activity ? InputBar_module_css_default.activityExpanded : InputBar_module_css_default.activity,
17373
+ children: renderSlot("conversation.input.activity", {
17374
+ locked,
17375
+ onActiveChange: setActivity
17376
+ })
17377
+ }),
16389
17378
  interruptible && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
16390
17379
  label: t("input.stop"),
16391
17380
  side: "top",
@@ -16458,7 +17447,7 @@ window.__ModuleLoader__.load({
16458
17447
  }),
16459
17448
  (0, react_jsx_runtime.jsxs)("div", {
16460
17449
  className: InputBar_module_css_default.dock,
16461
- children: [variant === "composer" && input !== void 0 && sessionId !== void 0 ? renderSlot("conversation.composer.dock", {}) : null, (0, react_jsx_runtime.jsx)(ContextMeter, {
17450
+ children: [variant === "composer" && input !== void 0 && sessionId !== void 0 ? renderSlot("conversation.composer.dock", {}) : null, activity ? null : (0, react_jsx_runtime.jsx)(ContextMeter, {
16462
17451
  useProjection,
16463
17452
  t
16464
17453
  })]
@@ -16468,7 +17457,7 @@ window.__ModuleLoader__.load({
16468
17457
  });
16469
17458
  //#endregion
16470
17459
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-conversation/src/client/skeleton/TodoPanel.module.css.mjs
16471
- const css = ".lXshSW_root{box-sizing:border-box;width:calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));max-width:calc(var(--dsh-composer-card-max-width) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));border:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-specific-tip);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;flex:none;margin:0 auto;overflow:hidden}.lXshSW_body{flex-direction:column;gap:8px;padding:6px 12px;display:flex}.lXshSW_header{text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:10px;width:100%;padding:0;display:flex}.lXshSW_lead{color:var(--dsw-alias-label-tertiary);flex:none;place-items:center;display:grid}.lXshSW_title{color:var(--dsw-alias-label-primary);flex:none;font-size:13px;font-weight:500;line-height:24px}.lXshSW_progress{min-width:0;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;flex:auto;font-size:13px;font-weight:400;line-height:20px;overflow:hidden}.lXshSW_chevron{color:var(--dsw-alias-label-tertiary);flex:none;place-items:center;display:grid}.lXshSW_list{flex-direction:column;gap:8px;max-height:180px;margin:0;padding:0;list-style:none;display:flex;overflow-y:auto}.lXshSW_item{min-width:0;color:var(--dsw-alias-label-secondary);align-items:center;gap:10px;font-size:13px;line-height:20px;display:flex}.lXshSW_glyph{flex:none;place-items:center;width:16px;height:16px;display:grid}.lXshSW_glyphCompleted{color:var(--dsw-alias-state-success-primary)}.lXshSW_glyphPending{color:var(--dsw-alias-label-caption)}.lXshSW_glyphProgress{color:var(--dsw-alias-state-business-primary);animation:1s linear infinite lXshSW_todo-progress-spin}@keyframes lXshSW_todo-progress-spin{to{transform:rotate(360deg)}}.lXshSW_content{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}";
17460
+ const css = ".lXshSW_root{box-sizing:border-box;width:calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));max-width:calc(var(--dsh-composer-card-max-width) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);background:var(--dsw-specific-menu);backdrop-filter:var(--dsw-menu-backdrop-filter);box-shadow:var(--dsw-elevation-panel);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border:0;border-radius:12px;flex:none;margin:0 auto;overflow:hidden}.lXshSW_body{flex-direction:column;gap:8px;padding:6px 12px;display:flex}.lXshSW_header{text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:10px;width:100%;padding:0;display:flex}.lXshSW_lead{color:var(--dsw-alias-label-tertiary);flex:none;place-items:center;display:grid}.lXshSW_title{color:var(--dsw-alias-label-primary);flex:none;font-size:13px;font-weight:500;line-height:24px}.lXshSW_progress{min-width:0;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;flex:auto;font-size:13px;font-weight:400;line-height:20px;overflow:hidden}.lXshSW_chevron{color:var(--dsw-alias-label-tertiary);flex:none;place-items:center;display:grid}.lXshSW_list{flex-direction:column;gap:8px;max-height:180px;margin:0;padding:0;list-style:none;display:flex;overflow-y:auto}.lXshSW_item{min-width:0;color:var(--dsw-alias-label-secondary);align-items:center;gap:10px;font-size:13px;line-height:20px;display:flex}.lXshSW_glyph{flex:none;place-items:center;width:16px;height:16px;display:grid}.lXshSW_content{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}";
16472
17461
  const tagId = "@deepseek-ai/dsh-client-ui-conversation/TodoPanel.module.css";
16473
17462
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
16474
17463
  const tag = document.createElement("style");
@@ -16482,17 +17471,13 @@ window.__ModuleLoader__.load({
16482
17471
  "chevron": "lXshSW_chevron",
16483
17472
  "content": "lXshSW_content",
16484
17473
  "glyph": "lXshSW_glyph",
16485
- "glyphCompleted": "lXshSW_glyphCompleted",
16486
- "glyphPending": "lXshSW_glyphPending",
16487
- "glyphProgress": "lXshSW_glyphProgress",
16488
17474
  "header": "lXshSW_header",
16489
17475
  "item": "lXshSW_item",
16490
17476
  "lead": "lXshSW_lead",
16491
17477
  "list": "lXshSW_list",
16492
17478
  "progress": "lXshSW_progress",
16493
17479
  "root": "lXshSW_root",
16494
- "title": "lXshSW_title",
16495
- "todo-progress-spin": "lXshSW_todo-progress-spin"
17480
+ "title": "lXshSW_title"
16496
17481
  };
16497
17482
  //#endregion
16498
17483
  //#region lib/types/client/skeleton/TodoPanel.js
@@ -16501,82 +17486,22 @@ window.__ModuleLoader__.load({
16501
17486
  function assertNever(value) {
16502
17487
  throw new Error(`unreachable todo status: ${String(value)}`);
16503
17488
  }
16504
- /** Status glyphs share the figma 14×14 artboard; the 16×16 `.glyph` cell centers them. */
16505
- function CompletedGlyph() {
16506
- return (0, react_jsx_runtime.jsxs)("svg", {
16507
- width: 14,
16508
- height: 14,
16509
- viewBox: "0 0 14 14",
16510
- fill: "none",
16511
- "aria-hidden": "true",
16512
- className: TodoPanel_module_css_default.glyphCompleted,
16513
- children: [(0, react_jsx_runtime.jsx)("circle", {
16514
- cx: "7",
16515
- cy: "7",
16516
- r: "6.4",
16517
- stroke: "currentColor",
16518
- strokeWidth: "1.2"
16519
- }), (0, react_jsx_runtime.jsx)("path", {
16520
- d: "M10.9631 5.71411L7.70154 8.97571C7.48011 9.19714 7.27736 9.40099 7.09229 9.54993C6.89742 9.70669 6.66314 9.85279 6.3634 9.90027C6.2049 9.92534 6.04339 9.92534 5.88489 9.90027C5.58515 9.85279 5.35087 9.70669 5.15601 9.54993C4.97093 9.40099 4.76818 9.19714 4.54675 8.97571L3.03516 7.46411L3.96313 6.53613L5.47473 8.04773C5.7169 8.28989 5.86196 8.43389 5.97888 8.52795C6.08597 8.61409 6.10875 8.60701 6.08997 8.604C6.11259 8.60758 6.13571 8.60758 6.15833 8.604C6.13954 8.60701 6.16232 8.61409 6.26941 8.52795C6.38633 8.43389 6.53139 8.28989 6.77356 8.04773L10.0352 4.78613L10.9631 5.71411Z",
16521
- fill: "currentColor"
16522
- })]
16523
- });
16524
- }
16525
- /** In-progress: business-blue ring fading out; CSS spins the svg. */
16526
- function ProgressGlyph() {
16527
- const gradientId = (0, react.useId)();
16528
- return (0, react_jsx_runtime.jsxs)("svg", {
16529
- width: 14,
16530
- height: 14,
16531
- viewBox: "0 0 14 14",
16532
- fill: "none",
16533
- "aria-hidden": "true",
16534
- className: TodoPanel_module_css_default.glyphProgress,
16535
- children: [(0, react_jsx_runtime.jsx)("defs", { children: (0, react_jsx_runtime.jsxs)("linearGradient", {
16536
- id: gradientId,
16537
- x1: "2.5",
16538
- y1: "12",
16539
- x2: "10.5",
16540
- y2: "3.5",
16541
- gradientUnits: "userSpaceOnUse",
16542
- children: [(0, react_jsx_runtime.jsx)("stop", { stopColor: "currentColor" }), (0, react_jsx_runtime.jsx)("stop", {
16543
- offset: "1",
16544
- stopColor: "currentColor",
16545
- stopOpacity: "0"
16546
- })]
16547
- }) }), (0, react_jsx_runtime.jsx)("circle", {
16548
- cx: "7",
16549
- cy: "7",
16550
- r: "6.4",
16551
- stroke: `url(#${gradientId})`,
16552
- strokeWidth: "1.2"
16553
- })]
16554
- });
16555
- }
16556
- /** Pending: dashed unstarted ring (figma dash 2.4 2.4). */
16557
- function PendingGlyph() {
16558
- return (0, react_jsx_runtime.jsx)("svg", {
16559
- width: 14,
16560
- height: 14,
16561
- viewBox: "0 0 14 14",
16562
- fill: "none",
16563
- "aria-hidden": "true",
16564
- className: TodoPanel_module_css_default.glyphPending,
16565
- children: (0, react_jsx_runtime.jsx)("circle", {
16566
- cx: "7",
16567
- cy: "7",
16568
- r: "6.4",
16569
- stroke: "currentColor",
16570
- strokeWidth: "1.2",
16571
- strokeDasharray: "2.4 2.4"
16572
- })
16573
- });
17489
+ /** Map Todo lifecycle state onto the shared compact status language. */
17490
+ function statusDotState(status) {
17491
+ switch (status) {
17492
+ case "completed": return "done";
17493
+ case "in_progress": return "ongoing";
17494
+ case "pending": return "idle";
17495
+ /* v8 ignore next -- closed TodoItem status union */
17496
+ default: return assertNever(status);
17497
+ }
16574
17498
  }
16575
- function StatusGlyph({ status }) {
17499
+ /** Return the localized status announced beside one decorative marker. */
17500
+ function statusLabel(status, t) {
16576
17501
  switch (status) {
16577
- case "completed": return (0, react_jsx_runtime.jsx)(CompletedGlyph, {});
16578
- case "in_progress": return (0, react_jsx_runtime.jsx)(ProgressGlyph, {});
16579
- case "pending": return (0, react_jsx_runtime.jsx)(PendingGlyph, {});
17502
+ case "completed": return t("todo.status.completed");
17503
+ case "in_progress": return t("todo.status.inProgress");
17504
+ case "pending": return t("todo.status.pending");
16580
17505
  /* v8 ignore next -- closed TodoItem status union */
16581
17506
  default: return assertNever(status);
16582
17507
  }
@@ -16612,7 +17537,7 @@ window.__ModuleLoader__.load({
16612
17537
  (0, react_jsx_runtime.jsx)("span", {
16613
17538
  className: TodoPanel_module_css_default.lead,
16614
17539
  "aria-hidden": true,
16615
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChecklistOutline14, {})
17540
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChecklistOutlineRegular, {})
16616
17541
  }),
16617
17542
  (0, react_jsx_runtime.jsx)("span", {
16618
17543
  className: TodoPanel_module_css_default.title,
@@ -16625,7 +17550,7 @@ window.__ModuleLoader__.load({
16625
17550
  (0, react_jsx_runtime.jsx)("span", {
16626
17551
  className: TodoPanel_module_css_default.chevron,
16627
17552
  "aria-hidden": true,
16628
- children: collapsed ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, {}) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {})
17553
+ children: collapsed ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutlineRegular, {}) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {})
16629
17554
  })
16630
17555
  ]
16631
17556
  }), !collapsed && (0, react_jsx_runtime.jsx)("ul", {
@@ -16635,8 +17560,9 @@ window.__ModuleLoader__.load({
16635
17560
  "data-status": item.status,
16636
17561
  children: [(0, react_jsx_runtime.jsx)("span", {
16637
17562
  className: TodoPanel_module_css_default.glyph,
16638
- "aria-hidden": true,
16639
- children: (0, react_jsx_runtime.jsx)(StatusGlyph, { status: item.status })
17563
+ role: "img",
17564
+ "aria-label": statusLabel(item.status, t),
17565
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: statusDotState(item.status) })
16640
17566
  }), (0, react_jsx_runtime.jsx)("span", {
16641
17567
  className: TodoPanel_module_css_default.content,
16642
17568
  children: item.content
@@ -16676,7 +17602,7 @@ window.__ModuleLoader__.load({
16676
17602
  "uiSession",
16677
17603
  "uiWorkspace",
16678
17604
  "locale",
16679
- "settingsScope"
17605
+ "configForms"
16680
17606
  ];
16681
17607
  /** Validated Conversation runtime configuration. */
16682
17608
  const Config = Schema.object({ maxConcurrentFileUploads: Schema.natural().min(1).default(2) });
@@ -16702,6 +17628,10 @@ window.__ModuleLoader__.load({
16702
17628
  getSnapshot: () => EMPTY_FILE_UPLOADS,
16703
17629
  subscribe: () => () => {}
16704
17630
  };
17631
+ /** The shell-installed bridge, when this document runs inside the Desktop application. */
17632
+ function hostPathBridge() {
17633
+ return globalThis.__DSH_HOST_PATHS__;
17634
+ }
16705
17635
  /** Resolve the session-scoped Conversation action face, failing loud. */
16706
17636
  function scopedConversation(sessions, id) {
16707
17637
  const scoped = sessions.scope(id);
@@ -16732,7 +17662,10 @@ window.__ModuleLoader__.load({
16732
17662
  }), "ui-conversation: dictionaries");
16733
17663
  const t = ctx.locale.bind(NS);
16734
17664
  const conversationStore = createConversationStore();
16735
- const submissionPolicy = new ComposerSubmissionPolicy(ctx.settingsScope.bind({ namespace: CONVERSATION_SETTINGS_NAMESPACE }));
17665
+ const submissionPolicy = new ComposerSubmissionPolicy(ctx.configForms.get(CONVERSATION_SETTINGS_NAMESPACE));
17666
+ ctx.effect(() => () => {
17667
+ submissionPolicy.dispose();
17668
+ });
16736
17669
  ctx.slots.inject("settings.general.item", () => ctx.slots.register({
16737
17670
  name: "settings.general.item",
16738
17671
  id: "composer-enter",
@@ -16750,6 +17683,7 @@ window.__ModuleLoader__.load({
16750
17683
  for (const entry of slots.entries("conversation.view")) {
16751
17684
  /* v8 ignore next -- list registration validates id at load. */
16752
17685
  if (entry.options.id === void 0) continue;
17686
+ if (!ctx.configForms.developerTools.enabled.getSnapshot() && entry.options.id === "trajectory") continue;
16753
17687
  tabs.push({
16754
17688
  id: entry.options.id,
16755
17689
  label: (0, _deepseek_ai_dsh_client_ui_slots.resolveSlotLabel)(entry.options.label) ?? entry.options.id
@@ -16787,7 +17721,9 @@ window.__ModuleLoader__.load({
16787
17721
  ctx.effect(() => {
16788
17722
  const disposeViews = slots.subscribe("conversation.view", refreshViews);
16789
17723
  const disposeLocale = ctx.locale.subscribe(refreshViews);
17724
+ const disposeDeveloperTools = ctx.configForms.developerTools.enabled.subscribe(refreshViews);
16790
17725
  return () => {
17726
+ disposeDeveloperTools();
16791
17727
  disposeLocale();
16792
17728
  disposeViews();
16793
17729
  };
@@ -16799,7 +17735,7 @@ window.__ModuleLoader__.load({
16799
17735
  scope.effect(() => commands.register({
16800
17736
  name: "file",
16801
17737
  label: () => t("input.file"),
16802
- icon: _deepseek_ai_dsh_client_ui_primitives.IconPaperclipOutline16,
17738
+ icon: _deepseek_ai_dsh_client_ui_primitives.IconPaperclipOutlineRegular,
16803
17739
  available: (session) => inputHub.canPickFiles(session.sessionId),
16804
17740
  ui: {
16805
17741
  kind: "action",
@@ -16828,9 +17764,9 @@ window.__ModuleLoader__.load({
16828
17764
  });
16829
17765
  const registerConversationRoot = () => slots.register({
16830
17766
  name: "main.conversation",
16831
- children: { "conversation.session.header": {
17767
+ children: { "conversation.header": {
16832
17768
  kind: "single",
16833
- scope: "session"
17769
+ scope: "session-maybe"
16834
17770
  } }
16835
17771
  }, ConversationRoot);
16836
17772
  const registerConversationContent = () => slots.registerFactory({
@@ -16899,16 +17835,51 @@ window.__ModuleLoader__.load({
16899
17835
  scope: "session"
16900
17836
  } },
16901
17837
  store: conversationStore,
16902
- inject: (sessionId, actions) => ({
16903
- hooks: { conversationViews },
16904
- bindDraftMirror: (write) => inputHub.shell(sessionId).bindMirror(write),
16905
- openView: (view, focus) => {
17838
+ inject: (sessionId, actions) => {
17839
+ const openView = (view, focus) => {
17840
+ if (!viewTabs().some((tab) => tab.id === view)) return;
16906
17841
  activateView(sessionId, view);
16907
17842
  actions.openView(view, focus);
16908
- }
16909
- })
17843
+ };
17844
+ const inspectionTarget = () => uiConversation.views.entries().find((definition) => definition.toolCallFocus !== void 0 && conversationViews.getSnapshot().some((view) => view.id === definition.target));
17845
+ const inspectCall = (callId) => {
17846
+ const target = inspectionTarget();
17847
+ if (target?.toolCallFocus !== void 0) openView(target.target, target.toolCallFocus(callId));
17848
+ };
17849
+ return {
17850
+ hooks: {
17851
+ conversationViews,
17852
+ inspectCall: {
17853
+ getSnapshot: () => inspectionTarget() === void 0 ? void 0 : inspectCall,
17854
+ subscribe: (listener) => {
17855
+ const disposeViews = conversationViews.subscribe(listener);
17856
+ const disposeDefinitions = uiConversation.views.subscribe(listener);
17857
+ return () => {
17858
+ disposeViews();
17859
+ disposeDefinitions();
17860
+ };
17861
+ }
17862
+ }
17863
+ },
17864
+ bindDraftMirror: (write) => inputHub.shell(sessionId).bindMirror(write),
17865
+ openView
17866
+ };
17867
+ }
16910
17868
  }, ConversationSession);
16911
- const registerConversationHeader = () => slots.register({
17869
+ const registerHeader = () => slots.register({
17870
+ name: "conversation.header",
17871
+ children: {
17872
+ "conversation.header.leading": {
17873
+ kind: "single",
17874
+ scope: "root"
17875
+ },
17876
+ "conversation.session.header": {
17877
+ kind: "single",
17878
+ scope: "session"
17879
+ }
17880
+ }
17881
+ }, ConversationHeader);
17882
+ const registerSessionHeader = () => slots.register({
16912
17883
  name: "conversation.session.header",
16913
17884
  locale: NS,
16914
17885
  children: {
@@ -16916,10 +17887,6 @@ window.__ModuleLoader__.load({
16916
17887
  kind: "single",
16917
17888
  scope: "session"
16918
17889
  },
16919
- "conversation.session.header.leading": {
16920
- kind: "single",
16921
- scope: "session"
16922
- },
16923
17890
  "conversation.session.header.actions": {
16924
17891
  kind: "list",
16925
17892
  scope: "session"
@@ -16977,6 +17944,10 @@ window.__ModuleLoader__.load({
16977
17944
  kind: "single",
16978
17945
  scope: "session"
16979
17946
  },
17947
+ "conversation.input.activity": {
17948
+ kind: "single",
17949
+ scope: "session"
17950
+ },
16980
17951
  "conversation.composer.dock": {
16981
17952
  kind: "list",
16982
17953
  scope: "session"
@@ -17002,13 +17973,45 @@ window.__ModuleLoader__.load({
17002
17973
  const conversation = concreteConversation(ctx);
17003
17974
  const shell = inputHub.shell(sessionId);
17004
17975
  const inputTriggers = inputHub.inputTriggers(sessionId);
17976
+ const bridge = hostPathBridge();
17005
17977
  return {
17006
17978
  keyboard: shell,
17007
- addFiles: (files) => {
17979
+ addFiles: (files, directories = /* @__PURE__ */ new Set()) => {
17008
17980
  if (sessions.binding(sessionId) === void 0) return t("file.sessionUnavailable");
17981
+ if (shell.snapshot.phase === "adjudicating" || shell.snapshot.phase === "submitting") return t("attachment.dropBlocked");
17982
+ const uploads = [];
17983
+ const references = [];
17984
+ const cwd = sessions.list.getSnapshot().byId[sessionId]?.cwd;
17985
+ for (const file of files) {
17986
+ const directory = directories.has(file);
17987
+ if (bridge === void 0 && directory) return t("attachment.directoryDesktopOnly");
17988
+ const path = bridge?.pathFor(file) ?? "";
17989
+ if (directory && path === "") return t("attachment.pathUnavailable");
17990
+ if (path === "" || !directory && isImageMediaType(file.type)) {
17991
+ uploads.push(file);
17992
+ continue;
17993
+ }
17994
+ const relative = relativizeToCwd(path, cwd);
17995
+ const mention = formatFileMention({
17996
+ path: directory ? `${relative}/` : relative,
17997
+ kind: "file"
17998
+ }, false);
17999
+ if (mention === void 0) return t("attachment.pathUnsupported");
18000
+ const label = workspaceTitleOf(path) || file.name;
18001
+ references.push({
18002
+ source: "reference",
18003
+ ref: mention,
18004
+ label: directory ? `${label}/` : label,
18005
+ appearance: directory ? "folder" : "file",
18006
+ clipboardText: mention
18007
+ });
18008
+ }
17009
18009
  try {
17010
- const drafts = conversation.createDrafts(sessionId, files);
17011
- if (!shell.addAttachments(drafts.map((draft) => draft.id))) conversation.releaseDraftAttachments(drafts);
18010
+ const drafts = conversation.createDrafts(sessionId, uploads);
18011
+ if (!shell.addFiles(references, drafts.map((draft) => draft.id))) {
18012
+ conversation.releaseDraftAttachments(drafts);
18013
+ return t("attachment.dropBlocked");
18014
+ }
17012
18015
  return null;
17013
18016
  } catch (error) {
17014
18017
  if (error instanceof UnsupportedImageMediaTypeError) return t("image.unsupportedType");
@@ -17061,7 +18064,8 @@ window.__ModuleLoader__.load({
17061
18064
  yield registerConversationRoot();
17062
18065
  yield registerConversationContent();
17063
18066
  yield registerConversationSession();
17064
- yield registerConversationHeader();
18067
+ yield registerHeader();
18068
+ yield registerSessionHeader();
17065
18069
  yield registerComposerBar();
17066
18070
  });
17067
18071
  ctx.plugin(ConversationController, {