@prettier-ai/dsh-client-ui-tool 0.1.2-alpha.2 → 0.1.2-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/client/ui-tool/README.md
5
- README.md: 773a93801ebc214e2d5c94d52864f5c5dd887100
6
- README.zh.md: 88df08d7b5b7d5d3978d90fd4df4cbbb2efeb1fa
5
+ README.md: 895274748d8ee5b7bece16e5b76836966cc52663
6
+ README.zh.md: f4cf11cabdb94f45c9b11e7f7538ad5042a791e6
package/README.md CHANGED
@@ -61,7 +61,7 @@ The package realizes one dispatch rule: atomic Tool views are keyed by wire Tool
61
61
 
62
62
  ### Details and cards
63
63
 
64
- The package fills `conversation.details.tool` with `ToolDetails`. Row and Details renderers share one pure card model for each terminal, read, diff, search, and web card. These models validate raw call arguments, result content, failure state, persisted metadata, Code Dispatch `parentCallId`, and Session path facts. Unsupported or malformed inputs use flattened Tool result text. Card-specific limits and fallback rules remain in the owning [terminal](../../../.agents/notes/implemented/feature/2026-07-28-web-terminal-card.md), [diff](../../../.agents/notes/implemented/feature/2026-07-30-web-diff-card.md), [read](../../../.agents/notes/implemented/feature/2026-07-30-web-read-card-frontend.md), [search](../../../.agents/notes/implemented/feature/2026-07-30-web-search-card.md), [web](../../../.agents/notes/implemented/feature/2026-07-30-web-result-card-frontend.md), and [question](../../../.agents/notes/implemented/feature/2026-07-29-ask-question-web-presentation.md) notes.
64
+ The package fills `conversation.details.tool` with `ToolDetails`. Row and Details renderers share one pure card model for each terminal, read, diff, search, and web card. These models validate raw call arguments, result content, failure state, persisted metadata, Code Dispatch `parentCallId`, and Session path facts. Generic rows retain the original `argsRaw` reference and format their input body only while it is expanded; structured cards skip generic-body formatting. Unsupported or malformed inputs use flattened Tool result text. Card-specific limits and fallback rules remain in the owning [terminal](../../../.agents/notes/implemented/feature/2026-07-28-web-terminal-card.md), [diff](../../../.agents/notes/implemented/feature/2026-07-30-web-diff-card.md), [read](../../../.agents/notes/implemented/feature/2026-07-30-web-read-card-frontend.md), [search](../../../.agents/notes/implemented/feature/2026-07-30-web-search-card.md), [web](../../../.agents/notes/implemented/feature/2026-07-30-web-result-card-frontend.md), and [question](../../../.agents/notes/implemented/feature/2026-07-29-ask-question-web-presentation.md) notes.
65
65
 
66
66
  </details>
67
67
 
package/README.zh.md CHANGED
@@ -61,7 +61,7 @@ owner 载荷为 `ToolCallOwnerProps`:`callId`、`toolName`、冻结的 `block`
61
61
 
62
62
  ### 详情与卡片
63
63
 
64
- 本包通过 `ToolDetails` 填充 `conversation.details.tool`。行 renderer 与 Details renderer 分别为 terminal、read、diff、search 和 web 卡片复用同一个纯 card model。这些 model 校验原始调用参数、结果内容、失败状态、持久 metadata、Code Dispatch `parentCallId` 与 Session 路径事实。不受支持或格式错误的输入使用压平的工具结果文本。各类卡片的上限与 fallback 规则仍由对应的 [terminal](../../../.agents/notes/implemented/feature/2026-07-28-web-terminal-card.zh.md)、[diff](../../../.agents/notes/implemented/feature/2026-07-30-web-diff-card.zh.md)、[read](../../../.agents/notes/implemented/feature/2026-07-30-web-read-card-frontend.zh.md)、[search](../../../.agents/notes/implemented/feature/2026-07-30-web-search-card.zh.md)、[web](../../../.agents/notes/implemented/feature/2026-07-30-web-result-card-frontend.zh.md) 与 [question](../../../.agents/notes/implemented/feature/2026-07-29-ask-question-web-presentation.zh.md) 笔记负责。
64
+ 本包通过 `ToolDetails` 填充 `conversation.details.tool`。行 renderer 与 Details renderer 分别为 terminal、read、diff、search 和 web 卡片复用同一个纯 card model。这些 model 校验原始调用参数、结果内容、失败状态、持久 metadata、Code Dispatch `parentCallId` 与 Session 路径事实。Generic row 保留原始 `argsRaw` 引用,只在展开期间格式化 input body;结构化卡片跳过 generic body 格式化。不受支持或格式错误的输入使用压平的工具结果文本。各类卡片的上限与 fallback 规则仍由对应的 [terminal](../../../.agents/notes/implemented/feature/2026-07-28-web-terminal-card.zh.md)、[diff](../../../.agents/notes/implemented/feature/2026-07-30-web-diff-card.zh.md)、[read](../../../.agents/notes/implemented/feature/2026-07-30-web-read-card-frontend.zh.md)、[search](../../../.agents/notes/implemented/feature/2026-07-30-web-search-card.zh.md)、[web](../../../.agents/notes/implemented/feature/2026-07-30-web-result-card-frontend.zh.md) 与 [question](../../../.agents/notes/implemented/feature/2026-07-29-ask-question-web-presentation.zh.md) 笔记负责。
65
65
 
66
66
  </details>
67
67
 
package/lib/client.js CHANGED
@@ -186,7 +186,13 @@ window.__ModuleLoader__.load({
186
186
  const picked = pickString(parsed, FILE_PATH_KEYS);
187
187
  return picked === void 0 ? void 0 : firstLine(picked);
188
188
  }
189
- function deriveBody(variant, argsRaw) {
189
+ /**
190
+ * Format one argument payload when its generic input body becomes visible.
191
+ * @param variant - row presentation selected for the Tool name.
192
+ * @param argsRaw - original argument JSON or incomplete raw text.
193
+ * @returns display body, or null for empty input.
194
+ */
195
+ function formatToolBody(variant, argsRaw) {
190
196
  if (argsRaw === "") return null;
191
197
  const parsed = parseArgs(argsRaw);
192
198
  if (parsed === void 0) return argsRaw;
@@ -214,12 +220,13 @@ window.__ModuleLoader__.load({
214
220
  const summary = variant === "others" && toolName !== "" && toolTitleKey === void 0 ? `${toolName} · ${base}` : base;
215
221
  const output = done ? resultText(block) || null : null;
216
222
  const errorSummary = state === "error" && output !== null ? firstLine(output) : null;
223
+ const bodyRaw = argsRaw === "" ? null : argsRaw;
217
224
  return {
218
225
  variant,
219
226
  titleKey: toolTitleKey ?? VARIANT_TITLE_KEYS[variant],
220
227
  summary,
221
228
  filePath: deriveFilePath(variant, argsRaw),
222
- body: deriveBody(variant, argsRaw),
229
+ bodyRaw,
223
230
  output,
224
231
  errorSummary,
225
232
  state
@@ -1095,7 +1102,7 @@ window.__ModuleLoader__.load({
1095
1102
  default: return null;
1096
1103
  }
1097
1104
  }
1098
- function ToolRow({ t, variant, toolName, icon, title, summary, summarySuffix, body, output, askQuestion, errorSummary, terminal, diff, read, search, web, state, filePath, onOpenFile, inspect }) {
1105
+ function ToolRow({ t, variant, toolName, icon, title, summary, summarySuffix, bodyRaw, output, askQuestion, errorSummary, terminal, diff, read, search, web, state, filePath, onOpenFile, inspect }) {
1099
1106
  const [expanded, setExpanded] = (0, react.useState)(false);
1100
1107
  const terminalLabels = (0, react.useMemo)(() => terminalBlockLabels(t), [t]);
1101
1108
  const diffLabels = (0, react.useMemo)(() => diffBlockLabels(t), [t]);
@@ -1109,8 +1116,15 @@ window.__ModuleLoader__.load({
1109
1116
  const webBody = web ?? null;
1110
1117
  const askQuestionBody = askQuestion ?? null;
1111
1118
  const outputText = output ?? null;
1112
- const expandable = body !== null || outputText !== null || (askQuestionBody ?? terminalBody ?? diffBody ?? readBody ?? searchBody ?? webBody) !== null;
1119
+ const card = askQuestionBody ?? terminalBody ?? diffBody ?? readBody ?? searchBody ?? webBody;
1120
+ const expandable = bodyRaw != null || outputText !== null || card !== null;
1113
1121
  const open = expanded && expandable;
1122
+ const bodyText = (0, react.useMemo)(() => open && card === null && bodyRaw != null ? formatToolBody(variant, bodyRaw) : null, [
1123
+ bodyRaw,
1124
+ card,
1125
+ open,
1126
+ variant
1127
+ ]);
1114
1128
  const status = stateStatus$1(state, t);
1115
1129
  const failureLine = state === "error" ? errorSummary ?? null : null;
1116
1130
  const summaryText = failureLine ?? terminalBody?.description ?? summary;
@@ -1131,7 +1145,7 @@ window.__ModuleLoader__.load({
1131
1145
  const fileLinkKeyDown = (event) => {
1132
1146
  if (event.key === "Enter" || event.key === " ") event.stopPropagation();
1133
1147
  };
1134
- const cardBody = variant === "code" ? null : body;
1148
+ const cardBody = variant === "code" ? null : bodyText;
1135
1149
  return (0, react_jsx_runtime.jsxs)("div", {
1136
1150
  className: ToolRow_module_css_default.root,
1137
1151
  "data-variant": variant,
@@ -1201,10 +1215,10 @@ window.__ModuleLoader__.load({
1201
1215
  ...webBody,
1202
1216
  labels: webLabels,
1203
1217
  className: ToolRow_module_css_default.webBody
1204
- }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [variant === "code" && body !== null && (0, react_jsx_runtime.jsx)("div", {
1218
+ }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [variant === "code" && bodyText !== null && (0, react_jsx_runtime.jsx)("div", {
1205
1219
  className: ToolRow_module_css_default.bodyScroll,
1206
1220
  children: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.CodeBlock, {
1207
- code: body,
1221
+ code: bodyText,
1208
1222
  lang: "typescript",
1209
1223
  copyLabel: t("copy"),
1210
1224
  copiedLabel: t("copied"),
@@ -1277,7 +1291,7 @@ window.__ModuleLoader__.load({
1277
1291
  icon: VARIANT_ICONS[model.variant],
1278
1292
  title: t(model.titleKey),
1279
1293
  summary: model.summary,
1280
- body: singleFile ? null : model.body,
1294
+ bodyRaw: singleFile ? null : model.bodyRaw,
1281
1295
  output: model.output,
1282
1296
  errorSummary: model.errorSummary,
1283
1297
  terminal,
@@ -1622,7 +1636,7 @@ window.__ModuleLoader__.load({
1622
1636
  icon: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.IconQuestionOutline14, {}),
1623
1637
  title: t("ask.rowTitle"),
1624
1638
  summary,
1625
- body: transcript === null ? model.body : null,
1639
+ bodyRaw: transcript === null ? model.bodyRaw : null,
1626
1640
  output: transcript === null ? model.output : null,
1627
1641
  askQuestion: transcript,
1628
1642
  state,
@@ -1700,9 +1714,15 @@ window.__ModuleLoader__.load({
1700
1714
  const state = model.state === "ok" && terminalModel !== null && terminalFailed(terminalModel) ? "error" : model.state;
1701
1715
  const status = stateStatus(state, t);
1702
1716
  const [expanded, setExpanded] = (0, react.useState)(false);
1703
- const genericBody = terminal === null && (model.state === "error" || isSettledPersistentShellCall(block)) && (model.body !== null || model.output !== null);
1717
+ const genericBody = terminal === null && (model.state === "error" || isSettledPersistentShellCall(block)) && (model.bodyRaw !== null || model.output !== null);
1704
1718
  const expandable = terminal !== null || genericBody;
1705
1719
  const open = expanded && expandable;
1720
+ const body = (0, react.useMemo)(() => open && genericBody && model.bodyRaw !== null ? formatToolBody(model.variant, model.bodyRaw) : null, [
1721
+ genericBody,
1722
+ model.bodyRaw,
1723
+ model.variant,
1724
+ open
1725
+ ]);
1706
1726
  const failureLine = model.state === "error" ? model.errorSummary : null;
1707
1727
  const toggleExpand = () => {
1708
1728
  setExpanded((v) => !v);
@@ -1761,17 +1781,17 @@ window.__ModuleLoader__.load({
1761
1781
  }) : (0, react_jsx_runtime.jsxs)("div", {
1762
1782
  className: bash_sample_module_css_default.ioCard,
1763
1783
  children: [
1764
- model.body !== null && (0, react_jsx_runtime.jsxs)("div", {
1784
+ body !== null && (0, react_jsx_runtime.jsxs)("div", {
1765
1785
  className: bash_sample_module_css_default.ioSection,
1766
1786
  children: [(0, react_jsx_runtime.jsx)("span", {
1767
1787
  className: bash_sample_module_css_default.ioLabel,
1768
1788
  children: t("row.input")
1769
1789
  }), (0, react_jsx_runtime.jsx)("span", {
1770
1790
  className: bash_sample_module_css_default.ioText,
1771
- children: model.body
1791
+ children: body
1772
1792
  })]
1773
1793
  }),
1774
- model.body !== null && model.output !== null && (0, react_jsx_runtime.jsx)("span", {
1794
+ body !== null && model.output !== null && (0, react_jsx_runtime.jsx)("span", {
1775
1795
  className: bash_sample_module_css_default.ioDivider,
1776
1796
  "aria-hidden": true
1777
1797
  }),
@@ -1823,7 +1843,6 @@ window.__ModuleLoader__.load({
1823
1843
  icon: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.IconEditOutline16, { size: 14 }),
1824
1844
  title: t(model.titleKey),
1825
1845
  summary: model.summary,
1826
- body: null,
1827
1846
  output: model.output,
1828
1847
  errorSummary: model.errorSummary,
1829
1848
  diff,
@@ -1867,7 +1886,6 @@ window.__ModuleLoader__.load({
1867
1886
  icon: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.IconBrowseOutline16, { size: 14 }),
1868
1887
  title: t(model.titleKey),
1869
1888
  summary: model.summary,
1870
- body: null,
1871
1889
  output: model.output,
1872
1890
  errorSummary: model.errorSummary,
1873
1891
  read,
@@ -1906,7 +1924,6 @@ window.__ModuleLoader__.load({
1906
1924
  icon: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.IconSearchOutline16, { size: 14 }),
1907
1925
  title: t(toolName === "grep" ? SEARCH_TITLE_KEYS.grep : toolName === "glob" ? SEARCH_TITLE_KEYS.glob : model.titleKey),
1908
1926
  summary: model.summary,
1909
- body: null,
1910
1927
  output: model.output,
1911
1928
  errorSummary: model.errorSummary,
1912
1929
  search,
@@ -2009,7 +2026,7 @@ window.__ModuleLoader__.load({
2009
2026
  title: t("todo.rowTitle"),
2010
2027
  summary: summary.text,
2011
2028
  summarySuffix: summary.extra > 0 ? `+${summary.extra}` : null,
2012
- body: model.body,
2029
+ bodyRaw: model.bodyRaw,
2013
2030
  output: model.output,
2014
2031
  errorSummary: model.errorSummary,
2015
2032
  state: model.state,
@@ -2046,7 +2063,6 @@ window.__ModuleLoader__.load({
2046
2063
  icon,
2047
2064
  title: t(toolName === "web_search" ? WEB_TITLE_KEYS.web_search : toolName === "web_fetch" ? WEB_TITLE_KEYS.web_fetch : model.titleKey),
2048
2065
  summary: model.summary,
2049
- body: null,
2050
2066
  output: model.output,
2051
2067
  errorSummary: model.errorSummary,
2052
2068
  web,
@@ -5,7 +5,7 @@ import { type ReadCardModel } from '../models/read-card-model.ts';
5
5
  import { type SearchCardModel } from '../models/search-card-model.ts';
6
6
  import { type TerminalCardModel } from '../models/terminal-card-model.ts';
7
7
  import type { AskQuestionCardModel } from '../models/ask-question-card-model.ts';
8
- import type { ToolRowState, ToolRowVariant } from '../models/tool-call-model.ts';
8
+ import { type ToolRowState, type ToolRowVariant } from '../models/tool-call-model.ts';
9
9
  import type { WebCardModelProps } from '../models/web-card-model.ts';
10
10
  export interface ToolRowProps {
11
11
  t: TranslateNS<'conversation'>;
@@ -23,8 +23,8 @@ export interface ToolRowProps {
23
23
  * error row, whose collapsed summary is the failure line instead.
24
24
  */
25
25
  summarySuffix?: string | null | undefined;
26
- /** Expanded-body input text; null = no input section. */
27
- body: string | null;
26
+ /** Original argument JSON formatted only while the row is expanded. */
27
+ bodyRaw?: string | null | undefined;
28
28
  /** Flattened result text for the expanded Output section; null/absent = no output section. */
29
29
  output?: string | null | undefined;
30
30
  /** Ask-user transcript card; card fields are mutually exclusive and replace text sections. */
@@ -51,5 +51,5 @@ export interface ToolRowProps {
51
51
  */
52
52
  inspect?: (() => void) | undefined;
53
53
  }
54
- export declare function ToolRow({ t, variant, toolName, icon, title, summary, summarySuffix, body, output, askQuestion, errorSummary, terminal, diff, read, search, web, state, filePath, onOpenFile, inspect, }: ToolRowProps): import("react").JSX.Element;
54
+ export declare function ToolRow({ t, variant, toolName, icon, title, summary, summarySuffix, bodyRaw, output, askQuestion, errorSummary, terminal, diff, read, search, web, state, filePath, onOpenFile, inspect, }: ToolRowProps): import("react").JSX.Element;
55
55
  //# sourceMappingURL=ToolRow.d.ts.map
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Pure row-model derivation for tool summary rows: variant classification,
3
- * one-line summary, expanded-body text, and flattened result output from the
4
- * frozen call slice. Input material comes from the call ARGUMENTS; output and
5
- * error material from the settled result node. A supported terminal call gets
6
- * its expanded body from `terminalCardModel` instead.
3
+ * one-line summary, expansion-time body input, and flattened result output
4
+ * from the frozen call slice. Input material comes from the call ARGUMENTS;
5
+ * output and error material from the settled result node. A supported terminal
6
+ * call gets its expanded body from `terminalCardModel` instead.
7
7
  */
8
8
  import type { ToolCallBlock, ToolResultNode } from '@prettier-ai/dsh-client-ui-chat/client';
9
9
  import type { LocaleKeysOf } from '@prettier-ai/dsh-client-ui-slots';
@@ -40,8 +40,8 @@ export interface ToolRowModel {
40
40
  * relative values against the session cwd before opening.
41
41
  */
42
42
  filePath: string | undefined;
43
- /** Expanded-body input text (pretty args); null = no input section. */
44
- body: string | null;
43
+ /** Original argument JSON retained for expansion-time body formatting. */
44
+ bodyRaw: string | null;
45
45
  /** Flattened result text ({@link resultText}); null while running or when the result carries no text. */
46
46
  output: string | null;
47
47
  /** First line of the result text on an error row; null for every other state. */
@@ -63,6 +63,13 @@ export declare function resultText(node: ToolResultNode): string;
63
63
  * @returns the path relative to the workspace root, or unchanged when it is not rooted there.
64
64
  */
65
65
  export declare function relativizeToCwd(text: string, cwd: string | undefined): string;
66
+ /**
67
+ * Format one argument payload when its generic input body becomes visible.
68
+ * @param variant - row presentation selected for the Tool name.
69
+ * @param argsRaw - original argument JSON or incomplete raw text.
70
+ * @returns display body, or null for empty input.
71
+ */
72
+ export declare function formatToolBody(variant: ToolRowVariant, argsRaw: string): string | null;
66
73
  /**
67
74
  * Derive the full row model from a frozen call slice.
68
75
  * @param toolName - wire tool name (dispatch-supplied; survives windowless results).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@prettier-ai/dsh-client-ui-tool",
3
3
  "description": "Client Tool call-tree renderer and keyed per-tool presentation slot",
4
- "version": "0.1.2-alpha.2",
4
+ "version": "0.1.2-alpha.3",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -53,19 +53,19 @@
53
53
  "react": "^18.2.0",
54
54
  "react-dom": "^18.2.0",
55
55
  "@prettier-ai/cordis": "^4.0.2",
56
- "@prettier-ai/dsh-api-remotes": "^0.1.2-alpha.2",
57
- "@prettier-ai/dsh-client-connection": "^0.1.2-alpha.2",
58
- "@prettier-ai/dsh-client-locale": "^0.1.2-alpha.2",
59
- "@prettier-ai/dsh-client-test-runtime": "^0.1.2-alpha.2",
60
- "@prettier-ai/dsh-client-ui-conversation": "^0.1.2-alpha.2",
61
- "@prettier-ai/dsh-client-ui-primitives": "^0.1.2-alpha.2",
62
- "@prettier-ai/dsh-invariants": "^0.1.2-alpha.2",
63
- "@prettier-ai/dsh-client-ui-slots": "^0.1.2-alpha.2",
64
- "@prettier-ai/dsh-client-ui-chat": "^0.1.2-alpha.2",
65
- "@prettier-ai/dsh-client-ui-renderer": "^0.1.2-alpha.2",
66
- "@prettier-ai/dsh-client-ui-session": "^0.1.2-alpha.2",
67
- "@prettier-ai/dsh-api-workspace-controller": "^0.1.2-alpha.2",
68
- "@prettier-ai/dsh-util-workspace-path": "^0.1.2-alpha.2"
56
+ "@prettier-ai/dsh-api-remotes": "^0.1.2-alpha.3",
57
+ "@prettier-ai/dsh-client-connection": "^0.1.2-alpha.3",
58
+ "@prettier-ai/dsh-client-locale": "^0.1.2-alpha.3",
59
+ "@prettier-ai/dsh-client-ui-conversation": "^0.1.2-alpha.3",
60
+ "@prettier-ai/dsh-client-test-runtime": "^0.1.2-alpha.3",
61
+ "@prettier-ai/dsh-client-ui-primitives": "^0.1.2-alpha.3",
62
+ "@prettier-ai/dsh-invariants": "^0.1.2-alpha.3",
63
+ "@prettier-ai/dsh-api-workspace-controller": "^0.1.2-alpha.3",
64
+ "@prettier-ai/dsh-client-ui-renderer": "^0.1.2-alpha.3",
65
+ "@prettier-ai/dsh-client-ui-session": "^0.1.2-alpha.3",
66
+ "@prettier-ai/dsh-util-workspace-path": "^0.1.2-alpha.3",
67
+ "@prettier-ai/dsh-client-ui-chat": "^0.1.2-alpha.3",
68
+ "@prettier-ai/dsh-client-ui-slots": "^0.1.2-alpha.3"
69
69
  },
70
70
  "files": [
71
71
  "lib/index.js",