dsh-better-display 0.3.7 → 0.3.9

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 (208) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/DESIGN.md +43 -3
  3. package/README.en.md +9 -1
  4. package/README.md +9 -1
  5. package/docs/dependency-update-policy.md +9 -0
  6. package/docs/extension-points.md +172 -0
  7. package/docs/official-rendering-bridge.md +59 -18
  8. package/docs/openapi.yaml +147 -0
  9. package/docs/runbooks/blank-reader.md +39 -0
  10. package/lib/client.js +1629 -586
  11. package/lib/client.js.map +1 -1
  12. package/lib/dsh-better-display.js +535 -57
  13. package/lib/types/client/AssistantNode.d.ts +20 -0
  14. package/lib/types/client/AssistantNode.d.ts.map +1 -0
  15. package/lib/types/client/AssistantNode.js +46 -0
  16. package/lib/types/client/AssistantNode.js.map +1 -0
  17. package/lib/types/client/Blocks.d.ts.map +1 -1
  18. package/lib/types/client/Blocks.js +33 -10
  19. package/lib/types/client/Blocks.js.map +1 -1
  20. package/lib/types/client/ChoreographedFlow.d.ts.map +1 -1
  21. package/lib/types/client/ChoreographedFlow.js +2 -0
  22. package/lib/types/client/ChoreographedFlow.js.map +1 -1
  23. package/lib/types/client/ClosedProcessSummary.d.ts.map +1 -1
  24. package/lib/types/client/ClosedProcessSummary.js +3 -1
  25. package/lib/types/client/ClosedProcessSummary.js.map +1 -1
  26. package/lib/types/client/McpAppFrame.d.ts.map +1 -1
  27. package/lib/types/client/McpAppFrame.js +5 -11
  28. package/lib/types/client/McpAppFrame.js.map +1 -1
  29. package/lib/types/client/OfficialContent.d.ts +17 -3
  30. package/lib/types/client/OfficialContent.d.ts.map +1 -1
  31. package/lib/types/client/OfficialContent.js +33 -7
  32. package/lib/types/client/OfficialContent.js.map +1 -1
  33. package/lib/types/client/Reader.d.ts.map +1 -1
  34. package/lib/types/client/Reader.js +76 -73
  35. package/lib/types/client/Reader.js.map +1 -1
  36. package/lib/types/client/SettingsSection.d.ts.map +1 -1
  37. package/lib/types/client/SettingsSection.js +0 -5
  38. package/lib/types/client/SettingsSection.js.map +1 -1
  39. package/lib/types/client/StickyLane.d.ts +12 -0
  40. package/lib/types/client/StickyLane.d.ts.map +1 -1
  41. package/lib/types/client/StickyLane.js +78 -2
  42. package/lib/types/client/StickyLane.js.map +1 -1
  43. package/lib/types/client/ToolActivity.d.ts.map +1 -1
  44. package/lib/types/client/ToolActivity.js +10 -5
  45. package/lib/types/client/ToolActivity.js.map +1 -1
  46. package/lib/types/client/deliverables.d.ts.map +1 -1
  47. package/lib/types/client/deliverables.js +2 -0
  48. package/lib/types/client/deliverables.js.map +1 -1
  49. package/lib/types/client/index.d.ts +3 -1
  50. package/lib/types/client/index.d.ts.map +1 -1
  51. package/lib/types/client/index.js +15 -1
  52. package/lib/types/client/index.js.map +1 -1
  53. package/lib/types/client/live-turn.d.ts +17 -5
  54. package/lib/types/client/live-turn.d.ts.map +1 -1
  55. package/lib/types/client/live-turn.js +106 -76
  56. package/lib/types/client/live-turn.js.map +1 -1
  57. package/lib/types/client/motion.d.ts +26 -2
  58. package/lib/types/client/motion.d.ts.map +1 -1
  59. package/lib/types/client/motion.js +144 -10
  60. package/lib/types/client/motion.js.map +1 -1
  61. package/lib/types/client/official-slots.d.ts +9 -0
  62. package/lib/types/client/official-slots.d.ts.map +1 -1
  63. package/lib/types/client/official-slots.js +22 -4
  64. package/lib/types/client/official-slots.js.map +1 -1
  65. package/lib/types/client/open-file.d.ts.map +1 -1
  66. package/lib/types/client/open-file.js +1 -6
  67. package/lib/types/client/open-file.js.map +1 -1
  68. package/lib/types/client/projection.d.ts +15 -2
  69. package/lib/types/client/projection.d.ts.map +1 -1
  70. package/lib/types/client/projection.js +16 -4
  71. package/lib/types/client/projection.js.map +1 -1
  72. package/lib/types/client/rewind-cut.d.ts +131 -0
  73. package/lib/types/client/rewind-cut.d.ts.map +1 -0
  74. package/lib/types/client/rewind-cut.js +321 -0
  75. package/lib/types/client/rewind-cut.js.map +1 -0
  76. package/lib/types/client/styles.d.ts +3 -0
  77. package/lib/types/client/styles.d.ts.map +1 -0
  78. package/lib/types/client/styles.js +25 -0
  79. package/lib/types/client/styles.js.map +1 -0
  80. package/lib/types/client/text-transform.d.ts +93 -0
  81. package/lib/types/client/text-transform.d.ts.map +1 -0
  82. package/lib/types/client/text-transform.js +183 -0
  83. package/lib/types/client/text-transform.js.map +1 -0
  84. package/lib/types/client/timeline.d.ts.map +1 -1
  85. package/lib/types/client/timeline.js.map +1 -1
  86. package/lib/types/client/tool-activity.d.ts +11 -4
  87. package/lib/types/client/tool-activity.d.ts.map +1 -1
  88. package/lib/types/client/tool-activity.js +54 -9
  89. package/lib/types/client/tool-activity.js.map +1 -1
  90. package/lib/types/client/turn-slots.d.ts +29 -0
  91. package/lib/types/client/turn-slots.d.ts.map +1 -0
  92. package/lib/types/client/turn-slots.js +62 -0
  93. package/lib/types/client/turn-slots.js.map +1 -0
  94. package/lib/types/client/types.d.ts +18 -0
  95. package/lib/types/client/types.d.ts.map +1 -1
  96. package/lib/types/dsh-better-display.d.ts +4 -1
  97. package/lib/types/dsh-better-display.d.ts.map +1 -1
  98. package/lib/types/dsh-better-display.js +55 -43
  99. package/lib/types/dsh-better-display.js.map +1 -1
  100. package/lib/types/flags.d.ts +7 -0
  101. package/lib/types/flags.d.ts.map +1 -0
  102. package/lib/types/flags.js +37 -0
  103. package/lib/types/flags.js.map +1 -0
  104. package/lib/types/log.d.ts +17 -0
  105. package/lib/types/log.d.ts.map +1 -0
  106. package/lib/types/log.js +122 -0
  107. package/lib/types/log.js.map +1 -0
  108. package/lib/types/metrics.d.ts +18 -0
  109. package/lib/types/metrics.d.ts.map +1 -0
  110. package/lib/types/metrics.js +35 -0
  111. package/lib/types/metrics.js.map +1 -0
  112. package/lib/types/reveal.d.ts +12 -0
  113. package/lib/types/reveal.d.ts.map +1 -0
  114. package/lib/types/reveal.js +147 -0
  115. package/lib/types/reveal.js.map +1 -0
  116. package/lib/types/workspace-path.d.ts +3 -0
  117. package/lib/types/workspace-path.d.ts.map +1 -0
  118. package/lib/types/workspace-path.js +5 -0
  119. package/lib/types/workspace-path.js.map +1 -0
  120. package/package.json +36 -5
  121. package/scripts/changelog.mjs +20 -0
  122. package/scripts/check-agents-md.mjs +67 -0
  123. package/scripts/check-bundle-size.mjs +38 -0
  124. package/scripts/check-dead-flags.mjs +55 -0
  125. package/scripts/check-todo-debt.mjs +69 -0
  126. package/scripts/security-audit-report.mjs +92 -0
  127. package/scripts/verify-commentary-visible.mjs +627 -0
  128. package/src/client/AssistantNode.tsx +72 -0
  129. package/src/client/Blocks.tsx +49 -10
  130. package/src/client/ChoreographedFlow.tsx +3 -1
  131. package/src/client/ClosedProcessSummary.tsx +3 -1
  132. package/src/client/McpAppFrame.tsx +5 -13
  133. package/src/client/OfficialContent.tsx +47 -9
  134. package/src/client/Reader.module.css +103 -21
  135. package/src/client/Reader.tsx +83 -88
  136. package/src/client/SettingsSection.tsx +1 -7
  137. package/src/client/StickyLane.tsx +81 -2
  138. package/src/client/ToolActivity.tsx +10 -6
  139. package/src/client/deliverables.ts +1 -0
  140. package/src/client/index.tsx +18 -2
  141. package/src/client/live-turn.ts +100 -69
  142. package/src/client/motion.tsx +142 -7
  143. package/src/client/official-slots.tsx +23 -4
  144. package/src/client/open-file.ts +2 -8
  145. package/src/client/projection.ts +16 -4
  146. package/src/client/rewind-cut.ts +340 -0
  147. package/src/client/styles.ts +22 -0
  148. package/src/client/text-transform.ts +265 -0
  149. package/src/client/timeline.ts +0 -2
  150. package/src/client/tool-activity.ts +67 -9
  151. package/src/client/turn-slots.ts +80 -0
  152. package/src/client/types.ts +19 -0
  153. package/src/dsh-better-display.ts +57 -42
  154. package/src/flags.ts +40 -0
  155. package/src/log.ts +137 -0
  156. package/src/metrics.ts +50 -0
  157. package/src/reveal.ts +90 -0
  158. package/src/workspace-path.ts +4 -0
  159. package/tests/browser-commentary.tsx +191 -0
  160. package/tests/chat-flow-hook.test.ts +1 -1
  161. package/tests/cloud-gate.test.ts +1 -1
  162. package/tests/context-tool-update.test.ts +1 -1
  163. package/tests/conversation-scroll.test.ts +1 -1
  164. package/tests/deliverables.test.ts +1 -1
  165. package/tests/entry.test.ts +1 -1
  166. package/tests/fixtures/reader-lane-owners.tsx +46 -0
  167. package/tests/fixtures/reader-official-users.tsx +234 -0
  168. package/tests/fixtures/reader-theme-overlap.html +80 -0
  169. package/tests/fixtures/reader-user-bubble.tsx +222 -0
  170. package/tests/flags.test.ts +66 -0
  171. package/tests/fold-choreography.test.ts +32 -8
  172. package/tests/fold-intensity.test.ts +11 -6
  173. package/tests/footer-precedence.test.ts +9 -1
  174. package/tests/history-word-regression.test.ts +1 -1
  175. package/tests/live-turn.test.ts +125 -54
  176. package/tests/log.test.ts +99 -0
  177. package/tests/mcp-apps.test.ts +1 -1
  178. package/tests/message-chrome.test.ts +1 -1
  179. package/tests/metrics.test.ts +52 -0
  180. package/tests/official-slots.test.ts +41 -2
  181. package/tests/open-file.test.ts +1 -1
  182. package/tests/pending-submission.test.ts +12 -1
  183. package/tests/pinned-selection.test.ts +16 -0
  184. package/tests/platform-media.test.ts +1 -1
  185. package/tests/projection.test.ts +66 -3
  186. package/tests/reader-glass-css.test.ts +28 -0
  187. package/tests/reader-official-users.test.ts +91 -0
  188. package/tests/reader-sticky-surface.test.ts +377 -0
  189. package/tests/reader-theme-lanes.test.ts +54 -0
  190. package/tests/reader-theme-overlap.test.ts +151 -0
  191. package/tests/reader-user-bubble.test.ts +137 -0
  192. package/tests/reasoning-follow.test.ts +1 -1
  193. package/tests/retiring-content.test.ts +229 -0
  194. package/tests/reveal.test.ts +128 -0
  195. package/tests/rewind-cut.test.ts +1090 -0
  196. package/tests/settings-copy.test.ts +1 -1
  197. package/tests/skill-status.test.ts +1 -1
  198. package/tests/stock-install.test.ts +9 -1
  199. package/tests/stream-buffer.test.ts +1 -1
  200. package/tests/styles.test.ts +75 -0
  201. package/tests/terminal-input-preview.test.ts +113 -0
  202. package/tests/text-transform.test.ts +272 -0
  203. package/tests/timeline.test.ts +1 -1
  204. package/tests/tool-clock.test.ts +1 -1
  205. package/tests/tool-diff.test.ts +1 -1
  206. package/tests/waiting-clock.test.ts +1 -1
  207. package/tests/word-timeline.test.ts +1 -1
  208. package/tsdown.config.ts +49 -1
package/lib/client.js CHANGED
@@ -17,9 +17,9 @@ window.__ModuleLoader__.load({
17
17
  };
18
18
  //#endregion
19
19
  let react = require("react");
20
+ let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
20
21
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
21
22
  let react_jsx_runtime = require("react/jsx-runtime");
22
- let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
23
23
  //#region node_modules/@deepseek-ai/dsh-util-workspace-path/lib/index.js
24
24
  /**
25
25
  * The `dsh-resource://file/…` address grammar: how a file is named across the
@@ -52,7 +52,7 @@ window.__ModuleLoader__.load({
52
52
  * @module @deepseek-ai/dsh-util-workspace-path
53
53
  */
54
54
  /** Whether a path uses a Windows drive or UNC prefix. */
55
- function isWindowsStylePath$1(value) {
55
+ function isWindowsStylePath(value) {
56
56
  return /^[A-Za-z]:[/\\]/.test(value) || value.startsWith("\\\\");
57
57
  }
58
58
  /**
@@ -61,7 +61,7 @@ window.__ModuleLoader__.load({
61
61
  * @returns `true` for an absolute path; `false` for a Workspace-relative one.
62
62
  */
63
63
  function isAbsoluteWorkspacePath$1(path) {
64
- return path.startsWith("/") || isWindowsStylePath$1(path);
64
+ return path.startsWith("/") || isWindowsStylePath(path);
65
65
  }
66
66
  /**
67
67
  * Resolve a Workspace-relative path into the Host-facing spelling used by path operations.
@@ -72,7 +72,7 @@ window.__ModuleLoader__.load({
72
72
  function resolveWorkspacePath(cwd, path) {
73
73
  if (isAbsoluteWorkspacePath$1(path)) return path;
74
74
  if (cwd === void 0 || cwd === "") return path;
75
- const separator = isWindowsStylePath$1(cwd) && cwd.includes("\\") ? "\\" : "/";
75
+ const separator = isWindowsStylePath(cwd) && cwd.includes("\\") ? "\\" : "/";
76
76
  return `${cwd.replace(/[/\\]+$/, "")}${separator}${path.replace(/^[/\\]+/, "")}`;
77
77
  }
78
78
  /**
@@ -83,7 +83,7 @@ window.__ModuleLoader__.load({
83
83
  */
84
84
  function abbreviateHomePath(path, home) {
85
85
  if (home === void 0 || home === "") return path;
86
- if (isWindowsStylePath$1(path) || isWindowsStylePath$1(home)) return path;
86
+ if (isWindowsStylePath(path) || isWindowsStylePath(home)) return path;
87
87
  const root = home.replace(/\/+$/, "");
88
88
  if (root === "" || root === "/") return path;
89
89
  if (path.replace(/\/+$/, "") === root) return "~";
@@ -109,12 +109,286 @@ window.__ModuleLoader__.load({
109
109
  return sessionFileAddress(sessionId, normalized);
110
110
  }
111
111
  //#endregion
112
+ //#region src/client/rewind-cut.ts
113
+ function asRecord$1(value) {
114
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
115
+ }
116
+ function safeSeq(value) {
117
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
118
+ }
119
+ /** The command payload of a `command` chat node, when it is structurally readable. */
120
+ function commandOf(node) {
121
+ if (node.kind !== "command") return void 0;
122
+ return asRecord$1(node.data);
123
+ }
124
+ /**
125
+ * The engine names an executed rewind command node can carry. The plugin
126
+ * registers its command as `rewind-plugin` (`ENGINE_COMMANDS = new
127
+ * Set(['rewind-plugin', 'rewind'])` in dsh-rewind-plugin's
128
+ * `src/client/hidden.ts`), and that is the name the client projection actually
129
+ * publishes — the session log's `command/run.name` is not what the Reader sees.
130
+ * `rewind` stays accepted because older logs and the bili-side proxy record the
131
+ * shorter spelling.
132
+ */
133
+ const REWIND_COMMANDS = /* @__PURE__ */ new Set(["rewind-plugin", "rewind"]);
134
+ /** True when a command payload is the rewind engine command, in either spelling. */
135
+ function isRewindCommand(command) {
136
+ return typeof command.name === "string" && REWIND_COMMANDS.has(command.name);
137
+ }
138
+ /**
139
+ * The render POSITION a row is anchored at: the view node's `anchorSeq`, else
140
+ * its payload seq.
141
+ *
142
+ * This is deliberately NOT integer-only. The host anchors synthetic rows at
143
+ * fractional offsets off a real seq (`CHAT_SYNTHETIC_SEQ_OFFSETS` in the
144
+ * official ChatView: `turn-process` at `controlAnchorSeq - 0.1`, `turn-tail` at
145
+ * `seq + 0.1`, an interrupted assistant step at `seq - 0.9`). An integer-only
146
+ * read made those rows invisible to the cut, so the last `turn-process` of a
147
+ * withdrawn turn survived on its own. Log seqs (marker, target) stay integer:
148
+ * see `safeSeq`.
149
+ */
150
+ function anchorSeqOf(node) {
151
+ const raw = node.anchorSeq ?? asRecord$1(node.data)?.seq;
152
+ return typeof raw === "number" && Number.isFinite(raw) && raw >= 0 ? raw : void 0;
153
+ }
154
+ /**
155
+ * Extract the rewind target seq from a `/rewind` command's structured `args`
156
+ * (e.g. `@5 chat`, `preview @5 both`). Locale-independent: it never parses the
157
+ * host's human outcome copy.
158
+ */
159
+ function rewindTargetOfArgs(args) {
160
+ if (typeof args !== "string") return void 0;
161
+ const match = args.match(/@(\d+)/);
162
+ return match === null ? void 0 : Number(match[1]);
163
+ }
164
+ /** True for the internal candidate-list probe (`/rewind __candidates`). */
165
+ function isCandidateCommand(command) {
166
+ return typeof command.args === "string" && command.args.includes("__candidates");
167
+ }
168
+ /** True for an impact preview (`/rewind preview @5 both`). */
169
+ function isPreviewCommand(command) {
170
+ return typeof command.args === "string" && command.args.includes("preview");
171
+ }
172
+ /**
173
+ * Merge overlapping or touching shadow ranges.
174
+ *
175
+ * Spans are kept SEPARATE unless they genuinely overlap: collapsing every cut
176
+ * to `[min target, max marker]` would hide a still-on-surface gap of new traffic
177
+ * between an earlier marker and a later target.
178
+ */
179
+ function coalesceCutSpans(spans) {
180
+ if (spans.length < 2) return [...spans];
181
+ const sorted = [...spans].sort((left, right) => left.start - right.start || left.end - right.end);
182
+ const merged = [];
183
+ for (const span of sorted) {
184
+ const last = merged.at(-1);
185
+ if (last !== void 0 && span.start <= last.end) {
186
+ if (span.end > last.end) last.end = span.end;
187
+ continue;
188
+ }
189
+ merged.push({
190
+ start: span.start,
191
+ end: span.end
192
+ });
193
+ }
194
+ return merged;
195
+ }
196
+ /**
197
+ * True when a row anchored at `seq` falls inside one of the cut spans.
198
+ *
199
+ * A cut runs from the target seq through the marker's own log seq, inclusive
200
+ * (`target <= anchorSeq && anchorSeq <= marker`), the same comparison
201
+ * `dsh-rewind-plugin`'s `RewindVisibilityBuilder` uses. The upper bound stops
202
+ * at the marker. Extending it to the next integer hides the following turn's
203
+ * process row, which the host anchors at `startSeq - 0.1` and therefore in
204
+ * `[marker, marker + 1)`. Fractional anchors inside the closed range still
205
+ * match: `anchorSeqOf` keeps them. A process or tail row parked outside the
206
+ * range is handled by `summaryTurns`, not by widening the cut. Spans stay
207
+ * disjoint, so new traffic between two rewinds survives.
208
+ */
209
+ function cutContains(cuts, seq) {
210
+ let low = 0;
211
+ let high = cuts.length - 1;
212
+ let found = -1;
213
+ while (low <= high) {
214
+ const middle = low + high >> 1;
215
+ const cut = cuts[middle];
216
+ if (cut === void 0) return false;
217
+ if (seq < cut.start) high = middle - 1;
218
+ else {
219
+ found = middle;
220
+ low = middle + 1;
221
+ }
222
+ }
223
+ const span = found < 0 ? void 0 : cuts[found];
224
+ return span !== void 0 && seq <= span.end;
225
+ }
226
+ /** The turn id a node belongs to (absent outside a turn). */
227
+ function turnIdOf(node) {
228
+ const turn = asRecord$1(asRecord$1(node.location)?.turn);
229
+ if (turn === void 0 || !Object.hasOwn(turn, "turn")) return void 0;
230
+ return turn.turn;
231
+ }
232
+ /**
233
+ * Node kinds that SUMMARIZE a turn instead of carrying its content, so the host
234
+ * anchors them at the turn's edges rather than at an event inside it.
235
+ */
236
+ const TURN_SUMMARY_KINDS = /* @__PURE__ */ new Set(["turn-process", "turn-tail"]);
237
+ /**
238
+ * True for a rewind command row the transcript should not keep.
239
+ *
240
+ * Probes (`preview`, `__candidates`) exist only to feed the popover. An
241
+ * executed rewind — success plus a marker seq — is the command that performed
242
+ * the cut, and the plugin hides that row even when its anchor sits outside
243
+ * the numeric range. A failed or still-running command stays visible.
244
+ */
245
+ function commandHidden(node) {
246
+ const command = commandOf(node);
247
+ if (command === void 0 || !isRewindCommand(command)) return false;
248
+ if (isPreviewCommand(command) || isCandidateCommand(command)) return true;
249
+ const outcome = asRecord$1(command.outcome);
250
+ return outcome?.kind === "success" && safeSeq(outcome.sourceEventSeq) !== void 0;
251
+ }
252
+ /** True when the row's own anchor falls in a cut, or the row is a rewind command to hide. */
253
+ function anchorWithdrawn(node, cuts) {
254
+ if (commandHidden(node)) return true;
255
+ const seq = anchorSeqOf(node);
256
+ return seq !== void 0 && cutContains(cuts, seq);
257
+ }
258
+ /**
259
+ * Turns whose process and tail rows must leave.
260
+ *
261
+ * The host opens a turn before its user message is logged and anchors
262
+ * `turn-process` at `controlAnchorSeq - 0.1`, below the first withdrawn
263
+ * event, and `turn-tail` at `turn.end.seq + 0.1`, which can sit past the
264
+ * marker. Containment therefore misses those two rows, and the transcript
265
+ * kept announcing `执行过程 / 本轮已停止,已生成的内容仍保留。`
266
+ *
267
+ * A summary leaves only when every content row of its turn is already
268
+ * withdrawn — the same rule as the plugin's `deriveTurnProcess`. One content
269
+ * row before the target (a mid-turn steering rewind) keeps the summary and
270
+ * that earlier message. A turn with no content rows is left alone.
271
+ */
272
+ function summaryTurns(chat, cuts) {
273
+ const stays = /* @__PURE__ */ new Map();
274
+ for (const key of chat.order) {
275
+ const node = chat.nodes.get(key);
276
+ if (node === void 0 || TURN_SUMMARY_KINDS.has(node.kind ?? "")) continue;
277
+ const id = turnIdOf(node);
278
+ if (id === void 0) continue;
279
+ const visible = node.visibility !== "hidden" && !anchorWithdrawn(node, cuts);
280
+ stays.set(id, (stays.get(id) ?? false) || visible);
281
+ }
282
+ const withdrawn = /* @__PURE__ */ new Set();
283
+ for (const [id, visible] of stays) if (!visible) withdrawn.add(id);
284
+ return withdrawn;
285
+ }
286
+ /** True when this row is a summary of a turn whose content is fully withdrawn. */
287
+ function summaryWithdrawn(node, summaries) {
288
+ if (!TURN_SUMMARY_KINDS.has(node.kind ?? "")) return false;
289
+ const id = turnIdOf(node);
290
+ return id !== void 0 && summaries.has(id);
291
+ }
292
+ /**
293
+ * The shadow ranges a session's executed rewinds produced, newest state last.
294
+ * An executed rewind cuts `[target, marker]` — the target itself is included,
295
+ * because a rewind restores the state *before* that message was sent (its text
296
+ * goes back to the composer).
297
+ */
298
+ function rewindCutSpans(chat) {
299
+ if (chat === void 0) return [];
300
+ const spans = [];
301
+ for (const key of chat.order) {
302
+ const node = chat.nodes.get(key);
303
+ if (node === void 0) continue;
304
+ const command = commandOf(node);
305
+ if (command === void 0 || !isRewindCommand(command)) continue;
306
+ if (isPreviewCommand(command) || isCandidateCommand(command)) continue;
307
+ const outcome = asRecord$1(command.outcome);
308
+ if (outcome?.kind !== "success") continue;
309
+ const marker = safeSeq(outcome.sourceEventSeq);
310
+ if (marker === void 0) continue;
311
+ const target = rewindTargetOfArgs(command.args);
312
+ if (target === void 0 || target > marker) continue;
313
+ spans.push({
314
+ start: target,
315
+ end: marker
316
+ });
317
+ }
318
+ return coalesceCutSpans(spans);
319
+ }
320
+ /**
321
+ * The chat keys the Reader should render, in snapshot order: withdrawn rows and
322
+ * rows the host itself marked hidden are dropped, everything else keeps its
323
+ * position. Returns the snapshot's own `order` array when nothing is filtered,
324
+ * so React selectors see a stable reference.
325
+ */
326
+ function visibleChatKeys(chat) {
327
+ const cuts = rewindCutSpans(chat);
328
+ const summaries = summaryTurns(chat, cuts);
329
+ const visible = [];
330
+ for (const key of chat.order) {
331
+ const node = chat.nodes.get(key);
332
+ if (node === void 0) continue;
333
+ if (node.visibility === "hidden") continue;
334
+ if (anchorWithdrawn(node, cuts) || summaryWithdrawn(node, summaries)) continue;
335
+ visible.push(key);
336
+ }
337
+ return visible.length === chat.order.length ? chat.order : visible;
338
+ }
339
+ /**
340
+ * A comparable signal for the visible row set, built for
341
+ * `useSyncExternalStore`-style subscription: the host re-runs a chat selector
342
+ * on every publish and compares the RESULT by `Object.is`, and a rewind
343
+ * publishes an in-place upsert of an existing command row. The snapshot's
344
+ * `order` array and node store are therefore both reference-stable across a
345
+ * rewind, so a selector on them never re-renders; a string does change exactly
346
+ * when the visible set does. Never return the array itself from a selector —
347
+ * a fresh array fails the `Object.is` check on every publish.
348
+ */
349
+ function visibleChatSignature(chat) {
350
+ return visibleChatKeys(chat).join("\0");
351
+ }
352
+ //#endregion
112
353
  //#region src/client/tool-activity.ts
113
- /** Public Step data includes tool-only model output before a chat node exists. */
114
- function readerFlow(group, turn, get) {
354
+ /**
355
+ * callId of a tool-call chat node. Drafts for a call whose node was cut must
356
+ * not be reintroduced after `group.keys` has already dropped that node.
357
+ */
358
+ function toolCallId(node) {
359
+ const callId = node.data?.root?.callId;
360
+ return typeof callId === "string" && callId.length > 0 ? callId : void 0;
361
+ }
362
+ /** callIds whose tool-call node sits inside a rewind cut. */
363
+ function cutToolCallIds(order, get, spans) {
364
+ const ids = /* @__PURE__ */ new Set();
365
+ for (const key of order) {
366
+ const node = get(key);
367
+ if (node?.kind !== "tool-call") continue;
368
+ const seq = anchorSeqOf(node);
369
+ if (seq === void 0 || !cutContains(spans, seq)) continue;
370
+ const callId = toolCallId(node);
371
+ if (callId !== void 0) ids.add(callId);
372
+ }
373
+ return ids;
374
+ }
375
+ /**
376
+ * Public Step data includes tool-only model output before a chat node exists.
377
+ *
378
+ * `sourceOrder` is the unfiltered chat order. Drafts that belong to a cut step,
379
+ * or to a call whose tool-call node was cut, are not put back. A draft that
380
+ * still has no tool-call node, on a step outside the cut, stays — that is the
381
+ * in-flight call the host has not published a node for yet.
382
+ */
383
+ function readerFlow(group, turn, get, sourceOrder) {
115
384
  const flow = [];
116
385
  const calls = /* @__PURE__ */ new Map();
117
386
  const assistantOrder = /* @__PURE__ */ new Map();
387
+ const spans = sourceOrder === void 0 ? [] : rewindCutSpans({
388
+ order: sourceOrder,
389
+ nodes: { get }
390
+ });
391
+ const cutCalls = spans.length === 0 || sourceOrder === void 0 ? void 0 : cutToolCallIds(sourceOrder, get, spans);
118
392
  for (const key of group.keys) {
119
393
  const node = get(key);
120
394
  if (!node || node.visibility === "hidden") continue;
@@ -141,10 +415,13 @@ window.__ModuleLoader__.load({
141
415
  }
142
416
  for (const step of turn?.steps ?? []) {
143
417
  const data = step.data.get("assistant-step");
418
+ const stepSeq = step.start?.seq;
419
+ const stepCut = typeof stepSeq === "number" && spans.length > 0 && cutContains(spans, stepSeq);
144
420
  let index = 0;
145
421
  for (const draft of data?.blocks ?? []) {
146
422
  if (draft.kind !== "tool-call" || !draft.callId) continue;
147
423
  const previous = calls.get(draft.callId);
424
+ if (!previous && (stepCut || cutCalls?.has(draft.callId) === true)) continue;
148
425
  calls.set(draft.callId, previous ? {
149
426
  ...previous,
150
427
  draft
@@ -169,9 +446,12 @@ window.__ModuleLoader__.load({
169
446
  }
170
447
  /** Read only top-level JSON string values, including an unfinished final string.
171
448
  * This never executes input or mistakes escaped/nested content for a path field. */
172
- function inputFields(raw) {
449
+ function parseInputFields(raw) {
173
450
  try {
174
- return objectValue(JSON.parse(raw)) ?? {};
451
+ return {
452
+ kind: "complete",
453
+ fields: objectValue(JSON.parse(raw)) ?? {}
454
+ };
175
455
  } catch {}
176
456
  const fields = Object.create(null);
177
457
  const prefix = raw.slice(0, 262144);
@@ -225,13 +505,20 @@ window.__ModuleLoader__.load({
225
505
  key = void 0;
226
506
  }
227
507
  }
228
- return fields;
508
+ return {
509
+ kind: "partial",
510
+ fields
511
+ };
512
+ }
513
+ function inputFields(raw) {
514
+ return parseInputFields(raw).fields;
229
515
  }
516
+ /** Name and raw arguments of any call block, whether it has landed or is pending. */
230
517
  function toolIdentity(entry) {
231
518
  const block = entry.block;
232
519
  return {
233
520
  name: block ? "kind" in block ? block.call?.name ?? entry.draft?.name ?? "工具调用" : block.name : entry.draft?.name ?? "工具调用",
234
- raw: block ? "kind" in block ? block.call?.argsRaw ?? entry.draft?.argsRaw ?? "" : "argsRaw" in block ? block.argsRaw : "" : entry.draft?.argsRaw ?? ""
521
+ raw: block ? "kind" in block ? block.call?.argsRaw ?? entry.draft?.argsRaw ?? "" : "argsRaw" in block ? block.argsRaw : entry.draft?.argsRaw ?? "" : entry.draft?.argsRaw ?? ""
235
522
  };
236
523
  }
237
524
  /** Name and raw arguments of any call block, whether it has landed or is pending. */
@@ -364,7 +651,7 @@ window.__ModuleLoader__.load({
364
651
  }
365
652
  function activityPhase(entry, turnClosed = false) {
366
653
  if (!entry.block) return turnClosed ? "interrupted" : "preparing";
367
- if (!("kind" in entry.block)) return turnClosed ? "interrupted" : "running";
654
+ if (!("kind" in entry.block)) return turnClosed ? "interrupted" : entry.block.phase === "preparing" ? "preparing" : "running";
368
655
  if (entry.block.error?.code === "ABORTED" || entry.block.error?.code === "interrupted") return "interrupted";
369
656
  const facts = executionFacts(entry.block);
370
657
  if (entry.block.isError || facts.signal || facts.exitCode !== void 0 && facts.exitCode !== 0 || entry.block.subCalls.some((block) => activityPhase({ block }, turnClosed) === "failed")) return "failed";
@@ -411,18 +698,21 @@ window.__ModuleLoader__.load({
411
698
  }
412
699
  function activitySummary(entry) {
413
700
  const { name, raw } = toolIdentity(entry);
414
- const args = inputFields(raw);
701
+ const parsed = parseInputFields(raw);
702
+ const args = parsed.fields;
415
703
  const target = stringValue(args, "file_path", "path", "filename", "filePath");
416
704
  const command = stringValue(args, "command", "cmd", "script");
417
705
  const description = stringValue(args, "description");
418
706
  const file = target?.split(/[/\\]/).at(-1);
419
707
  const category = /^(write|edit|apply_patch|patch|str_replace_editor)$/.test(name) ? "write" : /^(read|read_file)$/.test(name) ? "read" : /^(bash|shell|terminal|terminal_send|exec_command|pwsh)$/.test(name) ? "terminal" : /^(grep|glob|find|search)$/.test(name) ? "search" : /^(web_search|web_fetch|web_open)$/.test(name) ? "web" : /^(run_code|execute_code|code_interpreter|python|node|eval|repl)$/.test(name) ? "code" : "other";
708
+ const title = category === "write" ? `${name === "write" ? "写入" : "修改"}${file ? ` ${file}` : name === "apply_patch" ? "代码补丁" : "文件"}` : category === "read" ? `读取${file ? ` ${file}` : "文件"}` : category === "terminal" ? description || "运行命令" : category === "search" ? name === "glob" ? "查找文件" : "搜索内容" : category === "web" ? name === "web_search" ? "搜索网页" : "读取网页" : category === "code" ? description || "运行代码" : name;
420
709
  return {
421
710
  name,
422
711
  raw,
423
712
  args,
713
+ argsState: parsed.kind,
424
714
  category,
425
- title: category === "write" ? `${name === "write" ? "写入" : "修改"}${file ? ` ${file}` : name === "apply_patch" ? "代码补丁" : "文件"}` : category === "read" ? `读取${file ? ` ${file}` : "文件"}` : category === "terminal" ? description || "运行命令" : category === "search" ? name === "glob" ? "查找文件" : "搜索内容" : category === "web" ? name === "web_search" ? "搜索网页" : "读取网页" : category === "code" ? description || "运行代码" : name,
715
+ title,
426
716
  target: target ?? command ?? stringValue(args, "query", "pattern", "url"),
427
717
  command,
428
718
  cwd: stringValue(args, "workdir", "cwd"),
@@ -444,6 +734,7 @@ window.__ModuleLoader__.load({
444
734
  function dirname(path) {
445
735
  const normalized = path.replace(/[/\\]+$/, "");
446
736
  const at = Math.max(normalized.lastIndexOf("/"), normalized.lastIndexOf("\\"));
737
+ if (at === 0 || at === 2 && /^[A-Za-z]:/.test(normalized)) return normalized.slice(0, at + 1);
447
738
  return at === -1 ? "." : normalized.slice(0, at) || ".";
448
739
  }
449
740
  /**
@@ -523,6 +814,35 @@ window.__ModuleLoader__.load({
523
814
  } };
524
815
  }
525
816
  //#endregion
817
+ //#region src/workspace-path.ts
818
+ /** Absolute paths accepted by both POSIX and Windows hosts. */
819
+ function isAbsoluteWorkspacePath(path) {
820
+ return /^(?:\/|[A-Za-z]:[/\\]|\\\\)/.test(path);
821
+ }
822
+ //#endregion
823
+ //#region src/client/styles.ts
824
+ const plugin = "dsh-better-display";
825
+ const styles$1 = /* @__PURE__ */ new Map();
826
+ /** Retain injected CSS across host cleanup and restore it before Reader paints. */
827
+ function ensureStyles() {
828
+ if (typeof document === "undefined") return;
829
+ const live = /* @__PURE__ */ new Set();
830
+ for (const tag of document.querySelectorAll(`style[data-plugin="${plugin}"][data-plugin-css]`)) {
831
+ const id = tag.dataset.pluginCss;
832
+ if (id === void 0) continue;
833
+ styles$1.set(id, tag.textContent ?? "");
834
+ live.add(id);
835
+ }
836
+ for (const [id, text] of styles$1) {
837
+ if (live.has(id)) continue;
838
+ const tag = document.createElement("style");
839
+ tag.dataset.plugin = plugin;
840
+ tag.dataset.pluginCss = id;
841
+ tag.textContent = text;
842
+ document.head.appendChild(tag);
843
+ }
844
+ }
845
+ //#endregion
526
846
  //#region src/client/mcp-app.ts
527
847
  /**
528
848
  * Core pure functions for SEP-1865 / MCP Apps integration.
@@ -765,7 +1085,7 @@ ${trimmed}
765
1085
  }
766
1086
  //#endregion
767
1087
  //#region \0dshx-css-module:McpAppFrame.module.css.mjs
768
- const css$7 = ".tyd90a_card{border:1px solid var(--dsw-alias-border-l2,#00000014);background:var(--dsw-alias-bg-module-platform,transparent);border-radius:14px;margin:16px 0;transition:border-color .2s cubic-bezier(.22,1,.36,1),box-shadow .2s cubic-bezier(.22,1,.36,1);position:relative;overflow:hidden}.tyd90a_card:hover{border-color:var(--dsw-alias-border-l1,#00000029);box-shadow:0 2px 10px -2px #0000000a}.tyd90a_header{border-bottom:1px solid var(--dsw-alias-border-l2,#0000000f);background:var(--dsw-alias-interactive-bg-hover,#00000004);user-select:none;justify-content:space-between;align-items:center;height:36px;padding:0 14px;display:flex}.tyd90a_titleArea{align-items:center;gap:7px;min-width:0;display:flex}.tyd90a_icon{color:var(--dsw-alias-label-tertiary,#94a3b8);flex-shrink:0;justify-content:center;align-items:center;display:flex}.tyd90a_title{color:var(--dsw-alias-label-secondary,#64748b);letter-spacing:-.01em;text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:500;overflow:hidden}.tyd90a_actions{align-items:center;gap:4px;display:flex}.tyd90a_iconBtn{width:24px;height:24px;color:var(--dsw-alias-label-tertiary,#94a3b8);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:0;transition:all .15s;display:inline-flex}.tyd90a_iconBtn:hover{background:var(--dsw-alias-interactive-bg-hover,#0000000f);color:var(--dsw-alias-label-primary,#0f172a)}.tyd90a_iconBtn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#2563eb);outline-offset:1px}.tyd90a_iframeWrapper{background:0 0;width:100%;transition:height .25s cubic-bezier(.22,1,.36,1);position:relative}.tyd90a_iframe{background:0 0;border:none;width:100%;height:100%;display:block}.tyd90a_receipt{background:var(--dsw-alias-interactive-bg-hover,#22c55e0d);border-top:1px solid var(--dsw-alias-border-l2,#0000000f);color:var(--dsw-alias-label-primary,#0f172a);flex-wrap:wrap;justify-content:space-between;align-items:center;gap:6px 12px;padding:8px 14px;font-size:12px;line-height:18px;animation:.2s cubic-bezier(.22,1,.36,1) tyd90a_slideUp;display:flex}.tyd90a_receiptPrompt{color:var(--dsw-alias-label-secondary,#64748b);background:var(--dsw-alias-bg-base,#00000008);border:1px solid var(--dsw-alias-border-l2,#0000000f);user-select:text;cursor:text;overflow-wrap:anywhere;border-radius:6px;flex:100%;padding:6px 10px;font-size:12px;line-height:18px}@keyframes tyd90a_slideUp{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.tyd90a_receiptSummary{color:var(--dsw-alias-state-business-primary,#16a34a);text-overflow:ellipsis;white-space:nowrap;align-items:center;gap:6px;font-weight:500;display:flex;overflow:hidden}.tyd90a_receiptHint{align-items:center;gap:6px;display:flex}.tyd90a_sendKbd{color:var(--dsw-alias-label-tertiary,#94a3b8);background:var(--dsw-alias-bg-base,#0000000a);border:1px solid var(--dsw-alias-border-l2,#00000014);cursor:pointer;border-radius:5px;align-items:center;gap:4px;padding:2px 8px;font-family:inherit;font-size:11px;transition:all .15s;display:inline-flex}.tyd90a_sendKbd:hover{background:var(--dsw-alias-interactive-bg-hover,#00000014);color:var(--dsw-alias-label-primary,#0f172a)}.tyd90a_sendKbd:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#2563eb);outline-offset:1px}.tyd90a_streamingPlaceholder{border:1px dashed var(--dsw-alias-border-l2,#0000001f);background:var(--dsw-alias-interactive-bg-hover,#00000004);color:var(--dsw-alias-label-secondary,#64748b);border-radius:14px;align-items:center;gap:10px;margin:16px 0;padding:16px 18px;font-size:13px;display:flex}.tyd90a_pulseDot{background:var(--dsw-alias-state-business-primary,#2563eb);border-radius:50%;width:7px;height:7px;animation:1.5s ease-in-out infinite tyd90a_pulse}@keyframes tyd90a_pulse{0%,to{opacity:.35;transform:scale(.9)}50%{opacity:1;transform:scale(1.15)}}";
1088
+ const css$7 = ".tyd90a_card{border:1px solid var(--dsw-alias-border-l2,#00000014);background:var(--dsw-alias-bg-module-platform,transparent);border-radius:14px;margin:16px 0;transition:border-color .2s cubic-bezier(.22,1,.36,1),box-shadow .2s cubic-bezier(.22,1,.36,1);position:relative;overflow:hidden}.tyd90a_card:hover{border-color:var(--dsw-alias-border-l1,#00000029);box-shadow:0 2px 10px -2px #0000000a}.tyd90a_header{border-bottom:1px solid var(--dsw-alias-border-l2,#0000000f);background:var(--dsw-alias-interactive-bg-hover,#00000004);-webkit-user-select:none;user-select:none;justify-content:space-between;align-items:center;height:36px;padding:0 14px;display:flex}.tyd90a_titleArea{align-items:center;gap:7px;min-width:0;display:flex}.tyd90a_icon{color:var(--dsw-alias-label-tertiary,#94a3b8);flex-shrink:0;justify-content:center;align-items:center;display:flex}.tyd90a_title{color:var(--dsw-alias-label-secondary,#64748b);letter-spacing:-.01em;text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:500;overflow:hidden}.tyd90a_actions{align-items:center;gap:4px;display:flex}.tyd90a_iconBtn{width:24px;height:24px;color:var(--dsw-alias-label-tertiary,#94a3b8);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:0;transition:all .15s;display:inline-flex}.tyd90a_iconBtn:hover{background:var(--dsw-alias-interactive-bg-hover,#0000000f);color:var(--dsw-alias-label-primary,#0f172a)}.tyd90a_iconBtn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#2563eb);outline-offset:1px}.tyd90a_iframeWrapper{background:0 0;width:100%;transition:height .25s cubic-bezier(.22,1,.36,1);position:relative}.tyd90a_iframe{background:0 0;border:none;width:100%;height:100%;display:block}.tyd90a_receipt{background:var(--dsw-alias-interactive-bg-hover,#22c55e0d);border-top:1px solid var(--dsw-alias-border-l2,#0000000f);color:var(--dsw-alias-label-primary,#0f172a);flex-wrap:wrap;justify-content:space-between;align-items:center;gap:6px 12px;padding:8px 14px;font-size:12px;line-height:18px;animation:.2s cubic-bezier(.22,1,.36,1) tyd90a_slideUp;display:flex}.tyd90a_receiptPrompt{color:var(--dsw-alias-label-secondary,#64748b);background:var(--dsw-alias-bg-base,#00000008);border:1px solid var(--dsw-alias-border-l2,#0000000f);-webkit-user-select:text;user-select:text;cursor:text;overflow-wrap:anywhere;border-radius:6px;flex:100%;padding:6px 10px;font-size:12px;line-height:18px}@keyframes tyd90a_slideUp{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.tyd90a_receiptSummary{color:var(--dsw-alias-state-business-primary,#16a34a);text-overflow:ellipsis;white-space:nowrap;align-items:center;gap:6px;font-weight:500;display:flex;overflow:hidden}.tyd90a_receiptHint{align-items:center;gap:6px;display:flex}.tyd90a_sendKbd{color:var(--dsw-alias-label-tertiary,#94a3b8);background:var(--dsw-alias-bg-base,#0000000a);border:1px solid var(--dsw-alias-border-l2,#00000014);cursor:pointer;border-radius:5px;align-items:center;gap:4px;padding:2px 8px;font-family:inherit;font-size:11px;transition:all .15s;display:inline-flex}.tyd90a_sendKbd:hover{background:var(--dsw-alias-interactive-bg-hover,#00000014);color:var(--dsw-alias-label-primary,#0f172a)}.tyd90a_sendKbd:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#2563eb);outline-offset:1px}.tyd90a_streamingPlaceholder{border:1px dashed var(--dsw-alias-border-l2,#0000001f);background:var(--dsw-alias-interactive-bg-hover,#00000004);color:var(--dsw-alias-label-secondary,#64748b);border-radius:14px;align-items:center;gap:10px;margin:16px 0;padding:16px 18px;font-size:13px;display:flex}.tyd90a_pulseDot{background:var(--dsw-alias-state-business-primary,#2563eb);border-radius:50%;width:7px;height:7px;animation:1.5s ease-in-out infinite tyd90a_pulse}@keyframes tyd90a_pulse{0%,to{opacity:.35;transform:scale(.9)}50%{opacity:1;transform:scale(1.15)}}";
769
1089
  const tagId$7 = "dsh-better-display/McpAppFrame.module.css";
770
1090
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$7) + "]") === null) {
771
1091
  const tag = document.createElement("style");
@@ -806,7 +1126,6 @@ ${trimmed}
806
1126
  const iframeRef = (0, react.useRef)(null);
807
1127
  const lastParamsRef = (0, react.useRef)({});
808
1128
  const [height, setHeight] = (0, react.useState)(() => Math.max(60, Math.min(2400, initialHeight)));
809
- const [ready, setReady] = (0, react.useState)(false);
810
1129
  const [receipt, setReceipt] = (0, react.useState)(null);
811
1130
  const [lastPrompt, setLastPrompt] = (0, react.useState)(null);
812
1131
  const [reloadNonce, setReloadNonce] = (0, react.useState)(0);
@@ -829,7 +1148,7 @@ ${trimmed}
829
1148
  }, [title, writeComposer]);
830
1149
  const handleUserSubmit = (0, react.useCallback)((params) => {
831
1150
  lastParamsRef.current = params;
832
- let summary = "";
1151
+ let summary;
833
1152
  if (typeof params.choice === "string") {
834
1153
  const desc = typeof params.desc === "string" ? ` (${params.desc})` : "";
835
1154
  summary = `选择: ${params.choice}${desc}`;
@@ -861,13 +1180,9 @@ ${trimmed}
861
1180
  }
862
1181
  };
863
1182
  iframe.contentWindow?.postMessage(response, "*");
864
- setReady(true);
865
- return;
866
- }
867
- if (data.method === "ui/ready" || data.method === "ui/notifications/initialized") {
868
- setReady(true);
869
1183
  return;
870
1184
  }
1185
+ if (data.method === "ui/ready" || data.method === "ui/notifications/initialized") return;
871
1186
  if (data.method === "ui/resize" && data.params?.height) {
872
1187
  const h = Number(data.params.height);
873
1188
  if (Number.isFinite(h) && h > 0) setHeight(Math.max(60, Math.min(2400, Math.round(h))));
@@ -935,11 +1250,9 @@ ${trimmed}
935
1250
  styles: { variables: cssTokens }
936
1251
  }
937
1252
  }, "*");
938
- setReady(true);
939
1253
  }, []);
940
1254
  const handleReload = (0, react.useCallback)(() => {
941
1255
  setReloadNonce((n) => n + 1);
942
- setReady(false);
943
1256
  setReceipt(null);
944
1257
  }, []);
945
1258
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -10383,7 +10696,7 @@ ${trimmed}
10383
10696
  return count;
10384
10697
  }
10385
10698
  //#endregion
10386
- //#region node_modules/escape-string-regexp/index.js
10699
+ //#region node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp/index.js
10387
10700
  function escapeStringRegexp(string) {
10388
10701
  if (typeof string !== "string") throw new TypeError("Expected a string");
10389
10702
  return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
@@ -41815,7 +42128,7 @@ ${trimmed}
41815
42128
  }
41816
42129
  //#endregion
41817
42130
  //#region \0dshx-css-module:MarkdownText.module.css.mjs
41818
- const css$6 = ".zfLqdW_markdown{overflow-wrap:anywhere;min-width:0;font:var(--dsw-font-markdown-base);color:var(--dsw-alias-label-primary)}.zfLqdW_markdown strong{font-weight:600}.zfLqdW_markdown h1{font:var(--dsw-font-markdown-h1);margin:32px 0 16px}.zfLqdW_markdown h2{font:var(--dsw-font-markdown-h2);margin:32px 0 16px}.zfLqdW_markdown h3{font:var(--dsw-font-markdown-h3);margin:32px 0 16px}.zfLqdW_markdown h4{font:var(--dsw-font-markdown-h4);margin:16px 0}.zfLqdW_markdown :where(h5,h6){font:var(--dsw-font-markdown-base-strong);margin:16px 0}.zfLqdW_markdown :where(h1,h2,h3,h4,h5,h6) strong{font-weight:inherit}.zfLqdW_markdown p{margin:16px 0}.zfLqdW_markdown :where(h4,h5,h6)+:where(ul,ol){margin-top:8px}.zfLqdW_markdown :where(h4,h5,h6):has(+:where(ul,ol)){margin-bottom:8px}.zfLqdW_markdown a{color:var(--dsw-alias-state-business-primary);transition:box-shadow var(--ds-transition-duration) var(--ds-ease-in-out);border:2px solid #fff0;border-width:2px 3px;margin-left:-3px;margin-right:-3px;text-decoration:none;position:relative}.zfLqdW_markdown a:hover,.zfLqdW_markdown a:focus{text-decoration:underline var(--dsw-alias-state-business-primary);outline:none}.zfLqdW_markdown a:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary)}.zfLqdW_markdown :where(ul,ol){margin:16px 0;padding-left:18px}.zfLqdW_markdown li:not(:first-child){margin-top:6px}.zfLqdW_markdown li>:where(ul,ol){margin-top:4px}.zfLqdW_markdown li::marker{color:var(--dsw-alias-label-secondary);line-height:28px}.zfLqdW_markdown :where(ul,ol) ol{padding-left:0;list-style-position:inside}.zfLqdW_markdown :where(ul,ol) ol li p{display:inline}.zfLqdW_markdown li>p{margin:8px 0}.zfLqdW_markdown li>:first-child{margin-top:0}.zfLqdW_markdown li>:last-child:not(.md-code-block){margin-bottom:0}.zfLqdW_markdown hr{background:var(--dsw-alias-border-l2);border:none;height:1px;margin:32px 0;display:block}.zfLqdW_markdown blockquote{border-left:2px solid var(--dsw-alias-label-caption);margin:16px 0 0;padding-left:14px}.zfLqdW_markdown pre{font-family:var(--ds-font-family-code);margin:16px 0;overflow:auto}.zfLqdW_markdown :not(pre)>code{box-sizing:border-box;font:var(--dsw-font-markdown-code);font-family:var(--ds-font-family-code);background-color:var(--dsw-alias-markdown-inline-code);border-radius:6px;align-items:center;padding:0 5px;display:inline-flex;font-size:.875em!important}.zfLqdW_markdown :where(h1,h2,h3,h4,h5,h6) code{font:inherit;font-family:var(--ds-font-family-code)}.zfLqdW_markdown .katex-display{max-width:100%;overflow:auto hidden}.zfLqdW_markdown input[type=checkbox]{accent-color:var(--dsw-alias-label-secondary);margin:0 8px 0 0}.zfLqdW_tableScroll{overscroll-behavior-x:contain;max-width:100%;overflow-x:auto}.zfLqdW_tableScroll.md-table-wide{padding-bottom:var(--dsh-scrollbar-width,8px);overflow-x:hidden}.zfLqdW_tableScroll.md-table-wide:hover,.zfLqdW_tableScroll.md-table-wide:focus-visible{padding-bottom:0;overflow-x:auto}.zfLqdW_tableScroll:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}.zfLqdW_tableScroll table{border-collapse:collapse;width:max-content;max-width:max-content}.zfLqdW_tableFill table{width:100%;max-width:none}.zfLqdW_tableScroll th{text-align:start;border-bottom:1px solid var(--dsw-alias-border-l3);font:var(--dsw-font-markdown-table-head);border-top:none;min-width:100px;max-width:min(30vw,320px);padding:10px 16px}.zfLqdW_tableScroll td{border-bottom:1px solid var(--dsw-alias-border-l2);font:var(--dsw-font-markdown-table);min-width:100px;max-width:min(30vw,320px);padding:10px 16px}.zfLqdW_tableScroll th:first-child,.zfLqdW_tableScroll td:first-child{padding-left:0}.zfLqdW_tableScroll td:last-child{padding-right:0}.zfLqdW_tableScroll table code{font-size:13px}.zfLqdW_markdown>:first-child,.zfLqdW_markdown p:first-child{margin-top:0!important}.zfLqdW_markdown>:last-child,.zfLqdW_markdown p:last-child{margin-bottom:0!important}.zfLqdW_imageAlt{color:var(--dsw-alias-label-tertiary);font-style:italic}.zfLqdW_image{background:var(--dsw-alias-bg-base);object-fit:contain;border-radius:8px;width:auto;max-width:100%;height:auto;margin:0;display:block}.zfLqdW_fileMention{font:inherit;color:var(--dsw-alias-state-business-primary);cursor:pointer;background:0 0;border:none;margin:0;padding:0;text-decoration:none}.zfLqdW_fileMention:hover,.zfLqdW_fileMention:focus{text-decoration:underline var(--dsw-alias-state-business-primary);text-underline-offset:3px;outline:none}";
42131
+ const css$6 = ".zfLqdW_markdown{overflow-wrap:anywhere;min-width:0;font:var(--dsw-font-markdown-base);color:var(--dsw-alias-label-primary)}.zfLqdW_markdown strong{font-weight:600}.zfLqdW_markdown h1{font:var(--dsw-font-markdown-h1);margin:32px 0 16px}.zfLqdW_markdown h2{font:var(--dsw-font-markdown-h2);margin:32px 0 16px}.zfLqdW_markdown h3{font:var(--dsw-font-markdown-h3);margin:32px 0 16px}.zfLqdW_markdown h4{font:var(--dsw-font-markdown-h4);margin:16px 0}.zfLqdW_markdown :where(h5,h6){font:var(--dsw-font-markdown-base-strong);margin:16px 0}.zfLqdW_markdown :where(h1,h2,h3,h4,h5,h6) strong{font-weight:inherit}.zfLqdW_markdown p{margin:16px 0}.zfLqdW_markdown :where(h4,h5,h6)+:where(ul,ol){margin-top:8px}.zfLqdW_markdown :where(h4,h5,h6):has(+:where(ul,ol)){margin-bottom:8px}.zfLqdW_markdown a{color:var(--dsw-alias-state-business-primary);transition:box-shadow var(--ds-transition-duration) var(--ds-ease-in-out);border:2px solid #fff0;border-width:2px 3px;margin-left:-3px;margin-right:-3px;text-decoration:none;position:relative}.zfLqdW_markdown a:hover,.zfLqdW_markdown a:focus{-webkit-text-decoration:underline var(--dsw-alias-state-business-primary);text-decoration:underline var(--dsw-alias-state-business-primary);outline:none}.zfLqdW_markdown a:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary)}.zfLqdW_markdown :where(ul,ol){margin:16px 0;padding-left:18px}.zfLqdW_markdown li:not(:first-child){margin-top:6px}.zfLqdW_markdown li>:where(ul,ol){margin-top:4px}.zfLqdW_markdown li::marker{color:var(--dsw-alias-label-secondary);line-height:28px}.zfLqdW_markdown :where(ul,ol) ol{padding-left:0;list-style-position:inside}.zfLqdW_markdown :where(ul,ol) ol li p{display:inline}.zfLqdW_markdown li>p{margin:8px 0}.zfLqdW_markdown li>:first-child{margin-top:0}.zfLqdW_markdown li>:last-child:not(.md-code-block){margin-bottom:0}.zfLqdW_markdown hr{background:var(--dsw-alias-border-l2);border:none;height:1px;margin:32px 0;display:block}.zfLqdW_markdown blockquote{border-left:2px solid var(--dsw-alias-label-caption);margin:16px 0 0;padding-left:14px}.zfLqdW_markdown pre{font-family:var(--ds-font-family-code);margin:16px 0;overflow:auto}.zfLqdW_markdown :not(pre)>code{box-sizing:border-box;font:var(--dsw-font-markdown-code);font-family:var(--ds-font-family-code);background-color:var(--dsw-alias-markdown-inline-code);border-radius:6px;align-items:center;padding:0 5px;display:inline-flex;font-size:.875em!important}.zfLqdW_markdown :where(h1,h2,h3,h4,h5,h6) code{font:inherit;font-family:var(--ds-font-family-code)}.zfLqdW_markdown .katex-display{max-width:100%;overflow:auto hidden}.zfLqdW_markdown input[type=checkbox]{accent-color:var(--dsw-alias-label-secondary);margin:0 8px 0 0}.zfLqdW_tableScroll{overscroll-behavior-x:contain;max-width:100%;overflow-x:auto}.zfLqdW_tableScroll.md-table-wide{padding-bottom:var(--dsh-scrollbar-width,8px);overflow-x:hidden}:is(.zfLqdW_tableScroll.md-table-wide:hover,.zfLqdW_tableScroll.md-table-wide:focus-visible){padding-bottom:0;overflow-x:auto}.zfLqdW_tableScroll:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}.zfLqdW_tableScroll table{border-collapse:collapse;width:max-content;max-width:max-content}.zfLqdW_tableFill table{width:100%;max-width:none}.zfLqdW_tableScroll th{text-align:start;border-bottom:1px solid var(--dsw-alias-border-l3);font:var(--dsw-font-markdown-table-head);border-top:none;min-width:100px;max-width:min(30vw,320px);padding:10px 16px}.zfLqdW_tableScroll td{border-bottom:1px solid var(--dsw-alias-border-l2);font:var(--dsw-font-markdown-table);min-width:100px;max-width:min(30vw,320px);padding:10px 16px}.zfLqdW_tableScroll th:first-child,.zfLqdW_tableScroll td:first-child{padding-left:0}.zfLqdW_tableScroll td:last-child{padding-right:0}.zfLqdW_tableScroll table code{font-size:13px}.zfLqdW_markdown>:first-child,.zfLqdW_markdown p:first-child{margin-top:0!important}.zfLqdW_markdown>:last-child,.zfLqdW_markdown p:last-child{margin-bottom:0!important}.zfLqdW_imageAlt{color:var(--dsw-alias-label-tertiary);font-style:italic}.zfLqdW_image{background:var(--dsw-alias-bg-base);object-fit:contain;border-radius:8px;width:auto;max-width:100%;height:auto;margin:0;display:block}.zfLqdW_fileMention{font:inherit;color:var(--dsw-alias-state-business-primary);cursor:pointer;background:0 0;border:none;margin:0;padding:0;text-decoration:none}.zfLqdW_fileMention:hover,.zfLqdW_fileMention:focus{-webkit-text-decoration:underline var(--dsw-alias-state-business-primary);text-decoration:underline var(--dsw-alias-state-business-primary);text-underline-offset:3px;outline:none}";
41819
42132
  const tagId$6 = "dsh-better-display/MarkdownText.module.css";
41820
42133
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$6) + "]") === null) {
41821
42134
  const tag = document.createElement("style");
@@ -42423,7 +42736,7 @@ ${trimmed}
42423
42736
  const readerPathImages = { resolve: (value) => typeof window === "undefined" ? void 0 : localPathMediaUrl(window.location.protocol, window.location.origin, value) };
42424
42737
  //#endregion
42425
42738
  //#region \0dshx-css-module:Reader.module.css.mjs
42426
- const css$5 = ".gNoOdq_root{color:var(--dsw-alias-label-primary);padding:16px calc(var(--dsh-composer-side-clearance,16px) + 16px) 24px;overflow-anchor:auto;flex:none;min-width:0;font-family:inherit;font-size:16px;line-height:28px;container-type:inline-size}.gNoOdq_column{max-width:var(--dsh-chat-content-width,748px);flex-direction:column;gap:22px;width:100%;min-width:0;margin:0 auto;display:flex}.gNoOdq_toolbar{min-height:32px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-base);-webkit-backdrop-filter:blur(12px);justify-content:flex-end;align-items:center;gap:6px;padding:0;font-size:12px;display:flex;position:sticky;top:0}.gNoOdq_turnProcessSticky{background:var(--dsw-alias-bg-base);-webkit-backdrop-filter:blur(12px);align-items:center;min-height:32px;display:flex;position:sticky}.gNoOdq_turnProcessSticky .gNoOdq_disclosureButton{min-height:32px}.gNoOdq_textButton,.gNoOdq_historyButton,.gNoOdq_iconButton,.gNoOdq_jump,.gNoOdq_disclosureButton,.gNoOdq_imageOpen,.gNoOdq_dialogClose{font:inherit;cursor:pointer}.gNoOdq_textButton{color:var(--dsw-alias-label-secondary);white-space:nowrap;background:0 0;border:0;border-radius:6px;padding:2px 6px}.gNoOdq_textButton:hover,.gNoOdq_iconButton:hover,.gNoOdq_disclosureButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_root button:focus-visible,.gNoOdq_root summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:3px}.gNoOdq_turn{flex-direction:column;gap:14px;min-width:0;display:flex}.gNoOdq_turn+.gNoOdq_turn{margin-top:12px}.gNoOdq_userCluster{flex-direction:column;align-self:flex-end;align-items:flex-end;gap:8px;min-width:0;max-width:min(525px,82%);margin-bottom:4px;display:flex}.gNoOdq_userImages{flex-direction:column;align-items:flex-end;min-width:0;max-width:100%;display:flex}.gNoOdq_userImages .gNoOdq_imageFigure{align-self:flex-end}.gNoOdq_user{background:var(--dsw-specific-bubble);max-width:100%;color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;box-sizing:border-box;border-radius:22px;align-self:flex-end;padding:10px 16px;line-height:24px}.gNoOdq_user .gNoOdq_blocks{gap:10px}.gNoOdq_answer{overflow-wrap:anywhere;flex-direction:column;min-width:0;display:flex}.gNoOdq_readingText{min-width:0}.gNoOdq_reasonPlain{white-space:pre-wrap;overflow-wrap:anywhere;font:inherit;color:inherit}.gNoOdq_readingText button{min-width:24px;min-height:24px}.gNoOdq_streamWord{display:inline-block}.gNoOdq_streamInlineWord{display:inline}.gNoOdq_streamWord,.gNoOdq_streamInlineWord,.gNoOdq_streamAtom{opacity:1;filter:none}.gNoOdq_streamAtom{min-width:0}@media (prefers-reduced-motion:reduce){.gNoOdq_streamWord,.gNoOdq_streamInlineWord,.gNoOdq_streamAtom{opacity:1!important;filter:none!important}}.gNoOdq_retiringContent{min-width:0}.gNoOdq_retiringContent[data-reader-retiring=retiring]{overflow:hidden}.gNoOdq_mainFlow,.gNoOdq_blocks{flex-direction:column;gap:16px;min-width:0;display:flex}.gNoOdq_mainFlow:empty,.gNoOdq_blocks:empty{display:none}.gNoOdq_blocks>:first-child{margin-top:0}.gNoOdq_blocks>:last-child{margin-bottom:0}.gNoOdq_blocks .md-table-wide{max-width:100%}.gNoOdq_disclosure{min-width:0}.gNoOdq_disclosureButton{max-width:100%;min-height:32px;color:var(--dsw-alias-label-tertiary);text-align:left;background:0 0;border:0;border-radius:7px;align-items:center;gap:6px;margin-left:-6px;padding:4px 6px;font-size:14px;font-weight:400;line-height:24px;display:inline-flex}.gNoOdq_disclosure[data-reader-status-only]{align-items:center;min-height:32px;display:flex}.gNoOdq_statusText{min-width:0;max-width:100%;color:var(--dsw-alias-label-secondary);font-size:14px;font-weight:400;line-height:24px;display:inline-flex}.gNoOdq_srOnly{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.gNoOdq_think{--think-swap:.15s;--think-gap:50ms;--think-distance:8px;--think-blur:2px;--think-shimmer:2s;--think-base:var(--dsw-alias-label-secondary);--think-highlight:var(--dsw-alias-label-primary);--think-ease:ease-in-out;text-align:left;max-width:100%;display:inline-block;position:relative}.gNoOdq_thinkSizer{visibility:hidden;white-space:nowrap;display:block}.gNoOdq_thinkText{color:var(--think-base);white-space:nowrap;text-overflow:ellipsis;filter:blur();opacity:1;transition:transform var(--think-swap) var(--think-ease), filter var(--think-swap) var(--think-ease), opacity var(--think-swap) var(--think-ease);display:block;position:absolute;top:0;left:0;right:0;overflow:hidden;transform:translateY(0)}.gNoOdq_think[data-reader-status-phase=running] .gNoOdq_thinkText[data-reader-status-copy=current]{transition-delay:var(--think-gap)}.gNoOdq_think:not([data-reader-status-phase=idle]) .gNoOdq_thinkText{will-change:transform, filter, opacity}@supports (background-clip:text){.gNoOdq_think[data-active=true] .gNoOdq_thinkText:before{content:attr(data-text);pointer-events:none;background-image:linear-gradient(90deg, transparent 0%, transparent 40%, var(--think-highlight) 50%, transparent 60%, transparent 100%);color:#0000;-webkit-text-fill-color:transparent;animation:gNoOdq_thinkShimmer var(--think-shimmer) linear infinite;background-repeat:no-repeat;background-size:400% 100%;-webkit-background-clip:text;background-clip:text;position:absolute;inset:0}}@keyframes gNoOdq_thinkShimmer{0%{background-position:100% 0}to{background-position:0 0}}.gNoOdq_thinkText.gNoOdq_isExit{transform:translateY(calc(var(--think-distance) * -1));filter:blur(var(--think-blur));opacity:0}.gNoOdq_thinkText.gNoOdq_isEnterStart{transform:translateY(var(--think-distance));filter:blur(var(--think-blur));opacity:0;transition:none}[data-motion=off] .gNoOdq_thinkText{filter:none!important;opacity:1!important;transition:none!important;transform:none!important}[data-motion=off] .gNoOdq_thinkText[data-reader-status-copy=outgoing],[data-motion=off] .gNoOdq_thinkText:before{display:none!important}@media (prefers-reduced-motion:reduce),(forced-colors:active){.gNoOdq_thinkText{filter:none!important;opacity:1!important;transition:none!important;transform:none!important}.gNoOdq_thinkText[data-reader-status-copy=outgoing],.gNoOdq_thinkText:before{display:none!important}}.gNoOdq_processMeta{opacity:0;grid-template-rows:0fr;transition:grid-template-rows .26s cubic-bezier(.22,1,.36,1),opacity .16s ease-out;display:grid}.gNoOdq_processMeta[data-open=true]{opacity:1;grid-template-rows:1fr}.gNoOdq_processMetaInner{min-height:0;overflow:hidden}.gNoOdq_processMetaLine{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex-wrap:wrap;align-items:baseline;gap:8px;padding:8px 0 0 16px;font-size:12px;line-height:20px;display:flex}.gNoOdq_processMetaLine .gNoOdq_meta{color:inherit}.gNoOdq_chevron{stroke:currentColor;fill:none;stroke-width:1.4px;stroke-linecap:round;stroke-linejoin:round;flex:none;transition:transform .26s cubic-bezier(.22,1,.36,1)}.gNoOdq_chevron[data-open=true]{transform:rotate(90deg)}.gNoOdq_disclosureBody{transform-origin:top;will-change:height, opacity, transform;height:0;overflow:hidden}.gNoOdq_processContents{border-left:1px solid var(--dsw-alias-border-l2);padding:3px 0 2px var(--reader-gutter,16px);margin:0 0 0 var(--reader-rail,6px);color:var(--dsw-alias-label-secondary);font-size:14px;line-height:24px;display:flow-root}.gNoOdq_processContents>:last-child{margin-bottom:0}.gNoOdq_processCommentary{color:var(--dsw-alias-label-secondary);margin:4px 0 8px var(--reader-rail,6px);padding-left:var(--reader-gutter,16px);border-left:1px solid var(--dsw-alias-border-l2);font-size:14px;line-height:24px}.gNoOdq_processFrame{min-width:0}.gNoOdq_toolActivity{min-width:0;color:var(--dsw-alias-label-secondary)}.gNoOdq_nativeToolRow{min-width:0}.gNoOdq_rowSeparator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.gNoOdq_nativeToolSummary{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-tertiary);flex:1;font-size:14px;line-height:24px;overflow:hidden}.gNoOdq_nativeToolRow:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:3px;border-radius:4px}.gNoOdq_toolHeading{width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:11px;grid-template-columns:20px minmax(0,1fr) auto;align-items:start;gap:10px;padding:10px 14px 4px;display:grid}.gNoOdq_toolHeading:hover{background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_toolHeading:focus-visible{outline-offset:-3px!important}.gNoOdq_toolGlyph{height:22px;color:var(--dsw-alias-label-secondary);justify-content:center;align-items:center;display:flex}.gNoOdq_toolHeadingCopy{flex-direction:column;gap:3px;min-width:0;display:flex}.gNoOdq_toolTitle{overflow-wrap:anywhere;font-size:13px;font-weight:500;line-height:22px}.gNoOdq_toolTarget{-webkit-line-clamp:2;overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary);-webkit-box-orient:vertical;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:19px;display:-webkit-box;overflow:hidden}.gNoOdq_toolHeadingState{min-height:22px;color:var(--dsw-alias-label-secondary);align-items:center;gap:7px;display:flex}.gNoOdq_diffStat{font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";white-space:nowrap;flex:none;gap:6px;margin-left:8px;font-size:11px;line-height:18px;display:inline-flex}.gNoOdq_diffAdded{color:var(--dsw-alias-state-success-primary,#2f9e63)}.gNoOdq_diffRemoved{color:var(--dsw-alias-state-error-primary,#d1483c)}.gNoOdq_summaryRow{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;max-width:100%;display:flex}.gNoOdq_summaryRow>.gNoOdq_diffStatRoot{flex:none;margin-left:auto}.gNoOdq_summaryRow>:first-child{min-width:0}.gNoOdq_diffStatRoot{flex:none;position:relative}.gNoOdq_diffStatButton{cursor:pointer;font:inherit;font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";color:var(--dsw-alias-label-secondary);background:0 0;border:1px solid #0000;border-radius:6px;align-items:center;gap:6px;padding:2px 8px;font-size:11px;line-height:16px;transition:background .12s,border-color .12s;display:inline-flex}.gNoOdq_diffStatButton:hover,.gNoOdq_diffStatButton:focus-visible,.gNoOdq_diffStatButton[aria-expanded=true]{background:var(--dsw-alias-bg-module-platform,#7f7f7f1a);border-color:var(--dsw-alias-border-l2,#7f7f7f47)}.gNoOdq_diffStatButton:focus-visible{outline:none}.gNoOdq_diffStatButton[aria-expanded=true] .gNoOdq_diffCaret{opacity:1}.gNoOdq_diffOverlayRow{box-sizing:border-box;flex:100%;width:100%;min-width:0;max-width:100%;margin-top:6px}.gNoOdq_diffOverlay{box-sizing:border-box;background:var(--dsw-alias-bg-module-platform,#7f7f7f14);border:1px solid var(--dsw-alias-border-l2,#80808038);border-radius:10px;flex-direction:column;width:100%;min-width:0;max-width:100%;padding:8px;display:flex;overflow:hidden}.gNoOdq_diffTabs{scrollbar-width:thin;flex-wrap:nowrap;gap:6px;max-width:100%;margin-bottom:4px;padding-bottom:6px;display:flex;overflow-x:auto}.gNoOdq_diffTab{text-overflow:ellipsis;white-space:nowrap;cursor:pointer;max-width:220px;font:inherit;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-base,#fffc);border:1px solid var(--dsw-alias-border-l2,#80808033);border-radius:6px;flex:none;padding:3px 10px;font-size:11px;line-height:16px;transition:all .12s;overflow:hidden}.gNoOdq_diffTab:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.gNoOdq_diffTab[data-active]{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-state-business-primary,#1e90ff);background:var(--dsw-alias-bg-base);font-weight:500}.gNoOdq_diffScrollArea{overscroll-behavior:contain;-webkit-overflow-scrolling:touch;border:1px solid var(--dsw-alias-border-l2,#80808026);background:var(--dsw-alias-markdown-code-block,#0000000a);border-radius:8px;max-height:420px;overflow:auto}.gNoOdq_diffScrollArea [data-diff]{background:0 0!important;border-radius:0!important;margin:0!important}.gNoOdq_diffCaret{opacity:.6;flex:none;width:10px;font-size:10px}.gNoOdq_diffPath{text-overflow:ellipsis;white-space:nowrap;text-align:left;direction:rtl;flex:auto;min-width:0;overflow:hidden}.gNoOdq_diffStat{font-variant-numeric:tabular-nums;flex:none;gap:6px;font-size:11px;display:inline-flex}.gNoOdq_diffHunkBody{flex-direction:column;gap:4px;padding:2px 7px 7px 25px;display:flex}.gNoOdq_diffLines{font-size:11px;line-height:1.55;font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);white-space:pre;border-radius:6px;margin:0;padding:6px 8px;overflow-x:auto}.gNoOdq_diffLines[data-side=removed]{background:#d1483c1f}.gNoOdq_diffLines[data-side=added]{background:#2f9e631f}.gNoOdq_diffLineRemoved,.gNoOdq_diffLineAdded{display:block}.gNoOdq_diffLineRemoved{color:var(--dsw-alias-state-error-primary,#d1483c)}.gNoOdq_diffLineAdded{color:var(--dsw-alias-state-success-primary,#2f9e63)}.gNoOdq_diffEmpty{color:var(--dsw-alias-label-secondary);margin:0;padding:2px 0;font-size:11px}.gNoOdq_nativeToolSummary[data-running]{background-image:linear-gradient(90deg, currentColor 0%, currentColor 35%, color-mix(in srgb, currentColor 35%, transparent) 50%, currentColor 65%, currentColor 100%);-webkit-text-fill-color:transparent;background-position:100% 0;background-repeat:no-repeat;background-size:300% 100%;-webkit-background-clip:text;background-clip:text;animation:1.6s linear infinite gNoOdq_readerStepShimmer}@keyframes gNoOdq_readerStepShimmer{to{background-position:0 0}}.gNoOdq_toolElapsed[data-slow]{opacity:1;color:var(--dsw-alias-state-warning-primary,#d8862c);font-weight:500}.gNoOdq_toolElapsed{opacity:.72;font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";white-space:nowrap;flex:none;margin-left:8px;font-size:11px;line-height:18px}[data-motion=off] .gNoOdq_nativeToolSummary[data-running]{-webkit-text-fill-color:currentColor;background-image:none;animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_nativeToolSummary[data-running]{-webkit-text-fill-color:currentColor;background-image:none;animation:none!important}}.gNoOdq_toolState{white-space:nowrap;flex:none;margin-left:8px;font-size:11px;line-height:18px}.gNoOdq_toolState[data-phase=preparing],.gNoOdq_toolState[data-phase=running]{color:var(--dsw-alias-state-business-primary)}.gNoOdq_toolState[data-phase=preparing]:before,.gNoOdq_toolState[data-phase=running]:before{content:\"\";vertical-align:middle;background:currentColor;border-radius:50%;width:6px;height:6px;margin-right:6px;animation:1.4s ease-in-out infinite gNoOdq_readerRunningGlow;display:inline-block}@keyframes gNoOdq_readerRunningGlow{0%{box-shadow:0 0 0 0 color-mix(in srgb, currentColor 60%, transparent);opacity:1}70%{opacity:.7;box-shadow:0 0 0 7px #0000}to{opacity:1;box-shadow:0 0 #0000}}[data-motion=off] .gNoOdq_toolState[data-phase=preparing]:before,[data-motion=off] .gNoOdq_toolState[data-phase=running]:before{animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_toolState[data-phase=preparing]:before,.gNoOdq_toolState[data-phase=running]:before{animation:none!important}}.gNoOdq_toolState[data-phase=failed]{color:var(--dsw-alias-state-error-primary)}.gNoOdq_toolState[data-phase=interrupted]{color:inherit;opacity:.7}.gNoOdq_toolLedger{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex-wrap:wrap;align-items:baseline;gap:4px 12px;padding:10px 14px 0;font-size:11px;line-height:18px;display:flex}.gNoOdq_toolEngine{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.gNoOdq_toolDetails{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;min-width:0;margin:6px 0 0 22px;overflow:hidden}.gNoOdq_toolTabs{align-items:center;gap:15px;padding:0 14px;display:flex}.gNoOdq_toolTabs>button{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-bottom:2px solid #0000;padding:10px 1px 8px;font-size:12px;line-height:20px}.gNoOdq_toolTabs>button[aria-selected=true]{color:var(--dsw-alias-label-primary);border-bottom-color:var(--dsw-alias-state-business-primary)}.gNoOdq_toolPanel{flex-direction:column;gap:12px;min-width:0;padding:12px 14px 14px;font-size:13px;line-height:22px;display:flex}.gNoOdq_toolPanel:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-3px}.gNoOdq_toolDetailNote{color:var(--dsw-alias-label-secondary);margin:0 0 9px;font-size:12px;line-height:20px}.gNoOdq_toolRawLabel{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;font-weight:500}.gNoOdq_toolRaw{background:var(--dsw-alias-bg-module-platform);max-height:400px;color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;margin:0;padding:12px;font:12px/20px ui-monospace,SFMono-Regular,Menlo,monospace;overflow:auto}.gNoOdq_systemPrompt{background:var(--dsw-alias-bg-module-platform);max-height:320px;color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;margin:0;padding:12px;font:12px/20px ui-monospace,SFMono-Regular,Menlo,monospace;overflow:auto}.gNoOdq_commandInput{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.gNoOdq_toolReceipt .gNoOdq_blocks,.gNoOdq_toolDocument .gNoOdq_blocks{font-size:13px;line-height:22px}.gNoOdq_toolChildren{margin:0 14px 12px var(--reader-rail,6px);padding-left:var(--reader-gutter,16px);border-left:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:9px;display:flex}@container (width<=420px){.gNoOdq_toolHeading{grid-template-columns:16px minmax(0,1fr) auto;gap:7px;padding:11px 10px 6px}.gNoOdq_toolHeadingState{gap:4px}.gNoOdq_toolLedger{padding-left:33px;padding-right:10px}.gNoOdq_toolPanel{padding:10px}}@media (pointer:coarse){.gNoOdq_toolTabs>button{min-height:44px}}.gNoOdq_reasonCard{--reason-preview-height:224px;--reason-hold:.84s;--reason-step:.5s;--reason-lines:2;--reason-fade:28px;--reason-ease:cubic-bezier(.22, 1, .36, 1);border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);min-width:0;scroll-margin-block:16px calc(var(--dsh-composer-height,152px) + 16px);border-radius:12px;position:relative;overflow:hidden}.gNoOdq_reasonHeading{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;justify-content:space-between;align-items:baseline;gap:12px;padding:10px 16px 0;font-size:12px;line-height:20px;display:flex}.gNoOdq_reasonCard[data-overflow=false][data-expanded=false]{background:0 0;border-color:#0000;border-radius:0}.gNoOdq_reasonCard[data-overflow=false][data-expanded=false] .gNoOdq_reasonHeading{padding:0}.gNoOdq_reasonCard[data-overflow=false][data-expanded=false] .gNoOdq_reasonText{padding:4px 0 0 22px}.gNoOdq_reasonLabel{font-weight:500}.gNoOdq_reasonViewport{max-height:var(--reason-preview-height);scroll-behavior:auto;overflow-anchor:none;overscroll-behavior-y:contain;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l1) transparent;position:relative;overflow:auto}.gNoOdq_reasonCard[data-expanded=true] .gNoOdq_reasonViewport{max-height:min(60vh, 560px, var(--reason-reading-height,560px))}.gNoOdq_reasonViewport[data-edges=both],.gNoOdq_reasonCard[data-following=true][data-overflow=true] .gNoOdq_reasonViewport{-webkit-mask-image:linear-gradient(transparent 0, black var(--reason-fade), black calc(100% - var(--reason-fade)), transparent 100%);mask-image:linear-gradient(transparent 0, black var(--reason-fade), black calc(100% - var(--reason-fade)), transparent 100%)}.gNoOdq_reasonViewport[data-edges=top]{-webkit-mask-image:linear-gradient(transparent 0, black var(--reason-fade), black 100%);mask-image:linear-gradient(transparent 0, black var(--reason-fade), black 100%)}.gNoOdq_reasonViewport[data-edges=bottom]{-webkit-mask-image:linear-gradient(black 0, black calc(100% - var(--reason-fade)), transparent 100%);mask-image:linear-gradient(black 0, black calc(100% - var(--reason-fade)), transparent 100%)}.gNoOdq_reasonCard[data-expanded=true] .gNoOdq_reasonViewport{-webkit-mask-image:none;mask-image:none}.gNoOdq_reasonViewport:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-3px}.gNoOdq_reasonTrack{position:relative;transform:translateY(0)}.gNoOdq_reasonCard[data-following=true] .gNoOdq_reasonTrack{will-change:transform}.gNoOdq_reasonText{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;padding:8px 16px 16px;font-size:14px;line-height:24px}.gNoOdq_reasonText .gNoOdq_readingText>div{font-size:inherit;line-height:inherit;color:inherit}.gNoOdq_reasonFooter{color:var(--dsw-alias-label-secondary);justify-content:space-between;align-items:center;gap:8px;padding:2px 10px 8px;font-size:12px;line-height:20px;display:flex}.gNoOdq_reasonAction{min-height:28px;color:inherit;font:inherit;cursor:pointer;white-space:nowrap;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;gap:5px;padding:4px 6px;display:inline-flex}.gNoOdq_reasonAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_reasonAction:disabled{cursor:default;opacity:.65}.gNoOdq_reasonAction svg{fill:none;stroke:currentColor;stroke-width:1.3px;stroke-linecap:round;stroke-linejoin:round;flex:none}.gNoOdq_reasonCaption{padding-left:6px}@container (width<=480px){.gNoOdq_reasonCard{--reason-preview-height:192px}}@media (pointer:coarse){.gNoOdq_reasonAction{min-height:44px}}@media (prefers-reduced-motion:reduce){.gNoOdq_reasonTrack{will-change:auto!important;transition:none!important;transform:none!important}}@media (forced-colors:active){.gNoOdq_reasonViewport{-webkit-mask-image:none!important;mask-image:none!important}}.gNoOdq_processItem,.gNoOdq_tool{min-width:0;margin:0 0 18px}.gNoOdq_processLabel{color:var(--dsw-alias-label-tertiary);align-items:baseline;gap:12px;margin:0 0 6px;font-size:12px;line-height:20px;display:flex}.gNoOdq_processFootnote{color:var(--dsw-alias-label-tertiary);margin:14px 0 0;font-size:12px;line-height:20px}.gNoOdq_detail{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:22px}.gNoOdq_detail>summary{cursor:pointer;padding:3px 0}.gNoOdq_detail[open]>summary{margin-bottom:8px}.gNoOdq_tool>.gNoOdq_tool{margin:10px 0 0 12px}.gNoOdq_meta{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:20px}.gNoOdq_stopped{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-tertiary);border-radius:6px;align-self:flex-start;margin-top:12px;padding:0 6px;font-size:11px;line-height:18px}.gNoOdq_compactionRow{box-sizing:border-box;flex-direction:column;align-items:center;width:100%;margin:16px 0;display:flex}.gNoOdq_compactionLine{width:100%;color:var(--dsw-alias-label-tertiary);user-select:none;justify-content:center;align-items:center;gap:12px;font-size:11px;line-height:18px;display:flex}.gNoOdq_compactionLine:before,.gNoOdq_compactionLine:after{content:\"\";background:var(--dsw-alias-border-l1);opacity:.7;flex:1;height:1px}.gNoOdq_compactionRow>.gNoOdq_compactionLine{animation:.52s cubic-bezier(.4,0,.2,1) both gNoOdq_compactionLineIn}.gNoOdq_compactionRow>.gNoOdq_compactionLine>.gNoOdq_compactionPill{animation:.42s cubic-bezier(.34,1.4,.64,1) .12s both gNoOdq_compactionPillIn}.gNoOdq_compactionRow>.gNoOdq_compactionLine .gNoOdq_compactionIcon{animation:.9s cubic-bezier(.4,0,.2,1) .2s both gNoOdq_compactionDial}@keyframes gNoOdq_compactionLineIn{0%{opacity:0;transform:scaleX(.6)}to{opacity:1;transform:scaleX(1)}}@keyframes gNoOdq_compactionPillIn{0%{opacity:0;transform:translateY(-6px)scale(.94)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes gNoOdq_compactionDial{0%{opacity:0;transform:rotate(-140deg)}to{opacity:.7;transform:rotate(0)}}[data-motion=off] .gNoOdq_compactionRow>.gNoOdq_compactionLine,[data-motion=off] .gNoOdq_compactionRow>.gNoOdq_compactionLine>.gNoOdq_compactionPill,[data-motion=off] .gNoOdq_compactionRow>.gNoOdq_compactionLine .gNoOdq_compactionIcon{animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_compactionRow>.gNoOdq_compactionLine,.gNoOdq_compactionRow>.gNoOdq_compactionLine>.gNoOdq_compactionPill,.gNoOdq_compactionRow>.gNoOdq_compactionLine .gNoOdq_compactionIcon{animation:none!important}}.gNoOdq_compactionPill{background:var(--dsw-alias-bg-module-platform);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);border-radius:12px;align-items:center;gap:6px;padding:2px 10px;font-family:inherit;font-size:11px;line-height:18px;display:inline-flex}.gNoOdq_compactionButton{cursor:pointer;transition:color .14s,border-color .14s,background-color .14s}.gNoOdq_compactionButton:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_compactionIcon{opacity:.7;flex:none;width:12px;height:12px}.gNoOdq_compactionToggle{opacity:.8;margin-left:2px;font-size:10px}.gNoOdq_compactionSummaryBox{background:var(--dsw-alias-bg-module-platform);border:1px solid var(--dsw-alias-border-l2);width:100%;max-width:680px;color:var(--dsw-alias-label-secondary);box-sizing:border-box;border-radius:8px;margin-top:10px;padding:12px 16px;font-size:12px;line-height:20px}.gNoOdq_compactionSummaryHeader{color:var(--dsw-alias-label-tertiary);border-bottom:1px dashed var(--dsw-alias-border-l1);margin-bottom:8px;padding-bottom:4px;font-size:11px;font-weight:500}.gNoOdq_notice,.gNoOdq_error,.gNoOdq_attention{overflow-wrap:anywhere;border-radius:10px;padding:12px 14px;font-size:13px;line-height:20px}.gNoOdq_notice{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border:1px solid var(--dsw-alias-border-l2)}.gNoOdq_error{color:var(--dsw-alias-label-primary);background:#ef44440f;border:1px solid #ef444438;align-items:flex-start;gap:10px;display:flex}.gNoOdq_errorIcon{color:#ef4444;flex:none;width:16px;height:16px;margin-top:2px}.gNoOdq_errorCopy{flex:1;min-width:0}.gNoOdq_errorTitle{color:#dc2626;align-items:center;gap:8px;margin-bottom:2px;font-weight:500;display:flex}.gNoOdq_errorMessage{color:var(--dsw-alias-label-secondary);word-break:break-word;margin:0;font-size:12px;line-height:18px}.gNoOdq_errorCode{color:#dc2626;background:#ef44441f;border-radius:4px;padding:1px 5px;font-family:inherit;font-size:11px}.gNoOdq_attention{border:1px solid var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base);flex-direction:column;gap:3px;display:flex}.gNoOdq_attention span{color:var(--dsw-alias-label-secondary)}.gNoOdq_unknown{background:var(--dsw-alias-bg-module-platform);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;padding:12px 14px;font-size:13px;line-height:22px}.gNoOdq_unknown p{margin:0 0 6px}.gNoOdq_historyButton{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0;border-radius:8px;align-self:center;padding:4px 12px;font-size:12px}.gNoOdq_historyButton:disabled{opacity:.55;cursor:default}.gNoOdq_empty{color:var(--dsw-alias-label-tertiary);text-align:center;padding:40px 0}.gNoOdq_answerActions{align-items:center;gap:8px;min-height:28px;margin:13px 0 0 -6px;display:flex}.gNoOdq_userActions{align-items:center;gap:8px;min-height:28px;display:flex}.gNoOdq_messageClock{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-variant-numeric:tabular-nums;font-size:13px;line-height:24px}.gNoOdq_iconButton{color:var(--dsw-alias-label-tertiary);background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;padding:6px;display:inline-flex}.gNoOdq_iconButton svg{fill:none;stroke:currentColor;stroke-width:1.2px;stroke-linecap:round;stroke-linejoin:round}.gNoOdq_imageFigure{box-sizing:border-box;align-self:flex-start;width:min(100%,360px);max-width:100%;margin:0}.gNoOdq_imageFrame{background:var(--dsw-alias-bg-module-platform);border:1px solid var(--dsw-alias-border-l2);box-sizing:border-box;border-radius:12px;max-width:100%;min-height:96px;max-height:440px;position:relative;overflow:hidden}.gNoOdq_imageOpen{background:0 0;border:0;width:100%;height:100%;padding:0;display:flex;position:absolute;inset:0}.gNoOdq_imageOpen img{object-fit:contain;opacity:0;width:100%;height:100%;transition:opacity .2s cubic-bezier(.4,0,.2,1);display:block}.gNoOdq_imageOpen img[data-ready=true]{opacity:1}.gNoOdq_pendingImage{object-fit:contain;width:100%;max-width:100%;height:100%;display:block}.gNoOdq_imagePlaceholder{color:var(--dsw-alias-label-tertiary);pointer-events:none;flex-direction:column;justify-content:center;align-items:center;gap:8px;font-size:13px;display:flex;position:absolute;inset:0}.gNoOdq_imagePlaceholder button{pointer-events:auto}.gNoOdq_imageFigure figcaption{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;margin-top:6px;font-size:12px;line-height:20px}.gNoOdq_imageDialog{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);border-radius:16px;max-width:90vw;max-height:90vh;padding:38px 20px 20px}.gNoOdq_imageDialog::backdrop{background:var(--dsw-alias-bg-mask-photo)}.gNoOdq_imageDialog img{object-fit:contain;max-width:82vw;max-height:75vh;display:block}.gNoOdq_dialogClose{color:inherit;background:0 0;border:0;border-radius:8px;width:32px;height:32px;font-size:24px;position:absolute;top:4px;right:8px}.gNoOdq_jumpDock{bottom:calc(var(--dsh-composer-height,152px) + 16px);z-index:8;pointer-events:none;justify-content:flex-end;height:0;display:flex;position:sticky}.gNoOdq_deliverablesRoot{grid-template-columns:max-content minmax(0,1fr);align-items:start;column-gap:10px;margin-top:14px;font-size:13px;line-height:22px;display:grid}.gNoOdq_deliverablesLabel{color:var(--dsw-alias-label-tertiary);grid-area:1/1;padding-top:2px;font-size:12px;font-weight:500}.gNoOdq_deliverablesLane{grid-area:1/2;min-width:0}.gNoOdq_deliverablesRow{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;display:flex}.gNoOdq_deliverableChip{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);border-radius:6px;align-items:center;font-size:12px;line-height:20px;transition:border-color .16s,background-color .16s,color .16s;display:inline-flex;overflow:hidden}.gNoOdq_deliverableChip:hover{border-color:var(--dsw-alias-border-l3);background:var(--dsw-alias-bg-module-platform);box-shadow:0 1px 4px var(--dsw-alias-border-l1)}.gNoOdq_deliverableChip[data-status=opened]{color:#059669;background:#10b9811f;border-color:#10b981}.gNoOdq_chipMain{max-width:220px;color:inherit;font:inherit;cursor:pointer;text-align:left;background:0 0;border:none;align-items:center;gap:5px;padding:3px 6px 3px 8px;display:inline-flex}.gNoOdq_chipMain:hover{color:var(--dsw-alias-label-primary)}.gNoOdq_deliverableIcon,.gNoOdq_statusIcon{opacity:.8;flex:none;width:13px;height:13px}.gNoOdq_statusIcon{color:#10b981}.gNoOdq_deliverableName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.gNoOdq_chipActions{opacity:.65;border-left:1px solid #0000;align-items:center;gap:2px;padding-right:4px;transition:opacity .15s,border-left-color .15s;display:inline-flex}.gNoOdq_deliverableChip:hover .gNoOdq_chipActions{opacity:1;border-left-color:var(--dsw-alias-border-l2)}.gNoOdq_chipActionBtn{width:20px;height:20px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:4px;justify-content:center;align-items:center;padding:0;transition:color .12s,background-color .12s;display:inline-flex}.gNoOdq_chipActionBtn:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_actionIcon{width:12px;height:12px}.gNoOdq_deliverablesMore{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:12px}.gNoOdq_deliverablesShowFolder{color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:5px;align-items:center;gap:4px;padding:2px 7px;font-size:12px;transition:all .15s;display:inline-flex}.gNoOdq_deliverablesShowFolder:hover{color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l2)}.gNoOdq_deliverablesShowFolder[data-status=opened]{color:#10b981;background:#10b98114;border-color:#10b9814d}.gNoOdq_morphCluster{flex-direction:column;width:100%;min-width:0;display:flex}.gNoOdq_morphDrawer{transform-origin:top;will-change:height, opacity, transform;height:0;overflow:hidden}.gNoOdq_liveFoldImpact{animation:.18s cubic-bezier(.2,0,0,1) both gNoOdq_liveFoldElastic}@keyframes gNoOdq_liveFoldElastic{0%{transform:scale(1)}50%{transform:scale(1.015)}to{transform:scale(1)}}.gNoOdq_liveFoldContainer{top:calc(max(var(--reader-toolbar-height,40px), var(--reader-status-height,40px)) + var(--reader-sticky-lane,40px) * 2);z-index:4;background:var(--dsw-alias-bg-base);-webkit-backdrop-filter:blur(12px);transform-origin:0;will-change:transform, opacity;margin-bottom:6px;padding:4px 0;animation:.32s cubic-bezier(.16,1,.3,1) both gNoOdq_liveFoldPulse;position:sticky}@keyframes gNoOdq_liveFoldPulse{0%{opacity:.8;transform:translateY(-4px)scale(.98)}50%{opacity:1;transform:translateY(0)scale(1.02)}to{opacity:1;transform:translateY(0)scale(1)}}[data-motion=off] .gNoOdq_liveFoldContainer{animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_liveFoldContainer{animation:none!important}}.gNoOdq_priorFoldDrawer{flex-direction:column;gap:14px;width:100%;min-width:0;display:flex}.gNoOdq_jump{width:34px;height:34px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-button-floating-fill,var(--dsw-alias-bg-base));box-shadow:var(--dsw-elevation-panel,0 2px 8px var(--dsw-alias-border-l1));pointer-events:auto;border:0;border-radius:100px;flex:none;justify-content:center;align-items:center;margin-top:-34px;padding:0;display:flex}.gNoOdq_jump:hover{background:var(--dsw-alias-button-floating-hover,var(--dsw-alias-interactive-bg-hover))}.gNoOdq_foldSummary{text-overflow:ellipsis;align-items:baseline;max-width:100%;display:inline-flex;overflow:hidden;white-space:nowrap!important}.gNoOdq_foldSummaryPart{flex:none;align-items:baseline;display:inline-flex;white-space:nowrap!important}.gNoOdq_numberRollRoot{vertical-align:baseline;line-height:inherit;font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";text-align:center;flex-shrink:0;justify-content:center;min-width:1.45em;display:inline-flex;position:relative;overflow:hidden;white-space:nowrap!important}.gNoOdq_numberRollSizer{visibility:hidden;user-select:none;pointer-events:none;line-height:inherit;white-space:nowrap}.gNoOdq_numberRollDigit{line-height:inherit;white-space:nowrap;justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.gNoOdq_numberRollExit{animation:.24s cubic-bezier(.16,1,.3,1) forwards gNoOdq_numberRollOut}.gNoOdq_numberRollEnter{animation:.24s cubic-bezier(.16,1,.3,1) forwards gNoOdq_numberRollIn}@keyframes gNoOdq_numberRollOut{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-100%)}}@keyframes gNoOdq_numberRollIn{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}[data-motion=off] .gNoOdq_chevron,[data-motion=off] .gNoOdq_imageOpen img,[data-motion=off] .gNoOdq_processMeta,[data-motion=off] .gNoOdq_numberRollDigit{transition:none!important;animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_chevron,.gNoOdq_imageOpen img,.gNoOdq_processMeta,.gNoOdq_numberRollDigit{transition:none!important;animation:none!important}}.gNoOdq_turnStatus{white-space:nowrap;flex:none;align-self:flex-start;align-items:center;height:26px;margin:4px 0 12px;padding:0 4px;font-size:14px;line-height:22px;display:inline-flex}.gNoOdq_turnStatusLabel{background:linear-gradient(90deg, var(--dsw-static-deepseek-500,#4d6bfe) 0%, var(--dsw-static-deepseek-500,#4d6bfe) 40%, var(--dsw-static-deepseek-200,#a8c7fa) 50%, var(--dsw-static-deepseek-500,#4d6bfe) 60%, var(--dsw-static-deepseek-500,#4d6bfe) 100%);color:#0000;-webkit-text-fill-color:transparent;background-position:100% 0;background-size:250% 100%;-webkit-background-clip:text;background-clip:text;font-weight:500;animation:1.8s linear infinite gNoOdq_dsh-turn-status-shimmer}.gNoOdq_waitClock{flex:none;align-items:center;margin-left:8px;display:inline-flex}.gNoOdq_waitSeconds{font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";color:var(--dsw-alias-label-caption,#86909c);font-size:13px;font-weight:400}.gNoOdq_waitOvertime{color:var(--dsw-alias-state-warning-primary,#d8862c);background:color-mix(in srgb, var(--dsw-alias-state-warning-primary,#d8862c) 16%, transparent);border-radius:5px;margin-left:8px;padding:0 6px;font-size:11px;line-height:16px}.gNoOdq_turnStatusClock{font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";color:var(--dsw-alias-label-caption,#86868b);-webkit-text-fill-color:var(--dsw-alias-label-caption,#86868b);margin-left:8px;font-size:13px;font-weight:400}@keyframes gNoOdq_dsh-turn-status-shimmer{to{background-position:0 0}}[data-motion=off] .gNoOdq_turnStatusLabel{color:var(--dsw-static-deepseek-500,#4d6bfe)!important;-webkit-text-fill-color:var(--dsw-static-deepseek-500,#4d6bfe)!important;animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_turnStatusLabel{color:var(--dsw-static-deepseek-500,#4d6bfe)!important;-webkit-text-fill-color:var(--dsw-static-deepseek-500,#4d6bfe)!important;animation:none!important}}@media (pointer:coarse){.gNoOdq_disclosureButton{min-height:44px}}@media (width<=600px){.gNoOdq_root{padding-inline:20px}.gNoOdq_column{gap:18px}.gNoOdq_toolbar{font-size:11px}.gNoOdq_user{max-width:90%}}.gNoOdq_choreographedFlow{overflow-anchor:none;flex-direction:column;min-width:0;display:flex}.gNoOdq_flowCell{min-width:0;display:flow-root;overflow:clip}.gNoOdq_flowCell[hidden]{display:none}.gNoOdq_flowCellInner{flex-direction:column;min-width:0;padding-bottom:16px;display:flex}.gNoOdq_flowCellInner:empty{padding-bottom:0}.gNoOdq_choreographedFlow[data-reader-transition=collapse] .gNoOdq_flowCell *{animation-play-state:paused!important}.gNoOdq_numberRollExit,.gNoOdq_numberRollEnter{animation-duration:.16s}.gNoOdq_foldSummary{align-items:baseline;display:inline-flex;white-space:nowrap!important;flex-wrap:nowrap!important}.gNoOdq_toolbar{box-sizing:border-box;z-index:7;-webkit-backdrop-filter:none;border-bottom:0;align-self:stretch;width:100%;max-width:100%;min-height:40px}.gNoOdq_turnProcessSticky{box-sizing:border-box;width:calc(100% - var(--reader-control-width,148px));top:max(var(--reader-toolbar-height,40px), var(--reader-status-height,40px));z-index:6;-webkit-backdrop-filter:none;min-height:40px;box-shadow:0 -14px 0 var(--dsw-alias-bg-base), var(--reader-control-width,148px) 0 0 var(--dsw-alias-bg-base);background-clip:padding-box;border-bottom:1px solid #0000;padding-right:0}.gNoOdq_flowCell[data-flow-summary],.gNoOdq_closedProcessSummary{top:calc(max(var(--reader-toolbar-height,40px), var(--reader-status-height,40px)) + var(--reader-sticky-lane,40px));z-index:5;box-sizing:border-box;background:var(--dsw-alias-bg-base);border-bottom:0;min-height:40px;padding-block:4px;position:sticky;overflow:visible}.gNoOdq_flowCell[data-flow-summary]{box-shadow:0 -16px 0 var(--dsw-alias-bg-base)}.gNoOdq_closedProcessSummary{box-shadow:0 -14px 0 var(--dsw-alias-bg-base)}.gNoOdq_foldControl{background:var(--dsw-alias-bg-module-platform);border-radius:8px;align-items:center;gap:0;padding:2px;display:inline-flex}.gNoOdq_foldStop{color:var(--dsw-alias-label-secondary);white-space:nowrap;font:inherit;cursor:pointer;background:0 0;border:0;border-radius:6px;padding:2px 8px;font-size:12px;line-height:18px}.gNoOdq_foldStop[data-on]{background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary)}.gNoOdq_flowCell[data-flow-summary]>.gNoOdq_flowCellInner{padding-bottom:0}.gNoOdq_flowCell[data-flow-summary] .gNoOdq_disclosureButton,.gNoOdq_closedProcessSummary .gNoOdq_disclosureButton{width:auto;max-width:100%}.gNoOdq_flowCell[data-flow-summary] .gNoOdq_foldSummary,.gNoOdq_closedProcessSummary .gNoOdq_foldSummary{min-width:0}.gNoOdq_turnProcessSticky>.gNoOdq_disclosure{flex:auto;min-width:0}.gNoOdq_disclosureButton{width:max-content;max-width:calc(100% + 6px)}.gNoOdq_statusText{flex:0 auto}.gNoOdq_think{width:max-content;min-width:0}.gNoOdq_thinkSizer{white-space:normal;overflow-wrap:anywhere}.gNoOdq_thinkText{white-space:normal;overflow-wrap:anywhere;text-overflow:clip;overflow:visible}.gNoOdq_root[data-reader-glass] .gNoOdq_toolbar,.gNoOdq_root[data-reader-glass] .gNoOdq_turnProcessSticky,.gNoOdq_root[data-reader-glass] .gNoOdq_liveFoldContainer{-webkit-backdrop-filter:blur(16px);box-shadow:none;background:0 0;border:0;border-radius:0}.gNoOdq_root[data-reader-glass] .gNoOdq_flowCell[data-flow-summary],.gNoOdq_root[data-reader-glass] .gNoOdq_closedProcessSummary{box-shadow:none;z-index:auto;border-left:2px solid color-mix(in srgb, var(--dsw-alias-border-l2,#80808059) 80%, transparent);padding-block:2px;background:0 0;border-radius:0;min-height:32px;padding-left:10px;position:static}.gNoOdq_root[data-reader-glass] .gNoOdq_user{background:color-mix(in srgb, var(--dsw-specific-bubble,#00000014) 25%, transparent);-webkit-backdrop-filter:blur(12px);border:1px solid color-mix(in srgb, var(--dsw-alias-border-l1,#8080804d) 30%, transparent)}.gNoOdq_root[data-reader-glass] .gNoOdq_reasonCard{border-color:color-mix(in srgb, var(--dsw-alias-border-l1,#80808059) 65%, transparent);background:0 0}.gNoOdq_root[data-reader-glass] .gNoOdq_toolDetails,.gNoOdq_root[data-reader-glass] .gNoOdq_notice,.gNoOdq_root[data-reader-glass] .gNoOdq_unknown,.gNoOdq_root[data-reader-glass] .gNoOdq_toolRaw,.gNoOdq_root[data-reader-glass] .gNoOdq_systemPrompt,.gNoOdq_root[data-reader-glass] .gNoOdq_compactionSummaryBox,.gNoOdq_root[data-reader-glass] .gNoOdq_attention,.gNoOdq_root[data-reader-glass] .gNoOdq_imageFrame,.gNoOdq_root[data-reader-glass] .gNoOdq_imageDialog{background:0 0}.gNoOdq_root[data-reader-glass] .gNoOdq_diffOverlay{background:color-mix(in srgb, var(--dsw-alias-bg-module-platform,#7f7f7f1a) 20%, transparent);-webkit-backdrop-filter:blur(16px)}.gNoOdq_root[data-reader-glass] .gNoOdq_diffScrollArea{background:0 0}.gNoOdq_root[data-reader-glass] .gNoOdq_diffTab{background:color-mix(in srgb, var(--dsw-alias-bg-base,#fffc) 25%, transparent)}.gNoOdq_root[data-reader-glass] .gNoOdq_diffTab[data-active]{background:color-mix(in srgb, var(--dsw-alias-bg-base,#fff) 45%, transparent)}.gNoOdq_root[data-reader-glass] .md-code-block,.gNoOdq_root[data-reader-glass] [data-diff]{border:1px solid color-mix(in srgb, var(--dsw-alias-border-l1,#80808033) 30%, transparent);-webkit-backdrop-filter:blur(12px);background:color-mix(in srgb, var(--dsw-alias-markdown-code-block,#0000000f) 25%, transparent)!important}.gNoOdq_root[data-reader-glass] .gNoOdq_foldControl{background:color-mix(in srgb, var(--dsw-alias-bg-module-platform,#7f7f7f1a) 25%, transparent);border:1px solid color-mix(in srgb, var(--dsw-alias-border-l2,#80808033) 30%, transparent)}.gNoOdq_root[data-reader-glass] .gNoOdq_foldStop[data-on]{background:color-mix(in srgb, var(--dsw-alias-bg-base,#fff) 35%, transparent)}.gNoOdq_root[data-reader-glass] .gNoOdq_compactionPill,.gNoOdq_root[data-reader-glass] .gNoOdq_deliverableChip,.gNoOdq_root[data-reader-glass] .gNoOdq_toolState,.gNoOdq_root[data-reader-glass] .gNoOdq_diffStatButton{background:0 0;border-color:#0000}.gNoOdq_root[data-reader-glass] .gNoOdq_compactionPill:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_compactionPill:focus-visible,.gNoOdq_root[data-reader-glass] .gNoOdq_deliverableChip:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_deliverableChip:focus-within,.gNoOdq_root[data-reader-glass] .gNoOdq_toolState:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_diffStatButton:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_diffStatButton:focus-visible,.gNoOdq_root[data-reader-glass] .gNoOdq_diffStatButton[aria-expanded=true]{background:var(--dsw-alias-bg-module-platform,#7f7f7f1a);border-color:var(--dsw-alias-border-l2,#7f7f7f47)}";
42739
+ const css$5 = ".gNoOdq_root{color:var(--dsw-alias-label-primary);padding:16px calc(var(--dsh-composer-side-clearance,16px) + 16px) 24px;overflow-anchor:auto;--reader-lane-block:max(40px, calc(40px + var(--dsh-content-font-delta,0px)));--reader-lane-plate:linear-gradient(var(--dsw-alias-bg-base), var(--dsw-alias-bg-base)), linear-gradient(var(--dsw-alias-bg-layer-1,transparent), var(--dsw-alias-bg-layer-1,transparent));flex:none;min-width:0;font-family:inherit;font-size:16px;line-height:28px;container-type:inline-size}.gNoOdq_column{max-width:var(--dsh-chat-content-width,748px);flex-direction:column;gap:22px;width:100%;min-width:0;margin:0 auto;display:flex}.gNoOdq_column:focus,.gNoOdq_column:focus-visible{outline:none}.gNoOdq_toolbar{min-height:32px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-base);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);justify-content:flex-end;align-items:center;gap:6px;padding:0;font-size:12px;display:flex;position:sticky;top:0}.gNoOdq_turnProcessSticky{background:var(--dsw-alias-bg-base);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);align-items:center;min-height:32px;display:flex;position:sticky}.gNoOdq_turnProcessSticky .gNoOdq_disclosureButton{min-height:32px}.gNoOdq_textButton,.gNoOdq_historyButton,.gNoOdq_iconButton,.gNoOdq_jump,.gNoOdq_disclosureButton,.gNoOdq_imageOpen,.gNoOdq_dialogClose{font:inherit;cursor:pointer}.gNoOdq_textButton{color:var(--dsw-alias-label-secondary);white-space:nowrap;background:0 0;border:0;border-radius:6px;padding:2px 6px}.gNoOdq_textButton:hover,.gNoOdq_iconButton:hover,.gNoOdq_disclosureButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_root button:focus-visible,.gNoOdq_root summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:3px}.gNoOdq_turn,.gNoOdq_turnStickyRegion{flex-direction:column;gap:14px;min-width:0;display:flex}.gNoOdq_turnStickyLanes{top:var(--reader-toolbar-height,var(--reader-lane-block,40px));z-index:6;flex-direction:column;min-width:0;display:flex;position:sticky}.gNoOdq_turn+.gNoOdq_turn,.gNoOdq_retiringContent+.gNoOdq_retiringContent>.gNoOdq_turn{margin-top:12px}.gNoOdq_userCluster{flex-direction:column;align-self:stretch;align-items:flex-end;gap:8px;width:100%;min-width:0;max-width:100%;margin-bottom:4px;display:flex}.gNoOdq_userCluster>[data-slot]>*{box-sizing:border-box;align-self:stretch;width:100%;min-width:0;max-width:100%}.gNoOdq_userImages{flex-direction:column;align-self:flex-end;align-items:flex-end;width:fit-content;min-width:0;max-width:100%;display:flex}.gNoOdq_userImages .gNoOdq_imageFigure{align-self:flex-end}.gNoOdq_user{width:fit-content;max-width:min(calc(var(--dsh-chat-content-width,748px) * .702), 82%);border-radius:var(--dsw-radius-xl,22px);background:var(--dsw-specific-bubble);color:var(--dsw-alias-label-primary);font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word;box-sizing:border-box;align-self:flex-end;margin-left:auto;padding:10px 16px;font-weight:400}.gNoOdq_user .gNoOdq_blocks{gap:10px}.gNoOdq_answer{overflow-wrap:anywhere;flex-direction:column;min-width:0;display:flex}.gNoOdq_readingText{min-width:0}.gNoOdq_reasonPlain{white-space:pre-wrap;overflow-wrap:anywhere;font:inherit;color:inherit}.gNoOdq_readingText button{min-width:24px;min-height:24px}.gNoOdq_streamWord{display:inline-block}.gNoOdq_streamInlineWord{display:inline}.gNoOdq_streamWord,.gNoOdq_streamInlineWord,.gNoOdq_streamAtom{opacity:1;filter:none}.gNoOdq_streamAtom{min-width:0}@media (prefers-reduced-motion:reduce){.gNoOdq_streamWord,.gNoOdq_streamInlineWord,.gNoOdq_streamAtom{opacity:1!important;filter:none!important}}.gNoOdq_retiringContent{min-width:0}.gNoOdq_retiringContent[data-reader-retiring=retiring]{overflow:hidden}.gNoOdq_mainFlow,.gNoOdq_blocks{flex-direction:column;gap:16px;min-width:0;display:flex}.gNoOdq_mainFlow:empty,.gNoOdq_blocks:empty{display:none}.gNoOdq_blocks>:first-child{margin-top:0}.gNoOdq_blocks>:last-child{margin-bottom:0}.gNoOdq_blocks .md-table-wide{max-width:100%}.gNoOdq_disclosure{min-width:0}.gNoOdq_disclosureButton{max-width:100%;min-height:32px;color:var(--dsw-alias-label-tertiary);font-size:calc(14px + var(--dsh-content-font-delta,0px));line-height:calc(24px + var(--dsh-content-font-delta,0px));text-align:left;background:0 0;border:0;border-radius:7px;align-items:center;gap:6px;margin-left:-6px;padding:4px 6px;font-weight:400;display:inline-flex}.gNoOdq_disclosure[data-reader-status-only]{align-items:center;min-height:32px;display:flex}.gNoOdq_statusText{min-width:0;max-width:100%;font-size:calc(14px + var(--dsh-content-font-delta,0px));line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-secondary);font-weight:400;display:inline-flex}.gNoOdq_srOnly{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.gNoOdq_think{--think-swap:.15s;--think-gap:50ms;--think-distance:8px;--think-blur:2px;--think-shimmer:2s;--think-base:var(--dsw-alias-label-secondary);--think-highlight:var(--dsw-alias-label-primary);--think-ease:ease-in-out;text-align:left;max-width:100%;display:inline-block;position:relative}.gNoOdq_thinkSizer{visibility:hidden;white-space:nowrap;display:block}.gNoOdq_thinkText{color:var(--think-base);white-space:nowrap;text-overflow:ellipsis;filter:blur();opacity:1;transition:transform var(--think-swap) var(--think-ease), filter var(--think-swap) var(--think-ease), opacity var(--think-swap) var(--think-ease);display:block;position:absolute;top:0;left:0;right:0;overflow:hidden;transform:translateY(0)}.gNoOdq_think[data-reader-status-phase=running] .gNoOdq_thinkText[data-reader-status-copy=current]{transition-delay:var(--think-gap)}.gNoOdq_think:not([data-reader-status-phase=idle]) .gNoOdq_thinkText{will-change:transform, filter, opacity}@supports (background-clip:text){.gNoOdq_think[data-active=true] .gNoOdq_thinkText:before{content:attr(data-text);pointer-events:none;background-image:linear-gradient(90deg, transparent 0%, transparent 40%, var(--think-highlight) 50%, transparent 60%, transparent 100%);color:#0000;-webkit-text-fill-color:transparent;animation:gNoOdq_thinkShimmer var(--think-shimmer) linear infinite;background-repeat:no-repeat;background-size:400% 100%;background-clip:text;position:absolute;inset:0}}@keyframes gNoOdq_thinkShimmer{0%{background-position:100% 0}to{background-position:0 0}}.gNoOdq_thinkText.gNoOdq_isExit{transform:translateY(calc(var(--think-distance) * -1));filter:blur(var(--think-blur));opacity:0}.gNoOdq_thinkText.gNoOdq_isEnterStart{transform:translateY(var(--think-distance));filter:blur(var(--think-blur));opacity:0;transition:none}[data-motion=off] .gNoOdq_thinkText{filter:none!important;opacity:1!important;transition:none!important;transform:none!important}[data-motion=off] .gNoOdq_thinkText[data-reader-status-copy=outgoing],[data-motion=off] .gNoOdq_thinkText:before{display:none!important}@media (prefers-reduced-motion:reduce),(forced-colors:active){.gNoOdq_thinkText{filter:none!important;opacity:1!important;transition:none!important;transform:none!important}.gNoOdq_thinkText[data-reader-status-copy=outgoing],.gNoOdq_thinkText:before{display:none!important}}.gNoOdq_processMeta{opacity:0;grid-template-rows:0fr;transition:grid-template-rows .26s cubic-bezier(.22,1,.36,1),opacity .16s ease-out;display:grid}.gNoOdq_processMeta[data-open=true]{opacity:1;grid-template-rows:1fr}.gNoOdq_processMetaInner{min-height:0;overflow:hidden}.gNoOdq_processMetaLine{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex-wrap:wrap;align-items:baseline;gap:8px;padding:8px 0 0 16px;font-size:12px;line-height:20px;display:flex}.gNoOdq_processMetaLine .gNoOdq_meta{color:inherit}.gNoOdq_chevron{stroke:currentColor;fill:none;stroke-width:1.4px;stroke-linecap:round;stroke-linejoin:round;flex:none;transition:transform .26s cubic-bezier(.22,1,.36,1)}.gNoOdq_chevron[data-open=true]{transform:rotate(90deg)}.gNoOdq_disclosureBody{transform-origin:top;will-change:height, opacity, transform;height:0;overflow:hidden}.gNoOdq_processContents{border-left:1px solid var(--dsw-alias-border-l2);padding:3px 0 2px var(--reader-gutter,16px);margin:0 0 0 var(--reader-rail,6px);color:var(--dsw-alias-label-secondary);font-size:14px;line-height:24px;display:flow-root}.gNoOdq_processContents>:last-child{margin-bottom:0}.gNoOdq_processSeamRow{min-height:40px;margin-left:var(--reader-rail,6px);padding-left:var(--reader-gutter,16px);border-left:1px solid var(--dsw-alias-border-l2);box-sizing:border-box;align-items:center;display:flex}.gNoOdq_processSeamRow>.gNoOdq_disclosure{align-items:center;min-height:24px;display:flex}.gNoOdq_processSeamRow .gNoOdq_disclosureButton{min-height:24px;color:var(--dsw-alias-label-tertiary);padding-block:2px;font-size:12px;line-height:20px}.gNoOdq_flowCell:has(>.gNoOdq_flowCellInner>[data-reader-seam-after])>.gNoOdq_flowCellInner{padding-bottom:0}.gNoOdq_processFrame{min-width:0}.gNoOdq_toolActivity{min-width:0;color:var(--dsw-alias-label-secondary)}.gNoOdq_nativeToolRow{min-width:0}.gNoOdq_rowSeparator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.gNoOdq_nativeToolSummary{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-tertiary);flex:1;font-size:14px;line-height:24px;overflow:hidden}.gNoOdq_nativeToolRow:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:3px;border-radius:4px}.gNoOdq_toolHeading{width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:11px;grid-template-columns:20px minmax(0,1fr) auto;align-items:start;gap:10px;padding:10px 14px 4px;display:grid}.gNoOdq_toolHeading:hover{background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_toolHeading:focus-visible{outline-offset:-3px!important}.gNoOdq_toolGlyph{height:22px;color:var(--dsw-alias-label-secondary);justify-content:center;align-items:center;display:flex}.gNoOdq_toolHeadingCopy{flex-direction:column;gap:3px;min-width:0;display:flex}.gNoOdq_toolTitle{overflow-wrap:anywhere;font-size:13px;font-weight:500;line-height:22px}.gNoOdq_toolTarget{-webkit-line-clamp:2;overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary);-webkit-box-orient:vertical;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:19px;display:-webkit-box;overflow:hidden}.gNoOdq_toolHeadingState{min-height:22px;color:var(--dsw-alias-label-secondary);align-items:center;gap:7px;display:flex}.gNoOdq_diffStat{font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";white-space:nowrap;flex:none;gap:6px;margin-left:8px;font-size:11px;line-height:18px;display:inline-flex}.gNoOdq_diffAdded{color:var(--dsw-alias-state-success-primary,#2f9e63)}.gNoOdq_diffRemoved{color:var(--dsw-alias-state-error-primary,#d1483c)}.gNoOdq_summaryRow{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;max-width:100%;display:flex}.gNoOdq_summaryRow>.gNoOdq_diffStatRoot{flex:none;margin-left:auto}.gNoOdq_summaryRow>:first-child{min-width:0}.gNoOdq_diffStatRoot{flex:none;position:relative}.gNoOdq_diffStatButton{cursor:pointer;font:inherit;font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";color:var(--dsw-alias-label-secondary);background:0 0;border:1px solid #0000;border-radius:6px;align-items:center;gap:6px;padding:2px 8px;font-size:11px;line-height:16px;transition:background .12s,border-color .12s;display:inline-flex}.gNoOdq_diffStatButton:hover,.gNoOdq_diffStatButton:focus-visible,.gNoOdq_diffStatButton[aria-expanded=true]{background:var(--dsw-alias-bg-module-platform,#7f7f7f1a);border-color:var(--dsw-alias-border-l2,#7f7f7f47)}.gNoOdq_diffStatButton:focus-visible{outline:none}.gNoOdq_diffStatButton[aria-expanded=true] .gNoOdq_diffCaret{opacity:1}.gNoOdq_diffOverlayRow{box-sizing:border-box;flex:100%;width:100%;min-width:0;max-width:100%;margin-top:6px}.gNoOdq_diffOverlay{box-sizing:border-box;background:var(--dsw-alias-bg-module-platform,#7f7f7f14);border:1px solid var(--dsw-alias-border-l2,#80808038);border-radius:10px;flex-direction:column;width:100%;min-width:0;max-width:100%;padding:8px;display:flex;overflow:hidden}.gNoOdq_diffTabs{scrollbar-width:thin;flex-wrap:nowrap;gap:6px;max-width:100%;margin-bottom:4px;padding-bottom:6px;display:flex;overflow-x:auto}.gNoOdq_diffTab{text-overflow:ellipsis;white-space:nowrap;cursor:pointer;max-width:220px;font:inherit;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-base,#fffc);border:1px solid var(--dsw-alias-border-l2,#80808033);border-radius:6px;flex:none;padding:3px 10px;font-size:11px;line-height:16px;transition:all .12s;overflow:hidden}.gNoOdq_diffTab:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.gNoOdq_diffTab[data-active]{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-state-business-primary,#1e90ff);background:var(--dsw-alias-bg-base);font-weight:500}.gNoOdq_diffScrollArea{overscroll-behavior:contain;-webkit-overflow-scrolling:touch;border:1px solid var(--dsw-alias-border-l2,#80808026);background:var(--dsw-alias-markdown-code-block,#0000000a);border-radius:8px;max-height:420px;overflow:auto}.gNoOdq_diffScrollArea [data-diff]{background:0 0!important;border-radius:0!important;margin:0!important}.gNoOdq_diffCaret{opacity:.6;flex:none;width:10px;font-size:10px}.gNoOdq_diffPath{text-overflow:ellipsis;white-space:nowrap;text-align:left;direction:rtl;flex:auto;min-width:0;overflow:hidden}.gNoOdq_diffStat{font-variant-numeric:tabular-nums;flex:none;gap:6px;font-size:11px;display:inline-flex}.gNoOdq_diffHunkBody{flex-direction:column;gap:4px;padding:2px 7px 7px 25px;display:flex}.gNoOdq_diffLines{font-size:11px;line-height:1.55;font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);white-space:pre;border-radius:6px;margin:0;padding:6px 8px;overflow-x:auto}.gNoOdq_diffLines[data-side=removed]{background:#d1483c1f}.gNoOdq_diffLines[data-side=added]{background:#2f9e631f}.gNoOdq_diffLineRemoved,.gNoOdq_diffLineAdded{display:block}.gNoOdq_diffLineRemoved{color:var(--dsw-alias-state-error-primary,#d1483c)}.gNoOdq_diffLineAdded{color:var(--dsw-alias-state-success-primary,#2f9e63)}.gNoOdq_diffEmpty{color:var(--dsw-alias-label-secondary);margin:0;padding:2px 0;font-size:11px}.gNoOdq_nativeToolSummary[data-running]{background-image:linear-gradient(90deg, currentColor 0%, currentColor 35%, color-mix(in srgb, currentColor 35%, transparent) 50%, currentColor 65%, currentColor 100%);-webkit-text-fill-color:transparent;background-position:100% 0;background-repeat:no-repeat;background-size:300% 100%;background-clip:text;animation:1.6s linear infinite gNoOdq_readerStepShimmer}@keyframes gNoOdq_readerStepShimmer{to{background-position:0 0}}.gNoOdq_toolElapsed[data-slow]{opacity:1;color:var(--dsw-alias-state-warning-primary,#d8862c);font-weight:500}.gNoOdq_toolElapsed{opacity:.72;font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";white-space:nowrap;flex:none;margin-left:8px;font-size:11px;line-height:18px}[data-motion=off] .gNoOdq_nativeToolSummary[data-running]{-webkit-text-fill-color:currentColor;background-image:none;animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_nativeToolSummary[data-running]{-webkit-text-fill-color:currentColor;background-image:none;animation:none!important}}.gNoOdq_toolState{white-space:nowrap;flex:none;margin-left:8px;font-size:11px;line-height:18px}.gNoOdq_toolState[data-phase=preparing],.gNoOdq_toolState[data-phase=running]{color:var(--dsw-alias-state-business-primary)}.gNoOdq_toolState[data-phase=preparing]:before,.gNoOdq_toolState[data-phase=running]:before{content:\"\";vertical-align:middle;background:currentColor;border-radius:50%;width:6px;height:6px;margin-right:6px;animation:1.4s ease-in-out infinite gNoOdq_readerRunningGlow;display:inline-block}@keyframes gNoOdq_readerRunningGlow{0%{box-shadow:0 0 0 0 color-mix(in srgb, currentColor 60%, transparent);opacity:1}70%{opacity:.7;box-shadow:0 0 0 7px #0000}to{opacity:1;box-shadow:0 0 #0000}}[data-motion=off] .gNoOdq_toolState[data-phase=preparing]:before,[data-motion=off] .gNoOdq_toolState[data-phase=running]:before{animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_toolState[data-phase=preparing]:before,.gNoOdq_toolState[data-phase=running]:before{animation:none!important}}.gNoOdq_toolState[data-phase=failed]{color:var(--dsw-alias-state-error-primary)}.gNoOdq_toolState[data-phase=interrupted]{color:inherit;opacity:.7}.gNoOdq_toolLedger{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex-wrap:wrap;align-items:baseline;gap:4px 12px;padding:10px 14px 0;font-size:11px;line-height:18px;display:flex}.gNoOdq_toolEngine{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.gNoOdq_toolDetails{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;min-width:0;margin:6px 0 0 22px;overflow:hidden}.gNoOdq_toolTabs{align-items:center;gap:15px;padding:0 14px;display:flex}.gNoOdq_toolTabs>button{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-bottom:2px solid #0000;padding:10px 1px 8px;font-size:12px;line-height:20px}.gNoOdq_toolTabs>button[aria-selected=true]{color:var(--dsw-alias-label-primary);border-bottom-color:var(--dsw-alias-state-business-primary)}.gNoOdq_toolPanel{flex-direction:column;gap:12px;min-width:0;padding:12px 14px 14px;font-size:13px;line-height:22px;display:flex}.gNoOdq_toolPanel:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-3px}.gNoOdq_toolDetailNote{color:var(--dsw-alias-label-secondary);margin:0 0 9px;font-size:12px;line-height:20px}.gNoOdq_toolRawLabel{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;font-weight:500}.gNoOdq_toolRaw{background:var(--dsw-alias-bg-module-platform);max-height:400px;color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;margin:0;padding:12px;font:12px/20px ui-monospace,SFMono-Regular,Menlo,monospace;overflow:auto}.gNoOdq_systemPrompt{background:var(--dsw-alias-bg-module-platform);max-height:320px;color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;margin:0;padding:12px;font:12px/20px ui-monospace,SFMono-Regular,Menlo,monospace;overflow:auto}.gNoOdq_commandInput{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.gNoOdq_toolReceipt .gNoOdq_blocks,.gNoOdq_toolDocument .gNoOdq_blocks{font-size:13px;line-height:22px}.gNoOdq_toolChildren{margin:0 14px 12px var(--reader-rail,6px);padding-left:var(--reader-gutter,16px);border-left:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:9px;display:flex}@container (width<=420px){.gNoOdq_toolHeading{grid-template-columns:16px minmax(0,1fr) auto;gap:7px;padding:11px 10px 6px}.gNoOdq_toolHeadingState{gap:4px}.gNoOdq_toolLedger{padding-left:33px;padding-right:10px}.gNoOdq_toolPanel{padding:10px}}@media (pointer:coarse){.gNoOdq_toolTabs>button{min-height:44px}}.gNoOdq_reasonCard{--reason-preview-height:224px;--reason-hold:.84s;--reason-step:.5s;--reason-lines:2;--reason-fade:28px;--reason-ease:cubic-bezier(.22, 1, .36, 1);border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);min-width:0;scroll-margin-block:16px calc(var(--dsh-composer-height,152px) + 16px);border-radius:12px;position:relative;overflow:hidden}.gNoOdq_reasonHeading{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;justify-content:space-between;align-items:baseline;gap:12px;padding:10px 16px 0;font-size:12px;line-height:20px;display:flex}.gNoOdq_reasonCard[data-overflow=false][data-expanded=false]{background:0 0;border-color:#0000;border-radius:0}.gNoOdq_reasonCard[data-overflow=false][data-expanded=false] .gNoOdq_reasonHeading{padding:0}.gNoOdq_reasonCard[data-overflow=false][data-expanded=false] .gNoOdq_reasonText{padding:4px 0 0 22px}.gNoOdq_reasonLabel{font-weight:500}.gNoOdq_reasonViewport{max-height:var(--reason-preview-height);scroll-behavior:auto;overflow-anchor:none;overscroll-behavior-y:contain;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l1) transparent;position:relative;overflow:auto}.gNoOdq_reasonCard[data-expanded=true] .gNoOdq_reasonViewport{max-height:min(60vh, 560px, var(--reason-reading-height,560px))}.gNoOdq_reasonViewport[data-edges=both],.gNoOdq_reasonCard[data-following=true][data-overflow=true] .gNoOdq_reasonViewport{-webkit-mask-image:linear-gradient(transparent 0, black var(--reason-fade), black calc(100% - var(--reason-fade)), transparent 100%);mask-image:linear-gradient(transparent 0, black var(--reason-fade), black calc(100% - var(--reason-fade)), transparent 100%)}.gNoOdq_reasonViewport[data-edges=top]{-webkit-mask-image:linear-gradient(transparent 0, black var(--reason-fade), black 100%);mask-image:linear-gradient(transparent 0, black var(--reason-fade), black 100%)}.gNoOdq_reasonViewport[data-edges=bottom]{-webkit-mask-image:linear-gradient(black 0, black calc(100% - var(--reason-fade)), transparent 100%);mask-image:linear-gradient(black 0, black calc(100% - var(--reason-fade)), transparent 100%)}.gNoOdq_reasonCard[data-expanded=true] .gNoOdq_reasonViewport{mask-image:none}.gNoOdq_reasonViewport:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-3px}.gNoOdq_reasonTrack{position:relative;transform:translateY(0)}.gNoOdq_reasonCard[data-following=true] .gNoOdq_reasonTrack{will-change:transform}.gNoOdq_reasonText{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;padding:8px 16px 16px;font-size:14px;line-height:24px}.gNoOdq_reasonText .gNoOdq_readingText>div{font-size:inherit;line-height:inherit;color:inherit}.gNoOdq_reasonFooter{color:var(--dsw-alias-label-secondary);justify-content:space-between;align-items:center;gap:8px;padding:2px 10px 8px;font-size:12px;line-height:20px;display:flex}.gNoOdq_reasonAction{min-height:28px;color:inherit;font:inherit;cursor:pointer;white-space:nowrap;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;gap:5px;padding:4px 6px;display:inline-flex}.gNoOdq_reasonAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_reasonAction:disabled{cursor:default;opacity:.65}.gNoOdq_reasonAction svg{fill:none;stroke:currentColor;stroke-width:1.3px;stroke-linecap:round;stroke-linejoin:round;flex:none}.gNoOdq_reasonCaption{padding-left:6px}@container (width<=480px){.gNoOdq_reasonCard{--reason-preview-height:192px}}@media (pointer:coarse){.gNoOdq_reasonAction{min-height:44px}}@media (prefers-reduced-motion:reduce){.gNoOdq_reasonTrack{will-change:auto!important;transition:none!important;transform:none!important}}@media (forced-colors:active){.gNoOdq_reasonViewport{mask-image:none!important}}.gNoOdq_processItem,.gNoOdq_tool{min-width:0;margin:0 0 18px}.gNoOdq_processLabel{color:var(--dsw-alias-label-tertiary);align-items:baseline;gap:12px;margin:0 0 6px;font-size:12px;line-height:20px;display:flex}.gNoOdq_processFootnote{color:var(--dsw-alias-label-tertiary);margin:14px 0 0;font-size:12px;line-height:20px}.gNoOdq_detail{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:22px}.gNoOdq_detail>summary{cursor:pointer;padding:3px 0}.gNoOdq_detail[open]>summary{margin-bottom:8px}.gNoOdq_tool>.gNoOdq_tool{margin:10px 0 0 12px}.gNoOdq_meta{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:20px}.gNoOdq_stopped{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-tertiary);border-radius:6px;align-self:flex-start;margin-top:12px;padding:0 6px;font-size:11px;line-height:18px}.gNoOdq_compactionRow{box-sizing:border-box;flex-direction:column;align-items:center;width:100%;margin:16px 0;display:flex}.gNoOdq_compactionLine{width:100%;color:var(--dsw-alias-label-tertiary);-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;gap:12px;font-size:11px;line-height:18px;display:flex}.gNoOdq_compactionLine:before,.gNoOdq_compactionLine:after{content:\"\";background:var(--dsw-alias-border-l1);opacity:.7;flex:1;height:1px}.gNoOdq_compactionRow>.gNoOdq_compactionLine{animation:.52s cubic-bezier(.4,0,.2,1) both gNoOdq_compactionLineIn}.gNoOdq_compactionRow>.gNoOdq_compactionLine>.gNoOdq_compactionPill{animation:.42s cubic-bezier(.34,1.4,.64,1) .12s both gNoOdq_compactionPillIn}.gNoOdq_compactionRow>.gNoOdq_compactionLine .gNoOdq_compactionIcon{animation:.9s cubic-bezier(.4,0,.2,1) .2s both gNoOdq_compactionDial}@keyframes gNoOdq_compactionLineIn{0%{opacity:0;transform:scaleX(.6)}to{opacity:1;transform:scaleX(1)}}@keyframes gNoOdq_compactionPillIn{0%{opacity:0;transform:translateY(-6px)scale(.94)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes gNoOdq_compactionDial{0%{opacity:0;transform:rotate(-140deg)}to{opacity:.7;transform:rotate(0)}}[data-motion=off] .gNoOdq_compactionRow>.gNoOdq_compactionLine,[data-motion=off] .gNoOdq_compactionRow>.gNoOdq_compactionLine>.gNoOdq_compactionPill,[data-motion=off] .gNoOdq_compactionRow>.gNoOdq_compactionLine .gNoOdq_compactionIcon{animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_compactionRow>.gNoOdq_compactionLine,.gNoOdq_compactionRow>.gNoOdq_compactionLine>.gNoOdq_compactionPill,.gNoOdq_compactionRow>.gNoOdq_compactionLine .gNoOdq_compactionIcon{animation:none!important}}.gNoOdq_compactionPill{background:var(--dsw-alias-bg-module-platform);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);border-radius:12px;align-items:center;gap:6px;padding:2px 10px;font-family:inherit;font-size:11px;line-height:18px;display:inline-flex}.gNoOdq_compactionButton{cursor:pointer;transition:color .14s,border-color .14s,background-color .14s}.gNoOdq_compactionButton:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_compactionIcon{opacity:.7;flex:none;width:12px;height:12px}.gNoOdq_compactionToggle{opacity:.8;margin-left:2px;font-size:10px}.gNoOdq_compactionSummaryBox{background:var(--dsw-alias-bg-module-platform);border:1px solid var(--dsw-alias-border-l2);width:100%;max-width:680px;color:var(--dsw-alias-label-secondary);box-sizing:border-box;border-radius:8px;margin-top:10px;padding:12px 16px;font-size:12px;line-height:20px}.gNoOdq_compactionSummaryHeader{color:var(--dsw-alias-label-tertiary);border-bottom:1px dashed var(--dsw-alias-border-l1);margin-bottom:8px;padding-bottom:4px;font-size:11px;font-weight:500}.gNoOdq_notice,.gNoOdq_error,.gNoOdq_attention{overflow-wrap:anywhere;border-radius:10px;padding:12px 14px;font-size:13px;line-height:20px}.gNoOdq_notice{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border:1px solid var(--dsw-alias-border-l2)}.gNoOdq_error{color:var(--dsw-alias-label-primary);background:#ef44440f;border:1px solid #ef444438;align-items:flex-start;gap:10px;display:flex}.gNoOdq_errorIcon{color:#ef4444;flex:none;width:16px;height:16px;margin-top:2px}.gNoOdq_errorCopy{flex:1;min-width:0}.gNoOdq_errorTitle{color:#dc2626;align-items:center;gap:8px;margin-bottom:2px;font-weight:500;display:flex}.gNoOdq_errorMessage{color:var(--dsw-alias-label-secondary);word-break:break-word;margin:0;font-size:12px;line-height:18px}.gNoOdq_errorCode{color:#dc2626;background:#ef44441f;border-radius:4px;padding:1px 5px;font-family:inherit;font-size:11px}.gNoOdq_attention{border:1px solid var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base);flex-direction:column;gap:3px;display:flex}.gNoOdq_attention span{color:var(--dsw-alias-label-secondary)}.gNoOdq_unknown{background:var(--dsw-alias-bg-module-platform);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;padding:12px 14px;font-size:13px;line-height:22px}.gNoOdq_unknown p{margin:0 0 6px}.gNoOdq_historyButton{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0;border-radius:8px;align-self:center;padding:4px 12px;font-size:12px}.gNoOdq_historyButton:disabled{opacity:.55;cursor:default}.gNoOdq_empty{color:var(--dsw-alias-label-tertiary);text-align:center;padding:40px 0}.gNoOdq_answerActions{align-items:center;gap:8px;min-height:28px;margin:13px 0 0 -6px;display:flex}.gNoOdq_userActions{align-items:center;gap:8px;min-height:28px;display:flex}.gNoOdq_messageClock{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-variant-numeric:tabular-nums;font-size:13px;line-height:24px}.gNoOdq_iconButton{color:var(--dsw-alias-label-tertiary);background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;padding:6px;display:inline-flex}.gNoOdq_iconButton svg{fill:none;stroke:currentColor;stroke-width:1.2px;stroke-linecap:round;stroke-linejoin:round}.gNoOdq_imageFigure{box-sizing:border-box;align-self:flex-start;width:min(100%,360px);max-width:100%;margin:0}.gNoOdq_imageFrame{background:var(--dsw-alias-bg-module-platform);border:1px solid var(--dsw-alias-border-l2);box-sizing:border-box;border-radius:12px;max-width:100%;min-height:96px;max-height:440px;position:relative;overflow:hidden}.gNoOdq_imageOpen{background:0 0;border:0;width:100%;height:100%;padding:0;display:flex;position:absolute;inset:0}.gNoOdq_imageOpen img{object-fit:contain;opacity:0;width:100%;height:100%;transition:opacity .2s cubic-bezier(.4,0,.2,1);display:block}.gNoOdq_imageOpen img[data-ready=true]{opacity:1}.gNoOdq_pendingImage{object-fit:contain;width:100%;max-width:100%;height:100%;display:block}.gNoOdq_imagePlaceholder{color:var(--dsw-alias-label-tertiary);pointer-events:none;flex-direction:column;justify-content:center;align-items:center;gap:8px;font-size:13px;display:flex;position:absolute;inset:0}.gNoOdq_imagePlaceholder button{pointer-events:auto}.gNoOdq_imageFigure figcaption{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;margin-top:6px;font-size:12px;line-height:20px}.gNoOdq_imageDialog{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);border-radius:16px;max-width:90vw;max-height:90vh;padding:38px 20px 20px}.gNoOdq_imageDialog::backdrop{background:var(--dsw-alias-bg-mask-photo)}.gNoOdq_imageDialog img{object-fit:contain;max-width:82vw;max-height:75vh;display:block}.gNoOdq_dialogClose{color:inherit;background:0 0;border:0;border-radius:8px;width:32px;height:32px;font-size:24px;position:absolute;top:4px;right:8px}.gNoOdq_jumpDock{bottom:calc(var(--dsh-composer-height,152px) + 16px);z-index:8;pointer-events:none;justify-content:flex-end;height:0;display:flex;position:sticky}.gNoOdq_deliverablesRoot{grid-template-columns:max-content minmax(0,1fr);align-items:start;column-gap:10px;margin-top:14px;font-size:13px;line-height:22px;display:grid}.gNoOdq_deliverablesLabel{color:var(--dsw-alias-label-tertiary);grid-area:1/1;padding-top:2px;font-size:12px;font-weight:500}.gNoOdq_deliverablesLane{grid-area:1/2;min-width:0}.gNoOdq_deliverablesRow{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;display:flex}.gNoOdq_deliverableChip{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);border-radius:6px;align-items:center;font-size:12px;line-height:20px;transition:border-color .16s,background-color .16s,color .16s;display:inline-flex;overflow:hidden}.gNoOdq_deliverableChip:hover{border-color:var(--dsw-alias-border-l3);background:var(--dsw-alias-bg-module-platform);box-shadow:0 1px 4px var(--dsw-alias-border-l1)}.gNoOdq_deliverableChip[data-status=opened]{color:#059669;background:#10b9811f;border-color:#10b981}.gNoOdq_chipMain{max-width:220px;color:inherit;font:inherit;cursor:pointer;text-align:left;background:0 0;border:none;align-items:center;gap:5px;padding:3px 6px 3px 8px;display:inline-flex}.gNoOdq_chipMain:hover{color:var(--dsw-alias-label-primary)}.gNoOdq_deliverableIcon,.gNoOdq_statusIcon{opacity:.8;flex:none;width:13px;height:13px}.gNoOdq_statusIcon{color:#10b981}.gNoOdq_deliverableName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.gNoOdq_chipActions{opacity:.65;border-left:1px solid #0000;align-items:center;gap:2px;padding-right:4px;transition:opacity .15s,border-left-color .15s;display:inline-flex}.gNoOdq_deliverableChip:hover .gNoOdq_chipActions{opacity:1;border-left-color:var(--dsw-alias-border-l2)}.gNoOdq_chipActionBtn{width:20px;height:20px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:4px;justify-content:center;align-items:center;padding:0;transition:color .12s,background-color .12s;display:inline-flex}.gNoOdq_chipActionBtn:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_actionIcon{width:12px;height:12px}.gNoOdq_deliverablesMore{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:12px}.gNoOdq_deliverablesShowFolder{color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:5px;align-items:center;gap:4px;padding:2px 7px;font-size:12px;transition:all .15s;display:inline-flex}.gNoOdq_deliverablesShowFolder:hover{color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l2)}.gNoOdq_deliverablesShowFolder[data-status=opened]{color:#10b981;background:#10b98114;border-color:#10b9814d}.gNoOdq_morphCluster{flex-direction:column;width:100%;min-width:0;display:flex}.gNoOdq_morphDrawer{transform-origin:top;will-change:height, opacity, transform;height:0;overflow:hidden}.gNoOdq_liveFoldImpact{animation:.18s cubic-bezier(.2,0,0,1) both gNoOdq_liveFoldElastic}@keyframes gNoOdq_liveFoldElastic{0%{transform:scale(1)}50%{transform:scale(1.015)}to{transform:scale(1)}}.gNoOdq_liveFoldContainer{top:calc(var(--reader-toolbar-height,var(--reader-lane-block,40px)) + var(--reader-status-height,var(--reader-lane-block,40px)) + var(--reader-summary-height,var(--reader-lane-block,40px)));z-index:4;background:var(--dsw-alias-bg-base);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);transform-origin:0;will-change:transform, opacity;margin-bottom:6px;padding:4px 0;animation:.32s cubic-bezier(.16,1,.3,1) both gNoOdq_liveFoldPulse;position:sticky}@keyframes gNoOdq_liveFoldPulse{0%{opacity:.8;transform:translateY(-4px)scale(.98)}50%{opacity:1;transform:translateY(0)scale(1.02)}to{opacity:1;transform:translateY(0)scale(1)}}[data-motion=off] .gNoOdq_liveFoldContainer{animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_liveFoldContainer{animation:none!important}}.gNoOdq_priorFoldDrawer{flex-direction:column;gap:14px;width:100%;min-width:0;display:flex}.gNoOdq_jump{width:34px;height:34px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-button-floating-fill,var(--dsw-alias-bg-base));box-shadow:var(--dsw-elevation-panel,0 2px 8px var(--dsw-alias-border-l1));pointer-events:auto;border:0;border-radius:100px;flex:none;justify-content:center;align-items:center;margin-top:-34px;padding:0;display:flex}.gNoOdq_jump:hover{background:var(--dsw-alias-button-floating-hover,var(--dsw-alias-interactive-bg-hover))}.gNoOdq_foldSummary{text-overflow:ellipsis;align-items:baseline;max-width:100%;display:inline-flex;overflow:hidden;white-space:nowrap!important}.gNoOdq_foldSummaryPart{flex:none;align-items:baseline;display:inline-flex;white-space:nowrap!important}.gNoOdq_numberRollRoot{vertical-align:baseline;line-height:inherit;font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";text-align:center;flex-shrink:0;justify-content:center;min-width:1.45em;display:inline-flex;position:relative;overflow:hidden;white-space:nowrap!important}.gNoOdq_numberRollSizer{visibility:hidden;-webkit-user-select:none;user-select:none;pointer-events:none;line-height:inherit;white-space:nowrap}.gNoOdq_numberRollDigit{line-height:inherit;white-space:nowrap;justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.gNoOdq_numberRollExit{animation:.24s cubic-bezier(.16,1,.3,1) forwards gNoOdq_numberRollOut}.gNoOdq_numberRollEnter{animation:.24s cubic-bezier(.16,1,.3,1) forwards gNoOdq_numberRollIn}@keyframes gNoOdq_numberRollOut{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-100%)}}@keyframes gNoOdq_numberRollIn{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}[data-motion=off] .gNoOdq_chevron,[data-motion=off] .gNoOdq_imageOpen img,[data-motion=off] .gNoOdq_processMeta,[data-motion=off] .gNoOdq_numberRollDigit{transition:none!important;animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_chevron,.gNoOdq_imageOpen img,.gNoOdq_processMeta,.gNoOdq_numberRollDigit{transition:none!important;animation:none!important}}.gNoOdq_turnStatus{white-space:nowrap;flex:none;align-self:flex-start;align-items:center;height:26px;margin:4px 0 12px;padding:0 4px;font-size:14px;line-height:22px;display:inline-flex}.gNoOdq_turnStatusLabel{background:linear-gradient(90deg, var(--dsw-static-deepseek-500,#4d6bfe) 0%, var(--dsw-static-deepseek-500,#4d6bfe) 40%, var(--dsw-static-deepseek-200,#a8c7fa) 50%, var(--dsw-static-deepseek-500,#4d6bfe) 60%, var(--dsw-static-deepseek-500,#4d6bfe) 100%);color:#0000;-webkit-text-fill-color:transparent;background-position:100% 0;background-size:250% 100%;background-clip:text;font-weight:500;animation:1.8s linear infinite gNoOdq_dsh-turn-status-shimmer}.gNoOdq_waitClock{flex:none;align-items:center;margin-left:8px;display:inline-flex}.gNoOdq_waitSeconds{font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";color:var(--dsw-alias-label-caption,#86909c);font-size:13px;font-weight:400}.gNoOdq_waitOvertime{color:var(--dsw-alias-state-warning-primary,#d8862c);background:color-mix(in srgb, var(--dsw-alias-state-warning-primary,#d8862c) 16%, transparent);border-radius:5px;margin-left:8px;padding:0 6px;font-size:11px;line-height:16px}.gNoOdq_turnStatusClock{font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";color:var(--dsw-alias-label-caption,#86868b);-webkit-text-fill-color:var(--dsw-alias-label-caption,#86868b);margin-left:8px;font-size:13px;font-weight:400}@keyframes gNoOdq_dsh-turn-status-shimmer{to{background-position:0 0}}[data-motion=off] .gNoOdq_turnStatusLabel{color:var(--dsw-static-deepseek-500,#4d6bfe)!important;-webkit-text-fill-color:var(--dsw-static-deepseek-500,#4d6bfe)!important;animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_turnStatusLabel{color:var(--dsw-static-deepseek-500,#4d6bfe)!important;-webkit-text-fill-color:var(--dsw-static-deepseek-500,#4d6bfe)!important;animation:none!important}}@media (pointer:coarse){.gNoOdq_disclosureButton{min-height:44px}}@media (width<=600px){.gNoOdq_root{padding-inline:20px}.gNoOdq_column{gap:18px}.gNoOdq_toolbar{font-size:11px}}.gNoOdq_choreographedFlow{overflow-anchor:none;flex-direction:column;min-width:0;display:flex}.gNoOdq_flowCell{min-width:0;display:flow-root;overflow:clip}.gNoOdq_flowCell[hidden]{display:none}.gNoOdq_flowCellInner{flex-direction:column;min-width:0;padding-bottom:16px;display:flex}.gNoOdq_flowCellInner:empty{padding-bottom:0}.gNoOdq_choreographedFlow[data-reader-transition=collapse] .gNoOdq_flowCell *{animation-play-state:paused!important}.gNoOdq_numberRollExit,.gNoOdq_numberRollEnter{animation-duration:.16s}.gNoOdq_foldSummary{align-items:baseline;display:inline-flex;white-space:nowrap!important;flex-wrap:nowrap!important}.gNoOdq_toolbar{box-sizing:border-box;width:100%;max-width:100%;min-height:var(--reader-lane-block,40px);z-index:7;-webkit-backdrop-filter:none;backdrop-filter:none;border-bottom:0;align-self:stretch}.gNoOdq_turnProcessSticky{box-sizing:border-box;width:calc(100% - var(--reader-control-width,148px));top:var(--reader-toolbar-height,var(--reader-lane-block,40px));min-height:var(--reader-lane-block,40px);z-index:6;-webkit-backdrop-filter:none;backdrop-filter:none;box-shadow:0 -14px 0 var(--dsw-alias-bg-base), var(--reader-control-width,148px) 0 0 var(--dsw-alias-bg-base), 0 -14px 0 var(--dsw-alias-bg-layer-1,transparent), var(--reader-control-width,148px) 0 0 var(--dsw-alias-bg-layer-1,transparent), 0 -14px 0 Canvas, var(--reader-control-width,148px) 0 0 Canvas;background-clip:padding-box;border-bottom:1px solid #0000;padding-right:0}.gNoOdq_turnStickyLanes .gNoOdq_turnProcessSticky,.gNoOdq_turnStickyLanes .gNoOdq_closedProcessSummary{z-index:auto;position:static;top:auto}.gNoOdq_flowCell[data-flow-summary],.gNoOdq_closedProcessSummary{top:calc(var(--reader-toolbar-height,var(--reader-lane-block,40px)) + var(--reader-status-height,var(--reader-lane-block,40px)));z-index:5;box-sizing:border-box;min-height:var(--reader-lane-block,40px);background:var(--dsw-alias-bg-base);border-bottom:0;padding-block:4px;position:sticky;overflow:visible}.gNoOdq_root .md-code-block{z-index:0}.gNoOdq_turnStickyRegion:has(>.gNoOdq_turnStickyLanes>.gNoOdq_closedProcessSummary),.gNoOdq_turnStickyRegion:has(.gNoOdq_flowCell[data-flow-summary]){--reader-code-summary-height:var(--reader-summary-height,var(--reader-lane-block,40px))}.gNoOdq_root .md-code-block>:has(+[data-code-block-content]){top:calc(max(var(--reader-toolbar-height,40px), var(--reader-status-height,0px)) + var(--reader-status-height,0px) + var(--reader-code-summary-height,0px))}.gNoOdq_flowCell[data-flow-summary]{box-shadow:0 -16px 0 var(--dsw-alias-bg-base), 0 -16px 0 var(--dsw-alias-bg-layer-1,transparent), 0 -16px 0 Canvas}.gNoOdq_closedProcessSummary{box-shadow:0 -14px 0 var(--dsw-alias-bg-base), 0 -14px 0 var(--dsw-alias-bg-layer-1,transparent), 0 -14px 0 Canvas}.gNoOdq_foldControl{background:var(--dsw-alias-bg-module-platform);border-radius:8px;align-items:center;gap:0;padding:2px;display:inline-flex}.gNoOdq_foldStop{color:var(--dsw-alias-label-secondary);white-space:nowrap;font:inherit;cursor:pointer;background:0 0;border:0;border-radius:6px;padding:2px 8px;font-size:12px;line-height:18px}.gNoOdq_foldStop[data-on]{background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary)}.gNoOdq_flowCell[data-flow-summary]>.gNoOdq_flowCellInner{padding-bottom:0}.gNoOdq_flowCell[data-flow-summary] .gNoOdq_disclosureButton,.gNoOdq_closedProcessSummary .gNoOdq_disclosureButton{width:auto;max-width:100%}.gNoOdq_flowCell[data-flow-summary] .gNoOdq_foldSummary,.gNoOdq_closedProcessSummary .gNoOdq_foldSummary{min-width:0}.gNoOdq_turnProcessSticky>.gNoOdq_disclosure{flex:auto;min-width:0}.gNoOdq_disclosureButton{width:max-content;max-width:calc(100% + 6px)}.gNoOdq_statusText{flex:0 auto}.gNoOdq_think{width:max-content;min-width:0}.gNoOdq_thinkSizer{white-space:normal;overflow-wrap:anywhere}.gNoOdq_thinkText{white-space:normal;overflow-wrap:anywhere;text-overflow:clip;overflow:visible}.gNoOdq_toolbar,.gNoOdq_turnStickyLanes,.gNoOdq_turnProcessSticky,.gNoOdq_liveFoldContainer,.gNoOdq_flowCell[data-flow-summary],.gNoOdq_closedProcessSummary{background-color:canvas;background-image:var(--reader-lane-plate);background-repeat:no-repeat}.gNoOdq_root[data-reader-glass] .gNoOdq_toolbar,.gNoOdq_root[data-reader-glass] .gNoOdq_turnProcessSticky,.gNoOdq_root[data-reader-glass] .gNoOdq_liveFoldContainer{-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);box-shadow:none;background:0 0;border:0;border-radius:0}.gNoOdq_root[data-reader-glass] .gNoOdq_toolbar,.gNoOdq_root[data-reader-glass] .gNoOdq_turnProcessSticky{-webkit-backdrop-filter:none;backdrop-filter:none}.gNoOdq_root[data-reader-glass] .gNoOdq_toolbar{pointer-events:none}.gNoOdq_root[data-reader-glass] .gNoOdq_toolbar>.gNoOdq_textButton,.gNoOdq_root[data-reader-glass] .gNoOdq_turnProcessSticky .gNoOdq_disclosureButton{pointer-events:auto;background:color-mix(in srgb, var(--dsw-alias-bg-layer-1,#ffffffb3) 80%, transparent);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);border-radius:999px;padding:2px 10px}.gNoOdq_root[data-reader-glass] .gNoOdq_turnProcessSticky .gNoOdq_disclosureButton{max-width:100%;margin-left:0}.gNoOdq_root[data-reader-glass] .gNoOdq_toolbar>.gNoOdq_textButton:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_turnProcessSticky .gNoOdq_disclosureButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_root[data-reader-glass] .gNoOdq_flowCell[data-flow-summary],.gNoOdq_root[data-reader-glass] .gNoOdq_closedProcessSummary{box-shadow:none;z-index:auto;border-left:2px solid color-mix(in srgb, var(--dsw-alias-border-l2,#80808059) 80%, transparent);padding-block:2px;background:0 0;border-radius:0;min-height:32px;padding-left:10px;position:static}.gNoOdq_root[data-reader-glass] .gNoOdq_turnStickyLanes{z-index:auto;display:contents;position:static;top:auto}.gNoOdq_root[data-reader-glass] .gNoOdq_turnStickyRegion{--reader-code-summary-height:0px}.gNoOdq_root[data-reader-glass] .gNoOdq_turnStickyLanes .gNoOdq_turnProcessSticky{top:var(--reader-toolbar-height,var(--reader-lane-block,40px));z-index:6;position:sticky}.gNoOdq_root[data-reader-glass] .gNoOdq_user{background:color-mix(in srgb, var(--dsw-specific-bubble,#00000014) 25%, transparent);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);border:1px solid color-mix(in srgb, var(--dsw-alias-border-l1,#8080804d) 30%, transparent)}.gNoOdq_root[data-reader-glass] .gNoOdq_reasonCard{border-color:color-mix(in srgb, var(--dsw-alias-border-l1,#80808059) 65%, transparent);background:0 0}.gNoOdq_root[data-reader-glass] .gNoOdq_toolDetails,.gNoOdq_root[data-reader-glass] .gNoOdq_notice,.gNoOdq_root[data-reader-glass] .gNoOdq_unknown,.gNoOdq_root[data-reader-glass] .gNoOdq_toolRaw,.gNoOdq_root[data-reader-glass] .gNoOdq_systemPrompt,.gNoOdq_root[data-reader-glass] .gNoOdq_compactionSummaryBox,.gNoOdq_root[data-reader-glass] .gNoOdq_attention,.gNoOdq_root[data-reader-glass] .gNoOdq_imageFrame,.gNoOdq_root[data-reader-glass] .gNoOdq_imageDialog{background:0 0}.gNoOdq_root[data-reader-glass] .gNoOdq_diffOverlay{background:color-mix(in srgb, var(--dsw-alias-bg-module-platform,#7f7f7f1a) 20%, transparent);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px)}.gNoOdq_root[data-reader-glass] .gNoOdq_diffScrollArea{background:0 0}.gNoOdq_root[data-reader-glass] .gNoOdq_diffTab{background:color-mix(in srgb, var(--dsw-alias-bg-base,#fffc) 25%, transparent)}.gNoOdq_root[data-reader-glass] .gNoOdq_diffTab[data-active]{background:color-mix(in srgb, var(--dsw-alias-bg-base,#fff) 45%, transparent)}:is(.gNoOdq_root[data-reader-glass] .md-code-block,.gNoOdq_root[data-reader-glass] [data-diff]){border:1px solid color-mix(in srgb, var(--dsw-alias-border-l1,#80808033) 30%, transparent);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);background:color-mix(in srgb, var(--dsw-alias-markdown-code-block,#0000000f) 25%, transparent)!important}.gNoOdq_root[data-reader-glass] .gNoOdq_foldControl{background:color-mix(in srgb, var(--dsw-alias-bg-module-platform,#7f7f7f1a) 25%, transparent);border:1px solid color-mix(in srgb, var(--dsw-alias-border-l2,#80808033) 30%, transparent)}.gNoOdq_root[data-reader-glass] .gNoOdq_foldStop[data-on]{background:color-mix(in srgb, var(--dsw-alias-bg-base,#fff) 35%, transparent)}.gNoOdq_root[data-reader-glass] .gNoOdq_compactionPill,.gNoOdq_root[data-reader-glass] .gNoOdq_deliverableChip,.gNoOdq_root[data-reader-glass] .gNoOdq_toolState,.gNoOdq_root[data-reader-glass] .gNoOdq_diffStatButton{background:0 0;border-color:#0000}.gNoOdq_root[data-reader-glass] .gNoOdq_compactionPill:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_compactionPill:focus-visible,.gNoOdq_root[data-reader-glass] .gNoOdq_deliverableChip:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_deliverableChip:focus-within,.gNoOdq_root[data-reader-glass] .gNoOdq_toolState:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_diffStatButton:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_diffStatButton:focus-visible,.gNoOdq_root[data-reader-glass] .gNoOdq_diffStatButton[aria-expanded=true]{background:var(--dsw-alias-bg-module-platform,#7f7f7f1a);border-color:var(--dsw-alias-border-l2,#7f7f7f47)}";
42427
42740
  const tagId$5 = "dsh-better-display/Reader.module.css";
42428
42741
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
42429
42742
  const tag = document.createElement("style");
@@ -42534,7 +42847,6 @@ ${trimmed}
42534
42847
  "numberRollSizer": "gNoOdq_numberRollSizer",
42535
42848
  "pendingImage": "gNoOdq_pendingImage",
42536
42849
  "priorFoldDrawer": "gNoOdq_priorFoldDrawer",
42537
- "processCommentary": "gNoOdq_processCommentary",
42538
42850
  "processContents": "gNoOdq_processContents",
42539
42851
  "processFootnote": "gNoOdq_processFootnote",
42540
42852
  "processFrame": "gNoOdq_processFrame",
@@ -42543,6 +42855,7 @@ ${trimmed}
42543
42855
  "processMeta": "gNoOdq_processMeta",
42544
42856
  "processMetaInner": "gNoOdq_processMetaInner",
42545
42857
  "processMetaLine": "gNoOdq_processMetaLine",
42858
+ "processSeamRow": "gNoOdq_processSeamRow",
42546
42859
  "readerRunningGlow": "gNoOdq_readerRunningGlow",
42547
42860
  "readerStepShimmer": "gNoOdq_readerStepShimmer",
42548
42861
  "readingText": "gNoOdq_readingText",
@@ -42600,6 +42913,8 @@ ${trimmed}
42600
42913
  "turnStatus": "gNoOdq_turnStatus",
42601
42914
  "turnStatusClock": "gNoOdq_turnStatusClock",
42602
42915
  "turnStatusLabel": "gNoOdq_turnStatusLabel",
42916
+ "turnStickyLanes": "gNoOdq_turnStickyLanes",
42917
+ "turnStickyRegion": "gNoOdq_turnStickyRegion",
42603
42918
  "unknown": "gNoOdq_unknown",
42604
42919
  "user": "gNoOdq_user",
42605
42920
  "userActions": "gNoOdq_userActions",
@@ -42765,8 +43080,218 @@ ${trimmed}
42765
43080
  });
42766
43081
  }
42767
43082
  //#endregion
43083
+ //#region src/client/text-transform.ts
43084
+ /**
43085
+ * Cordis service name. Another client plugin lists this in `inject` and
43086
+ * registers a transformer. The reading view paints the result. The session
43087
+ * block, transcript, and fold inputs stay on the original text.
43088
+ */
43089
+ const TEXT_TRANSFORM_SERVICE = "dsh-better-display.text-transform";
43090
+ const KINDS = /* @__PURE__ */ new Set(["reasoning", "body"]);
43091
+ function isKind(value) {
43092
+ return KINDS.has(value);
43093
+ }
43094
+ function reportTransformError(error) {
43095
+ console.warn("[dsh-better-display] text transform failed; showing original text", error);
43096
+ }
43097
+ function passthrough(request) {
43098
+ return {
43099
+ text: request.text,
43100
+ final: !request.streaming,
43101
+ transformRevision: 0,
43102
+ motionRevision: 0
43103
+ };
43104
+ }
43105
+ function normalize(value, request) {
43106
+ if (typeof value === "string") return {
43107
+ text: value,
43108
+ final: !request.streaming
43109
+ };
43110
+ if (!value || typeof value.text !== "string") return {
43111
+ text: request.text,
43112
+ final: !request.streaming
43113
+ };
43114
+ return {
43115
+ text: value.text,
43116
+ final: typeof value.final === "boolean" ? value.final : !request.streaming
43117
+ };
43118
+ }
43119
+ /**
43120
+ * Appends keep the motion revision. A replacement gets a new one so the
43121
+ * timeline treats the swapped string as already settled.
43122
+ */
43123
+ function nextDisplayCursor(previous, display) {
43124
+ if (!previous) return {
43125
+ ...display,
43126
+ transformRevision: 0,
43127
+ motionRevision: 0
43128
+ };
43129
+ if (previous.text === display.text && previous.final === display.final) return previous;
43130
+ const appended = display.text.startsWith(previous.text);
43131
+ return {
43132
+ text: display.text,
43133
+ final: display.final,
43134
+ transformRevision: previous.transformRevision + 1,
43135
+ motionRevision: appended ? previous.motionRevision : previous.motionRevision + 1
43136
+ };
43137
+ }
43138
+ /**
43139
+ * Streaming flag fed to the reveal. With no transformer this is the model's
43140
+ * flag. A transformer that reports `final: !streaming` produces the same flag.
43141
+ */
43142
+ function displayStreaming(sourceStreaming, shown, active) {
43143
+ return active ? !shown.final : sourceStreaming;
43144
+ }
43145
+ var TextTransformRegistryImpl = class {
43146
+ stacks = /* @__PURE__ */ new Map();
43147
+ listeners = /* @__PURE__ */ new Map();
43148
+ cursors = /* @__PURE__ */ new Map();
43149
+ register(kind, transformer) {
43150
+ const requested = [...new Set(Array.isArray(kind) ? kind : [kind])];
43151
+ for (const item of requested) if (!isKind(item)) throw new Error(`Unknown display text kind: ${String(item)}`);
43152
+ const bound = [];
43153
+ for (const item of requested) {
43154
+ const entry = { transformer };
43155
+ try {
43156
+ entry.unsubscribe = transformer.subscribe?.(() => {
43157
+ this.emit(item);
43158
+ });
43159
+ } catch (error) {
43160
+ reportTransformError(error);
43161
+ }
43162
+ const stack = this.stacks.get(item) ?? [];
43163
+ stack.push(entry);
43164
+ this.stacks.set(item, stack);
43165
+ bound.push({
43166
+ kind: item,
43167
+ entry
43168
+ });
43169
+ this.emit(item);
43170
+ }
43171
+ return () => {
43172
+ for (const { kind: item, entry } of bound) {
43173
+ try {
43174
+ entry.unsubscribe?.();
43175
+ } catch (error) {
43176
+ reportTransformError(error);
43177
+ }
43178
+ const stack = this.stacks.get(item);
43179
+ if (!stack) continue;
43180
+ const next = stack.filter((candidate) => candidate !== entry);
43181
+ if (next.length > 0) this.stacks.set(item, next);
43182
+ else this.stacks.delete(item);
43183
+ this.emit(item);
43184
+ }
43185
+ };
43186
+ }
43187
+ has(kind) {
43188
+ return (this.stacks.get(kind)?.length ?? 0) > 0;
43189
+ }
43190
+ read(request) {
43191
+ const transformer = this.stacks.get(request.kind)?.at(-1)?.transformer;
43192
+ if (!transformer) return passthrough(request);
43193
+ let display;
43194
+ try {
43195
+ display = normalize(transformer.read(request), request);
43196
+ } catch (error) {
43197
+ reportTransformError(error);
43198
+ display = {
43199
+ text: request.text,
43200
+ final: !request.streaming
43201
+ };
43202
+ }
43203
+ const key = `${request.kind}\u0000${request.blockKey}`;
43204
+ const next = nextDisplayCursor(this.cursors.get(key), display);
43205
+ this.cursors.set(key, next);
43206
+ return next;
43207
+ }
43208
+ subscribe(kind, listener) {
43209
+ const set = this.listeners.get(kind) ?? /* @__PURE__ */ new Set();
43210
+ set.add(listener);
43211
+ this.listeners.set(kind, set);
43212
+ return () => {
43213
+ set.delete(listener);
43214
+ };
43215
+ }
43216
+ release(kind, blockKey) {
43217
+ this.cursors.delete(`${kind}\u0000${blockKey}`);
43218
+ }
43219
+ emit(kind) {
43220
+ const set = this.listeners.get(kind);
43221
+ if (!set) return;
43222
+ for (const listener of [...set]) listener();
43223
+ }
43224
+ };
43225
+ function createTextTransformRegistry() {
43226
+ return new TextTransformRegistryImpl();
43227
+ }
43228
+ let active;
43229
+ /** Points the reading view at the registry this client plugin provides. */
43230
+ function installTextTransformRegistry(registry) {
43231
+ const previous = active;
43232
+ active = registry;
43233
+ return () => {
43234
+ active = previous;
43235
+ };
43236
+ }
43237
+ function activeTextTransform() {
43238
+ return active;
43239
+ }
43240
+ /**
43241
+ * Subscribe while mounted. The reveal components call this only after
43242
+ * `has(kind)`, so an empty registry adds no hook and no listener.
43243
+ */
43244
+ function useDisplayText(registry, request) {
43245
+ const [epoch, setEpoch] = (0, react.useState)(0);
43246
+ const { text, streaming, blockKey, kind, source } = request;
43247
+ (0, react.useEffect)(() => registry.subscribe(kind, () => {
43248
+ setEpoch((value) => value + 1);
43249
+ }), [registry, kind]);
43250
+ (0, react.useEffect)(() => () => {
43251
+ registry.release(kind, blockKey);
43252
+ }, [
43253
+ registry,
43254
+ kind,
43255
+ blockKey
43256
+ ]);
43257
+ return (0, react.useMemo)(() => registry.read({
43258
+ text,
43259
+ streaming,
43260
+ blockKey,
43261
+ kind,
43262
+ source
43263
+ }), [
43264
+ registry,
43265
+ text,
43266
+ streaming,
43267
+ blockKey,
43268
+ kind,
43269
+ source,
43270
+ epoch
43271
+ ]);
43272
+ }
43273
+ /** Chain-slot owner. Extra fields are optional so older callers still type-check. */
43274
+ function readerBlockOwner(block, streaming, source, presentation, holdFormatting) {
43275
+ return {
43276
+ block,
43277
+ streaming,
43278
+ source,
43279
+ presentation: {
43280
+ startedAt: presentation.startedAt,
43281
+ interrupted: presentation.interrupted,
43282
+ liveText: presentation.liveText
43283
+ },
43284
+ holdFormatting,
43285
+ liveText: presentation.liveText
43286
+ };
43287
+ }
43288
+ /** Copy actions read this. Display text never replaces it. */
43289
+ function originalAnswerText(blocks) {
43290
+ return blocks.flatMap((block) => block.kind === "text" && typeof block.text === "string" ? [block.text] : []).join("\n\n");
43291
+ }
43292
+ //#endregion
42768
43293
  //#region \0dshx-css-module:TurnMetrics.module.css.mjs
42769
- const css$4 = "._QZbGG_container{color:var(--dsw-alias-label-tertiary);align-items:center;gap:2px;font-size:13px;line-height:24px;display:inline-flex;position:relative}._QZbGG_pillButton{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-tertiary);cursor:pointer;border-radius:12px;outline:none;align-items:center;gap:5px;padding:2px 8px;font-family:inherit;font-size:11px;transition:all .14s;display:inline-flex}._QZbGG_pillButton:hover,._QZbGG_pillButton[data-active=true]{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover)}._QZbGG_timeButton{height:28px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:28px;align-items:center;gap:4px;padding:6px 8px;font-family:inherit;font-size:13px;line-height:24px;display:inline-flex}._QZbGG_timeButton:hover,._QZbGG_timeButton[data-active=true]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}._QZbGG_pillIcon{opacity:.8;flex:none;width:12px;height:12px}._QZbGG_metricsPop{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);backdrop-filter:blur(10px);z-index:50;text-align:left;border-radius:10px;flex-direction:column;gap:8px;width:260px;padding:12px 14px;animation:.14s ease-out _QZbGG_popIn;display:flex;position:absolute;bottom:calc(100% + 8px);left:0;box-shadow:0 6px 20px #00000024}@keyframes _QZbGG_popIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}._QZbGG_popHeader{color:var(--dsw-alias-label-primary);border-bottom:1px solid var(--dsw-alias-border-l1);justify-content:space-between;align-items:center;padding-bottom:6px;font-size:12px;font-weight:600;display:flex}._QZbGG_popSection{flex-direction:column;gap:4px;display:flex}._QZbGG_popSectionTitle{text-transform:uppercase;letter-spacing:.5px;color:var(--dsw-alias-label-tertiary);margin-top:2px;font-size:10px;font-weight:600}._QZbGG_popGrid{grid-template-columns:1fr auto;gap:3px 12px;font-size:11px;line-height:18px;display:grid}._QZbGG_popLabel{color:var(--dsw-alias-label-secondary)}._QZbGG_popValue{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;text-align:right;font-weight:500}._QZbGG_popBadge{background:var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:3px;margin-left:4px;padding:0 4px;font-size:10px}";
43294
+ const css$4 = "._QZbGG_container{color:var(--dsw-alias-label-tertiary);align-items:center;gap:2px;font-size:13px;line-height:24px;display:inline-flex;position:relative}._QZbGG_pillButton{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-tertiary);cursor:pointer;border-radius:12px;outline:none;align-items:center;gap:5px;padding:2px 8px;font-family:inherit;font-size:11px;transition:all .14s;display:inline-flex}._QZbGG_pillButton:hover,._QZbGG_pillButton[data-active=true]{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover)}._QZbGG_timeButton{height:28px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:28px;align-items:center;gap:4px;padding:6px 8px;font-family:inherit;font-size:13px;line-height:24px;display:inline-flex}._QZbGG_timeButton:hover,._QZbGG_timeButton[data-active=true]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}._QZbGG_pillIcon{opacity:.8;flex:none;width:12px;height:12px}._QZbGG_metricsPop{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);z-index:50;text-align:left;border-radius:10px;flex-direction:column;gap:8px;width:260px;padding:12px 14px;animation:.14s ease-out _QZbGG_popIn;display:flex;position:absolute;bottom:calc(100% + 8px);left:0;box-shadow:0 6px 20px #00000024}@keyframes _QZbGG_popIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}._QZbGG_popHeader{color:var(--dsw-alias-label-primary);border-bottom:1px solid var(--dsw-alias-border-l1);justify-content:space-between;align-items:center;padding-bottom:6px;font-size:12px;font-weight:600;display:flex}._QZbGG_popSection{flex-direction:column;gap:4px;display:flex}._QZbGG_popSectionTitle{text-transform:uppercase;letter-spacing:.5px;color:var(--dsw-alias-label-tertiary);margin-top:2px;font-size:10px;font-weight:600}._QZbGG_popGrid{grid-template-columns:1fr auto;gap:3px 12px;font-size:11px;line-height:18px;display:grid}._QZbGG_popLabel{color:var(--dsw-alias-label-secondary)}._QZbGG_popValue{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;text-align:right;font-weight:500}._QZbGG_popBadge{background:var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:3px;margin-left:4px;padding:0 4px;font-size:10px}";
42770
43295
  const tagId$4 = "dsh-better-display/TurnMetrics.module.css";
42771
43296
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
42772
43297
  const tag = document.createElement("style");
@@ -43129,7 +43654,7 @@ ${trimmed}
43129
43654
  };
43130
43655
  });
43131
43656
  }
43132
- function ReadingMarkdown({ text, streaming, holdFormatting, startedAt, interrupted = false, liveText = false, kind = "body", fileMentions }) {
43657
+ function MarkdownStream({ text, streaming, holdFormatting, startedAt, interrupted = false, liveText = false, kind = "body", fileMentions, transformed = false }) {
43133
43658
  const root = (0, react.useRef)(null);
43134
43659
  const presentation = useStreamingText(text, streaming, {
43135
43660
  startedAt,
@@ -43153,6 +43678,7 @@ ${trimmed}
43153
43678
  "data-ud-motion": "reader-text-arrival",
43154
43679
  "data-ud-motion-type": "reveal",
43155
43680
  "data-ud-motion-no-flash": "true",
43681
+ "data-text-transform": transformed ? streaming ? "live" : "final" : void 0,
43156
43682
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MotionMarkdown, {
43157
43683
  text: presentation.text,
43158
43684
  streaming: effectiveMode,
@@ -43162,7 +43688,32 @@ ${trimmed}
43162
43688
  })
43163
43689
  });
43164
43690
  }
43165
- function ReadingReasoning({ text, streaming, holdFormatting, startedAt, interrupted = false, liveText = false }) {
43691
+ function TransformedMarkdown({ registry, blockKey, source, text, streaming, ...props }) {
43692
+ const shown = useDisplayText(registry, {
43693
+ text,
43694
+ streaming,
43695
+ blockKey,
43696
+ kind: "body",
43697
+ source
43698
+ });
43699
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarkdownStream, {
43700
+ ...props,
43701
+ text: shown.text,
43702
+ streaming: displayStreaming(streaming, shown, true),
43703
+ transformed: true
43704
+ });
43705
+ }
43706
+ function ReadingMarkdown({ blockKey, source, ...props }) {
43707
+ const registry = activeTextTransform();
43708
+ if (registry?.has("body")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TransformedMarkdown, {
43709
+ registry,
43710
+ blockKey,
43711
+ source,
43712
+ ...props
43713
+ });
43714
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarkdownStream, { ...props });
43715
+ }
43716
+ function ReasoningStream({ text, streaming, holdFormatting, startedAt, interrupted = false, liveText = false, transformed = false }) {
43166
43717
  const presentation = useStreamingText(text, streaming, {
43167
43718
  startedAt,
43168
43719
  interrupted: interrupted || !liveText,
@@ -43179,6 +43730,7 @@ ${trimmed}
43179
43730
  "data-ud-motion": "reader-text-arrival",
43180
43731
  "data-ud-motion-type": "reveal",
43181
43732
  "data-ud-motion-no-flash": "true",
43733
+ "data-text-transform": transformed ? streaming ? "live" : "final" : void 0,
43182
43734
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MotionPlainText, {
43183
43735
  text: presentation.text,
43184
43736
  enabled: liveText && presentation.reveal,
@@ -43186,7 +43738,32 @@ ${trimmed}
43186
43738
  })
43187
43739
  });
43188
43740
  }
43189
- function fallback(block, streaming, source, loadImage, fillComposer, holdFormatting, presentation, fileMentions) {
43741
+ function TransformedReasoning({ registry, blockKey, source, text, streaming, ...props }) {
43742
+ const shown = useDisplayText(registry, {
43743
+ text,
43744
+ streaming,
43745
+ blockKey,
43746
+ kind: "reasoning",
43747
+ source
43748
+ });
43749
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReasoningStream, {
43750
+ ...props,
43751
+ text: shown.text,
43752
+ streaming: displayStreaming(streaming, shown, true),
43753
+ transformed: true
43754
+ });
43755
+ }
43756
+ function ReadingReasoning({ blockKey, source, ...props }) {
43757
+ const registry = activeTextTransform();
43758
+ if (registry?.has("reasoning")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TransformedReasoning, {
43759
+ registry,
43760
+ blockKey,
43761
+ source,
43762
+ ...props
43763
+ });
43764
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReasoningStream, { ...props });
43765
+ }
43766
+ function fallback(block, streaming, source, loadImage, fillComposer, holdFormatting, presentation, blockKey, fileMentions) {
43190
43767
  switch (block.kind) {
43191
43768
  case "text": return source === "user" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
43192
43769
  text: block.text,
@@ -43196,7 +43773,9 @@ ${trimmed}
43196
43773
  streaming,
43197
43774
  holdFormatting,
43198
43775
  ...presentation,
43199
- fileMentions
43776
+ fileMentions,
43777
+ blockKey,
43778
+ source
43200
43779
  });
43201
43780
  case "image": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageBlock, {
43202
43781
  attachment: block.attachment,
@@ -43206,7 +43785,9 @@ ${trimmed}
43206
43785
  text: block.text,
43207
43786
  streaming,
43208
43787
  holdFormatting,
43209
- ...presentation
43788
+ ...presentation,
43789
+ blockKey,
43790
+ source
43210
43791
  });
43211
43792
  case "tool-call": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.JsonBlock, {
43212
43793
  label: `工具参数 · ${block.name}`,
@@ -43235,20 +43816,21 @@ ${trimmed}
43235
43816
  }
43236
43817
  }
43237
43818
  const Blocks = (0, react.memo)(function Blocks({ blocks, streaming = false, source = "assistant", holdFormatting = false, startedAt, interrupted, liveText, renderSlotChain, loadImage, fillComposer, fileMentions }) {
43819
+ const reactId = (0, react.useId)();
43238
43820
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ComposerFillContext.Provider, {
43239
43821
  value: fillComposer,
43240
43822
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
43241
43823
  className: Reader_module_css_default.blocks,
43242
43824
  "data-streaming": streaming || void 0,
43243
- children: blocks.map((block, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockBoundary, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderSlotChain("dsh-better-display.block", {
43244
- block,
43245
- streaming,
43246
- source
43247
- }, { fallback: fallback(block, streaming, source, loadImage, fillComposer, holdFormatting, {
43825
+ children: blocks.map((block, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockBoundary, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderSlotChain("dsh-better-display.block", readerBlockOwner(block, streaming, source, {
43826
+ startedAt,
43827
+ interrupted,
43828
+ liveText
43829
+ }, holdFormatting), { fallback: fallback(block, streaming, source, loadImage, fillComposer, holdFormatting, {
43248
43830
  startedAt,
43249
43831
  interrupted,
43250
43832
  liveText
43251
- }, fileMentions) }) }) }, block.kind === "image" ? `image:${block.attachment.attachmentId}:${index}` : `${index}:${block.kind}`))
43833
+ }, `${reactId}:${index}:${block.kind}`, fileMentions) }) }) }, block.kind === "image" ? `image:${block.attachment.attachmentId}:${index}` : `${index}:${block.kind}`))
43252
43834
  })
43253
43835
  });
43254
43836
  });
@@ -43293,7 +43875,7 @@ ${trimmed}
43293
43875
  }
43294
43876
  function CopyAnswer({ blocks, onFork, metrics, extraActions }) {
43295
43877
  const { receipt, copy } = useCopyReceipt();
43296
- const text = blocks.filter((block) => block.kind === "text").map((block) => block.text).join("\n\n");
43878
+ const text = originalAnswerText(blocks);
43297
43879
  const endedAt = metrics?.endedAt;
43298
43880
  const hasMetrics = metrics !== void 0 && (metrics.usage !== void 0 || metrics.runMs !== void 0 || endedAt !== void 0);
43299
43881
  if (!text.trim() && !onFork && !hasMetrics) return null;
@@ -43784,14 +44366,22 @@ ${trimmed}
43784
44366
  images: "dsh-better-display.official.images/conversation.message.images"
43785
44367
  };
43786
44368
  const officialSeat = (family, source = OFFICIAL_SLOTS[family]) => `dsh-better-display.official.${family}/${source}`;
43787
- const READER_NODES = /* @__PURE__ */ new Set([
43788
- "user",
43789
- "steering",
43790
- "assistant-step",
44369
+ const READER_OWNED_NODES = /* @__PURE__ */ new Set([
43791
44370
  "tool-call",
43792
44371
  "turn-tail",
43793
44372
  "turn-process"
43794
44373
  ]);
44374
+ /**
44375
+ * Mirror a chat-node registration into the Reader seat.
44376
+ * Assistant replacements are the entries that would actually replace the
44377
+ * official renderer on the host. The official priority itself stays out, so
44378
+ * Reader keeps its own answer markdown until a plugin opts in.
44379
+ */
44380
+ function acceptMirroredChatNode(entry) {
44381
+ const key = entry.options.key ?? "";
44382
+ if (key === "assistant-step") return (entry.options.priority ?? 0) < 0;
44383
+ return !READER_OWNED_NODES.has(key);
44384
+ }
43795
44385
  const EXPECTED = {
43796
44386
  actions: {
43797
44387
  kind: "list",
@@ -43941,7 +44531,7 @@ ${trimmed}
43941
44531
  const target = officialSeat(family);
43942
44532
  const declared = slots.spec(target);
43943
44533
  if (spec.kind !== declared?.kind || spec.scope !== declared.scope) throw new Error(`Official slot contract changed: ${source}`);
43944
- return mirrorOfficialSlot(slots, source, target, `dsh-better-display.official.${family}`, family === "nodes" ? (entry) => !READER_NODES.has(entry.options.key ?? "") : void 0);
44534
+ return mirrorOfficialSlot(slots, source, target, `dsh-better-display.official.${family}`, family === "nodes" ? acceptMirroredChatNode : void 0);
43945
44535
  }));
43946
44536
  }
43947
44537
  } catch (error) {
@@ -44006,11 +44596,8 @@ ${trimmed}
44006
44596
  })
44007
44597
  });
44008
44598
  }
44009
- function OfficialNode({ node, fallback, ...render }) {
44010
- const official = render.official;
44011
- const [disclosureReset] = (0, react.useState)(() => (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(0));
44012
- if (!official) return fallback;
44013
- const owner = {
44599
+ function chatNodeOwner(render, official) {
44600
+ return {
44014
44601
  cwd: render.cwd,
44015
44602
  openFile: render.openFile ?? (() => {}),
44016
44603
  openSkill: () => {},
@@ -44023,13 +44610,18 @@ ${trimmed}
44023
44610
  }),
44024
44611
  fileMentions: official.officialFileMentions
44025
44612
  };
44613
+ }
44614
+ function OfficialNode({ node, fallback, ...render }) {
44615
+ const official = render.official;
44616
+ const [disclosureReset] = (0, react.useState)(() => (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(0));
44617
+ if (!official) return fallback;
44026
44618
  const turn = node.location.kind === "turn" || node.location.kind === "step" ? node.location.turn : void 0;
44027
44619
  const renderNode = official.renderSlot;
44028
44620
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
44029
44621
  "data-reader-official-node": node.kind,
44030
44622
  ...node.kind === "user" || node.kind === "steering" ? chatSeatProps(node.kind, node.key) : {},
44031
44623
  children: renderNode(OFFICIAL_SEATS.nodes, {
44032
- ...owner,
44624
+ ...chatNodeOwner(render, official),
44033
44625
  node
44034
44626
  }, {
44035
44627
  entryKey: node.kind,
@@ -44041,6 +44633,46 @@ ${trimmed}
44041
44633
  })
44042
44634
  });
44043
44635
  }
44636
+ /**
44637
+ * Body of one assistant segment. A mirrored assistant-step replacement draws
44638
+ * it; Reader markdown is the fallback when no replacement is registered.
44639
+ * The caller keeps reasoning blocks on the reading card.
44640
+ */
44641
+ function OfficialAssistantBody({ node, blocks, streaming = false, holdFormatting = false, startedAt, interrupted = false, liveText = false, ...render }) {
44642
+ const official = render.official;
44643
+ const [disclosureReset] = (0, react.useState)(() => (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(0));
44644
+ const fallback = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Blocks, {
44645
+ ...render,
44646
+ blocks,
44647
+ streaming,
44648
+ holdFormatting,
44649
+ startedAt,
44650
+ interrupted,
44651
+ liveText
44652
+ });
44653
+ if (!official) return fallback;
44654
+ const turn = node.location.kind === "turn" || node.location.kind === "step" ? node.location.turn : void 0;
44655
+ const view = blocks.length === node.data.blocks.length && blocks.every((block, index) => block === node.data.blocks[index]) ? node : {
44656
+ ...node,
44657
+ data: {
44658
+ ...node.data,
44659
+ blocks
44660
+ }
44661
+ };
44662
+ const renderNode = official.renderSlot;
44663
+ return renderNode(OFFICIAL_SEATS.nodes, {
44664
+ ...chatNodeOwner(render, official),
44665
+ node: view,
44666
+ groupPart: "response"
44667
+ }, {
44668
+ entryKey: "assistant-step",
44669
+ hookContext: {
44670
+ turnData: turn?.data,
44671
+ disclosureReset
44672
+ },
44673
+ fallback
44674
+ });
44675
+ }
44044
44676
  function OfficialTail({ official, owner, produced }) {
44045
44677
  const tailOwner = owner && official ? {
44046
44678
  ...owner,
@@ -44054,6 +44686,69 @@ ${trimmed}
44054
44686
  }) : null;
44055
44687
  }
44056
44688
  //#endregion
44689
+ //#region src/client/turn-slots.ts
44690
+ /**
44691
+ * Keep live turns in the incoming `groups` order, and keep a departing turn
44692
+ * next to the live neighbour that preceded it.
44693
+ *
44694
+ * A rewind removes turn keys from the visible order. Unmounting them in that
44695
+ * same commit snaps the transcript, so the lane retains the last group object
44696
+ * until the collapse finishes. A re-render, a stream tick, or a reconnect that
44697
+ * still contains the same keys only replaces the group object and leaves
44698
+ * `live` true — those updates must not start a collapse. A key that returns
44699
+ * is live again where `groups` places it. Loading older history therefore
44700
+ * stays in transcript order instead of appending the older turns after the
44701
+ * ones already on screen. A departing slot is inserted immediately after the
44702
+ * nearest preceding slot that is still live, or at the front when it had none,
44703
+ * so several departing neighbours keep their relative order.
44704
+ *
44705
+ * Returns `current` itself when nothing changed, so a React state update can
44706
+ * bail out on `Object.is`.
44707
+ */
44708
+ function reconcileTurnSlots(current, groups) {
44709
+ const incoming = new Map(groups.map((group) => [group.key, group]));
44710
+ const next = groups.map((group) => ({
44711
+ group,
44712
+ live: true
44713
+ }));
44714
+ for (const slot of current) {
44715
+ if (incoming.has(slot.group.key)) continue;
44716
+ insertDeparting(next, {
44717
+ group: slot.group,
44718
+ live: false
44719
+ }, precedingLiveKey(current, incoming, slot.group.key));
44720
+ }
44721
+ return next.length === current.length && next.every((slot, index) => slot.live === current[index].live && slot.group === current[index].group) ? current : next;
44722
+ }
44723
+ /** Nearest preceding slot that is still in the incoming order, if any. */
44724
+ function precedingLiveKey(current, incoming, key) {
44725
+ const index = current.findIndex((slot) => slot.group.key === key);
44726
+ for (let cursor = index - 1; cursor >= 0; cursor--) {
44727
+ const candidate = current[cursor].group.key;
44728
+ if (incoming.has(candidate)) return candidate;
44729
+ }
44730
+ }
44731
+ /**
44732
+ * Place a departing slot after `anchorKey`, or at the front when the slot had
44733
+ * no preceding live neighbour. Slots that share an anchor keep `current` order
44734
+ * because each one is inserted at the end of the departing run after that anchor.
44735
+ */
44736
+ function insertDeparting(next, slot, anchorKey) {
44737
+ if (anchorKey === void 0) {
44738
+ const firstLive = next.findIndex((item) => item.live);
44739
+ next.splice(firstLive < 0 ? next.length : firstLive, 0, slot);
44740
+ return;
44741
+ }
44742
+ const anchorIndex = next.findIndex((item) => item.group.key === anchorKey);
44743
+ if (anchorIndex < 0) {
44744
+ next.unshift(slot);
44745
+ return;
44746
+ }
44747
+ let insertAt = anchorIndex + 1;
44748
+ while (insertAt < next.length && next[insertAt]?.live === false) insertAt++;
44749
+ next.splice(insertAt, 0, slot);
44750
+ }
44751
+ //#endregion
44057
44752
  //#region src/client/motion.tsx
44058
44753
  const EASING = "cubic-bezier(.22,1,.36,1)";
44059
44754
  function useMotionAllowed(enabled) {
@@ -44066,7 +44761,7 @@ ${trimmed}
44066
44761
  }, []);
44067
44762
  return enabled && !reduced;
44068
44763
  }
44069
- function usePinnedSelection(root, selector = "[data-reader-answer], [data-reader-process]") {
44764
+ function usePinnedSelection(root, selector = "[data-reader-answer], [data-reader-body], [data-reader-process]") {
44070
44765
  const [keys, setKeys] = (0, react.useState)([]);
44071
44766
  (0, react.useEffect)(() => {
44072
44767
  const update = () => {
@@ -44312,12 +45007,14 @@ ${trimmed}
44312
45007
  });
44313
45008
  }
44314
45009
  /** Retire only narration that was actually visible; historical rows stay folded. */
44315
- function RetiringContent({ visible, children }) {
45010
+ function RetiringContent({ visible, children, onRetired }) {
44316
45011
  const { enabled } = (0, react.useContext)(StreamMotionContext);
44317
45012
  const root = (0, react.useRef)(null);
44318
45013
  const animation = (0, react.useRef)(null);
44319
45014
  const [present, setPresent] = (0, react.useState)(visible);
44320
45015
  const [focusHeld, setFocusHeld] = (0, react.useState)(false);
45016
+ const retired = (0, react.useRef)(onRetired);
45017
+ retired.current = onRetired;
44321
45018
  (0, react.useLayoutEffect)(() => {
44322
45019
  const element = root.current;
44323
45020
  if (visible) {
@@ -44327,16 +45024,38 @@ ${trimmed}
44327
45024
  return;
44328
45025
  }
44329
45026
  if (!element) return;
44330
- if (element.contains(document.activeElement)) {
44331
- setFocusHeld(true);
45027
+ let retiredNow = false;
45028
+ const retireNow = () => {
45029
+ if (retiredNow) return;
45030
+ retiredNow = true;
45031
+ animation.current?.cancel();
45032
+ animation.current = null;
45033
+ focusSurvivesRetire(element);
45034
+ setPresent(false);
45035
+ retired.current?.();
45036
+ };
45037
+ if (!enabled || document.hidden) {
45038
+ retireNow();
44332
45039
  return;
44333
45040
  }
44334
- if (focusHeld) return;
45041
+ const canListen = typeof document.addEventListener === "function";
45042
+ const holdsFocus = element.contains(document.activeElement);
45043
+ if (holdsFocus || focusHeld) {
45044
+ if (holdsFocus) setFocusHeld(true);
45045
+ const onHiddenWhileHeld = () => {
45046
+ if (document.hidden) retireNow();
45047
+ };
45048
+ if (canListen) document.addEventListener("visibilitychange", onHiddenWhileHeld);
45049
+ return () => {
45050
+ if (canListen) document.removeEventListener("visibilitychange", onHiddenWhileHeld);
45051
+ };
45052
+ }
44335
45053
  const from = element.getBoundingClientRect().height;
44336
45054
  animation.current?.cancel();
44337
45055
  animation.current = null;
44338
- if (!enabled || from < 1) {
45056
+ if (from < 1) {
44339
45057
  setPresent(false);
45058
+ retired.current?.();
44340
45059
  return;
44341
45060
  }
44342
45061
  const next = element.animate([{
@@ -44351,12 +45070,26 @@ ${trimmed}
44351
45070
  fill: "both"
44352
45071
  });
44353
45072
  animation.current = next;
44354
- next.onfinish = () => {
44355
- if (animation.current === next) {
44356
- animation.current = null;
44357
- next.cancel();
44358
- setPresent(false);
44359
- }
45073
+ let settled = false;
45074
+ const settle = () => {
45075
+ if (settled || animation.current !== next) return;
45076
+ settled = true;
45077
+ animation.current = null;
45078
+ next.cancel();
45079
+ setPresent(false);
45080
+ retired.current?.();
45081
+ };
45082
+ next.onfinish = settle;
45083
+ const deadline = window.setTimeout(settle, 460);
45084
+ const onHide = () => {
45085
+ if (document.hidden) settle();
45086
+ };
45087
+ if (canListen) document.addEventListener("visibilitychange", onHide);
45088
+ return () => {
45089
+ window.clearTimeout(deadline);
45090
+ if (canListen) document.removeEventListener("visibilitychange", onHide);
45091
+ if (animation.current === next) animation.current = null;
45092
+ next.cancel();
44360
45093
  };
44361
45094
  }, [
44362
45095
  visible,
@@ -44376,6 +45109,80 @@ ${trimmed}
44376
45109
  children
44377
45110
  });
44378
45111
  }
45112
+ /**
45113
+ * Keeps a departing turn mounted for the length of its own collapse.
45114
+ *
45115
+ * A rewind removes turns from the visible order, and unmounting them outright
45116
+ * snapped the transcript: every withdrawn row disappeared in one frame with
45117
+ * nothing to scroll. Instead each departing turn is retained, rendered with
45118
+ * `visible={false}` so it animates to zero height, and released only once the
45119
+ * collapse has settled — so the reader watches the rows fold away and the rows
45120
+ * below glide up into their place.
45121
+ *
45122
+ * Live slots follow the incoming group order, so older history stays above the
45123
+ * tail. A collapsing turn stays next to the live neighbour that preceded it;
45124
+ * appending it would jump it to the bottom for the length of the animation.
45125
+ * Retention is bounded by the animation itself: `onRetired`
45126
+ * drops the slot, so a departing turn lives for one collapse and no longer —
45127
+ * and a key that comes back later is re-added as a live slot.
45128
+ */
45129
+ function RetiringTurns({ groups, render }) {
45130
+ const [slots, setSlots] = (0, react.useState)(() => groups.map((group) => ({
45131
+ group,
45132
+ live: true
45133
+ })));
45134
+ (0, react.useLayoutEffect)(() => {
45135
+ setSlots((current) => reconcileTurnSlots(current, groups));
45136
+ }, [groups]);
45137
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: slots.map((slot) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RetiringContent, {
45138
+ visible: slot.live,
45139
+ onRetired: () => setSlots((current) => current.filter((candidate) => candidate.live || candidate.group.key !== slot.group.key)),
45140
+ children: render(slot.group)
45141
+ }, slot.group.key)) });
45142
+ }
45143
+ /** A turn that is still on screen, not one this commit is about to unmount. */
45144
+ function survivingTurn(node) {
45145
+ if (!(node instanceof HTMLElement) || node.dataset.readerRetiring === "retiring") return null;
45146
+ const turn = node.hasAttribute("data-reader-turn") ? node : node.querySelector("[data-reader-turn]");
45147
+ if (turn === null) return null;
45148
+ const retiring = turn.closest("[data-reader-retiring]");
45149
+ if (retiring instanceof HTMLElement && retiring.dataset.readerRetiring === "retiring") return null;
45150
+ return turn;
45151
+ }
45152
+ /**
45153
+ * Where focus goes when cut content is removed without an animation.
45154
+ * Prefer the nearest turn that is still live. Otherwise the reading column
45155
+ * (or the host scrollport) so focus does not fall through to the document.
45156
+ */
45157
+ function retireFocusTarget(element) {
45158
+ const parent = element.parentElement;
45159
+ if (parent) {
45160
+ const siblings = [...parent.children];
45161
+ const index = siblings.indexOf(element);
45162
+ for (let cursor = index - 1; cursor >= 0; cursor--) {
45163
+ const turn = survivingTurn(siblings[cursor]);
45164
+ if (turn) return turn;
45165
+ }
45166
+ for (let cursor = index + 1; cursor < siblings.length; cursor++) {
45167
+ const turn = survivingTurn(siblings[cursor]);
45168
+ if (turn) return turn;
45169
+ }
45170
+ }
45171
+ const column = element.closest("[data-chat-flow]");
45172
+ if (column && !element.contains(column)) return column;
45173
+ const scroll = element.closest("[data-conversation-scroll]");
45174
+ if (scroll && !element.contains(scroll)) return scroll;
45175
+ return null;
45176
+ }
45177
+ /** Move focus out of `element` before it unmounts. A no-op when focus is elsewhere. */
45178
+ function focusSurvivesRetire(element) {
45179
+ const active = document.activeElement;
45180
+ if (active === null || !element.contains(active)) return;
45181
+ const target = retireFocusTarget(element);
45182
+ if (target === null || element.contains(target)) return;
45183
+ if (target.tabIndex < 0) target.tabIndex = -1;
45184
+ target.focus({ preventScroll: true });
45185
+ }
44379
45186
  function useReadingScroll(root, motion) {
44380
45187
  const port = (0, react.useRef)(null);
44381
45188
  const following = (0, react.useRef)(true);
@@ -44591,6 +45398,345 @@ ${trimmed}
44591
45398
  };
44592
45399
  }
44593
45400
  //#endregion
45401
+ //#region src/client/fold-choreography.ts
45402
+ /** Presentation clock, not model/network time. */
45403
+ const FOLD_TIMING = {
45404
+ collapse: 320,
45405
+ count: 160,
45406
+ settle: 80,
45407
+ reveal: 180,
45408
+ /**
45409
+ * Slack added to every phase deadline before the watchdog forces the next phase.
45410
+ *
45411
+ * The choreography advances on animation promises and rendered frames. Both are
45412
+ * best-effort: a cancelled animation *rejects* and a compositor that never
45413
+ * finishes one leaves its promise pending, while a backgrounded tab stops
45414
+ * delivering frames. Without a deadline the machine would sit in a non-idle
45415
+ * phase forever, and a non-idle phase freezes both the frame source and the text
45416
+ * reveal, so the turn would look stuck until a remount. This is the liveness
45417
+ * guarantee that does not depend on any of them.
45418
+ */
45419
+ watchdogSlack: 240
45420
+ };
45421
+ /** A step always has the same parent and React key, even when its membership changes. */
45422
+ function flowRows(items) {
45423
+ return items.flatMap((item) => item.kind === "fold" ? [{
45424
+ kind: "summary",
45425
+ key: item.key,
45426
+ item
45427
+ }, ...item.steps.map((step) => ({
45428
+ kind: "step",
45429
+ key: step.key,
45430
+ step,
45431
+ foldKey: item.key
45432
+ }))] : [{
45433
+ kind: "step",
45434
+ key: item.key,
45435
+ step: item.step
45436
+ }]);
45437
+ }
45438
+ function retiringKeys(before, after, open) {
45439
+ const folded = new Set(flowRows(after).filter((row) => row.kind === "step" && row.foldKey && !open[row.foldKey]).map((row) => row.key));
45440
+ return flowRows(before).filter((row) => row.kind === "step" && !row.foldKey && folded.has(row.key)).map((row) => row.key);
45441
+ }
45442
+ /** Insert only new summary slots. Never admit incoming content during shrink. */
45443
+ function collapseRows(before, target) {
45444
+ const rows = flowRows(before);
45445
+ const headers = new Set(rows.filter((row) => row.kind === "summary").map((row) => row.key));
45446
+ for (const item of target) {
45447
+ if (item.kind !== "fold" || headers.has(item.key)) continue;
45448
+ const members = new Set(item.steps.map((step) => step.key));
45449
+ const at = rows.findIndex((row) => members.has(row.key));
45450
+ if (at >= 0) rows.splice(at, 0, {
45451
+ kind: "summary",
45452
+ key: item.key,
45453
+ item: {
45454
+ ...item,
45455
+ summary: item.summary.replace(/\d+/g, "0")
45456
+ }
45457
+ });
45458
+ }
45459
+ return rows;
45460
+ }
45461
+ function containsNewUser(before, after) {
45462
+ const users = new Set(before.filter((item) => item.kind === "user").map((item) => item.key));
45463
+ return after.some((item) => item.kind === "user" && !users.has(item.key));
45464
+ }
45465
+ //#endregion
45466
+ //#region src/client/LiveFold.tsx
45467
+ /** Values are presentation commits, never live network counters. */
45468
+ function SubtleNumberRoll({ value, motion }) {
45469
+ const [outgoing, setOutgoing] = (0, react.useState)(null);
45470
+ const previous = (0, react.useRef)(value);
45471
+ (0, react.useLayoutEffect)(() => {
45472
+ if (value === previous.current) return;
45473
+ const old = previous.current;
45474
+ previous.current = value;
45475
+ if (!motion) {
45476
+ setOutgoing(null);
45477
+ return;
45478
+ }
45479
+ setOutgoing(old);
45480
+ const timer = window.setTimeout(() => setOutgoing(null), FOLD_TIMING.count);
45481
+ return () => window.clearTimeout(timer);
45482
+ }, [value, motion]);
45483
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
45484
+ className: Reader_module_css_default.numberRollRoot,
45485
+ "aria-hidden": "true",
45486
+ children: [
45487
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
45488
+ className: Reader_module_css_default.numberRollSizer,
45489
+ children: value
45490
+ }),
45491
+ outgoing !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
45492
+ className: `${Reader_module_css_default.numberRollDigit} ${Reader_module_css_default.numberRollExit}`,
45493
+ children: outgoing
45494
+ }, `out-${outgoing}`),
45495
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
45496
+ className: `${Reader_module_css_default.numberRollDigit} ${outgoing !== null ? Reader_module_css_default.numberRollEnter : ""}`,
45497
+ children: value
45498
+ }, `cur-${value}`)
45499
+ ]
45500
+ });
45501
+ }
45502
+ function FoldSummaryText({ summary, motion }) {
45503
+ const parts = (0, react.useMemo)(() => {
45504
+ const regex = /([^\d]+)(\d+)/g;
45505
+ const result = [];
45506
+ let end = 0;
45507
+ for (const match of summary.matchAll(regex)) {
45508
+ result.push({
45509
+ text: match[1],
45510
+ number: Number(match[2])
45511
+ });
45512
+ end = match.index + match[0].length;
45513
+ }
45514
+ if (end < summary.length) result.push({ text: summary.slice(end) });
45515
+ return result;
45516
+ }, [summary]);
45517
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
45518
+ className: Reader_module_css_default.foldSummary,
45519
+ "data-reader-fold-summary": summary,
45520
+ "aria-label": summary,
45521
+ children: parts.map((part) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
45522
+ className: Reader_module_css_default.foldSummaryPart,
45523
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: part.text }), part.number !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SubtleNumberRoll, {
45524
+ value: part.number,
45525
+ motion
45526
+ })]
45527
+ }, part.text))
45528
+ });
45529
+ }
45530
+ //#endregion
45531
+ //#region src/client/projection.ts
45532
+ function groupNodes(order, get) {
45533
+ const groups = [];
45534
+ const seenTurns = /* @__PURE__ */ new Set();
45535
+ for (const key of order) {
45536
+ const node = get(key);
45537
+ if (!node || node.visibility === "hidden") continue;
45538
+ const turn = node.location.kind === "step" || node.location.kind === "turn" ? node.location.turn.turn : null;
45539
+ const previous = groups.at(-1);
45540
+ if (turn !== null && previous?.turn === turn) previous.keys.push(key);
45541
+ else {
45542
+ groups.push({
45543
+ key: turn === null ? `node:${key}` : seenTurns.has(turn) ? `turn:${turn}:${key}` : `turn:${turn}`,
45544
+ turn,
45545
+ keys: [key]
45546
+ });
45547
+ if (turn !== null) seenTurns.add(turn);
45548
+ }
45549
+ }
45550
+ return groups;
45551
+ }
45552
+ function boundaryOf(turn) {
45553
+ return {
45554
+ status: turn?.status ?? "unknown",
45555
+ reason: turn?.end?.data.reason.kind ?? null,
45556
+ latestStep: turn?.steps.at(-1)?.step ?? -1,
45557
+ closingStep: turn?.data.get("turn-tail")?.closing?.step ?? null
45558
+ };
45559
+ }
45560
+ /**
45561
+ * A settled body step before the closing step of a successful turn.
45562
+ *
45563
+ * This is presentation classification only. Narration is never process content
45564
+ * and never folds. The flag only marks body text that is no longer the turn's
45565
+ * final answer, so copy and fork stay on that final answer.
45566
+ */
45567
+ function isEarlierNarration(data, boundary) {
45568
+ if (data.status !== "settled" || boundary.status !== "closed" || boundary.reason !== "completed") return false;
45569
+ if (data.blocks.some((block) => block.kind === "image" || block.kind === "other")) return false;
45570
+ return boundary.closingStep !== null && data.step < boundary.closingStep;
45571
+ }
45572
+ function processExpanded(choice, boundary) {
45573
+ return choice ?? !(boundary.status === "closed" && boundary.reason === "completed");
45574
+ }
45575
+ /** Reading while running must not pin the process open after completion. */
45576
+ function processChoiceKey(groupKey, boundary) {
45577
+ return `${groupKey}:${boundary.status}:${boundary.reason ?? "pending"}`;
45578
+ }
45579
+ /**
45580
+ * A body-only assistant step is not a thinking/process disclosure.
45581
+ *
45582
+ * Narration (text/image/other blocks) is always visible, so it never counts as
45583
+ * foldable process content; only literal reasoning does. Tool calls arrive as
45584
+ * their own flow entries and are checked separately by the reader.
45585
+ */
45586
+ function hasProcessContent(node, _boundary) {
45587
+ if (!node || node.visibility === "hidden") return false;
45588
+ if (node.kind === "assistant-step") return node.data.blocks.some((block) => block.kind === "reasoning" && block.text.trim() !== "");
45589
+ return node.kind === "context" || node.kind === "model-retry" || node.kind === "system-prompt" || node.kind === "turn-process" || node.kind === "command" || node.kind === "manual-compaction" || node.kind === "compaction";
45590
+ }
45591
+ function hasVisibleBody(blocks) {
45592
+ return blocks.some((block) => block.kind === "image" || block.kind === "other" || block.kind === "text" && block.text.trim() !== "");
45593
+ }
45594
+ /** Keep native block order. In particular, never lift a later Think above text. */
45595
+ function assistantSegments(blocks) {
45596
+ const segments = [];
45597
+ let previous;
45598
+ blocks.forEach((block, index) => {
45599
+ if (block.kind === "tool-call") {
45600
+ previous = void 0;
45601
+ return;
45602
+ }
45603
+ const kind = block.kind === "reasoning" ? "reasoning" : "body";
45604
+ if (previous?.kind === kind) previous.blocks.push(block);
45605
+ else {
45606
+ previous = {
45607
+ kind,
45608
+ start: index,
45609
+ blocks: [block]
45610
+ };
45611
+ segments.push(previous);
45612
+ }
45613
+ });
45614
+ return segments;
45615
+ }
45616
+ function terminalLabel(reason) {
45617
+ switch (reason) {
45618
+ case "completed": return null;
45619
+ case "aborted":
45620
+ case "interrupted": return "本轮已停止,已生成的内容仍保留。";
45621
+ case "blocked": return "本轮需要处理阻塞事项;请查看原对话与下方操作区。";
45622
+ case "max-tokens": return "输出达到本轮长度限制,内容可能尚未完整。";
45623
+ case "error": return "本轮未完成;错误信息保留在下方。";
45624
+ case null: return null;
45625
+ default: return `本轮结束状态:${reason}。请在原对话中核对完整记录。`;
45626
+ }
45627
+ }
45628
+ /**
45629
+ * Extract the first usable fork anchor seq from candidate message nodes.
45630
+ * Only the durable closing message seq cuts the intended turn prefix: an
45631
+ * absent anchor must surface as undefined (never as 0 or NaN), because the
45632
+ * host treats a missing atSeq as a whole-session fork.
45633
+ */
45634
+ function forkAnchorSeq(candidates) {
45635
+ for (const candidate of candidates) {
45636
+ const seq = candidate?.seq;
45637
+ if (typeof seq === "number" && Number.isFinite(seq)) return seq;
45638
+ }
45639
+ }
45640
+ //#endregion
45641
+ //#region src/client/AssistantNode.tsx
45642
+ function isNode$1(node, kind) {
45643
+ return node.kind === kind;
45644
+ }
45645
+ const AssistantNode = (0, react.memo)(function AssistantNode({ useChat, nodeKey, boundary, processOpen = false, pinned = false, folded = false, partStart, seamSummary, seamAfter = false, motion, onRead, returnFocusTo, ...render }) {
45646
+ const node = useChat((snapshot) => snapshot.nodes.get(nodeKey));
45647
+ if (!node || node.visibility === "hidden" || !isNode$1(node, "assistant-step")) return null;
45648
+ const data = node.data;
45649
+ const parts = assistantSegments(data.blocks);
45650
+ const earlier = isEarlierNarration(data, boundary);
45651
+ const hasToolCalls = data.blocks.some((block) => block.kind === "tool-call");
45652
+ const isProcessStep = earlier || folded || hasToolCalls || boundary.latestStep > 0 && data.step < boundary.latestStep;
45653
+ const body = data.blocks.filter((block) => block.kind !== "reasoning" && block.kind !== "tool-call");
45654
+ const visible = partStart === void 0 ? parts : parts.filter((part) => part.start === partStart);
45655
+ const bodyProps = {
45656
+ streaming: data.status === "running",
45657
+ holdFormatting: pinned,
45658
+ startedAt: data.time,
45659
+ interrupted: data.status === "interrupted",
45660
+ liveText: true
45661
+ };
45662
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: visible.map((part) => {
45663
+ const last = parts.findIndex((item) => item.start === part.start) === parts.length - 1;
45664
+ if (part.kind === "reasoning") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProcessFragment, {
45665
+ open: processOpen,
45666
+ motion,
45667
+ onRead,
45668
+ returnFocusTo,
45669
+ nodeKey,
45670
+ framed: true,
45671
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReasoningCard, {
45672
+ step: data.step,
45673
+ active: processOpen && boundary.status === "open" && data.step === boundary.latestStep,
45674
+ motion,
45675
+ selected: pinned,
45676
+ onRead,
45677
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Blocks, {
45678
+ ...render,
45679
+ blocks: part.blocks,
45680
+ streaming: data.status === "running" && last && data.blocks.at(-1)?.kind === "reasoning",
45681
+ holdFormatting: pinned,
45682
+ startedAt: data.time,
45683
+ interrupted: data.status === "interrupted",
45684
+ liveText: true
45685
+ })
45686
+ })
45687
+ }, part.start);
45688
+ if (!hasVisibleBody(part.blocks)) return null;
45689
+ const isFinalAnswer = !isProcessStep;
45690
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [seamSummary && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
45691
+ className: Reader_module_css_default.processSeamRow,
45692
+ "data-reader-process-seam": true,
45693
+ "data-reader-process-seam-summary": seamSummary,
45694
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Disclosure, {
45695
+ open: false,
45696
+ onChange: () => onRead(),
45697
+ ariaLabel: "被折叠的过程",
45698
+ label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FoldSummaryText, {
45699
+ summary: seamSummary,
45700
+ motion: false
45701
+ })
45702
+ })
45703
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
45704
+ className: Reader_module_css_default.answer,
45705
+ "data-reader-body": true,
45706
+ "data-reader-anchor": true,
45707
+ "data-reader-key": nodeKey,
45708
+ "data-reader-source-start": part.start,
45709
+ "data-reader-seam-after": seamAfter || void 0,
45710
+ "data-answer-status": data.status,
45711
+ "data-answer-phase": isFinalAnswer ? "body" : "process",
45712
+ children: [
45713
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OfficialAssistantBody, {
45714
+ ...render,
45715
+ node,
45716
+ blocks: part.blocks,
45717
+ ...bodyProps
45718
+ }),
45719
+ isFinalAnswer && last && data.status === "interrupted" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
45720
+ className: Reader_module_css_default.stopped,
45721
+ children: "已停止"
45722
+ }),
45723
+ isFinalAnswer && last && data.status !== "running" && boundary.status === "closed" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopyAnswer, {
45724
+ blocks: body,
45725
+ onFork: (() => {
45726
+ const anchor = forkAnchorSeq([data.finalNode, { seq: render.forkSeq }]);
45727
+ return render.forkAt && anchor !== void 0 ? () => render.forkAt(anchor) : void 0;
45728
+ })(),
45729
+ metrics: render.metrics,
45730
+ extraActions: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OfficialActions, {
45731
+ official: render.official,
45732
+ messageId: data.finalNode?.messageId
45733
+ })
45734
+ })
45735
+ ]
45736
+ })] }, part.start);
45737
+ }) });
45738
+ });
45739
+ //#endregion
44594
45740
  //#region src/client/native/tool-call-model.ts
44595
45741
  /**
44596
45742
  * Pure row-model derivation for tool summary rows: variant classification,
@@ -44801,6 +45947,10 @@ ${trimmed}
44801
45947
  other: _deepseek_ai_dsh_client_ui_primitives.IconSparkleRegular
44802
45948
  };
44803
45949
  const number = new Intl.NumberFormat("zh-CN");
45950
+ const preparingTerminalLabels = {
45951
+ ...terminalBlockLabels,
45952
+ running: "正在生成命令"
45953
+ };
44804
45954
  const language = (path) => path?.split(".").at(-1);
44805
45955
  const duration = (ms) => ms < 1e3 ? `${Math.round(ms)} 毫秒` : `${(ms / 1e3).toFixed(ms < 1e4 ? 1 : 0)} 秒`;
44806
45956
  function generatedInput(content, target, preparing) {
@@ -44824,7 +45974,9 @@ ${trimmed}
44824
45974
  })]
44825
45975
  });
44826
45976
  }
44827
- function InputView({ model, preparing, fillComposer }) {
45977
+ function InputView({ model, phase, fillComposer }) {
45978
+ const preparing = phase === "preparing";
45979
+ const inProgress = preparing || phase === "running";
44828
45980
  if ((model.name === "render_ui" || model.name === "show_widget") && typeof model.args?.html === "string") return preparing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StreamingMcpAppPlaceholder, { title: typeof model.args.title === "string" ? model.args.title : void 0 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(McpAppFrame, {
44829
45981
  html: model.args.html,
44830
45982
  title: typeof model.args.title === "string" ? model.args.title : void 0,
@@ -44839,9 +45991,15 @@ ${trimmed}
44839
45991
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.TerminalBlock, {
44840
45992
  command: model.command,
44841
45993
  cwd: model.cwd,
44842
- labels: terminalBlockLabels
45994
+ running: inProgress,
45995
+ labels: preparing ? preparingTerminalLabels : terminalBlockLabels
44843
45996
  })]
44844
45997
  });
45998
+ if (model.category === "terminal" && preparing && model.argsState === "partial") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
45999
+ className: Reader_module_css_default.toolDetailNote,
46000
+ "data-reader-tool-command-pending": true,
46001
+ children: "命令仍在生成,收到可识别的命令文本后会显示预览。"
46002
+ });
44845
46003
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.JsonTree, {
44846
46004
  data: model.args,
44847
46005
  label: preparing ? "已收到的输入字段" : "工具输入",
@@ -44924,7 +46082,7 @@ ${trimmed}
44924
46082
  children: phase === "interrupted" ? "已中断,没有工具结果。已生成的输入仍可查看。" : phase === "preparing" ? "模型正在生成工具输入,工具还未开始执行。" : "工具已开始执行,正在等待结果。"
44925
46083
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InputView, {
44926
46084
  model,
44927
- preparing: phase === "preparing",
46085
+ phase,
44928
46086
  fillComposer: render.fillComposer
44929
46087
  })] });
44930
46088
  const meta = objectValue(block.meta);
@@ -44936,7 +46094,7 @@ ${trimmed}
44936
46094
  }),
44937
46095
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InputView, {
44938
46096
  model,
44939
- preparing: false,
46097
+ phase,
44940
46098
  fillComposer: render.fillComposer
44941
46099
  }),
44942
46100
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
@@ -45299,7 +46457,7 @@ ${trimmed}
45299
46457
  }),
45300
46458
  tab === "input" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InputView, {
45301
46459
  model: preview.model,
45302
- preparing: preview.phase === "preparing",
46460
+ phase: preview.phase,
45303
46461
  fillComposer: render.fillComposer
45304
46462
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
45305
46463
  className: Reader_module_css_default.detail,
@@ -45372,106 +46530,6 @@ ${trimmed}
45372
46530
  }, child.callId))] });
45373
46531
  }
45374
46532
  //#endregion
45375
- //#region src/client/projection.ts
45376
- function groupNodes(order, get) {
45377
- const groups = [];
45378
- const seenTurns = /* @__PURE__ */ new Set();
45379
- for (const key of order) {
45380
- const node = get(key);
45381
- if (!node || node.visibility === "hidden") continue;
45382
- const turn = node.location.kind === "step" || node.location.kind === "turn" ? node.location.turn.turn : null;
45383
- const previous = groups.at(-1);
45384
- if (turn !== null && previous?.turn === turn) previous.keys.push(key);
45385
- else {
45386
- groups.push({
45387
- key: turn === null ? `node:${key}` : seenTurns.has(turn) ? `turn:${turn}:${key}` : `turn:${turn}`,
45388
- turn,
45389
- keys: [key]
45390
- });
45391
- if (turn !== null) seenTurns.add(turn);
45392
- }
45393
- }
45394
- return groups;
45395
- }
45396
- function boundaryOf(turn) {
45397
- return {
45398
- status: turn?.status ?? "unknown",
45399
- reason: turn?.end?.data.reason.kind ?? null,
45400
- latestStep: turn?.steps.at(-1)?.step ?? -1,
45401
- closingStep: turn?.data.get("turn-tail")?.closing?.step ?? null
45402
- };
45403
- }
45404
- function isEarlierNarration(data, boundary) {
45405
- if (data.status !== "settled" || boundary.status !== "closed" || boundary.reason !== "completed") return false;
45406
- if (data.blocks.some((block) => block.kind === "image" || block.kind === "other")) return false;
45407
- return boundary.closingStep !== null && data.step < boundary.closingStep;
45408
- }
45409
- function processExpanded(choice, boundary) {
45410
- return choice ?? !(boundary.status === "closed" && boundary.reason === "completed");
45411
- }
45412
- /** Reading while running must not pin the process open after completion. */
45413
- function processChoiceKey(groupKey, boundary) {
45414
- return `${groupKey}:${boundary.status}:${boundary.reason ?? "pending"}`;
45415
- }
45416
- /** A body-only assistant step is not a thinking/process disclosure. */
45417
- function hasProcessContent(node, boundary) {
45418
- if (!node || node.visibility === "hidden") return false;
45419
- if (node.kind === "assistant-step") {
45420
- const data = node.data;
45421
- return data.blocks.some((block) => block.kind === "reasoning" && block.text.trim() !== "") || isEarlierNarration(data, boundary) && hasVisibleBody(data.blocks);
45422
- }
45423
- return node.kind === "context" || node.kind === "model-retry" || node.kind === "system-prompt" || node.kind === "turn-process" || node.kind === "command" || node.kind === "manual-compaction" || node.kind === "compaction";
45424
- }
45425
- function hasVisibleBody(blocks) {
45426
- return blocks.some((block) => block.kind === "image" || block.kind === "other" || block.kind === "text" && block.text.trim() !== "");
45427
- }
45428
- /** Keep native block order. In particular, never lift a later Think above text. */
45429
- function assistantSegments(blocks) {
45430
- const segments = [];
45431
- let previous;
45432
- blocks.forEach((block, index) => {
45433
- if (block.kind === "tool-call") {
45434
- previous = void 0;
45435
- return;
45436
- }
45437
- const kind = block.kind === "reasoning" ? "reasoning" : "body";
45438
- if (previous?.kind === kind) previous.blocks.push(block);
45439
- else {
45440
- previous = {
45441
- kind,
45442
- start: index,
45443
- blocks: [block]
45444
- };
45445
- segments.push(previous);
45446
- }
45447
- });
45448
- return segments;
45449
- }
45450
- function terminalLabel(reason) {
45451
- switch (reason) {
45452
- case "completed": return null;
45453
- case "aborted":
45454
- case "interrupted": return "本轮已停止,已生成的内容仍保留。";
45455
- case "blocked": return "本轮需要处理阻塞事项;请查看原对话与下方操作区。";
45456
- case "max-tokens": return "输出达到本轮长度限制,内容可能尚未完整。";
45457
- case "error": return "本轮未完成;错误信息保留在下方。";
45458
- case null: return null;
45459
- default: return `本轮结束状态:${reason}。请在原对话中核对完整记录。`;
45460
- }
45461
- }
45462
- /**
45463
- * Extract the first usable fork anchor seq from candidate message nodes.
45464
- * Only the durable closing message seq cuts the intended turn prefix: an
45465
- * absent anchor must surface as undefined (never as 0 or NaN), because the
45466
- * host treats a missing atSeq as a whole-session fork.
45467
- */
45468
- function forkAnchorSeq(candidates) {
45469
- for (const candidate of candidates) {
45470
- const seq = candidate?.seq;
45471
- if (typeof seq === "number" && Number.isFinite(seq)) return seq;
45472
- }
45473
- }
45474
- //#endregion
45475
46533
  //#region src/client/open-file.ts
45476
46534
  function deliverableOpenModeOf(value) {
45477
46535
  return value === "sidebar" ? "sidebar" : "external";
@@ -45487,12 +46545,6 @@ ${trimmed}
45487
46545
  function isFolderOpenPath(path) {
45488
46546
  return path === "." || path === "";
45489
46547
  }
45490
- function isWindowsStylePath(value) {
45491
- return /^[A-Za-z]:[/\\]/.test(value) || value.startsWith("\\\\");
45492
- }
45493
- function isAbsoluteWorkspacePath(path) {
45494
- return path.startsWith("/") || isWindowsStylePath(path);
45495
- }
45496
46548
  function encodeSegment(segment) {
45497
46549
  return encodeURIComponent(segment).replace(/%3A/gi, ":");
45498
46550
  }
@@ -46399,7 +47451,7 @@ ${trimmed}
46399
47451
  }
46400
47452
  //#endregion
46401
47453
  //#region \0dshx-css-module:TimelineRail.module.css.mjs
46402
- const css$1 = ".oG8zJG_slot{z-index:10;pointer-events:none;height:0;position:sticky;top:0}.oG8zJG_frame{--turn-rail-band:calc(var(--dsh-conversation-viewport-height,100dvh) - var(--dsh-composer-height,152px));--turn-preview-height:100px;top:calc(var(--turn-rail-band) / 2);width:26px;height:min(var(--turn-natural-height), max(0px, calc(var(--turn-rail-band) - 64px)), 420px);cursor:pointer;pointer-events:auto;transition:height .22s cubic-bezier(.2,.8,.2,1);position:absolute;right:6px;transform:translateY(-50%)}.oG8zJG_scroller{overscroll-behavior:contain;scrollbar-width:none;position:absolute;inset:0;overflow-y:auto}.oG8zJG_scroller::-webkit-scrollbar{display:none}.oG8zJG_fadeTop{-webkit-mask-image:linear-gradient(#0000 0,#000 24px 100%);mask-image:linear-gradient(#0000 0,#000 24px 100%)}.oG8zJG_fadeBottom{-webkit-mask-image:linear-gradient(#000 0 calc(100% - 24px),#0000 100%);mask-image:linear-gradient(#000 0 calc(100% - 24px),#0000 100%)}.oG8zJG_fadeTop.oG8zJG_fadeBottom{-webkit-mask-image:linear-gradient(#0000 0,#000 24px calc(100% - 24px),#0000 100%);mask-image:linear-gradient(#0000 0,#000 24px calc(100% - 24px),#0000 100%)}.oG8zJG_marks{height:var(--turn-natural-height);position:relative}.oG8zJG_markPosition{top:calc(var(--turn-natural-position) + var(--turn-rail-inset));height:12px;transition:top .22s cubic-bezier(.2,.8,.2,1);position:absolute;left:0;right:0;transform:translateY(-50%)}.oG8zJG_mark{cursor:pointer;pointer-events:none;background:0 0;border:0;justify-content:flex-end;align-items:center;width:24px;padding:0;display:flex;position:absolute;inset:0 0 0 auto}.oG8zJG_tick{border-radius:2px;flex:none;transition:width .1s cubic-bezier(.16,1,.3,1),height .1s cubic-bezier(.16,1,.3,1),opacity .1s,background-color .14s}.oG8zJG_markBusy .oG8zJG_tick{animation:1s ease-in-out infinite alternate oG8zJG_markBusyPulse}@keyframes oG8zJG_markBusyPulse{0%{opacity:.4;width:8px}to{opacity:1;width:18px}}.oG8zJG_preview{top:clamp(0px, calc(var(--turn-natural-position) + var(--turn-rail-inset) - var(--turn-scroll-top,0px) - var(--turn-preview-height) / 2), calc(100% - var(--turn-preview-height)));box-sizing:border-box;width:min(280px,100cqw - 120px);max-height:var(--turn-preview-height);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base);backdrop-filter:blur(12px);pointer-events:none;z-index:40;border-radius:10px;padding:10px 12px;transition:top .14s cubic-bezier(.2,.8,.2,1);animation:.12s ease-out oG8zJG_previewFadeIn;position:absolute;right:calc(100% + 10px);overflow:hidden;box-shadow:0 4px 18px #0000001f}@keyframes oG8zJG_previewFadeIn{0%{opacity:0;transform:translate(4px)}to{opacity:1;transform:translate(0)}}.oG8zJG_previewPrompt{-webkit-line-clamp:2;text-overflow:ellipsis;word-break:break-word;-webkit-box-orient:vertical;font-size:12px;font-weight:500;line-height:18px;display:-webkit-box;overflow:hidden}.oG8zJG_previewResponse{color:var(--dsw-alias-label-tertiary);-webkit-line-clamp:2;text-overflow:ellipsis;word-break:break-word;-webkit-box-orient:vertical;margin-top:4px;font-size:11px;line-height:16px;display:-webkit-box;overflow:hidden}@media (width<=960px){.oG8zJG_slot{display:none!important}}";
47454
+ const css$1 = ".oG8zJG_slot{z-index:10;pointer-events:none;height:0;position:sticky;top:0}.oG8zJG_frame{--turn-rail-band:calc(var(--dsh-conversation-viewport-height,100dvh) - var(--dsh-composer-height,152px));--turn-preview-height:100px;top:calc(var(--turn-rail-band) / 2);width:26px;height:min(var(--turn-natural-height), max(0px, calc(var(--turn-rail-band) - 64px)), 420px);cursor:pointer;pointer-events:auto;transition:height .22s cubic-bezier(.2,.8,.2,1);position:absolute;right:6px;transform:translateY(-50%)}.oG8zJG_scroller{overscroll-behavior:contain;scrollbar-width:none;position:absolute;inset:0;overflow-y:auto}.oG8zJG_scroller::-webkit-scrollbar{display:none}.oG8zJG_fadeTop{mask-image:linear-gradient(#0000 0,#000 24px 100%)}.oG8zJG_fadeBottom{mask-image:linear-gradient(#000 0 calc(100% - 24px),#0000 100%)}.oG8zJG_fadeTop.oG8zJG_fadeBottom{mask-image:linear-gradient(#0000 0,#000 24px calc(100% - 24px),#0000 100%)}.oG8zJG_marks{height:var(--turn-natural-height);position:relative}.oG8zJG_markPosition{top:calc(var(--turn-natural-position) + var(--turn-rail-inset));height:12px;transition:top .22s cubic-bezier(.2,.8,.2,1);position:absolute;left:0;right:0;transform:translateY(-50%)}.oG8zJG_mark{cursor:pointer;pointer-events:none;background:0 0;border:0;justify-content:flex-end;align-items:center;width:24px;padding:0;display:flex;position:absolute;inset:0 0 0 auto}.oG8zJG_tick{border-radius:2px;flex:none;transition:width .1s cubic-bezier(.16,1,.3,1),height .1s cubic-bezier(.16,1,.3,1),opacity .1s,background-color .14s}.oG8zJG_markBusy .oG8zJG_tick{animation:1s ease-in-out infinite alternate oG8zJG_markBusyPulse}@keyframes oG8zJG_markBusyPulse{0%{opacity:.4;width:8px}to{opacity:1;width:18px}}.oG8zJG_preview{top:clamp(0px, calc(var(--turn-natural-position) + var(--turn-rail-inset) - var(--turn-scroll-top,0px) - var(--turn-preview-height) / 2), calc(100% - var(--turn-preview-height)));box-sizing:border-box;width:min(280px,100cqw - 120px);max-height:var(--turn-preview-height);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);pointer-events:none;z-index:40;border-radius:10px;padding:10px 12px;transition:top .14s cubic-bezier(.2,.8,.2,1);animation:.12s ease-out oG8zJG_previewFadeIn;position:absolute;right:calc(100% + 10px);overflow:hidden;box-shadow:0 4px 18px #0000001f}@keyframes oG8zJG_previewFadeIn{0%{opacity:0;transform:translate(4px)}to{opacity:1;transform:translate(0)}}.oG8zJG_previewPrompt{-webkit-line-clamp:2;text-overflow:ellipsis;word-break:break-word;-webkit-box-orient:vertical;font-size:12px;font-weight:500;line-height:18px;display:-webkit-box;overflow:hidden}.oG8zJG_previewResponse{color:var(--dsw-alias-label-tertiary);-webkit-line-clamp:2;text-overflow:ellipsis;word-break:break-word;-webkit-box-orient:vertical;margin-top:4px;font-size:11px;line-height:16px;display:-webkit-box;overflow:hidden}@media (width<=960px){.oG8zJG_slot{display:none!important}}";
46403
47455
  const tagId$1 = "dsh-better-display/TimelineRail.module.css";
46404
47456
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
46405
47457
  const tag = document.createElement("style");
@@ -46708,27 +47760,6 @@ ${trimmed}
46708
47760
  if (extra) parts.push(`记录×${extra}`);
46709
47761
  return parts.join(" · ") || "此前步骤";
46710
47762
  }
46711
- /** One chain: fold only when a new reasoning step has prior body/tool/reasoning. */
46712
- function splitChain(chain) {
46713
- const lastReasoning = chain.findLastIndex((step) => step.kind === "reasoning");
46714
- if (lastReasoning < 0) return {
46715
- fold: null,
46716
- open: chain
46717
- };
46718
- const prior = chain.slice(0, lastReasoning);
46719
- if (!prior.length) return {
46720
- fold: null,
46721
- open: chain
46722
- };
46723
- if (!prior.some((step) => step.kind === "reasoning" || step.kind === "body" || step.kind === "tool")) return {
46724
- fold: null,
46725
- open: chain
46726
- };
46727
- return {
46728
- fold: prior,
46729
- open: chain.slice(lastReasoning)
46730
- };
46731
- }
46732
47763
  function skipReasoning(part) {
46733
47764
  return part.kind === "reasoning" && !part.blocks.some((block) => block.kind === "reasoning" && block.text.trim() !== "");
46734
47765
  }
@@ -46808,46 +47839,117 @@ ${trimmed}
46808
47839
  }
46809
47840
  return steps;
46810
47841
  }
47842
+ /** Only a run that contains real thinking/tool work is worth folding. */
47843
+ function foldableRun(run) {
47844
+ return run.some((step) => step.kind === "reasoning" || step.kind === "tool");
47845
+ }
47846
+ /**
47847
+ * One live chain: narration stays visible, while every earlier reasoning/tool
47848
+ * run collapses into its own box at its original position.
47849
+ */
46811
47850
  function presentLiveTurn(steps, boundary, autoFold = true) {
46812
47851
  const live = autoFold && liveFoldEnabled(boundary);
46813
47852
  const items = [];
46814
- let chain = [];
46815
- const flush = () => {
46816
- if (!chain.length) return;
46817
- if (!live) {
46818
- for (const step of chain) items.push({
46819
- kind: "open",
46820
- key: step.key,
46821
- step
46822
- });
46823
- chain = [];
46824
- return;
46825
- }
46826
- const { fold, open } = splitChain(chain);
46827
- if (fold?.length) items.push({
47853
+ const open = (step) => items.push({
47854
+ kind: "open",
47855
+ key: step.key,
47856
+ step
47857
+ });
47858
+ const fold = (run) => {
47859
+ if (!run.length) return;
47860
+ if (live && foldableRun(run)) items.push({
46828
47861
  kind: "fold",
46829
- key: `live-fold:${chain[0].key}`,
46830
- steps: fold,
46831
- summary: foldSummary(fold)
47862
+ key: `live-fold:${run[0].key}`,
47863
+ steps: run,
47864
+ summary: foldSummary(run)
46832
47865
  });
46833
- for (const step of open) items.push({
46834
- kind: "open",
46835
- key: step.key,
46836
- step
46837
- });
46838
- chain = [];
47866
+ else for (const step of run) open(step);
47867
+ };
47868
+ let run = [];
47869
+ const flush = () => {
47870
+ fold(run);
47871
+ run = [];
46839
47872
  };
47873
+ const segments = [];
47874
+ let segment = [];
46840
47875
  for (const step of steps) if (step.kind === "user") {
47876
+ segments.push(segment);
47877
+ segments.push([step]);
47878
+ segment = [];
47879
+ } else segment.push(step);
47880
+ segments.push(segment);
47881
+ for (const part of segments) {
47882
+ if (!part.length) continue;
47883
+ const first = part[0];
47884
+ if (part.length === 1 && first.kind === "user") {
47885
+ items.push({
47886
+ kind: "user",
47887
+ key: first.key,
47888
+ step: first
47889
+ });
47890
+ continue;
47891
+ }
47892
+ if (!live) {
47893
+ for (const step of part) open(step);
47894
+ continue;
47895
+ }
47896
+ const lastReasoning = part.findLastIndex((step) => step.kind === "reasoning");
47897
+ if (lastReasoning <= 0) {
47898
+ for (const step of part) open(step);
47899
+ continue;
47900
+ }
47901
+ for (let index = 0; index < part.length; index++) {
47902
+ const step = part[index];
47903
+ if (index < lastReasoning) {
47904
+ if (step.kind === "body") {
47905
+ flush();
47906
+ open(step);
47907
+ } else run.push(step);
47908
+ } else {
47909
+ if (index === lastReasoning) flush();
47910
+ open(step);
47911
+ }
47912
+ }
46841
47913
  flush();
46842
- items.push({
46843
- kind: "user",
46844
- key: step.key,
46845
- step
46846
- });
46847
- } else chain.push(step);
46848
- flush();
47914
+ }
46849
47915
  return items;
46850
47916
  }
47917
+ /**
47918
+ * Summaries for collapsed process that sits between two narration blocks.
47919
+ *
47920
+ * A live-fold cell already shows that summary while the turn is open. Drawing
47921
+ * the seam as well repeats the same counts, so a run whose every step is
47922
+ * already inside a fold cell contributes neither a seam nor `after`. `after`
47923
+ * is what marks the previous body with `data-reader-seam-after` and drops its
47924
+ * bottom padding; skipping the seam must leave that spacing alone.
47925
+ */
47926
+ function planProcessSeams(steps, liveItems, expanded) {
47927
+ const before = /* @__PURE__ */ new Map();
47928
+ const after = /* @__PURE__ */ new Set();
47929
+ if (expanded) return {
47930
+ before,
47931
+ after
47932
+ };
47933
+ const liveFolded = new Set(liveItems.flatMap((item) => item.kind === "fold" ? item.steps.map((step) => step.key) : []));
47934
+ let previousBody;
47935
+ let process = [];
47936
+ for (const step of steps) if (step.kind === "body") {
47937
+ const folded = process.filter((item) => item.kind !== "user");
47938
+ if (!(folded.length > 0 && folded.every((item) => liveFolded.has(item.key))) && previousBody && folded.some((item) => item.kind === "reasoning" || item.kind === "tool" || item.kind === "other")) {
47939
+ before.set(step.key, foldSummary(folded));
47940
+ after.add(previousBody.key);
47941
+ }
47942
+ previousBody = step;
47943
+ process = [];
47944
+ } else if (step.kind === "user") {
47945
+ previousBody = void 0;
47946
+ process = [];
47947
+ } else process.push(step);
47948
+ return {
47949
+ before,
47950
+ after
47951
+ };
47952
+ }
46851
47953
  //#endregion
46852
47954
  //#region src/client/fold-intensity.ts
46853
47955
  function frostedGlassOf(state) {
@@ -46861,136 +47963,6 @@ ${trimmed}
46861
47963
  return intensity === 2;
46862
47964
  }
46863
47965
  //#endregion
46864
- //#region src/client/fold-choreography.ts
46865
- /** Presentation clock, not model/network time. */
46866
- const FOLD_TIMING = {
46867
- collapse: 320,
46868
- count: 160,
46869
- settle: 80,
46870
- reveal: 180,
46871
- /**
46872
- * Slack added to every phase deadline before the watchdog forces the next phase.
46873
- *
46874
- * The choreography advances on animation promises and rendered frames. Both are
46875
- * best-effort: a cancelled animation *rejects* and a compositor that never
46876
- * finishes one leaves its promise pending, while a backgrounded tab stops
46877
- * delivering frames. Without a deadline the machine would sit in a non-idle
46878
- * phase forever, and a non-idle phase freezes both the frame source and the text
46879
- * reveal, so the turn would look stuck until a remount. This is the liveness
46880
- * guarantee that does not depend on any of them.
46881
- */
46882
- watchdogSlack: 240
46883
- };
46884
- /** A step always has the same parent and React key, even when its membership changes. */
46885
- function flowRows(items) {
46886
- return items.flatMap((item) => item.kind === "fold" ? [{
46887
- kind: "summary",
46888
- key: item.key,
46889
- item
46890
- }, ...item.steps.map((step) => ({
46891
- kind: "step",
46892
- key: step.key,
46893
- step,
46894
- foldKey: item.key
46895
- }))] : [{
46896
- kind: "step",
46897
- key: item.key,
46898
- step: item.step
46899
- }]);
46900
- }
46901
- function retiringKeys(before, after, open) {
46902
- const folded = new Set(flowRows(after).filter((row) => row.kind === "step" && row.foldKey && !open[row.foldKey]).map((row) => row.key));
46903
- return flowRows(before).filter((row) => row.kind === "step" && !row.foldKey && folded.has(row.key)).map((row) => row.key);
46904
- }
46905
- /** Insert only new summary slots. Never admit incoming content during shrink. */
46906
- function collapseRows(before, target) {
46907
- const rows = flowRows(before);
46908
- const headers = new Set(rows.filter((row) => row.kind === "summary").map((row) => row.key));
46909
- for (const item of target) {
46910
- if (item.kind !== "fold" || headers.has(item.key)) continue;
46911
- const members = new Set(item.steps.map((step) => step.key));
46912
- const at = rows.findIndex((row) => members.has(row.key));
46913
- if (at >= 0) rows.splice(at, 0, {
46914
- kind: "summary",
46915
- key: item.key,
46916
- item: {
46917
- ...item,
46918
- summary: item.summary.replace(/\d+/g, "0")
46919
- }
46920
- });
46921
- }
46922
- return rows;
46923
- }
46924
- function containsNewUser(before, after) {
46925
- const users = new Set(before.filter((item) => item.kind === "user").map((item) => item.key));
46926
- return after.some((item) => item.kind === "user" && !users.has(item.key));
46927
- }
46928
- //#endregion
46929
- //#region src/client/LiveFold.tsx
46930
- /** Values are presentation commits, never live network counters. */
46931
- function SubtleNumberRoll({ value, motion }) {
46932
- const [outgoing, setOutgoing] = (0, react.useState)(null);
46933
- const previous = (0, react.useRef)(value);
46934
- (0, react.useLayoutEffect)(() => {
46935
- if (value === previous.current) return;
46936
- const old = previous.current;
46937
- previous.current = value;
46938
- if (!motion) {
46939
- setOutgoing(null);
46940
- return;
46941
- }
46942
- setOutgoing(old);
46943
- const timer = window.setTimeout(() => setOutgoing(null), FOLD_TIMING.count);
46944
- return () => window.clearTimeout(timer);
46945
- }, [value, motion]);
46946
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
46947
- className: Reader_module_css_default.numberRollRoot,
46948
- "aria-hidden": "true",
46949
- children: [
46950
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
46951
- className: Reader_module_css_default.numberRollSizer,
46952
- children: value
46953
- }),
46954
- outgoing !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
46955
- className: `${Reader_module_css_default.numberRollDigit} ${Reader_module_css_default.numberRollExit}`,
46956
- children: outgoing
46957
- }, `out-${outgoing}`),
46958
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
46959
- className: `${Reader_module_css_default.numberRollDigit} ${outgoing !== null ? Reader_module_css_default.numberRollEnter : ""}`,
46960
- children: value
46961
- }, `cur-${value}`)
46962
- ]
46963
- });
46964
- }
46965
- function FoldSummaryText({ summary, motion }) {
46966
- const parts = (0, react.useMemo)(() => {
46967
- const regex = /([^\d]+)(\d+)/g;
46968
- const result = [];
46969
- let end = 0;
46970
- for (const match of summary.matchAll(regex)) {
46971
- result.push({
46972
- text: match[1],
46973
- number: Number(match[2])
46974
- });
46975
- end = match.index + match[0].length;
46976
- }
46977
- if (end < summary.length) result.push({ text: summary.slice(end) });
46978
- return result;
46979
- }, [summary]);
46980
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
46981
- className: Reader_module_css_default.foldSummary,
46982
- "data-reader-fold-summary": summary,
46983
- "aria-label": summary,
46984
- children: parts.map((part) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
46985
- className: Reader_module_css_default.foldSummaryPart,
46986
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: part.text }), part.number !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SubtleNumberRoll, {
46987
- value: part.number,
46988
- motion
46989
- })]
46990
- }, part.text))
46991
- });
46992
- }
46993
- //#endregion
46994
47966
  //#region src/client/DiffPanel.tsx
46995
47967
  /**
46996
47968
  * Reveals and withdraws its child by animating real height, in the plugin's own
@@ -47159,6 +48131,123 @@ ${trimmed}
47159
48131
  })] });
47160
48132
  }
47161
48133
  //#endregion
48134
+ //#region src/client/StickyLane.tsx
48135
+ const MIN_LANE_PX = 40;
48136
+ const LaneOwnerContext = (0, react.createContext)(null);
48137
+ const ownersByRoot = /* @__PURE__ */ new WeakMap();
48138
+ /** One map per Reader, so two roots that both contain turn 1 do not share a writer. */
48139
+ function ReaderLaneScope({ children }) {
48140
+ const owners = (0, react.useRef)(/* @__PURE__ */ new Map());
48141
+ (0, react.useLayoutEffect)(() => {
48142
+ const map = owners.current;
48143
+ return () => {
48144
+ map.clear();
48145
+ };
48146
+ }, []);
48147
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LaneOwnerContext.Provider, {
48148
+ value: owners.current,
48149
+ children
48150
+ });
48151
+ }
48152
+ function laneScope(el) {
48153
+ return el.closest("[data-reader-turn]") ?? el.closest("[data-dsh-better-display]");
48154
+ }
48155
+ function ownersFor(el, scoped) {
48156
+ if (scoped) return scoped;
48157
+ const root = el.closest("[data-dsh-better-display]") ?? el;
48158
+ let owners = ownersByRoot.get(root);
48159
+ if (!owners) {
48160
+ owners = /* @__PURE__ */ new Map();
48161
+ ownersByRoot.set(root, owners);
48162
+ }
48163
+ return owners;
48164
+ }
48165
+ function publishedLanePx(el) {
48166
+ return Math.max(MIN_LANE_PX, Math.ceil(el.getBoundingClientRect().height));
48167
+ }
48168
+ /** One writer per turn inside a single Reader. A retiring summary cannot clear the lane that replaced it. */
48169
+ function publishLaneHeight(el, property, scoped = null) {
48170
+ const scope = laneScope(el);
48171
+ if (!scope) return () => {};
48172
+ const owners = ownersFor(el, scoped);
48173
+ const root = el.closest("[data-dsh-better-display]");
48174
+ const key = `${property}\0${scope.getAttribute("data-reader-turn") ?? "root"}`;
48175
+ const update = () => {
48176
+ if (owners.get(key) !== el) return;
48177
+ scope.style.setProperty(property, `${publishedLanePx(el)}px`);
48178
+ };
48179
+ owners.set(key, el);
48180
+ update();
48181
+ const observer = new ResizeObserver(update);
48182
+ observer.observe(el);
48183
+ return () => {
48184
+ observer.disconnect();
48185
+ if (owners.get(key) !== el) return;
48186
+ owners.delete(key);
48187
+ scope.style.removeProperty(property);
48188
+ if (!scoped && root && owners.size === 0) ownersByRoot.delete(root);
48189
+ };
48190
+ }
48191
+ function usePublishedHeight(property) {
48192
+ const owners = (0, react.useContext)(LaneOwnerContext);
48193
+ const ref = (0, react.useRef)(null);
48194
+ (0, react.useLayoutEffect)(() => {
48195
+ const el = ref.current;
48196
+ if (!el) return;
48197
+ return publishLaneHeight(el, property, owners);
48198
+ }, [owners, property]);
48199
+ return ref;
48200
+ }
48201
+ function useSummaryLane(ref, active) {
48202
+ const owners = (0, react.useContext)(LaneOwnerContext);
48203
+ (0, react.useLayoutEffect)(() => {
48204
+ const el = ref.current;
48205
+ if (!active || !el) return;
48206
+ return publishLaneHeight(el, "--reader-summary-height", owners);
48207
+ }, [
48208
+ active,
48209
+ owners,
48210
+ ref
48211
+ ]);
48212
+ }
48213
+ /** Publish real lane geometry; wrapped labels must not collide with statistics. */
48214
+ function StickyLane({ kind, className, children }) {
48215
+ const ref = (0, react.useRef)(null);
48216
+ (0, react.useLayoutEffect)(() => {
48217
+ const el = ref.current;
48218
+ const scope = el?.closest(kind === "toolbar" ? "[data-dsh-better-display]" : "[data-reader-turn]");
48219
+ if (!el || !scope) return;
48220
+ const property = kind === "toolbar" ? "--reader-toolbar-height" : "--reader-status-height";
48221
+ const update = () => {
48222
+ scope.style.setProperty(property, `${Math.max(MIN_LANE_PX, el.getBoundingClientRect().height)}px`);
48223
+ if (kind !== "toolbar") return;
48224
+ const controls = el.querySelectorAll("button");
48225
+ let width = 80;
48226
+ if (controls.length > 0) {
48227
+ const first = controls[0].getBoundingClientRect();
48228
+ width = controls[controls.length - 1].getBoundingClientRect().right - first.left;
48229
+ }
48230
+ scope.style.setProperty("--reader-control-width", `${width + 28}px`);
48231
+ };
48232
+ update();
48233
+ const observer = new ResizeObserver(update);
48234
+ observer.observe(el);
48235
+ if (kind === "toolbar") for (const control of el.querySelectorAll("button")) observer.observe(control);
48236
+ return () => {
48237
+ observer.disconnect();
48238
+ scope.style.removeProperty(property);
48239
+ if (kind === "toolbar") scope.style.removeProperty("--reader-control-width");
48240
+ };
48241
+ }, [kind]);
48242
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
48243
+ ref,
48244
+ className,
48245
+ "data-reader-lane": kind,
48246
+ "data-ud-check": kind === "toolbar" ? "reader-toolbar" : void 0,
48247
+ children
48248
+ });
48249
+ }
48250
+ //#endregion
47162
48251
  //#region src/client/ChoreographedFlow.tsx
47163
48252
  const FlowSnapshot = (0, react.createContext)(null);
47164
48253
  /** Public projection only. Descendants cannot leak live data through a frozen frame. */
@@ -47201,6 +48290,7 @@ ${trimmed}
47201
48290
  /** Manual disclosure shares the measured-size path; children survive until finish. */
47202
48291
  function FlowCell({ hidden, instant, motion, rowKey, children, summary = false }) {
47203
48292
  const ref = (0, react.useRef)(null);
48293
+ useSummaryLane(ref, summary);
47204
48294
  const [present, setPresent] = (0, react.useState)(!hidden);
47205
48295
  const previous = (0, react.useRef)(hidden);
47206
48296
  if (!hidden && !present) setPresent(true);
@@ -47458,9 +48548,11 @@ ${trimmed}
47458
48548
  /** Keep process counts discoverable after the live-fold presentation retires. */
47459
48549
  function ClosedProcessSummary({ steps, open, onChange, controls }) {
47460
48550
  const button = (0, react.useRef)(null);
48551
+ const lane = usePublishedHeight("--reader-summary-height");
47461
48552
  if (!steps.length) return null;
47462
48553
  const summary = foldSummary(steps);
47463
48554
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
48555
+ ref: lane,
47464
48556
  className: Reader_module_css_default.closedProcessSummary,
47465
48557
  "data-reader-closed-summary": summary,
47466
48558
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -47483,45 +48575,6 @@ ${trimmed}
47483
48575
  });
47484
48576
  }
47485
48577
  //#endregion
47486
- //#region src/client/StickyLane.tsx
47487
- /** Publish real lane geometry; wrapped labels must not collide with statistics. */
47488
- function StickyLane({ kind, className, children }) {
47489
- const ref = (0, react.useRef)(null);
47490
- (0, react.useLayoutEffect)(() => {
47491
- const el = ref.current;
47492
- const scope = el?.closest(kind === "toolbar" ? "[data-dsh-better-display]" : "[data-reader-turn]");
47493
- if (!el || !scope) return;
47494
- const property = kind === "toolbar" ? "--reader-toolbar-height" : "--reader-status-height";
47495
- const update = () => {
47496
- scope.style.setProperty(property, `${el.getBoundingClientRect().height}px`);
47497
- if (kind !== "toolbar") return;
47498
- const controls = el.querySelectorAll("button");
47499
- let width = 80;
47500
- if (controls.length > 0) {
47501
- const first = controls[0].getBoundingClientRect();
47502
- width = controls[controls.length - 1].getBoundingClientRect().right - first.left;
47503
- }
47504
- scope.style.setProperty("--reader-control-width", `${width + 28}px`);
47505
- };
47506
- update();
47507
- const observer = new ResizeObserver(update);
47508
- observer.observe(el);
47509
- if (kind === "toolbar") for (const control of el.querySelectorAll("button")) observer.observe(control);
47510
- return () => {
47511
- observer.disconnect();
47512
- scope.style.removeProperty(property);
47513
- if (kind === "toolbar") scope.style.removeProperty("--reader-control-width");
47514
- };
47515
- }, [kind]);
47516
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
47517
- ref,
47518
- className,
47519
- "data-reader-lane": kind,
47520
- "data-ud-check": kind === "toolbar" ? "reader-toolbar" : void 0,
47521
- children
47522
- });
47523
- }
47524
- //#endregion
47525
48578
  //#region src/client/Reader.tsx
47526
48579
  function isNode(node, kind) {
47527
48580
  return node.kind === kind;
@@ -47541,6 +48594,9 @@ ${trimmed}
47541
48594
  return typeof block === "object" && block !== null && block.type === "text" && typeof block.text === "string";
47542
48595
  }).map((block) => block.text).join("");
47543
48596
  }
48597
+ function inboxAttachmentCount(item) {
48598
+ return (item.content ?? []).filter((block) => typeof block === "object" && block !== null && block.type !== "text").length;
48599
+ }
47544
48600
  function cleanErrorMessage(raw) {
47545
48601
  if (!raw) return "模型服务暂时无响应或连接中断,请稍后重试。";
47546
48602
  let str = raw.trim();
@@ -47693,102 +48749,9 @@ ${trimmed}
47693
48749
  children: content
47694
48750
  });
47695
48751
  });
47696
- const AssistantNode = (0, react.memo)(function AssistantNode({ useChat, nodeKey, boundary, processOpen = false, pinned = false, folded = false, partStart, motion, onRead, returnFocusTo, ...render }) {
47697
- const node = useChat((snapshot) => snapshot.nodes.get(nodeKey));
47698
- if (!node || node.visibility === "hidden" || !isNode(node, "assistant-step")) return null;
47699
- const data = node.data;
47700
- const parts = assistantSegments(data.blocks);
47701
- const earlier = isEarlierNarration(data, boundary);
47702
- const hasToolCalls = data.blocks.some((block) => block.kind === "tool-call");
47703
- const isProcessStep = earlier || folded || hasToolCalls || boundary.latestStep > 0 && data.step < boundary.latestStep;
47704
- const body = data.blocks.filter((block) => block.kind !== "reasoning" && block.kind !== "tool-call");
47705
- const visible = partStart === void 0 ? parts : parts.filter((part) => part.start === partStart);
47706
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: visible.map((part) => {
47707
- const last = parts.findIndex((item) => item.start === part.start) === parts.length - 1;
47708
- return part.kind === "reasoning" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProcessFragment, {
47709
- open: processOpen,
47710
- motion,
47711
- onRead,
47712
- returnFocusTo,
47713
- nodeKey,
47714
- framed: true,
47715
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReasoningCard, {
47716
- step: data.step,
47717
- active: processOpen && boundary.status === "open" && data.step === boundary.latestStep,
47718
- motion,
47719
- selected: pinned,
47720
- onRead,
47721
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Blocks, {
47722
- ...render,
47723
- blocks: part.blocks,
47724
- streaming: data.status === "running" && last && data.blocks.at(-1)?.kind === "reasoning",
47725
- holdFormatting: pinned,
47726
- startedAt: data.time,
47727
- interrupted: data.status === "interrupted",
47728
- liveText: true
47729
- })
47730
- })
47731
- }, part.start) : isProcessStep ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProcessFragment, {
47732
- open: processOpen,
47733
- motion,
47734
- onRead,
47735
- returnFocusTo,
47736
- nodeKey,
47737
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("article", {
47738
- className: Reader_module_css_default.processCommentary,
47739
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Blocks, {
47740
- ...render,
47741
- blocks: part.blocks,
47742
- streaming: data.status === "running",
47743
- holdFormatting: pinned,
47744
- startedAt: data.time,
47745
- interrupted: data.status === "interrupted",
47746
- liveText: true
47747
- })
47748
- })
47749
- }, part.start) : hasVisibleBody(part.blocks) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RetiringContent, {
47750
- visible: pinned || processOpen || !earlier && !folded,
47751
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
47752
- className: Reader_module_css_default.answer,
47753
- "data-reader-answer": true,
47754
- "data-reader-anchor": true,
47755
- "data-reader-key": nodeKey,
47756
- "data-reader-source-start": part.start,
47757
- "data-answer-status": data.status,
47758
- "data-answer-phase": earlier || folded ? "process" : "body",
47759
- children: [
47760
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Blocks, {
47761
- ...render,
47762
- blocks: part.blocks,
47763
- streaming: data.status === "running",
47764
- holdFormatting: pinned,
47765
- startedAt: data.time,
47766
- interrupted: data.status === "interrupted",
47767
- liveText: true
47768
- }),
47769
- last && data.status === "interrupted" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
47770
- className: Reader_module_css_default.stopped,
47771
- children: "已停止"
47772
- }),
47773
- last && !earlier && !folded && data.status !== "running" && boundary.status === "closed" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopyAnswer, {
47774
- blocks: body,
47775
- onFork: (() => {
47776
- const anchor = forkAnchorSeq([data.finalNode, { seq: render.forkSeq }]);
47777
- return render.forkAt && anchor !== void 0 ? () => render.forkAt(anchor) : void 0;
47778
- })(),
47779
- metrics: render.metrics,
47780
- extraActions: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OfficialActions, {
47781
- official: render.official,
47782
- messageId: data.finalNode?.messageId
47783
- })
47784
- })
47785
- ]
47786
- })
47787
- }, part.start);
47788
- }) });
47789
- });
47790
- const MainNode = (0, react.memo)(function MainNode({ useChat, nodeKey, boundary, pinned, processOpen = false, ...render }) {
48752
+ const MainNode = (0, react.memo)(function MainNode({ useChat, nodeKey, boundary, pinned, processOpen: _processOpen = false, ...render }) {
47791
48753
  const node = useChat((snapshot) => snapshot.nodes.get(nodeKey));
48754
+ const [disclosureReset] = (0, react.useState)(() => (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(0));
47792
48755
  if (!node || node.visibility === "hidden") return null;
47793
48756
  if (isNode(node, "user") || isNode(node, "steering")) {
47794
48757
  const blocks = contentBlocks(node.data.content);
@@ -47796,37 +48759,77 @@ ${trimmed}
47796
48759
  const otherBlocks = blocks.filter((b) => b.kind !== "image");
47797
48760
  const text = otherBlocks.filter((block) => block.kind === "text").map((block) => block.text).join("\n\n");
47798
48761
  const time = node.data.time;
47799
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
48762
+ const fallback = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
48763
+ node.kind === "steering" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
48764
+ className: Reader_module_css_default.meta,
48765
+ children: "补充消息"
48766
+ }),
48767
+ imageBlocks.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
48768
+ className: Reader_module_css_default.userImages,
48769
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Blocks, {
48770
+ ...render,
48771
+ blocks: imageBlocks,
48772
+ source: "user"
48773
+ })
48774
+ }),
48775
+ otherBlocks.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
48776
+ className: Reader_module_css_default.user,
48777
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Blocks, {
48778
+ ...render,
48779
+ blocks: otherBlocks,
48780
+ source: "user"
48781
+ })
48782
+ }),
48783
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UserMessageActions, {
48784
+ text,
48785
+ time
48786
+ })
48787
+ ] });
48788
+ const official = render.official;
48789
+ let rendered = fallback;
48790
+ if (official) {
48791
+ const turn = node.location.kind === "turn" || node.location.kind === "step" ? node.location.turn : void 0;
48792
+ const owner = {
48793
+ cwd: render.cwd,
48794
+ openFile: render.openFile ?? (() => {}),
48795
+ openSkill: () => {},
48796
+ forkAt: render.forkAt ?? (() => {}),
48797
+ inspectCall: (callId) => official.openView("trajectory", callId),
48798
+ loadImage: official.officialImageLoader,
48799
+ renderMessageImages: (images) => official.renderSlot(OFFICIAL_SEATS.images, {
48800
+ ...images,
48801
+ loadImage: official.officialImageLoader
48802
+ }),
48803
+ fileMentions: official.officialFileMentions,
48804
+ sessionId: render.sessionId
48805
+ };
48806
+ const options = {
48807
+ hookContext: {
48808
+ turnData: turn?.data,
48809
+ disclosureReset
48810
+ },
48811
+ fallback
48812
+ };
48813
+ rendered = node.kind === "user" ? official.renderSlot(OFFICIAL_SEATS.nodes, {
48814
+ ...owner,
48815
+ node
48816
+ }, {
48817
+ ...options,
48818
+ entryKey: "user"
48819
+ }) : official.renderSlot(OFFICIAL_SEATS.nodes, {
48820
+ ...owner,
48821
+ node
48822
+ }, {
48823
+ ...options,
48824
+ entryKey: "steering"
48825
+ });
48826
+ }
48827
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
47800
48828
  className: Reader_module_css_default.userCluster,
47801
48829
  "data-reader-anchor": true,
47802
48830
  "data-reader-key": nodeKey,
47803
48831
  ...chatSeatProps(node.kind, nodeKey),
47804
- children: [
47805
- node.kind === "steering" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
47806
- className: Reader_module_css_default.meta,
47807
- children: "补充消息"
47808
- }),
47809
- imageBlocks.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
47810
- className: Reader_module_css_default.userImages,
47811
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Blocks, {
47812
- ...render,
47813
- blocks: imageBlocks,
47814
- source: "user"
47815
- })
47816
- }),
47817
- otherBlocks.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
47818
- className: Reader_module_css_default.user,
47819
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Blocks, {
47820
- ...render,
47821
- blocks: otherBlocks,
47822
- source: "user"
47823
- })
47824
- }),
47825
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UserMessageActions, {
47826
- text,
47827
- time
47828
- })
47829
- ]
48832
+ children: rendered
47830
48833
  });
47831
48834
  }
47832
48835
  if (isNode(node, "assistant-step")) return null;
@@ -47962,7 +48965,7 @@ ${trimmed}
47962
48965
  }
47963
48966
  return 0;
47964
48967
  }
47965
- function GroupStatus({ group, sessionId, useChat, pending, motion }) {
48968
+ function GroupStatus({ group, useChat, pending, motion }) {
47966
48969
  const text = useChat((snapshot) => {
47967
48970
  const turn = group.turn === null ? void 0 : snapshot.timeline.turns.get(group.turn);
47968
48971
  if (turn?.status === "closed") {
@@ -48213,11 +49216,12 @@ ${trimmed}
48213
49216
  const flow = (0, react.useMemo)(() => readerFlow({
48214
49217
  ...group,
48215
49218
  keys: mainKeys
48216
- }, turn, (key) => nodes.get(key)), [
49219
+ }, turn, (key) => nodes.get(key), snapshot.order), [
48217
49220
  nodes,
48218
49221
  group,
48219
49222
  mainKeys,
48220
- turn
49223
+ turn,
49224
+ snapshot.order
48221
49225
  ]);
48222
49226
  const steps = (0, react.useMemo)(() => segmentLiveTurn(flow, (key) => nodes.get(key)), [flow, nodes]);
48223
49227
  const liveItems = (0, react.useMemo)(() => presentLiveTurn(steps, boundary, autoFold), [
@@ -48229,8 +49233,15 @@ ${trimmed}
48229
49233
  return () => {};
48230
49234
  }), () => props.openPrefs?.getSnapshot()?.deliverableOpenMode, () => "external"));
48231
49235
  const hasProcess = flow.some((item) => item.kind === "tool" || hasProcessContent(nodes.get(item.nodeKey), boundary));
49236
+ const showStatusLane = hasProcess && !isAwaitingModel;
49237
+ const showClosedSummary = boundary.status === "closed" && hasProcess && autoFold;
48232
49238
  const holdingSelection = selectedProcessKeys.some((key) => flow.some((item) => item.key === key) || liveItems.some((item) => item.kind === "fold" ? item.key === key || item.steps.some((step) => step.key === key || "nodeKey" in step && step.nodeKey === key) : item.key === key || "nodeKey" in item.step && item.step.nodeKey === key));
48233
49239
  const expanded = !autoFold || holdingSelection || processExpanded(expansionChoice, boundary);
49240
+ const seamPlan = (0, react.useMemo)(() => planProcessSeams(steps, liveItems, expanded), [
49241
+ steps,
49242
+ liveItems,
49243
+ expanded
49244
+ ]);
48234
49245
  const [foldOpenByKey, setFoldOpenByKey] = (0, react.useState)({});
48235
49246
  (0, react.useLayoutEffect)(() => {
48236
49247
  if (autoFold) setFoldOpenByKey((current) => Object.keys(current).length ? {} : current);
@@ -48329,6 +49340,7 @@ ${trimmed}
48329
49340
  fileMentions,
48330
49341
  metrics,
48331
49342
  official,
49343
+ sessionId: props.sessionId,
48332
49344
  cwd
48333
49345
  };
48334
49346
  const terminal = terminalLabel(boundary.reason);
@@ -48348,7 +49360,9 @@ ${trimmed}
48348
49360
  folded,
48349
49361
  motion,
48350
49362
  onRead: pinProcess,
48351
- returnFocusTo: processButton
49363
+ returnFocusTo: processButton,
49364
+ seamSummary: step.kind === "body" ? seamPlan.before.get(step.key) : void 0,
49365
+ seamAfter: step.kind === "body" && seamPlan.after.has(step.key)
48352
49366
  }) });
48353
49367
  if (step.kind === "tool") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockBoundary, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ProcessFragment, {
48354
49368
  open: processOpen,
@@ -48401,57 +49415,55 @@ ${trimmed}
48401
49415
  boundary,
48402
49416
  nodeKey: group.keys[0]
48403
49417
  }) }),
48404
- hasProcess && !isAwaitingModel && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StickyLane, {
48405
- kind: "status",
48406
- className: Reader_module_css_default.turnProcessSticky,
48407
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Disclosure, {
48408
- open: expanded,
48409
- onChange: setExpanded,
48410
- controls: flowId,
48411
- buttonRef: processButton,
48412
- label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupStatus, {
48413
- group,
48414
- sessionId: props.sessionId,
48415
- useChat: props.useChat,
48416
- pending: interaction,
48417
- motion
48418
- })
48419
- })
48420
- }),
48421
- boundary.status === "closed" && hasProcess && autoFold && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ClosedProcessSummary, {
48422
- open: expanded,
48423
- onChange: setExpanded,
48424
- controls: flowId,
48425
- steps: steps.filter((step) => {
48426
- if (step.kind === "user") return false;
48427
- if (step.kind !== "body") return true;
48428
- const node = nodes.get(step.nodeKey);
48429
- return !!node && isNode(node, "assistant-step") && (isEarlierNarration(node.data, boundary) || node.data.blocks.some((block) => block.kind === "tool-call") || boundary.latestStep > 0 && node.data.step < boundary.latestStep);
48430
- })
48431
- }),
48432
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChoreographedFlow, {
48433
- id: flowId,
48434
- frame: presentation,
48435
- motion,
48436
- enabled: autoFold && boundary.status === "open" && !holdingSelection,
48437
- urgent: hasTurnError || interaction !== void 0 || !sessionRunning,
48438
- open: foldOpenByKey,
48439
- processOpen: expanded,
48440
- onOpenChange: (key, value) => {
48441
- pinProcess();
48442
- setFoldOpenByKey((current) => ({
48443
- ...current,
48444
- [key]: value
48445
- }));
48446
- },
48447
- renderStep
49418
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
49419
+ className: Reader_module_css_default.turnStickyRegion,
49420
+ "data-reader-sticky-region": true,
49421
+ children: [(showStatusLane || showClosedSummary) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
49422
+ className: Reader_module_css_default.turnStickyLanes,
49423
+ children: [showStatusLane && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StickyLane, {
49424
+ kind: "status",
49425
+ className: Reader_module_css_default.turnProcessSticky,
49426
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Disclosure, {
49427
+ open: expanded,
49428
+ onChange: setExpanded,
49429
+ controls: flowId,
49430
+ buttonRef: processButton,
49431
+ label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupStatus, {
49432
+ group,
49433
+ useChat: props.useChat,
49434
+ pending: interaction,
49435
+ motion
49436
+ })
49437
+ })
49438
+ }), showClosedSummary && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ClosedProcessSummary, {
49439
+ open: expanded,
49440
+ onChange: setExpanded,
49441
+ controls: flowId,
49442
+ steps: steps.filter((step) => step.kind !== "user" && step.kind !== "body")
49443
+ })]
49444
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChoreographedFlow, {
49445
+ id: flowId,
49446
+ frame: presentation,
49447
+ motion,
49448
+ enabled: autoFold && boundary.status === "open" && !holdingSelection,
49449
+ urgent: hasTurnError || interaction !== void 0 || !sessionRunning,
49450
+ open: foldOpenByKey,
49451
+ processOpen: expanded,
49452
+ onOpenChange: (key, value) => {
49453
+ pinProcess();
49454
+ setFoldOpenByKey((current) => ({
49455
+ ...current,
49456
+ [key]: value
49457
+ }));
49458
+ },
49459
+ renderStep
49460
+ })]
48448
49461
  }),
48449
49462
  !hasProcess && boundary.status === "open" && !isAwaitingModel && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
48450
49463
  className: Reader_module_css_default.disclosure,
48451
49464
  "data-reader-status-only": true,
48452
49465
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupStatus, {
48453
49466
  group,
48454
- sessionId: props.sessionId,
48455
49467
  useChat: props.useChat,
48456
49468
  pending: interaction,
48457
49469
  motion
@@ -48477,10 +49489,22 @@ ${trimmed}
48477
49489
  });
48478
49490
  });
48479
49491
  function Reader(props) {
49492
+ (0, react.useInsertionEffect)(() => {
49493
+ ensureStyles();
49494
+ }, []);
48480
49495
  const root = (0, react.useRef)(null);
48481
49496
  const activatedAt = (0, react.useRef)(Date.now());
48482
49497
  const order = props.useChat((snapshot) => snapshot.order);
48483
49498
  const nodes = props.useChat((snapshot) => snapshot.nodes);
49499
+ const rewindSignature = props.useChat((snapshot) => visibleChatSignature(snapshot));
49500
+ const renderKeys = (0, react.useMemo)(() => visibleChatKeys({
49501
+ order,
49502
+ nodes
49503
+ }), [
49504
+ order,
49505
+ nodes,
49506
+ rewindSignature
49507
+ ]);
48484
49508
  const timeline = props.useChat((snapshot) => snapshot.timeline);
48485
49509
  const running = props.useSession((snapshot) => snapshot.running);
48486
49510
  const pending = props.useSessionStatus((snapshot) => snapshot.get(props.sessionId)?.pendingInteraction);
@@ -48516,7 +49540,7 @@ ${trimmed}
48516
49540
  pendingList,
48517
49541
  visibleSubmissions
48518
49542
  ]);
48519
- const waitAnchor = waitingAnchor(order, (key) => nodes.get(key), pendingList);
49543
+ const waitAnchor = waitingAnchor(renderKeys, (key) => nodes.get(key), pendingList);
48520
49544
  const motion = useMotionAllowed(props.useStore((state) => state.motion));
48521
49545
  const prefsSnap = (0, react.useSyncExternalStore)(props.openPrefs?.subscribe ?? ((fn) => {
48522
49546
  return () => {};
@@ -48534,14 +49558,14 @@ ${trimmed}
48534
49558
  enabled: motion,
48535
49559
  activatedAt: activatedAt.current
48536
49560
  }), [motion]);
48537
- const groups = (0, react.useMemo)(() => groupNodes(order, (key) => nodes.get(key)), [
48538
- order,
49561
+ const groups = (0, react.useMemo)(() => groupNodes(renderKeys, (key) => nodes.get(key)), [
49562
+ renderKeys,
48539
49563
  nodes,
48540
49564
  timeline
48541
49565
  ]);
48542
49566
  const isAwaitingModel = (0, react.useMemo)(() => {
48543
49567
  if (!running && pendingList.length > 0) return true;
48544
- const lastKey = order.at(-1);
49568
+ const lastKey = renderKeys.at(-1);
48545
49569
  const lastNode = lastKey ? nodes.get(lastKey) : void 0;
48546
49570
  if (!lastKey || !lastNode) return false;
48547
49571
  if (lastNode.kind === "assistant-step") {
@@ -48554,7 +49578,7 @@ ${trimmed}
48554
49578
  }, [
48555
49579
  running,
48556
49580
  pendingList,
48557
- order,
49581
+ renderKeys,
48558
49582
  nodes,
48559
49583
  groups,
48560
49584
  timeline
@@ -48644,7 +49668,7 @@ ${trimmed}
48644
49668
  scroll.release,
48645
49669
  timelineItems
48646
49670
  ]);
48647
- const lastKey = order.at(-1);
49671
+ const lastKey = renderKeys.at(-1);
48648
49672
  const lastNode = lastKey ? nodes.get(lastKey) : void 0;
48649
49673
  const lastSubmissionId = pendingList.length ? pendingList[pendingList.length - 1].requestId : null;
48650
49674
  const lastOrderKeyRef = (0, react.useRef)(lastKey);
@@ -48663,7 +49687,7 @@ ${trimmed}
48663
49687
  ]);
48664
49688
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StreamMotionContext.Provider, {
48665
49689
  value: streamMotion,
48666
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
49690
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReaderLaneScope, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
48667
49691
  ref: root,
48668
49692
  className: Reader_module_css_default.root,
48669
49693
  "data-reader-build": "0.3.4",
@@ -48681,6 +49705,7 @@ ${trimmed}
48681
49705
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
48682
49706
  className: Reader_module_css_default.column,
48683
49707
  "data-chat-flow": "",
49708
+ tabIndex: -1,
48684
49709
  children: [
48685
49710
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StickyLane, {
48686
49711
  kind: "toolbar",
@@ -48725,20 +49750,23 @@ ${trimmed}
48725
49750
  role: "status",
48726
49751
  children: "正在读取会话…"
48727
49752
  }),
48728
- groups.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TurnGroup, {
48729
- ...props,
48730
- group,
48731
- motion,
48732
- autoFold,
48733
- pinnedKeys,
48734
- selectedProcessKeys,
48735
- isAwaitingModel: isAwaitingModel && group.key === groups.at(-1)?.key
48736
- }, group.key)),
49753
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RetiringTurns, {
49754
+ groups,
49755
+ render: (group) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TurnGroup, {
49756
+ ...props,
49757
+ group,
49758
+ motion,
49759
+ autoFold,
49760
+ pinnedKeys,
49761
+ selectedProcessKeys,
49762
+ isAwaitingModel: isAwaitingModel && group.key === groups.at(-1)?.key
49763
+ })
49764
+ }),
48737
49765
  pendingInputs.map((item, index) => {
48738
49766
  const submission = "requestId" in item ? item : void 0;
48739
49767
  const text = submission?.text ?? inboxText(item);
48740
49768
  const images = submission ? pendingSubmissionImages(submission) : [];
48741
- const attachmentCount = images.length;
49769
+ const attachmentCount = submission ? images.length : inboxAttachmentCount(item);
48742
49770
  const requestId = submission?.requestId ?? `inbox-${index}`;
48743
49771
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
48744
49772
  className: Reader_module_css_default.userCluster,
@@ -48811,7 +49839,7 @@ ${trimmed}
48811
49839
  })
48812
49840
  ]
48813
49841
  })]
48814
- })
49842
+ }) })
48815
49843
  });
48816
49844
  }
48817
49845
  //#endregion
@@ -49311,7 +50339,12 @@ ${trimmed}
49311
50339
  "remote",
49312
50340
  "remote.session"
49313
50341
  ];
50342
+ ensureStyles();
49314
50343
  function apply(ctx) {
50344
+ const textTransform = createTextTransformRegistry();
50345
+ const restoreTextTransform = installTextTransformRegistry(textTransform);
50346
+ ctx.provide(TEXT_TRANSFORM_SERVICE, textTransform);
50347
+ ctx.effect(() => restoreTextTransform);
49315
50348
  const store = createReaderStore();
49316
50349
  const prefs = store.create();
49317
50350
  installBetterDisplaySettings(ctx, prefs);
@@ -49394,13 +50427,20 @@ ${trimmed}
49394
50427
  const res = await fetch("/better-display/reveal", {
49395
50428
  method: "POST",
49396
50429
  headers: { "Content-Type": "application/json" },
49397
- body: JSON.stringify({ path: targetPath })
50430
+ body: JSON.stringify({
50431
+ path: targetPath,
50432
+ sessionId
50433
+ })
49398
50434
  });
49399
50435
  if (res.ok) {
49400
50436
  if ((await res.json()).ok) return;
49401
50437
  }
49402
50438
  } catch {}
49403
50439
  const parentDir = dirname(targetPath);
50440
+ if (!isAbsoluteWorkspacePath(parentDir)) {
50441
+ console.warn("[dsh-better-display] reveal failed; refusing to open a relative parent:", targetPath);
50442
+ return;
50443
+ }
49404
50444
  const remoteSession = ctx.remote?.session ?? ctx.get?.("remote.session");
49405
50445
  if (remoteSession?.openWorkspacePath) await remoteSession.openWorkspacePath({ path: parentDir });
49406
50446
  } catch (error) {
@@ -49459,9 +50499,12 @@ ${trimmed}
49459
50499
  }
49460
50500
  //#endregion
49461
50501
  exports.McpAppFrame = McpAppFrame;
50502
+ exports.TEXT_TRANSFORM_SERVICE = TEXT_TRANSFORM_SERVICE;
49462
50503
  exports.apply = apply;
50504
+ exports.createTextTransformRegistry = createTextTransformRegistry;
49463
50505
  exports.inject = inject;
49464
50506
  exports.name = name;
50507
+ exports.originalAnswerText = originalAnswerText;
49465
50508
  return module.exports;
49466
50509
  }
49467
50510
  });