dsh-edge 0.1.0

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 (159) hide show
  1. package/LICENSE +21 -0
  2. package/README.i18n.yaml +6 -0
  3. package/README.md +183 -0
  4. package/README.zh.md +183 -0
  5. package/THIRD_PARTY_NOTICES.md +199 -0
  6. package/dist/_headers +3 -0
  7. package/dist/assets/fonts/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  8. package/dist/assets/fonts/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  9. package/dist/assets/fonts/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  10. package/dist/assets/fonts/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  11. package/dist/assets/fonts/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  12. package/dist/assets/fonts/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  13. package/dist/assets/fonts/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  14. package/dist/assets/fonts/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  15. package/dist/assets/fonts/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  16. package/dist/assets/fonts/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  17. package/dist/assets/fonts/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  18. package/dist/assets/fonts/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  19. package/dist/assets/fonts/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  20. package/dist/assets/fonts/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  21. package/dist/assets/fonts/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  22. package/dist/assets/fonts/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  23. package/dist/assets/fonts/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  24. package/dist/assets/fonts/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  25. package/dist/assets/fonts/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  26. package/dist/assets/fonts/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  27. package/dist/assets/fonts/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  28. package/dist/assets/fonts/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  29. package/dist/assets/fonts/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  30. package/dist/assets/fonts/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  31. package/dist/assets/fonts/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  32. package/dist/assets/fonts/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  33. package/dist/assets/fonts/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  34. package/dist/assets/fonts/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  35. package/dist/assets/fonts/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  36. package/dist/assets/fonts/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  37. package/dist/assets/fonts/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  38. package/dist/assets/fonts/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  39. package/dist/assets/fonts/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  40. package/dist/assets/fonts/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  41. package/dist/assets/fonts/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  42. package/dist/assets/fonts/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  43. package/dist/assets/fonts/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  44. package/dist/assets/fonts/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  45. package/dist/assets/fonts/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  46. package/dist/assets/fonts/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  47. package/dist/assets/fonts/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  48. package/dist/assets/fonts/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  49. package/dist/assets/fonts/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  50. package/dist/assets/fonts/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  51. package/dist/assets/fonts/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  52. package/dist/assets/fonts/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  53. package/dist/assets/fonts/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  54. package/dist/assets/fonts/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  55. package/dist/assets/fonts/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  56. package/dist/assets/fonts/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  57. package/dist/assets/fonts/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  58. package/dist/assets/fonts/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  59. package/dist/assets/fonts/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  60. package/dist/assets/fonts/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  61. package/dist/assets/fonts/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  62. package/dist/assets/fonts/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  63. package/dist/assets/fonts/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  64. package/dist/assets/fonts/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  65. package/dist/assets/fonts/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  66. package/dist/assets/index-C-1AiF3k.js +112 -0
  67. package/dist/assets/index-CSGf6Qzd.css +1 -0
  68. package/dist/assets/langs/c-BIGW1oBm.js +2 -0
  69. package/dist/assets/langs/cpp-DIPi6g--.js +2 -0
  70. package/dist/assets/langs/csharp-DSvCPggb.js +2 -0
  71. package/dist/assets/langs/css-CLj8gQPS.js +2 -0
  72. package/dist/assets/langs/go-C27-OAKa.js +2 -0
  73. package/dist/assets/langs/html-CfGypltT.js +2 -0
  74. package/dist/assets/langs/ini-BEwlwnbL.js +2 -0
  75. package/dist/assets/langs/java-CylS5w8V.js +2 -0
  76. package/dist/assets/langs/kotlin-BdnUsdx6.js +2 -0
  77. package/dist/assets/langs/less-B1dDrJ26.js +2 -0
  78. package/dist/assets/langs/lua-BaeVxFsk.js +2 -0
  79. package/dist/assets/langs/markdown-Cvjx9yec.js +2 -0
  80. package/dist/assets/langs/mdx-Cmh6b_Ma.js +2 -0
  81. package/dist/assets/langs/php-D-uCvoST.js +2 -0
  82. package/dist/assets/langs/python-B6aJPvgy.js +2 -0
  83. package/dist/assets/langs/ruby-DEItuUFs.js +2 -0
  84. package/dist/assets/langs/rust-B1yitclQ.js +2 -0
  85. package/dist/assets/langs/scss-D5BDwBP9.js +2 -0
  86. package/dist/assets/langs/sql-CRqJ_cUM.js +2 -0
  87. package/dist/assets/langs/swift-D82vCrfD.js +2 -0
  88. package/dist/assets/langs/toml-vGWfd6FD.js +2 -0
  89. package/dist/assets/langs/xml-sdJ4AIDG.js +2 -0
  90. package/dist/assets/langs/yaml-Buea-lGh.js +2 -0
  91. package/dist/assets/vendor-Cjbwl5VI.js +411 -0
  92. package/dist/assets/vendor-CjyC-hUb.css +1 -0
  93. package/dist/favicon.svg +8 -0
  94. package/dist/index.html +35 -0
  95. package/dist/manifest.webmanifest +16 -0
  96. package/dist/plugins/@deepseek-ai/dsh-api-gateway/client.js +420 -0
  97. package/dist/plugins/@deepseek-ai/dsh-api-remotes/client.js +5937 -0
  98. package/dist/plugins/@deepseek-ai/dsh-client-connection/client.js +10207 -0
  99. package/dist/plugins/@deepseek-ai/dsh-client-locale/client.js +1231 -0
  100. package/dist/plugins/@deepseek-ai/dsh-client-modules/client.js +259 -0
  101. package/dist/plugins/@deepseek-ai/dsh-client-runtime/client.js +10539 -0
  102. package/dist/plugins/@deepseek-ai/dsh-client-ui-agent-preset/client.js +1725 -0
  103. package/dist/plugins/@deepseek-ai/dsh-client-ui-commands/client.js +1116 -0
  104. package/dist/plugins/@deepseek-ai/dsh-client-ui-conversation/client.js +9832 -0
  105. package/dist/plugins/@deepseek-ai/dsh-client-ui-deliverables/client.js +373 -0
  106. package/dist/plugins/@deepseek-ai/dsh-client-ui-edge/client.js +549 -0
  107. package/dist/plugins/@deepseek-ai/dsh-client-ui-input-trigger/client.js +859 -0
  108. package/dist/plugins/@deepseek-ai/dsh-client-ui-jobs/client.js +280 -0
  109. package/dist/plugins/@deepseek-ai/dsh-client-ui-layout/client.js +456 -0
  110. package/dist/plugins/@deepseek-ai/dsh-client-ui-model-selection/client.js +804 -0
  111. package/dist/plugins/@deepseek-ai/dsh-client-ui-permission-presets/client.js +461 -0
  112. package/dist/plugins/@deepseek-ai/dsh-client-ui-settings/client.js +254 -0
  113. package/dist/plugins/@deepseek-ai/dsh-client-ui-settings-general/client.js +609 -0
  114. package/dist/plugins/@deepseek-ai/dsh-client-ui-sidebar/client.js +292 -0
  115. package/dist/plugins/@deepseek-ai/dsh-client-ui-skill/client.js +327 -0
  116. package/dist/plugins/@deepseek-ai/dsh-client-ui-subagent/client.js +710 -0
  117. package/dist/plugins/@deepseek-ai/dsh-client-ui-theme/client.js +1312 -0
  118. package/dist/plugins/@deepseek-ai/dsh-client-ui-tool/client.js +1630 -0
  119. package/dist/plugins/@deepseek-ai/dsh-client-ui-trajectory/client.js +7370 -0
  120. package/dist/plugins/@deepseek-ai/dsh-client-ui-user-questions/client.js +700 -0
  121. package/dist/plugins/@deepseek-ai/dsh-client-ui-workflow-run/client.js +474 -0
  122. package/dist/plugins/@deepseek-ai/dsh-client-ui-workspace/client.js +2426 -0
  123. package/dist/plugins/@deepseek-ai/dsh-typert-registry/client.js +1372 -0
  124. package/package.json +97 -0
  125. package/scripts/assemble-web.mjs +230 -0
  126. package/scripts/bundle-size.d.mts +2 -0
  127. package/scripts/bundle-size.mjs +26 -0
  128. package/scripts/bundle.mjs +53 -0
  129. package/scripts/cli.d.mts +39 -0
  130. package/scripts/cli.mjs +496 -0
  131. package/scripts/install.d.mts +149 -0
  132. package/scripts/install.mjs +989 -0
  133. package/scripts/legal-files.mjs +24 -0
  134. package/scripts/verify-packed.mjs +32 -0
  135. package/scripts/wrangler-config.d.mts +18 -0
  136. package/scripts/wrangler-config.mjs +84 -0
  137. package/src/agent.ts +119 -0
  138. package/src/auth.ts +352 -0
  139. package/src/deepseek.ts +231 -0
  140. package/src/deployment.ts +147 -0
  141. package/src/direct-shell-core-empty.ts +10 -0
  142. package/src/direct-shell-protocol.ts +5 -0
  143. package/src/direct-shell.ts +341 -0
  144. package/src/do-session-persistence.ts +1064 -0
  145. package/src/edge-api.ts +796 -0
  146. package/src/edge-credentials.ts +56 -0
  147. package/src/edge-remotes.ts +41 -0
  148. package/src/edge-workspace-store.ts +339 -0
  149. package/src/http.ts +212 -0
  150. package/src/index.ts +196 -0
  151. package/src/instance.ts +1007 -0
  152. package/src/isolated-direct-shell-unavailable.ts +11 -0
  153. package/src/protocol.ts +39 -0
  154. package/src/release.ts +9 -0
  155. package/src/session-store.ts +1110 -0
  156. package/src/sse.ts +86 -0
  157. package/src/web-search.ts +38 -0
  158. package/src/workspace.ts +270 -0
  159. package/wrangler.jsonc +56 -0
@@ -0,0 +1,1630 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@deepseek-ai/dsh-client-ui-tool",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let react_jsx_runtime = require("react/jsx-runtime");
8
+ let react = require("react");
9
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
10
+ let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
11
+ //#region lib/types/client/tool/models/tool-call-model.js
12
+ /** Figma row titles per variant (design literals, not translatable copy). */
13
+ const VARIANT_TITLES = {
14
+ search: "Search",
15
+ read: "Read",
16
+ bash: "Bash",
17
+ write: "Write",
18
+ edit: "Edit",
19
+ code: "Code",
20
+ others: "Tool call"
21
+ };
22
+ /**
23
+ * Known tool name -> variant.
24
+ *
25
+ * `cordis_define` is deliberately absent: ui-cordis registers a keyed
26
+ * `tool.call.toolview` entry for it, and a keyed hit REPLACES the generic row
27
+ * (this table is only reached through GenericToolCard, the dispatch fallback in
28
+ * ToolCallTree). An entry here would be unreachable, and a second title for the
29
+ * same call would be a second answer to a question the card already owns.
30
+ */
31
+ const TOOL_VARIANTS = {
32
+ bash: "bash",
33
+ pwsh: "bash",
34
+ read: "read",
35
+ web_fetch: "read",
36
+ web_search: "search",
37
+ grep: "search",
38
+ glob: "search",
39
+ write: "write",
40
+ edit: "edit",
41
+ run_code: "code",
42
+ cordis_package_inspect: "read",
43
+ cordis_runtime_inspect: "read",
44
+ cordis_run: "others",
45
+ cordis_stop: "others",
46
+ cordis_undefine: "others"
47
+ };
48
+ /** Tool-owned titles that refine a generic row variant without replacing it. */
49
+ const TOOL_TITLES = {
50
+ cordis_package_inspect: "Inspect",
51
+ cordis_runtime_inspect: "Inspect",
52
+ cordis_run: "Run Cordis Plugin",
53
+ cordis_stop: "Stop Cordis Plugin",
54
+ cordis_undefine: "Remove Cordis Plugin",
55
+ pwsh: "Pwsh"
56
+ };
57
+ /**
58
+ * Classify a tool name into its row variant.
59
+ * @param toolName - wire tool name.
60
+ * @returns matching variant, others when unknown.
61
+ */
62
+ function classifyTool(toolName) {
63
+ return TOOL_VARIANTS[toolName] ?? "others";
64
+ }
65
+ /**
66
+ * Flatten a settled result's content blocks to display text: text blocks
67
+ * verbatim, other block shapes as pretty JSON. Empty content on a failed call
68
+ * falls back to the structured error's `name: code` line.
69
+ * @param node - the settled result node.
70
+ * @returns the flattened result text (may be empty).
71
+ */
72
+ function resultText(node) {
73
+ const parts = [];
74
+ for (const block of node.content) if (block.type === "text") parts.push(block.text);
75
+ else parts.push(JSON.stringify(block, null, 2));
76
+ if (parts.length === 0 && node.error !== void 0) parts.push(`${node.error.name}: ${node.error.code}`);
77
+ return parts.join("\n");
78
+ }
79
+ function parseArgs(argsRaw) {
80
+ try {
81
+ return JSON.parse(argsRaw);
82
+ } catch {
83
+ return;
84
+ }
85
+ }
86
+ function firstLine(text) {
87
+ const nl = text.indexOf("\n");
88
+ return nl === -1 ? text : text.slice(0, nl);
89
+ }
90
+ function pickString(args, keys) {
91
+ for (const key of keys) {
92
+ const v = args[key];
93
+ if (typeof v === "string" && v !== "") return v;
94
+ }
95
+ }
96
+ /** Summary key preference per variant (args-derived; result-derived summaries are a ledger item). */
97
+ const SUMMARY_KEYS = {
98
+ bash: ["description", "command"],
99
+ read: [
100
+ "path",
101
+ "file_path",
102
+ "url"
103
+ ],
104
+ search: [
105
+ "query",
106
+ "pattern",
107
+ "url"
108
+ ],
109
+ write: ["path", "file_path"],
110
+ edit: ["path", "file_path"],
111
+ code: ["description"],
112
+ others: []
113
+ };
114
+ /**
115
+ * Strip the workspace root from a workspace-rooted absolute path (display only).
116
+ * @param text - the path to shorten.
117
+ * @param cwd - session workspace root; absent or empty leaves the path unchanged.
118
+ * @returns the path relative to the workspace root, or unchanged when it is not rooted there.
119
+ */
120
+ function relativizeToCwd(text, cwd) {
121
+ if (cwd === void 0 || cwd === "") return text;
122
+ const root = cwd.replace(/[/\\]+$/, "");
123
+ if (text.startsWith(`${root}/`) || text.startsWith(`${root}\\`)) return text.slice(root.length + 1);
124
+ return text;
125
+ }
126
+ function deriveSummary(variant, argsRaw) {
127
+ const parsed = parseArgs(argsRaw);
128
+ if (typeof parsed !== "object" || parsed === null) return firstLine(argsRaw);
129
+ const args = parsed;
130
+ const picked = pickString(args, SUMMARY_KEYS[variant]);
131
+ if (picked !== void 0) return firstLine(picked);
132
+ for (const v of Object.values(args)) if (typeof v === "string" && v !== "") return firstLine(v);
133
+ return firstLine(argsRaw);
134
+ }
135
+ /** Path keys only — never `url` (web_fetch lands on the read variant). */
136
+ const FILE_PATH_KEYS = ["path", "file_path"];
137
+ /** File-tool variants whose summary may be an openable workspace path. */
138
+ const FILE_PATH_VARIANTS = new Set([
139
+ "read",
140
+ "write",
141
+ "edit"
142
+ ]);
143
+ function deriveFilePath(variant, argsRaw) {
144
+ if (!FILE_PATH_VARIANTS.has(variant)) return void 0;
145
+ const parsed = parseArgs(argsRaw);
146
+ if (typeof parsed !== "object" || parsed === null) return void 0;
147
+ const picked = pickString(parsed, FILE_PATH_KEYS);
148
+ return picked === void 0 ? void 0 : firstLine(picked);
149
+ }
150
+ function deriveBody(variant, argsRaw) {
151
+ if (argsRaw === "") return null;
152
+ const parsed = parseArgs(argsRaw);
153
+ if (parsed === void 0) return argsRaw;
154
+ if (variant === "code" && typeof parsed === "object" && parsed !== null) {
155
+ const code = parsed.code;
156
+ if (typeof code === "string" && code !== "") return code;
157
+ }
158
+ return JSON.stringify(parsed, null, 2);
159
+ }
160
+ /**
161
+ * Derive the full row model from a frozen call slice.
162
+ * @param toolName - wire tool name (dispatch-supplied; survives windowless results).
163
+ * @param block - RunningToolCall or ToolResultNode off the snapshot caches.
164
+ * @param cwd - session workspace root; workspace-rooted path summaries display relative to it.
165
+ * @returns the row model.
166
+ */
167
+ function toolRowModel(toolName, block, cwd) {
168
+ const variant = classifyTool(toolName);
169
+ const done = "kind" in block;
170
+ const argsRaw = (done ? block.call?.argsRaw : block.argsRaw) ?? "";
171
+ const state = !done ? "running" : block.error?.code === "interrupted" ? "stopped" : block.isError ? "error" : "ok";
172
+ const base = argsRaw === "" ? block.callId : relativizeToCwd(deriveSummary(variant, argsRaw), cwd);
173
+ const toolTitle = TOOL_TITLES[toolName];
174
+ const summary = variant === "others" && toolName !== "" && toolTitle === void 0 ? `${toolName} · ${base}` : base;
175
+ const output = done ? resultText(block) || null : null;
176
+ const errorSummary = state === "error" && output !== null ? firstLine(output) : null;
177
+ return {
178
+ variant,
179
+ title: toolTitle ?? VARIANT_TITLES[variant],
180
+ summary,
181
+ filePath: deriveFilePath(variant, argsRaw),
182
+ body: deriveBody(variant, argsRaw),
183
+ output,
184
+ errorSummary,
185
+ state
186
+ };
187
+ }
188
+ //#endregion
189
+ //#region lib/types/client/tool/models/read-card-model.js
190
+ /**
191
+ * Derive the read-card props for a tool call, or null when this call is not a
192
+ * read card and belongs on the generic path.
193
+ *
194
+ * The read card is result-side only, so only a settled call whose result view
195
+ * declares `card:'read'` produces one. Every other case is null — the
196
+ * documented generic-card default:
197
+ *
198
+ * - A running call: it has no result view yet, and a read carries no content at
199
+ * call time.
200
+ * - A settled call whose result view is not a read card — including a `card`
201
+ * value this UI version does not know, which arrives over the wire and cannot
202
+ * be trusted to be one of the compiled variants, and the read tool's own
203
+ * generic fallback for an error result or a non-envelope body.
204
+ *
205
+ * The label is the read view's `title` when the tool supplied one (the
206
+ * presentation contract's replacement-title rule), otherwise the file path
207
+ * relativized to the session workspace so a workspace-rooted absolute path
208
+ * displays the same short form the row summary shows.
209
+ * @param block - RunningToolCall or ToolResultNode off the snapshot caches.
210
+ * @param sessionCwd - the session workspace root; a workspace-rooted absolute
211
+ * path label displays relative to it. Absent leaves the path as authored.
212
+ * @returns the read-card props, or null for the generic path.
213
+ */
214
+ function readCardModel(block, sessionCwd) {
215
+ if (!("kind" in block)) return null;
216
+ const result = block.resultView?.card === "read" ? block.resultView : null;
217
+ if (result === null) return null;
218
+ const lines = result.lines.map((line) => ({
219
+ number: line.number,
220
+ text: line.text
221
+ }));
222
+ return {
223
+ label: result.title ?? relativizeToCwd(result.path, sessionCwd),
224
+ lines,
225
+ totalLines: result.totalLines,
226
+ lang: result.lang
227
+ };
228
+ }
229
+ //#endregion
230
+ //#region lib/types/client/tool/models/diff-card-model.js
231
+ /**
232
+ * Narrow a wire `card:'diff'` view's `diffs` to well-formed hunks. The event
233
+ * view crosses the wire and `toolEventViewSchema` validates only the `card`
234
+ * string, so a version mismatch or an anomalous plugin can deliver a `diff` card
235
+ * whose `diffs` is absent, not an array, or carries malformed hunks. Returning
236
+ * null for any of those routes the block to the generic path instead of letting
237
+ * DiffBlock's `for...of`/`split` throw and crash the row or the details panel.
238
+ * @param diffs - the view's `diffs` field, unverified.
239
+ * @returns the validated hunks, or null when the payload is not usable.
240
+ */
241
+ function narrowDiffs(diffs) {
242
+ if (!Array.isArray(diffs) || diffs.length === 0) return null;
243
+ const out = [];
244
+ for (const hunk of diffs) {
245
+ if (typeof hunk !== "object" || hunk === null) return null;
246
+ const { path, oldText, newText } = hunk;
247
+ if (typeof path !== "string") return null;
248
+ if (oldText !== null && typeof oldText !== "string") return null;
249
+ if (typeof newText !== "string") return null;
250
+ out.push({
251
+ path,
252
+ oldText,
253
+ newText
254
+ });
255
+ }
256
+ return out;
257
+ }
258
+ /**
259
+ * Derive the diff-card props for a tool call, or null when this call is not a
260
+ * diff card and belongs on the generic path.
261
+ *
262
+ * The result side is authoritative once the call settles: the write/edit tools
263
+ * return the applied contextual hunks there (an edit's real before/after, a
264
+ * create's whole-file diff), which replace the call-time diff derived from the
265
+ * arguments alone. While the call is still running only the call side exists,
266
+ * so a running write/edit shows its intended change. Null is the documented
267
+ * generic-card default and covers every non-diff card — including a `card`
268
+ * value this UI version does not know, which arrives over the wire and cannot
269
+ * be trusted to be one of the compiled variants — and a settled call whose
270
+ * result view is generic (how write/edit keep their execution errors on the
271
+ * generic path).
272
+ *
273
+ * This derivation consumes only `diffs`; the render intent's `title` field is
274
+ * deliberately dropped. The row supplies its own title (`Edit`/`Write · path`
275
+ * from the args), which outranks the view's `title`. A tool that names its own
276
+ * diff header therefore does not surface that text on the Web row.
277
+ * @param block - RunningToolCall or ToolResultNode off the snapshot caches.
278
+ * @returns the diff-card props, or null for the generic path.
279
+ */
280
+ function diffCardModel(block) {
281
+ if (!("kind" in block)) {
282
+ const call = block.callView?.card === "diff" ? block.callView : null;
283
+ const diffs = call === null ? null : narrowDiffs(call.diffs);
284
+ return diffs === null ? null : { card: { diffs } };
285
+ }
286
+ const result = block.resultView?.card === "diff" ? block.resultView : null;
287
+ const diffs = result === null ? null : narrowDiffs(result.diffs);
288
+ return diffs === null ? null : { card: { diffs } };
289
+ }
290
+ //#endregion
291
+ //#region lib/types/client/tool/models/search-card-model.js
292
+ /**
293
+ * Whether every file group in a matches view is structurally valid: the wire
294
+ * frame carries `shape` and `card` as strings the host schema checks, but not the
295
+ * grouped `files` fields, so a version mismatch or loose producer could deliver
296
+ * `shape: 'matches'` with a missing or malformed `files`. Rendering that would
297
+ * crash {@link SearchBlock} at `.reduce`/`.map`; invalid fields select the
298
+ * generic path instead.
299
+ * @param files - the candidate `files` field off the untrusted result view.
300
+ * @returns whether `files` is a valid {@link SearchFileGroup} array.
301
+ */
302
+ function isValidFiles(files) {
303
+ return Array.isArray(files) && files.every((file) => typeof file === "object" && file !== null && typeof file.path === "string" && Array.isArray(file.matches) && file.matches.every((match) => typeof match === "object" && match !== null && typeof match.lineNumber === "number" && typeof match.line === "string"));
304
+ }
305
+ /**
306
+ * Flatten a settled tool result's content blocks to their text, joined by
307
+ * newlines. The search view carries no result text — a UI without a card falls
308
+ * back to the raw `tool/result` content — so the truncation recovery footer is
309
+ * read from the block's own content here. Non-text blocks (a search result
310
+ * carries none) are skipped.
311
+ * @param content - the result node's content blocks.
312
+ * @returns the joined text, or undefined when empty.
313
+ */
314
+ function flattenContent(content) {
315
+ const text = content.filter((block) => block.type === "text" && typeof block.text === "string").map((block) => block.text).join("\n");
316
+ return text === "" ? void 0 : text;
317
+ }
318
+ /**
319
+ * Derive the search-card props for a tool call, or null when this call is not a
320
+ * search card and belongs on the generic path.
321
+ *
322
+ * Only the result side matters: the search card carries no call-time state, so
323
+ * a still-running call (no result view) is null, as is a settled call whose
324
+ * result view is not a search card — including a `card` value this UI version
325
+ * does not know, which arrives over the wire and cannot be trusted to be one of
326
+ * the compiled variants, a `card: 'search'` view whose `shape` is neither
327
+ * `matches` nor `paths` (equally untrusted wire data), and a generic result a
328
+ * `grep`/`glob` failure or nested `run_code` dispatch produces (its text keeps
329
+ * the generic path).
330
+ * @param block - RunningToolCall or ToolResultNode off the snapshot caches.
331
+ * @returns the search-card props, or null for the generic path.
332
+ */
333
+ function searchCardModel(block) {
334
+ if (!("kind" in block)) return null;
335
+ const result = block.resultView?.card === "search" ? block.resultView : null;
336
+ if (result === null) return null;
337
+ const common = {
338
+ truncated: result.truncated,
339
+ total: result.total
340
+ };
341
+ const recovery = result.truncated ? flattenContent(block.content) : void 0;
342
+ if (result.shape === "matches") {
343
+ if (!isValidFiles(result.files)) return null;
344
+ return {
345
+ title: result.title,
346
+ recovery,
347
+ card: {
348
+ kind: "matches",
349
+ files: result.files,
350
+ ...common
351
+ }
352
+ };
353
+ }
354
+ if (result.shape !== "paths") return null;
355
+ if (!Array.isArray(result.paths) || !result.paths.every((path) => typeof path === "string")) return null;
356
+ return {
357
+ title: result.title,
358
+ recovery,
359
+ card: {
360
+ kind: "paths",
361
+ paths: result.paths,
362
+ ...common
363
+ }
364
+ };
365
+ }
366
+ //#endregion
367
+ //#region lib/types/client/tool/models/terminal-card-model.js
368
+ /**
369
+ * Pure derivation of the terminal-card props from a frozen call slice: the
370
+ * `card:'terminal'` render intent the shell tools declare arrives on the
371
+ * snapshot as `callView`/`resultView`, and this is the one place that turns
372
+ * that pair into what {@link TerminalBlock} draws. Both conversation render
373
+ * sites (the chat tool row's expanded body and the details panel's Output
374
+ * section) call this, so the command, cwd, output and exit status they show
375
+ * are derived once.
376
+ * @module
377
+ */
378
+ /**
379
+ * Build the TerminalBlock display copy from the conversation locale seat —
380
+ * the one place the primitive's label surface pairs with this package's
381
+ * dictionary, shared by every terminal render site (chat row, bash row,
382
+ * details panel).
383
+ * @param t - the render site's conversation locale seat.
384
+ * @returns the full label set for {@link TerminalBlockProps}'s `labels`.
385
+ */
386
+ function terminalBlockLabels(t) {
387
+ return {
388
+ signal: (signal) => t("terminal.signal", { signal }),
389
+ exitCode: (code) => t("terminal.exitCode", { code }),
390
+ running: t("terminal.running"),
391
+ failed: t("terminal.failed"),
392
+ done: t("terminal.done"),
393
+ copy: t("copy"),
394
+ copied: t("copied"),
395
+ noOutput: t("terminal.noOutput"),
396
+ collapseAria: t("terminal.collapseAria"),
397
+ collapse: t("collapse"),
398
+ expandAria: (hidden) => t("terminal.expandAria", { n: hidden }),
399
+ expand: (hidden) => t("terminal.expandRest", { n: hidden })
400
+ };
401
+ }
402
+ /**
403
+ * True when a settled terminal card reports a failing exit — a non-zero code
404
+ * or a terminating signal. The bash tool settles a failing command as a
405
+ * completed call (`isError` stays false: the exit status is result data), so
406
+ * this is the collapsed row's only failure signal; without it the red exit
407
+ * pill would be visible only after expanding the card.
408
+ * @param model - a derived terminal card.
409
+ * @returns whether the card's exit status is a failure.
410
+ */
411
+ function terminalFailed(model) {
412
+ const { exitCode, signal, running } = model.card;
413
+ return running !== true && (exitCode !== void 0 && exitCode !== 0 || signal !== void 0);
414
+ }
415
+ /**
416
+ * Resolve a terminal view's working directory the way the render-intent
417
+ * contract assigns to the UI bridge: an absolute path is used as-is, a relative
418
+ * one joins under the session workspace, and an omitted one IS the session
419
+ * workspace. A pure presenter cannot see the session cwd, which is why this
420
+ * resolution belongs here rather than in the tool. Without a session cwd there
421
+ * is nothing to resolve against, so a relative path stays as authored and an
422
+ * omitted one stays absent (the prompt row then draws a bare `$`).
423
+ * @param viewCwd - the cwd the terminal call view carries, if any.
424
+ * @param sessionCwd - the session workspace root, if the caller knows it.
425
+ * @returns the working directory for the prompt label, or undefined.
426
+ */
427
+ function resolveTerminalCwd(viewCwd, sessionCwd) {
428
+ if (viewCwd === void 0 || viewCwd === "") return sessionCwd;
429
+ if (sessionCwd === void 0 || sessionCwd === "") return normalizeSegments(viewCwd);
430
+ return normalizeSegments((0, _deepseek_ai_dsh_client_runtime_client.resolveWorkspacePath)(sessionCwd, viewCwd));
431
+ }
432
+ /**
433
+ * Collapse `.` and `..` segments so the prompt label names the directory the
434
+ * command actually ran in. The bash executor resolves the workdir before
435
+ * running, so a joined `/w/app/..` must display as `w`, not as `..`. Separators
436
+ * are preserved as authored (a Windows path keeps its backslashes) because this
437
+ * value is only ever displayed; a `..` that would climb past the root is
438
+ * dropped, which is what a filesystem does with it. A UNC path's `server` and
439
+ * `share` are part of its root, not poppable segments: Windows cannot climb
440
+ * above a share, so `\\\\server\\share` with a `..` stays there.
441
+ * @param path - a joined or absolute path, possibly carrying `.`/`..` segments.
442
+ * @returns the same path with those segments resolved.
443
+ */
444
+ function normalizeSegments(path) {
445
+ if (!/(?:^|[/\\])\.\.?(?:[/\\]|$)/.test(path)) return path;
446
+ const unc = /^[/\\]{2}([^/\\]+)[/\\]+([^/\\]+)/.exec(path);
447
+ if (unc !== null) {
448
+ const [matched, server, share] = unc;
449
+ const root = `\\\\${String(server)}\\${String(share)}`;
450
+ const rest = collapse(path.slice(matched.length), true);
451
+ return rest === "" ? root : `${root}\\${rest}`;
452
+ }
453
+ const separator = path.includes("\\") && !path.includes("/") ? "\\" : "/";
454
+ const rooted = /^[/\\]/.test(path);
455
+ const drive = /^[A-Za-z]:/.exec(path)?.[0] ?? "";
456
+ const body = collapse(path.slice(drive.length), rooted || drive !== "", separator);
457
+ const leading = rooted ? separator : "";
458
+ return drive === "" ? `${leading}${body}` : `${drive}${rooted ? leading : separator}${body}`;
459
+ }
460
+ /**
461
+ * Collapse the `.`/`..` segments of a path body against a known root state.
462
+ * @param body - the path after any drive letter or UNC root.
463
+ * @param rooted - the body hangs off a root, so a `..` at its top is dropped
464
+ * the way a filesystem drops one; without a root the `..` is kept, since it
465
+ * stays meaningful against a cwd this function cannot see.
466
+ * @param separator - separator to rejoin with (default `/`).
467
+ * @returns the collapsed body, without leading or trailing separators.
468
+ */
469
+ function collapse(body, rooted, separator = "/") {
470
+ const kept = [];
471
+ for (const segment of body.split(/[/\\]/)) {
472
+ if (segment === "" || segment === ".") continue;
473
+ if (segment === "..") {
474
+ if (kept.length > 0 && kept[kept.length - 1] !== "..") kept.pop();
475
+ else if (!rooted) kept.push(segment);
476
+ continue;
477
+ }
478
+ kept.push(segment);
479
+ }
480
+ return kept.join(separator);
481
+ }
482
+ /**
483
+ * Derive the terminal-card props for a tool call, or null when this call is
484
+ * not a terminal card and belongs on the generic path.
485
+ *
486
+ * The call side supplies the command and its working directory; the result
487
+ * side supplies the captured output and exit status. Three cases produce
488
+ * null, all of them the documented generic-card default:
489
+ *
490
+ * - Neither side declares `card:'terminal'` — including a `card` value this
491
+ * UI version does not know, which arrives over the wire and therefore
492
+ * cannot be trusted to be one of the compiled variants.
493
+ * - A settled call whose result view is not a terminal card: the result
494
+ * presentation decides how the settled call renders, and the bash tool
495
+ * returns a generic fenced card for an execution error or a background
496
+ * start, whose text and error styling the generic path preserves.
497
+ *
498
+ * Window truncation can drop the call head from a settled result (see
499
+ * `ToolResultNode.call`/`callView` in dsh-client-runtime), leaving a terminal
500
+ * result with no call side. That still renders: the command falls back to the
501
+ * result view's replacement title, then to an empty command (the prompt line
502
+ * draws bare), and the prompt shows no cwd.
503
+ * @param block - RunningToolCall or ToolResultNode off the snapshot caches.
504
+ * @param sessionCwd - the session workspace root, which resolves an omitted or
505
+ * relative view cwd (see {@link resolveTerminalCwd}); absent leaves both unresolved.
506
+ * @returns the terminal-card props, or null for the generic path.
507
+ */
508
+ function terminalCardModel(block, sessionCwd) {
509
+ const call = block.callView?.card === "terminal" ? block.callView : null;
510
+ if (!("kind" in block)) return call === null ? null : {
511
+ description: call.description,
512
+ card: {
513
+ command: call.title,
514
+ cwd: resolveTerminalCwd(call.cwd, sessionCwd),
515
+ output: void 0,
516
+ exitCode: void 0,
517
+ signal: void 0,
518
+ running: true
519
+ }
520
+ };
521
+ const result = block.resultView?.card === "terminal" ? block.resultView : null;
522
+ if (result === null) return null;
523
+ return {
524
+ description: call?.description,
525
+ card: {
526
+ command: result.title ?? call?.title ?? "",
527
+ cwd: call === null ? void 0 : resolveTerminalCwd(call.cwd, sessionCwd),
528
+ output: result.output,
529
+ exitCode: result.exitCode,
530
+ signal: result.signal,
531
+ running: false
532
+ }
533
+ };
534
+ }
535
+ //#endregion
536
+ //#region lib/types/client/tool/models/web-card-model.js
537
+ /**
538
+ * Derive the web-card props for a tool call, or null when this call is not a
539
+ * web card and belongs on the generic path.
540
+ *
541
+ * The result side supplies the whole card: the sources and answer for a
542
+ * `search`, the URL and status for a `fetch`. Cases producing null, all of
543
+ * them the documented generic-card default:
544
+ *
545
+ * - A running call (no `resultView` yet): the web tools keep a generic pending
546
+ * card, so nothing web-shaped exists until the call settles.
547
+ * - A settled call whose result view is not a web card — including a `card`
548
+ * value this UI version does not know, which arrives over the wire and so
549
+ * cannot be trusted to be one of the compiled variants, and a generic result
550
+ * view (a web tool's error path returns the generic card, whose text the
551
+ * generic path preserves).
552
+ * - A web card whose `kind` this UI version does not know (a newer host's
553
+ * value): the wire cannot be trusted to be `search` or `fetch`, so it takes
554
+ * the generic path rather than rendering as a malformed fetch.
555
+ * @param block - RunningToolCall or ToolResultNode off the snapshot caches.
556
+ * @returns the web-card props, or null for the generic path.
557
+ */
558
+ function webCardModel(block) {
559
+ if (!("kind" in block)) return null;
560
+ const result = block.resultView;
561
+ if (result?.card !== "web") return null;
562
+ if (result.kind === "search") return {
563
+ kind: "search",
564
+ answer: result.answer,
565
+ sources: result.sources.map((source) => ({
566
+ url: source.url,
567
+ title: source.title,
568
+ snippet: source.snippet,
569
+ publishedAt: source.publishedAt
570
+ })),
571
+ truncated: result.truncated
572
+ };
573
+ if (result.kind === "fetch") return {
574
+ kind: "fetch",
575
+ url: result.url,
576
+ statusCode: result.statusCode,
577
+ truncated: result.truncated
578
+ };
579
+ return null;
580
+ }
581
+ //#endregion
582
+ //#region ../../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
583
+ function r(e) {
584
+ var t, f, n = "";
585
+ if ("string" == typeof e || "number" == typeof e) n += e;
586
+ else if ("object" == typeof e) if (Array.isArray(e)) {
587
+ var o = e.length;
588
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
589
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
590
+ return n;
591
+ }
592
+ function clsx() {
593
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
594
+ return n;
595
+ }
596
+ //#endregion
597
+ //#region \0dsh-css:/private/var/folders/nm/n5smty9962gf5rhjc5855kt80000gn/T/dsh-edge-release-worktree.XXXXXX.RcJjogaGt4/repo/packages/client/ui-tool/src/client/tool/components/ToolRow.module.css.mjs
598
+ const css$3 = "._3P0koG_root{flex-direction:column;display:flex}._3P0koG_row{position:relative;overflow:hidden}._3P0koG_root[data-state=running] ._3P0koG_row:after{content:\"\";background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite _3P0koG_dsh-tool-row-sweep;position:absolute;top:0;bottom:0;left:0}@keyframes _3P0koG_dsh-tool-row-sweep{0%{left:-300px}90%,to{left:100%}}._3P0koG_leading{flex-shrink:0}._3P0koG_root[data-tool^=cordis_] ._3P0koG_leading,._3P0koG_root[data-tool^=cordis_] ._3P0koG_title{color:var(--dsw-alias-state-business-primary)}._3P0koG_root[data-tool^=cordis_] ._3P0koG_title{font-weight:500}._3P0koG_root[data-tool^=cordis_] ._3P0koG_sep{background:var(--dsw-alias-state-business-primary)}._3P0koG_chevron{color:var(--dsw-alias-label-secondary)}._3P0koG_title{font-weight:400}._3P0koG_sep{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}._3P0koG_summary{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-tertiary);flex:auto;font-size:14px;line-height:24px;overflow:hidden}._3P0koG_summarySuffix{white-space:nowrap;color:var(--dsw-alias-label-tertiary);flex:none;margin-left:4px;font-size:14px;line-height:24px}._3P0koG_fileLink{text-overflow:ellipsis;white-space:nowrap;min-width:0;font:inherit;text-align:left;color:var(--dsw-alias-label-secondary);text-decoration:underline;text-decoration-color:var(--dsw-alias-label-quaternary);text-underline-offset:3px;cursor:pointer;background:0 0;border:none;flex:auto;margin:0;padding:0;font-size:14px;line-height:24px;overflow:hidden}._3P0koG_fileLink:hover{color:var(--dsw-alias-label-primary);text-decoration-color:currentColor}._3P0koG_errorSummary{color:var(--dsw-alias-state-error-primary)}._3P0koG_bodyWrap{flex-direction:column;display:flex}._3P0koG_inspectButton{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-secondary);cursor:pointer;opacity:0;border-radius:999px;align-self:flex-start;align-items:center;gap:4px;margin:4px 0 2px 4px;padding:2px 8px;font-size:11px;line-height:16px;transition:opacity .1s;display:inline-flex}._3P0koG_root:hover ._3P0koG_inspectButton,._3P0koG_inspectButton:focus-visible{opacity:1}._3P0koG_inspectButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}._3P0koG_bodyScroll{max-height:260px;overflow-y:auto}._3P0koG_ioCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-markdown-code-block);font:var(--dsw-font-markdown-code-block-small);border-radius:12px;flex-direction:column;margin:4px 0 4px 4px;display:flex}._3P0koG_ioSection{grid-template-columns:max-content 1fr;align-items:baseline;column-gap:14px;max-height:150px;padding:12px 16px;display:grid;overflow-y:auto}._3P0koG_ioSection::-webkit-scrollbar-thumb{background-clip:padding-box;border:2px solid #0000;border-radius:6px}._3P0koG_ioSection::-webkit-scrollbar-track{margin:6px 0}._3P0koG_ioLabel{color:var(--dsw-alias-label-caption);align-self:start;position:sticky;top:0}._3P0koG_ioDivider{background:var(--dsw-alias-border-l2);flex:none;height:1px}._3P0koG_ioText{white-space:pre-wrap;word-break:break-word;min-width:0;color:var(--dsw-alias-label-secondary)}._3P0koG_ioText[data-error]{color:var(--dsw-alias-state-error-primary)}._3P0koG_codeBody,._3P0koG_terminalBody,._3P0koG_diffBody,._3P0koG_readBody,._3P0koG_searchBody,._3P0koG_webBody{margin:4px 0 4px 4px}._3P0koG_searchRecovery{white-space:pre-wrap;overflow-wrap:anywhere;font:var(--dsw-font-xs-13);color:var(--dsw-alias-label-tertiary);margin:4px 0 4px 4px}._3P0koG_codeBody{--dsl-code-block-content-font:var(--dsw-font-markdown-code-block-small)}._3P0koG_terminalBody{--dsl-terminal-font:var(--dsw-font-markdown-code-block-small);--dsl-terminal-line-height:18px;--dsl-terminal-output-max-height:224px;border:1px solid var(--dsw-alias-border-l1)}._3P0koG_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}";
599
+ const tagId$3 = "@deepseek-ai/dsh-client-ui-tool/ToolRow.module.css";
600
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
601
+ const tag = document.createElement("style");
602
+ tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-tool";
603
+ tag.dataset.pluginCss = tagId$3;
604
+ tag.textContent = css$3;
605
+ document.head.appendChild(tag);
606
+ }
607
+ var ToolRow_module_css_default = {
608
+ "leading": "_3P0koG_leading",
609
+ "summarySuffix": "_3P0koG_summarySuffix",
610
+ "inspectButton": "_3P0koG_inspectButton",
611
+ "searchBody": "_3P0koG_searchBody",
612
+ "ioSection": "_3P0koG_ioSection",
613
+ "codeBody": "_3P0koG_codeBody",
614
+ "summary": "_3P0koG_summary",
615
+ "fileLink": "_3P0koG_fileLink",
616
+ "searchRecovery": "_3P0koG_searchRecovery",
617
+ "bodyScroll": "_3P0koG_bodyScroll",
618
+ "webBody": "_3P0koG_webBody",
619
+ "sep": "_3P0koG_sep",
620
+ "visuallyHidden": "_3P0koG_visuallyHidden",
621
+ "title": "_3P0koG_title",
622
+ "bodyWrap": "_3P0koG_bodyWrap",
623
+ "ioCard": "_3P0koG_ioCard",
624
+ "ioDivider": "_3P0koG_ioDivider",
625
+ "ioText": "_3P0koG_ioText",
626
+ "dsh-tool-row-sweep": "_3P0koG_dsh-tool-row-sweep",
627
+ "errorSummary": "_3P0koG_errorSummary",
628
+ "ioLabel": "_3P0koG_ioLabel",
629
+ "chevron": "_3P0koG_chevron",
630
+ "terminalBody": "_3P0koG_terminalBody",
631
+ "readBody": "_3P0koG_readBody",
632
+ "root": "_3P0koG_root",
633
+ "row": "_3P0koG_row",
634
+ "diffBody": "_3P0koG_diffBody"
635
+ };
636
+ //#endregion
637
+ //#region lib/types/client/tool/components/ToolRow.js
638
+ /** Leading-slot state substitution: the tool icon yields to the terminal state
639
+ * semantic (error = red, interrupted = amber halo). Running keeps the icon —
640
+ * the row sweep (CSS on data-state) carries the in-flight signal. */
641
+ function leadingFor$1(state, icon) {
642
+ switch (state) {
643
+ case "error": return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "error" });
644
+ case "stopped": return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "warning" });
645
+ default: return icon;
646
+ }
647
+ }
648
+ /** Visually hidden run-state label: the StateDot and the CSS sweep are both
649
+ * aria-hidden / colour-only, so assistive technology needs this text to know a
650
+ * row is running, failed, or interrupted. null in the ok state (the icon and
651
+ * summary already describe a settled row). */
652
+ function stateStatus$1(state, t) {
653
+ switch (state) {
654
+ case "running": return t("row.running");
655
+ case "error": return t("row.failed");
656
+ case "stopped": return t("row.stopped");
657
+ default: return null;
658
+ }
659
+ }
660
+ function ToolRow({ t, variant, toolName, icon, title, summary, summarySuffix, body, output, errorSummary, terminal, diff, read, search, web, state, filePath, onOpenFile, inspect }) {
661
+ const [expanded, setExpanded] = (0, react.useState)(false);
662
+ const terminalBody = terminal ?? null;
663
+ const diffBody = diff ?? null;
664
+ const readBody = read ?? null;
665
+ const searchBody = search ?? null;
666
+ const webBody = web ?? null;
667
+ const outputText = output ?? null;
668
+ const expandable = body !== null || outputText !== null || (terminalBody ?? diffBody ?? readBody ?? searchBody ?? webBody) !== null;
669
+ const open = expanded && expandable;
670
+ const status = stateStatus$1(state, t);
671
+ const failureLine = state === "error" ? errorSummary ?? null : null;
672
+ const summaryText = failureLine ?? summary;
673
+ const suffix = failureLine === null ? summarySuffix ?? null : null;
674
+ const fileLink = filePath !== void 0 && onOpenFile !== void 0 && failureLine === null;
675
+ const toggleExpand = () => {
676
+ setExpanded((v) => !v);
677
+ };
678
+ const openFile = (event) => {
679
+ event.stopPropagation();
680
+ if (filePath !== void 0) onOpenFile?.(filePath);
681
+ };
682
+ const fileLinkKeyDown = (event) => {
683
+ if (event.key === "Enter" || event.key === " ") event.stopPropagation();
684
+ };
685
+ const cardBody = variant === "code" ? null : body;
686
+ return (0, react_jsx_runtime.jsxs)("div", {
687
+ className: ToolRow_module_css_default.root,
688
+ "data-variant": variant,
689
+ "data-tool": toolName,
690
+ "data-state": state,
691
+ children: [status !== null && (0, react_jsx_runtime.jsx)("span", {
692
+ className: ToolRow_module_css_default.visuallyHidden,
693
+ children: status
694
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.DisclosureRow, {
695
+ rowClassName: ToolRow_module_css_default.row,
696
+ leadingClassName: ToolRow_module_css_default.leading,
697
+ titleClassName: ToolRow_module_css_default.title,
698
+ chevronClassName: ToolRow_module_css_default.chevron,
699
+ icon: leadingFor$1(state, icon),
700
+ title,
701
+ open,
702
+ expandable,
703
+ expandOnRowClick: true,
704
+ keepContentWhenOpen: true,
705
+ onToggle: toggleExpand,
706
+ collapsedContent: summaryText !== "" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
707
+ (0, react_jsx_runtime.jsx)("span", {
708
+ className: ToolRow_module_css_default.sep,
709
+ "aria-hidden": true
710
+ }),
711
+ fileLink ? (0, react_jsx_runtime.jsx)("button", {
712
+ type: "button",
713
+ className: ToolRow_module_css_default.fileLink,
714
+ onClick: openFile,
715
+ onKeyDown: fileLinkKeyDown,
716
+ children: summaryText
717
+ }) : (0, react_jsx_runtime.jsx)("span", {
718
+ className: clsx(ToolRow_module_css_default.summary, failureLine !== null && ToolRow_module_css_default.errorSummary),
719
+ children: summaryText
720
+ }),
721
+ suffix !== null && (0, react_jsx_runtime.jsx)("span", {
722
+ className: ToolRow_module_css_default.summarySuffix,
723
+ children: suffix
724
+ })
725
+ ] }),
726
+ children: (0, react_jsx_runtime.jsxs)("div", {
727
+ className: ToolRow_module_css_default.bodyWrap,
728
+ children: [terminalBody !== null ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.TerminalBlock, {
729
+ ...terminalBody.card,
730
+ maxLines: Infinity,
731
+ labels: terminalBlockLabels(t),
732
+ className: ToolRow_module_css_default.terminalBody
733
+ }) : diffBody !== null ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.DiffBlock, {
734
+ ...diffBody.card,
735
+ maxLines: 8,
736
+ className: ToolRow_module_css_default.diffBody
737
+ }) : readBody !== null ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.ReadBlock, {
738
+ ...readBody,
739
+ maxLines: 8,
740
+ className: ToolRow_module_css_default.readBody
741
+ }) : searchBody !== null ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SearchBlock, {
742
+ ...searchBody.card,
743
+ maxLines: 8,
744
+ className: ToolRow_module_css_default.searchBody
745
+ }), searchBody.recovery !== void 0 && (0, react_jsx_runtime.jsx)("div", {
746
+ className: ToolRow_module_css_default.searchRecovery,
747
+ children: searchBody.recovery
748
+ })] }) : webBody !== null ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.WebBlock, {
749
+ ...webBody,
750
+ className: ToolRow_module_css_default.webBody
751
+ }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [variant === "code" && body !== null && (0, react_jsx_runtime.jsx)("div", {
752
+ className: ToolRow_module_css_default.bodyScroll,
753
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.CodeBlock, {
754
+ code: body,
755
+ lang: "typescript",
756
+ copyLabel: t("copy"),
757
+ copiedLabel: t("copied"),
758
+ className: ToolRow_module_css_default.codeBody
759
+ })
760
+ }), (cardBody !== null || outputText !== null) && (0, react_jsx_runtime.jsxs)("div", {
761
+ className: ToolRow_module_css_default.ioCard,
762
+ children: [
763
+ cardBody !== null && (0, react_jsx_runtime.jsxs)("div", {
764
+ className: ToolRow_module_css_default.ioSection,
765
+ children: [(0, react_jsx_runtime.jsx)("span", {
766
+ className: ToolRow_module_css_default.ioLabel,
767
+ children: "IN"
768
+ }), (0, react_jsx_runtime.jsx)("span", {
769
+ className: ToolRow_module_css_default.ioText,
770
+ children: cardBody
771
+ })]
772
+ }),
773
+ cardBody !== null && outputText !== null && (0, react_jsx_runtime.jsx)("span", {
774
+ className: ToolRow_module_css_default.ioDivider,
775
+ "aria-hidden": true
776
+ }),
777
+ outputText !== null && (0, react_jsx_runtime.jsxs)("div", {
778
+ className: ToolRow_module_css_default.ioSection,
779
+ children: [(0, react_jsx_runtime.jsx)("span", {
780
+ className: ToolRow_module_css_default.ioLabel,
781
+ children: "OUT"
782
+ }), (0, react_jsx_runtime.jsx)("span", {
783
+ className: ToolRow_module_css_default.ioText,
784
+ "data-error": state === "error" || void 0,
785
+ children: outputText
786
+ })]
787
+ })
788
+ ]
789
+ })] }), inspect !== void 0 && (0, react_jsx_runtime.jsxs)("button", {
790
+ type: "button",
791
+ className: ToolRow_module_css_default.inspectButton,
792
+ onClick: inspect,
793
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconInspectOutline12, {}), "Inspect"]
794
+ })]
795
+ })
796
+ })]
797
+ });
798
+ }
799
+ //#endregion
800
+ //#region lib/types/client/tool/toolviews/GenericToolCard.js
801
+ /** Variant leading icons (figma table); all glyphs render at 14 inside the 16px leading box. */
802
+ const VARIANT_ICONS = {
803
+ search: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutline16, { size: 14 }),
804
+ read: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBrowseOutline16, { size: 14 }),
805
+ bash: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconApiOutline14, { size: 14 }),
806
+ write: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, { size: 14 }),
807
+ edit: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, { size: 14 }),
808
+ code: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCodeOutline16, { size: 14 }),
809
+ others: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSparkle16, { size: 14 })
810
+ };
811
+ function GenericToolCard({ toolName, block, cwd, openFile, inspect, t }) {
812
+ const model = toolRowModel(toolName, block, cwd);
813
+ const terminal = terminalCardModel(block, cwd);
814
+ const read = readCardModel(block, cwd);
815
+ const diff = diffCardModel(block);
816
+ const search = searchCardModel(block);
817
+ const web = webCardModel(block);
818
+ const state = model.state === "ok" && terminal !== null && terminalFailed(terminal) ? "error" : model.state;
819
+ const singleFile = model.filePath !== void 0;
820
+ return (0, react_jsx_runtime.jsx)(ToolRow, {
821
+ t,
822
+ variant: model.variant,
823
+ toolName,
824
+ icon: VARIANT_ICONS[model.variant],
825
+ title: model.title,
826
+ summary: terminal?.description ?? search?.title ?? model.summary,
827
+ body: singleFile ? null : model.body,
828
+ output: model.output,
829
+ errorSummary: model.errorSummary,
830
+ terminal,
831
+ diff,
832
+ read,
833
+ search,
834
+ web,
835
+ state,
836
+ filePath: model.filePath,
837
+ onOpenFile: singleFile ? openFile : void 0,
838
+ inspect
839
+ });
840
+ }
841
+ //#endregion
842
+ //#region \0dsh-css:/private/var/folders/nm/n5smty9962gf5rhjc5855kt80000gn/T/dsh-edge-release-worktree.XXXXXX.RcJjogaGt4/repo/packages/client/ui-tool/src/client/tool/ToolCallTree.module.css.mjs
843
+ const css$2 = ".ngI5ma_callRow{border-radius:6px}.ngI5ma_subCalls{border-left:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:4px;margin:4px 0 2px 22px;padding-left:8px;display:flex}";
844
+ const tagId$2 = "@deepseek-ai/dsh-client-ui-tool/ToolCallTree.module.css";
845
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
846
+ const tag = document.createElement("style");
847
+ tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-tool";
848
+ tag.dataset.pluginCss = tagId$2;
849
+ tag.textContent = css$2;
850
+ document.head.appendChild(tag);
851
+ }
852
+ var ToolCallTree_module_css_default = {
853
+ "callRow": "ngI5ma_callRow",
854
+ "subCalls": "ngI5ma_subCalls"
855
+ };
856
+ //#endregion
857
+ //#region lib/types/client/tool/ToolCallTree.js
858
+ /** Root/subcall Tool composition with one keyed atomic dispatch path. */
859
+ /** Resolve a Tool call's wire name from either lifecycle form. */
860
+ function callName(node) {
861
+ return "kind" in node ? node.call?.name ?? "" : node.name;
862
+ }
863
+ /** One atomic call dispatched through the Tool-owned keyed slot. */
864
+ const ToolCall = (0, react.memo)(function ToolCall({ renderSlot, callId, toolName, block, openFile, selected, cwd, inspectCall, t, children }) {
865
+ const owner = (0, react.useMemo)(() => ({
866
+ callId,
867
+ toolName,
868
+ block,
869
+ openFile,
870
+ cwd,
871
+ inspect: () => {
872
+ inspectCall(callId);
873
+ }
874
+ }), [
875
+ callId,
876
+ toolName,
877
+ block,
878
+ openFile,
879
+ cwd,
880
+ inspectCall
881
+ ]);
882
+ return (0, react_jsx_runtime.jsxs)("div", {
883
+ className: ToolCallTree_module_css_default.callRow,
884
+ "data-chat-anchor-key": `call:${callId}`,
885
+ "data-chat-call-id": callId,
886
+ "data-selected": selected || void 0,
887
+ children: [renderSlot("tool.call.toolview", owner, {
888
+ entryKey: toolName,
889
+ fallback: (0, react_jsx_runtime.jsx)(GenericToolCard, {
890
+ ...owner,
891
+ t
892
+ })
893
+ }), children]
894
+ });
895
+ });
896
+ const ToolCallBranch = (0, react.memo)(function ToolCallBranch({ renderSlot, block, selectedCallId, cwd, openFile, inspectCall, t }) {
897
+ return (0, react_jsx_runtime.jsx)(ToolCall, {
898
+ renderSlot,
899
+ callId: block.callId,
900
+ toolName: callName(block),
901
+ block,
902
+ openFile,
903
+ selected: block.callId === selectedCallId,
904
+ cwd,
905
+ inspectCall,
906
+ t,
907
+ children: block.subCalls.length > 0 ? (0, react_jsx_runtime.jsx)("div", {
908
+ className: ToolCallTree_module_css_default.subCalls,
909
+ "data-subcalls": true,
910
+ children: block.subCalls.map((child) => (0, react_jsx_runtime.jsx)(ToolCallBranch, {
911
+ renderSlot,
912
+ block: child,
913
+ selectedCallId,
914
+ cwd,
915
+ openFile,
916
+ inspectCall,
917
+ t
918
+ }, child.callId))
919
+ }) : null
920
+ });
921
+ });
922
+ /**
923
+ * Render one root Tool call and its recursive children through the same
924
+ * atomic keyed dispatch.
925
+ * @param props - whole-Tool owner data and the Tool-owned child-slot share.
926
+ * @returns the Tool call tree.
927
+ */
928
+ function ToolCallTree({ renderSlot, node, selectedCallId, cwd, openFile, inspectCall, t }) {
929
+ const block = node.data.root;
930
+ return (0, react_jsx_runtime.jsx)(ToolCallBranch, {
931
+ renderSlot,
932
+ block,
933
+ selectedCallId,
934
+ cwd,
935
+ openFile,
936
+ inspectCall,
937
+ t
938
+ });
939
+ }
940
+ //#endregion
941
+ //#region \0dsh-css:/private/var/folders/nm/n5smty9962gf5rhjc5855kt80000gn/T/dsh-edge-release-worktree.XXXXXX.RcJjogaGt4/repo/packages/client/ui-tool/src/client/tool/ToolDetails.module.css.mjs
942
+ const css$1 = ".rnWy0a_description{color:var(--dsw-alias-label-secondary);font:var(--dsw-font-xs-13);margin:0 0 6px}.rnWy0a_cardBody{margin:0}.rnWy0a_recovery{white-space:pre-wrap;overflow-wrap:anywhere;color:var(--dsw-alias-label-tertiary);font:var(--dsw-font-xs-13);margin:6px 0 0}.rnWy0a_code{background:var(--dsw-alias-markdown-code-block);font-family:var(--ds-font-family-code);color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;border-radius:12px;margin:0;padding:16px;font-size:13px;line-height:22px}.rnWy0a_code[data-error]{color:var(--dsw-alias-state-error-primary)}.rnWy0a_read,.rnWy0a_web{margin:0}.rnWy0a_empty{color:var(--dsw-alias-label-tertiary);padding:8px 0;font-size:13px;line-height:20px}";
943
+ const tagId$1 = "@deepseek-ai/dsh-client-ui-tool/ToolDetails.module.css";
944
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
945
+ const tag = document.createElement("style");
946
+ tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-tool";
947
+ tag.dataset.pluginCss = tagId$1;
948
+ tag.textContent = css$1;
949
+ document.head.appendChild(tag);
950
+ }
951
+ var ToolDetails_module_css_default = {
952
+ "cardBody": "rnWy0a_cardBody",
953
+ "read": "rnWy0a_read",
954
+ "code": "rnWy0a_code",
955
+ "description": "rnWy0a_description",
956
+ "recovery": "rnWy0a_recovery",
957
+ "web": "rnWy0a_web",
958
+ "empty": "rnWy0a_empty"
959
+ };
960
+ //#endregion
961
+ //#region lib/types/client/tool/ToolDetails.js
962
+ /** Card-aware output body for the selected Tool call in details. */
963
+ /**
964
+ * Render the selected Tool call's structured output when its presentation
965
+ * intent is known, otherwise preserve the flattened result text.
966
+ * @param props - selected call slice, workspace root, and locale seat.
967
+ * @returns the details output body.
968
+ */
969
+ function ToolDetails({ block, cwd, t }) {
970
+ const terminal = terminalCardModel(block, cwd);
971
+ if (terminal !== null) return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [terminal.description !== void 0 ? (0, react_jsx_runtime.jsx)("div", {
972
+ className: ToolDetails_module_css_default.description,
973
+ children: terminal.description
974
+ }) : null, (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.TerminalBlock, {
975
+ ...terminal.card,
976
+ labels: terminalBlockLabels(t),
977
+ className: ToolDetails_module_css_default.cardBody
978
+ })] });
979
+ const read = readCardModel(block, cwd);
980
+ if (read !== null) return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.ReadBlock, {
981
+ ...read,
982
+ className: ToolDetails_module_css_default.read
983
+ });
984
+ const diff = diffCardModel(block);
985
+ if (diff !== null) return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.DiffBlock, {
986
+ ...diff.card,
987
+ className: ToolDetails_module_css_default.cardBody
988
+ });
989
+ const search = searchCardModel(block);
990
+ if (search !== null) return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SearchBlock, {
991
+ ...search.card,
992
+ className: ToolDetails_module_css_default.cardBody
993
+ }), search.recovery !== void 0 ? (0, react_jsx_runtime.jsx)("div", {
994
+ className: ToolDetails_module_css_default.recovery,
995
+ children: search.recovery
996
+ }) : null] });
997
+ const web = webCardModel(block);
998
+ if (web !== null) {
999
+ const body = "kind" in block ? resultText(block) : "";
1000
+ return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.WebBlock, {
1001
+ ...web,
1002
+ className: ToolDetails_module_css_default.web
1003
+ }), body !== "" ? (0, react_jsx_runtime.jsx)("pre", {
1004
+ className: ToolDetails_module_css_default.code,
1005
+ children: body
1006
+ }) : null] });
1007
+ }
1008
+ if (!("kind" in block)) return (0, react_jsx_runtime.jsx)("div", {
1009
+ className: ToolDetails_module_css_default.empty,
1010
+ children: t("details.running")
1011
+ });
1012
+ return (0, react_jsx_runtime.jsx)("pre", {
1013
+ className: ToolDetails_module_css_default.code,
1014
+ "data-error": block.isError || void 0,
1015
+ children: resultText(block)
1016
+ });
1017
+ }
1018
+ //#endregion
1019
+ //#region lib/types/client/locale.js
1020
+ /** Locale namespace supplied by the conversation owner to Tool renderers. */
1021
+ const CONVERSATION_NS = "conversation";
1022
+ //#endregion
1023
+ //#region lib/types/client/tool/toolviews/ask-question-row.js
1024
+ function isAnswer(value) {
1025
+ return typeof value === "object" && value !== null;
1026
+ }
1027
+ /** Answered-count summary from the result JSON (a skipped question has
1028
+ * empty `selected` and no `custom`); null when answer fields are invalid. */
1029
+ function answeredSummary(text, t) {
1030
+ let parsed;
1031
+ try {
1032
+ parsed = JSON.parse(text);
1033
+ } catch {
1034
+ return null;
1035
+ }
1036
+ if (typeof parsed !== "object" || parsed === null) return null;
1037
+ const answers = parsed.answers;
1038
+ if (!Array.isArray(answers) || !answers.every(isAnswer)) return null;
1039
+ const answered = answers.filter((a) => Array.isArray(a.selected) && a.selected.length > 0 || typeof a.custom === "string" && a.custom !== "").length;
1040
+ return t("ask.answered", {
1041
+ answered,
1042
+ total: answers.length
1043
+ });
1044
+ }
1045
+ /** One-line question-interaction row (the whole row toggles the call's
1046
+ * Input/Output sections, ToolRow's unified expand). */
1047
+ function AskQuestionRow({ toolName, block, inspect, t }) {
1048
+ const model = toolRowModel(toolName, block);
1049
+ const code = "kind" in block ? block.error?.code : void 0;
1050
+ let summary = model.summary;
1051
+ let state = model.state;
1052
+ if (code === "ASK_CANCELLED") summary = t("ask.cancelled");
1053
+ else if (code === "ASK_ABORTED") {
1054
+ summary = t("ask.interrupted");
1055
+ state = "stopped";
1056
+ } else if (model.state === "running") summary = t("ask.waiting");
1057
+ else if ("kind" in block && model.state === "ok") summary = answeredSummary(block.content.filter((b) => b.type === "text").map((b) => b.text).join(""), t) ?? model.summary;
1058
+ return (0, react_jsx_runtime.jsx)(ToolRow, {
1059
+ t,
1060
+ variant: model.variant,
1061
+ toolName,
1062
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconQuestionOutline14, {}),
1063
+ title: t("ask.rowTitle"),
1064
+ summary,
1065
+ body: model.body,
1066
+ output: model.output,
1067
+ state,
1068
+ inspect
1069
+ });
1070
+ }
1071
+ /**
1072
+ * The ask-question row as a plain registrant plugin following the chat
1073
+ * toolview declaration across independent activation and reload lifetimes.
1074
+ */
1075
+ const askQuestionToolview = {
1076
+ name: "ask-question-toolview",
1077
+ inject: ["slots"],
1078
+ /**
1079
+ * Register the ask-question row into the Tool-owned keyed view slot.
1080
+ * @param ctx - registrant context (disposal rides ctx.effect inside slots.register).
1081
+ */
1082
+ apply(ctx) {
1083
+ ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
1084
+ name: "tool.call.toolview",
1085
+ key: "ask_user_question",
1086
+ locale: CONVERSATION_NS
1087
+ }, AskQuestionRow));
1088
+ }
1089
+ };
1090
+ //#endregion
1091
+ //#region \0dsh-css:/private/var/folders/nm/n5smty9962gf5rhjc5855kt80000gn/T/dsh-edge-release-worktree.XXXXXX.RcJjogaGt4/repo/packages/client/ui-tool/src/client/tool/toolviews/bash-sample.module.css.mjs
1092
+ const css = ".PMP91q_card{flex-direction:column;display:flex}.PMP91q_terminal{--dsl-terminal-font:var(--dsw-font-markdown-code-block-small);--dsl-terminal-line-height:18px;--dsl-terminal-output-max-height:224px;border:1px solid var(--dsw-alias-border-l1);margin:4px 0 4px 4px}.PMP91q_ioCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-markdown-code-block);font:var(--dsw-font-markdown-code-block-small);border-radius:12px;flex-direction:column;margin:4px 0 4px 4px;display:flex}.PMP91q_ioSection{grid-template-columns:max-content 1fr;align-items:baseline;column-gap:14px;max-height:150px;padding:12px 16px;display:grid;overflow-y:auto}.PMP91q_ioSection::-webkit-scrollbar-thumb{background-clip:padding-box;border:2px solid #0000;border-radius:6px}.PMP91q_ioSection::-webkit-scrollbar-track{margin:6px 0}.PMP91q_ioLabel{color:var(--dsw-alias-label-caption);align-self:start;position:sticky;top:0}.PMP91q_ioDivider{background:var(--dsw-alias-border-l2);flex:none;height:1px}.PMP91q_ioText{white-space:pre-wrap;word-break:break-word;min-width:0;color:var(--dsw-alias-label-secondary)}.PMP91q_ioText[data-error]{color:var(--dsw-alias-state-error-primary)}.PMP91q_root[data-expandable]{cursor:pointer}.PMP91q_root{align-items:center;min-width:0;height:24px;display:flex;position:relative;overflow:hidden}.PMP91q_root[data-state=running]:after{content:\"\";background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite PMP91q_dsh-bash-row-sweep;position:absolute;top:0;bottom:0;left:0}@keyframes PMP91q_dsh-bash-row-sweep{0%{left:-300px}90%,to{left:100%}}.PMP91q_leading{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;margin-right:6px;display:inline-flex;position:relative}.PMP91q_chevron{color:var(--dsw-alias-label-secondary)}.PMP91q_iconIdle{opacity:1;transition:opacity .1s;display:inline-flex}.PMP91q_chevronHover{opacity:0;margin:auto;transition:opacity .1s;position:absolute;inset:0}.PMP91q_root:hover .PMP91q_iconIdle{opacity:0}.PMP91q_root:hover .PMP91q_chevronHover{opacity:1}.PMP91q_title{color:var(--dsw-alias-label-secondary);flex:none;font-size:14px;line-height:24px}.PMP91q_sep{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.PMP91q_summary{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-tertiary);flex:auto;font-size:14px;line-height:24px;overflow:hidden}.PMP91q_errorSummary{color:var(--dsw-alias-state-error-primary)}.PMP91q_bodyWrap{flex-direction:column;display:flex}.PMP91q_inspectButton{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-secondary);cursor:pointer;opacity:0;border-radius:999px;align-self:flex-start;align-items:center;gap:4px;margin:4px 0 2px 4px;padding:2px 8px;font-size:11px;line-height:16px;transition:opacity .1s;display:inline-flex}.PMP91q_card:hover .PMP91q_inspectButton,.PMP91q_inspectButton:focus-visible{opacity:1}.PMP91q_inspectButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.PMP91q_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}";
1093
+ const tagId = "@deepseek-ai/dsh-client-ui-tool/bash-sample.module.css";
1094
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
1095
+ const tag = document.createElement("style");
1096
+ tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-tool";
1097
+ tag.dataset.pluginCss = tagId;
1098
+ tag.textContent = css;
1099
+ document.head.appendChild(tag);
1100
+ }
1101
+ var bash_sample_module_css_default = {
1102
+ "ioDivider": "PMP91q_ioDivider",
1103
+ "sep": "PMP91q_sep",
1104
+ "summary": "PMP91q_summary",
1105
+ "bodyWrap": "PMP91q_bodyWrap",
1106
+ "title": "PMP91q_title",
1107
+ "ioSection": "PMP91q_ioSection",
1108
+ "terminal": "PMP91q_terminal",
1109
+ "dsh-bash-row-sweep": "PMP91q_dsh-bash-row-sweep",
1110
+ "iconIdle": "PMP91q_iconIdle",
1111
+ "ioCard": "PMP91q_ioCard",
1112
+ "visuallyHidden": "PMP91q_visuallyHidden",
1113
+ "ioLabel": "PMP91q_ioLabel",
1114
+ "root": "PMP91q_root",
1115
+ "chevronHover": "PMP91q_chevronHover",
1116
+ "card": "PMP91q_card",
1117
+ "ioText": "PMP91q_ioText",
1118
+ "chevron": "PMP91q_chevron",
1119
+ "errorSummary": "PMP91q_errorSummary",
1120
+ "inspectButton": "PMP91q_inspectButton",
1121
+ "leading": "PMP91q_leading"
1122
+ };
1123
+ //#endregion
1124
+ //#region lib/types/client/tool/toolviews/bash-sample.js
1125
+ function leadingFor(state) {
1126
+ switch (state) {
1127
+ case "error": return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "error" });
1128
+ case "stopped": return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "warning" });
1129
+ default: return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconApiOutline14, { size: 14 });
1130
+ }
1131
+ }
1132
+ /** Visually hidden status — StateDot is aria-hidden; AT needs a text label. */
1133
+ function stateStatus(state, t) {
1134
+ switch (state) {
1135
+ case "running": return t("bash.running");
1136
+ case "error": return t("bash.failed");
1137
+ case "stopped": return t("bash.stopped");
1138
+ default: return null;
1139
+ }
1140
+ }
1141
+ /**
1142
+ * Bash row: icon + Bash · {description} in the shared ToolRow chrome, the
1143
+ * whole row toggling the command's terminal or generic error card (ToolRow's unified
1144
+ * expand interaction, replicated locally per the registrant posture).
1145
+ */
1146
+ function BashRow({ toolName, block, sessionId, useSessions, inspect, t }) {
1147
+ const model = toolRowModel(toolName, block);
1148
+ const terminal = terminalCardModel(block, useSessions((list) => list.byId[sessionId]?.cwd));
1149
+ const state = model.state === "ok" && terminal !== null && terminalFailed(terminal) ? "error" : model.state;
1150
+ const status = stateStatus(state, t);
1151
+ const [expanded, setExpanded] = (0, react.useState)(false);
1152
+ const genericError = terminal === null && model.state === "error" && (model.body !== null || model.output !== null);
1153
+ const expandable = terminal !== null || genericError;
1154
+ const open = expanded && expandable;
1155
+ const failureLine = model.state === "error" ? model.errorSummary : null;
1156
+ const toggleExpand = () => {
1157
+ setExpanded((v) => !v);
1158
+ };
1159
+ const toggleFromKeyboard = (event) => {
1160
+ if (!expandable || event.key !== "Enter" && event.key !== " ") return;
1161
+ event.preventDefault();
1162
+ toggleExpand();
1163
+ };
1164
+ const leading = open ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: bash_sample_module_css_default.chevron }) : expandable ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("span", {
1165
+ className: bash_sample_module_css_default.iconIdle,
1166
+ children: leadingFor(state)
1167
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: clsx(bash_sample_module_css_default.chevron, bash_sample_module_css_default.chevronHover) })] }) : leadingFor(state);
1168
+ return (0, react_jsx_runtime.jsxs)("div", {
1169
+ className: bash_sample_module_css_default.card,
1170
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1171
+ className: bash_sample_module_css_default.root,
1172
+ "data-sample": "bash",
1173
+ "data-variant": "bash",
1174
+ "data-state": state,
1175
+ "data-expandable": expandable || void 0,
1176
+ role: expandable ? "button" : void 0,
1177
+ tabIndex: expandable ? 0 : void 0,
1178
+ "aria-expanded": expandable ? open : void 0,
1179
+ onClick: expandable ? toggleExpand : void 0,
1180
+ onKeyDown: expandable ? toggleFromKeyboard : void 0,
1181
+ children: [
1182
+ (0, react_jsx_runtime.jsx)("span", {
1183
+ className: bash_sample_module_css_default.leading,
1184
+ children: leading
1185
+ }),
1186
+ status !== null && (0, react_jsx_runtime.jsx)("span", {
1187
+ className: bash_sample_module_css_default.visuallyHidden,
1188
+ children: status
1189
+ }),
1190
+ (0, react_jsx_runtime.jsx)("span", {
1191
+ className: bash_sample_module_css_default.title,
1192
+ children: model.title
1193
+ }),
1194
+ (0, react_jsx_runtime.jsx)("span", {
1195
+ className: bash_sample_module_css_default.sep,
1196
+ "aria-hidden": true
1197
+ }),
1198
+ (0, react_jsx_runtime.jsx)("span", {
1199
+ className: clsx(bash_sample_module_css_default.summary, failureLine !== null && bash_sample_module_css_default.errorSummary),
1200
+ children: failureLine ?? terminal?.description ?? model.summary
1201
+ })
1202
+ ]
1203
+ }), open && (0, react_jsx_runtime.jsxs)("div", {
1204
+ className: bash_sample_module_css_default.bodyWrap,
1205
+ children: [terminal !== null ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.TerminalBlock, {
1206
+ ...terminal.card,
1207
+ maxLines: Infinity,
1208
+ labels: terminalBlockLabels(t),
1209
+ className: bash_sample_module_css_default.terminal
1210
+ }) : (0, react_jsx_runtime.jsxs)("div", {
1211
+ className: bash_sample_module_css_default.ioCard,
1212
+ children: [
1213
+ model.body !== null && (0, react_jsx_runtime.jsxs)("div", {
1214
+ className: bash_sample_module_css_default.ioSection,
1215
+ children: [(0, react_jsx_runtime.jsx)("span", {
1216
+ className: bash_sample_module_css_default.ioLabel,
1217
+ children: "IN"
1218
+ }), (0, react_jsx_runtime.jsx)("span", {
1219
+ className: bash_sample_module_css_default.ioText,
1220
+ children: model.body
1221
+ })]
1222
+ }),
1223
+ model.body !== null && model.output !== null && (0, react_jsx_runtime.jsx)("span", {
1224
+ className: bash_sample_module_css_default.ioDivider,
1225
+ "aria-hidden": true
1226
+ }),
1227
+ model.output !== null && (0, react_jsx_runtime.jsxs)("div", {
1228
+ className: bash_sample_module_css_default.ioSection,
1229
+ children: [(0, react_jsx_runtime.jsx)("span", {
1230
+ className: bash_sample_module_css_default.ioLabel,
1231
+ children: "OUT"
1232
+ }), (0, react_jsx_runtime.jsx)("span", {
1233
+ className: bash_sample_module_css_default.ioText,
1234
+ "data-error": true,
1235
+ children: model.output
1236
+ })]
1237
+ })
1238
+ ]
1239
+ }), inspect !== void 0 && (0, react_jsx_runtime.jsxs)("button", {
1240
+ type: "button",
1241
+ className: bash_sample_module_css_default.inspectButton,
1242
+ onClick: inspect,
1243
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconInspectOutline12, {}), "Inspect"]
1244
+ })]
1245
+ })]
1246
+ });
1247
+ }
1248
+ /**
1249
+ * The sample as a plain registrant plugin. Slot injection follows the chat
1250
+ * toolview declaration across independent activation and reload lifetimes.
1251
+ */
1252
+ const bashToolviewSample = {
1253
+ name: "bash-toolview-sample",
1254
+ inject: ["slots"],
1255
+ /**
1256
+ * Register the bash row into the Tool-owned keyed view slot.
1257
+ * @param ctx - registrant context (disposal rides ctx.effect inside slots.register).
1258
+ */
1259
+ apply(ctx) {
1260
+ ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
1261
+ name: "tool.call.toolview",
1262
+ key: "bash",
1263
+ locale: CONVERSATION_NS
1264
+ }, BashRow));
1265
+ }
1266
+ };
1267
+ //#endregion
1268
+ //#region lib/types/client/tool/toolviews/file-mutation-row.js
1269
+ /**
1270
+ * File-mutation row: icon + {Edit,Write} · {path} in the shared ToolRow chrome,
1271
+ * with the applied diff as the row's collapsed-by-default card body. The
1272
+ * summary is a path link (a file tool's interaction); the host's `openFile`
1273
+ * resolves it against the session cwd, so this passes the tool's own path
1274
+ * verbatim. An errored mutation has no diff card, so ToolRow surfaces the
1275
+ * model-facing error text through its Output section and its first line in the
1276
+ * collapsed summary instead.
1277
+ */
1278
+ function FileMutationRow({ toolName, block, cwd, openFile, inspect, t }) {
1279
+ const model = toolRowModel(toolName, block, cwd);
1280
+ const diff = diffCardModel(block);
1281
+ return (0, react_jsx_runtime.jsx)(ToolRow, {
1282
+ t,
1283
+ variant: model.variant,
1284
+ toolName,
1285
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, { size: 14 }),
1286
+ title: model.title,
1287
+ summary: model.summary,
1288
+ body: null,
1289
+ output: model.output,
1290
+ errorSummary: model.errorSummary,
1291
+ diff,
1292
+ state: model.state,
1293
+ filePath: model.filePath,
1294
+ onOpenFile: openFile,
1295
+ inspect
1296
+ });
1297
+ }
1298
+ /**
1299
+ * The file-mutation rows as a plain registrant plugin following the chat
1300
+ * toolview declaration across independent activation and reload lifetimes.
1301
+ */
1302
+ const fileMutationToolview = {
1303
+ name: "file-mutation-toolview",
1304
+ inject: ["slots"],
1305
+ /**
1306
+ * Register the file-mutation row into the Tool-owned keyed view slot
1307
+ * under both mutation tool names.
1308
+ * @param ctx - registrant context (disposal rides ctx.effect inside slots.register).
1309
+ */
1310
+ apply(ctx) {
1311
+ ctx.slots.inject("tool.call.toolview", function* () {
1312
+ yield ctx.slots.register({
1313
+ name: "tool.call.toolview",
1314
+ key: "edit",
1315
+ locale: CONVERSATION_NS
1316
+ }, FileMutationRow);
1317
+ yield ctx.slots.register({
1318
+ name: "tool.call.toolview",
1319
+ key: "write",
1320
+ locale: CONVERSATION_NS
1321
+ }, FileMutationRow);
1322
+ });
1323
+ }
1324
+ };
1325
+ //#endregion
1326
+ //#region lib/types/client/tool/toolviews/read-row.js
1327
+ /**
1328
+ * Read row: icon + Read · {path} in the shared ToolRow chrome, with the file's
1329
+ * read card as the row's collapsed-by-default card body. The summary path is an
1330
+ * openable host link when the row names a single file.
1331
+ */
1332
+ function ReadRow({ toolName, block, cwd, openFile, inspect, t }) {
1333
+ const model = toolRowModel(toolName, block, cwd);
1334
+ const read = readCardModel(block, cwd);
1335
+ return (0, react_jsx_runtime.jsx)(ToolRow, {
1336
+ t,
1337
+ variant: model.variant,
1338
+ toolName,
1339
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBrowseOutline16, { size: 14 }),
1340
+ title: model.title,
1341
+ summary: model.summary,
1342
+ body: null,
1343
+ output: model.output,
1344
+ errorSummary: model.errorSummary,
1345
+ read,
1346
+ state: model.state,
1347
+ filePath: model.filePath,
1348
+ onOpenFile: openFile,
1349
+ inspect
1350
+ });
1351
+ }
1352
+ /**
1353
+ * The read row as a plain registrant plugin following the atomic Tool-view
1354
+ * declaration across independent activation and reload lifetimes.
1355
+ */
1356
+ const readToolview = {
1357
+ name: "read-toolview",
1358
+ inject: ["slots"],
1359
+ /**
1360
+ * Register the read row into the Tool-owned keyed view slot.
1361
+ * @param ctx - registrant context (disposal rides ctx.effect inside slots.register).
1362
+ */
1363
+ apply(ctx) {
1364
+ ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
1365
+ name: "tool.call.toolview",
1366
+ key: "read",
1367
+ locale: CONVERSATION_NS
1368
+ }, ReadRow));
1369
+ }
1370
+ };
1371
+ //#endregion
1372
+ //#region lib/types/client/tool/toolviews/search-row.js
1373
+ const SEARCH_TITLES = {
1374
+ grep: "Grep",
1375
+ glob: "Glob"
1376
+ };
1377
+ /**
1378
+ * Search row: icon + Grep/Glob · {summary} in the shared ToolRow chrome, with the
1379
+ * completed search's card as the row's collapsed-by-default card body (a capped
1380
+ * search's recovery footer rides below it, inside ToolRow). Registered under
1381
+ * both `grep` and `glob`; the derived model's `kind` decides the card shape. A
1382
+ * settled call with no search card surfaces its model-facing text through
1383
+ * ToolRow's Output section, since the keyed SearchRow owns this render slot.
1384
+ */
1385
+ function SearchRow({ toolName, block, inspect, t }) {
1386
+ const model = toolRowModel(toolName, block);
1387
+ const search = searchCardModel(block);
1388
+ return (0, react_jsx_runtime.jsx)(ToolRow, {
1389
+ t,
1390
+ variant: model.variant,
1391
+ toolName,
1392
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutline16, { size: 14 }),
1393
+ title: SEARCH_TITLES[toolName] ?? model.title,
1394
+ summary: search?.title ?? model.summary,
1395
+ body: null,
1396
+ output: model.output,
1397
+ errorSummary: model.errorSummary,
1398
+ search,
1399
+ state: model.state,
1400
+ inspect
1401
+ });
1402
+ }
1403
+ /**
1404
+ * The search view follows the atomic Tool-view declaration across activation
1405
+ * and reload. One component registers under both keys because `grep` and
1406
+ * `glob` are the same visual object discriminated by the result view's `kind`.
1407
+ */
1408
+ const searchToolview = {
1409
+ name: "search-toolview",
1410
+ inject: ["slots"],
1411
+ /**
1412
+ * Register the search row into the Tool-owned keyed view slot under both
1413
+ * the `grep` and `glob` tool names.
1414
+ * @param ctx - registrant context (disposal rides ctx.effect inside slots.register).
1415
+ */
1416
+ apply(ctx) {
1417
+ ctx.slots.inject("tool.call.toolview", function* () {
1418
+ yield ctx.slots.register({
1419
+ name: "tool.call.toolview",
1420
+ key: "grep",
1421
+ locale: CONVERSATION_NS
1422
+ }, SearchRow);
1423
+ yield ctx.slots.register({
1424
+ name: "tool.call.toolview",
1425
+ key: "glob",
1426
+ locale: CONVERSATION_NS
1427
+ }, SearchRow);
1428
+ });
1429
+ }
1430
+ };
1431
+ //#endregion
1432
+ //#region lib/types/client/tool/toolviews/plan-summary.js
1433
+ /**
1434
+ * Pure plan derivation for the todo_write row's one-line summary. Several items
1435
+ * may be `in_progress` at once — parallel work runs concurrent tasks, so a
1436
+ * summary built from one active item would silently drop the rest. The plan
1437
+ * strip header derives its own counts inline and shares nothing with this, so
1438
+ * this stays inside the toolviews domain rather than in `contract/` (the
1439
+ * inter-domain face).
1440
+ * @module
1441
+ */
1442
+ /**
1443
+ * Derive the counts and the active summary from a whole-list snapshot. It names
1444
+ * the first `in_progress` item and counts the remaining active ones, so a
1445
+ * parallel plan reports how many tasks are running rather than naming one and
1446
+ * hiding the others. `activeContent` is null when nothing is in progress, or
1447
+ * when the first active item's content is missing, mistyped, or blank once
1448
+ * trimmed — the tool's own rule for usable content, applied here because a
1449
+ * rejected call keeps its args verbatim. The row then renders the counts alone
1450
+ * rather than falling back to the generic tool summary: the counts are already
1451
+ * known to be good, and the active-item clause is the only part an unusable
1452
+ * name costs.
1453
+ * @param todos - the whole list, in model order.
1454
+ * @returns the done/total counts and the two summary halves.
1455
+ */
1456
+ function planSummary(todos) {
1457
+ const active = todos.filter((t) => t.status === "in_progress");
1458
+ const first = active[0]?.content;
1459
+ const named = typeof first === "string" && first.trim() !== "";
1460
+ return {
1461
+ done: todos.filter((t) => t.status === "completed").length,
1462
+ total: todos.length,
1463
+ activeContent: named ? first : null,
1464
+ activeExtra: named ? active.length - 1 : 0
1465
+ };
1466
+ }
1467
+ //#endregion
1468
+ //#region lib/types/client/tool/toolviews/todo-row.js
1469
+ function isItem(value) {
1470
+ return typeof value === "object" && value !== null;
1471
+ }
1472
+ function summarize(argsRaw, t) {
1473
+ let parsed;
1474
+ try {
1475
+ parsed = JSON.parse(argsRaw);
1476
+ } catch {
1477
+ return null;
1478
+ }
1479
+ if (typeof parsed !== "object" || parsed === null) return null;
1480
+ const todos = parsed.todos;
1481
+ if (!Array.isArray(todos) || !todos.every(isItem)) return null;
1482
+ const { done, total, activeContent, activeExtra } = planSummary(todos);
1483
+ const head = t("todo.completed", {
1484
+ done,
1485
+ total
1486
+ });
1487
+ return {
1488
+ text: activeContent === null ? head : `${head} · ${activeContent}`,
1489
+ extra: activeExtra
1490
+ };
1491
+ }
1492
+ /** One-line plan update row (the whole row toggles the call's Input/Output
1493
+ * sections, ToolRow's unified expand). Non-ok execution states keep the
1494
+ * shared row's dot semantics — a cancelled call wrote no todo/write, so it
1495
+ * must not read as a completed update. */
1496
+ function TodoRow({ toolName, block, inspect, t }) {
1497
+ const model = toolRowModel(toolName, block);
1498
+ const summary = summarize(("kind" in block ? block.call?.argsRaw : block.argsRaw) ?? "", t) ?? {
1499
+ text: model.summary,
1500
+ extra: 0
1501
+ };
1502
+ return (0, react_jsx_runtime.jsx)(ToolRow, {
1503
+ t,
1504
+ variant: model.variant,
1505
+ toolName,
1506
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChecklistOutline14, {}),
1507
+ title: t("todo.rowTitle"),
1508
+ summary: summary.text,
1509
+ summarySuffix: summary.extra > 0 ? `+${summary.extra}` : null,
1510
+ body: model.body,
1511
+ output: model.output,
1512
+ errorSummary: model.errorSummary,
1513
+ state: model.state,
1514
+ inspect
1515
+ });
1516
+ }
1517
+ /**
1518
+ * The todo row as a plain registrant plugin following the atomic Tool-view
1519
+ * declaration across independent activation and reload lifetimes.
1520
+ */
1521
+ const todoToolview = {
1522
+ name: "todo-toolview",
1523
+ inject: ["slots"],
1524
+ /**
1525
+ * Register the todo row into the Tool-owned keyed view slot.
1526
+ * @param ctx - registrant context (disposal rides ctx.effect inside slots.register).
1527
+ */
1528
+ apply(ctx) {
1529
+ ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
1530
+ name: "tool.call.toolview",
1531
+ key: "todo_write",
1532
+ locale: CONVERSATION_NS
1533
+ }, TodoRow));
1534
+ }
1535
+ };
1536
+ //#endregion
1537
+ //#region lib/types/client/tool/toolviews/web-row.js
1538
+ /** web_fetch reads one URL; web_search queries. Titles are figma literals. */
1539
+ const WEB_TITLES = {
1540
+ web_search: "Search",
1541
+ web_fetch: "Fetch"
1542
+ };
1543
+ /**
1544
+ * Web row: icon + Search/Fetch · {summary} in the shared ToolRow chrome, with
1545
+ * the completed retrieval's web card as the row's collapsed-by-default card
1546
+ * body. The row discriminates on `toolName` only to pick its icon and title.
1547
+ */
1548
+ function WebRow({ toolName, block, inspect, t }) {
1549
+ const model = toolRowModel(toolName, block);
1550
+ const web = webCardModel(block);
1551
+ const icon = toolName === "web_fetch" ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBrowseOutline16, { size: 14 }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconGlobeOutline14, { size: 14 });
1552
+ return (0, react_jsx_runtime.jsx)(ToolRow, {
1553
+ t,
1554
+ variant: model.variant,
1555
+ toolName,
1556
+ icon,
1557
+ title: WEB_TITLES[toolName] ?? model.title,
1558
+ summary: model.summary,
1559
+ body: null,
1560
+ output: model.output,
1561
+ errorSummary: model.errorSummary,
1562
+ web,
1563
+ state: model.state,
1564
+ inspect
1565
+ });
1566
+ }
1567
+ /**
1568
+ * The web rows follow the atomic Tool-view declaration across activation and
1569
+ * reload. One WebRow component registers under both web tool names.
1570
+ */
1571
+ const webToolview = {
1572
+ name: "web-toolview",
1573
+ inject: ["slots"],
1574
+ /**
1575
+ * Register the web row under both web tool names' keyed toolview holes.
1576
+ * @param ctx - registrant context (disposal rides ctx.effect inside slots.register).
1577
+ */
1578
+ apply(ctx) {
1579
+ ctx.slots.inject("tool.call.toolview", function* () {
1580
+ yield ctx.slots.register({
1581
+ name: "tool.call.toolview",
1582
+ key: "web_search",
1583
+ locale: CONVERSATION_NS
1584
+ }, WebRow);
1585
+ yield ctx.slots.register({
1586
+ name: "tool.call.toolview",
1587
+ key: "web_fetch",
1588
+ locale: CONVERSATION_NS
1589
+ }, WebRow);
1590
+ });
1591
+ }
1592
+ };
1593
+ //#endregion
1594
+ //#region lib/types/client/apply.js
1595
+ /** Required service: the slot registry that owns both Tool render seats. */
1596
+ const inject = ["slots"];
1597
+ /**
1598
+ * Mount the whole-Tool renderers and built-in atomic Tool registrations.
1599
+ * @param ctx - Client root context.
1600
+ */
1601
+ function apply(ctx) {
1602
+ ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({
1603
+ name: "conversation.chat.node",
1604
+ key: "tool-call",
1605
+ locale: CONVERSATION_NS,
1606
+ children: { "tool.call.toolview": {
1607
+ kind: "keyed",
1608
+ scope: "session"
1609
+ } }
1610
+ }, ToolCallTree));
1611
+ ctx.slots.inject("conversation.details.tool", () => ctx.slots.register({
1612
+ name: "conversation.details.tool",
1613
+ locale: CONVERSATION_NS
1614
+ }, ToolDetails));
1615
+ ctx.plugin(bashToolviewSample);
1616
+ ctx.plugin(readToolview);
1617
+ ctx.plugin(fileMutationToolview);
1618
+ ctx.plugin(searchToolview);
1619
+ ctx.plugin(webToolview);
1620
+ ctx.plugin(todoToolview);
1621
+ ctx.plugin(askQuestionToolview);
1622
+ }
1623
+ //#endregion
1624
+ exports.apply = apply;
1625
+ exports.inject = inject;
1626
+ return module.exports;
1627
+ }
1628
+ });
1629
+
1630
+ //# sourceMappingURL=client.js.map