indusagi 0.13.1 → 0.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.13.2]
4
+
5
+ ### Added
6
+ - **Saffron Tool-Event Grammar**: `react-ink` `ToolEventBlock` now renders every tool call/result with a colour-keyed `●` status dot (running → accent, success → green, error → red), a **bold** neutral tool name, a dim `(summary)`, and a `└` elbow connector on result lines — replacing the old `>` / `=` / `!` markers.
7
+ - **Collapsed / Expanded Tool Output**: new `COLLAPSED_CONTENT_LINES` (2) and `EXPANDED_CONTENT_LINES` (20) exports. A collapsed tool reads as a tight 2–3 line block (`● Action` + `└ summary` + `… N more line(s)`); expanding lifts the cap to ~20 lines. The overflow marker takes an optional `moreHint` prop (e.g. `ctrl+o to expand`).
8
+
9
+ ### Changed
10
+ - **Diff Tool Header**: `ToolResultBlock` shows the edit/write change-summary as a `└` line above the colored diff block (collapsed cap `0`→`1`).
11
+ - **TaskPanel**: the "Tool Activity" header renders only when there are tool rows — an empty list shows nothing.
12
+ - **Version Bump**: Updated package version to `0.13.2`.
13
+
3
14
  ## [0.13.1]
4
15
 
5
16
  ### Added
package/dist/cli.js CHANGED
@@ -10430,19 +10430,22 @@ function describeToolResult(message, showImages, args, theme) {
10430
10430
 
10431
10431
  // src/react-ink/components/ToolEventBlock.tsx
10432
10432
  import stripAnsi5 from "strip-ansi";
10433
- function statusMarker(status) {
10433
+ var STATUS_DOT = "\u25CF";
10434
+ var COLLAPSED_CONTENT_LINES = 2;
10435
+ var EXPANDED_CONTENT_LINES = 20;
10436
+ function contentConnector(isFirst) {
10437
+ return isFirst ? "\u2514 " : " ";
10438
+ }
10439
+ function statusColorKey(status) {
10434
10440
  switch (status) {
10435
10441
  case "error":
10436
- return "!";
10442
+ return "error";
10437
10443
  case "success":
10438
- return "=";
10444
+ return "success";
10439
10445
  default:
10440
- return ">";
10446
+ return "accent";
10441
10447
  }
10442
10448
  }
10443
- function statusColorKey(status) {
10444
- return status === "error" ? "error" : "text";
10445
- }
10446
10449
  function plainToolText(text) {
10447
10450
  return stripAnsi5(text);
10448
10451
  }
@@ -10478,7 +10481,8 @@ function ToolEventBlock({
10478
10481
  emptyText,
10479
10482
  indent = 0,
10480
10483
  marginBottom = 1,
10481
- maxContentLines = 10,
10484
+ maxContentLines = COLLAPSED_CONTENT_LINES,
10485
+ moreHint,
10482
10486
  preformatted = false,
10483
10487
  showSummaryInline = false,
10484
10488
  showTitle = true,
@@ -10498,21 +10502,22 @@ function ToolEventBlock({
10498
10502
  ...detailLines.map((text) => ({ kind: "detail", text }))
10499
10503
  ];
10500
10504
  const { visibleLines, hiddenLineCount } = clampContentLines(combinedLines, maxContentLines);
10505
+ const contentIndent = showTitle ? 2 : 0;
10501
10506
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom, marginLeft: indent, children: [
10502
10507
  showTitle ? /* @__PURE__ */ jsxs(Box, { children: [
10503
- /* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), plainToolText(`${statusMarker(status)} `)) }),
10504
- /* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), plainToolText(title)) }),
10508
+ /* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), `${STATUS_DOT} `) }),
10509
+ /* @__PURE__ */ jsx(Text, { bold: true, children: theme.color("text", plainToolText(title)) }),
10505
10510
  showSummaryInline && normalizedSummary ? /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(` (${normalizedSummary})`)) }) : null
10506
10511
  ] }) : null,
10507
- visibleLines.map((line, index) => /* @__PURE__ */ jsx(
10508
- Box,
10509
- {
10510
- marginLeft: line.kind === "response" ? showTitle ? 2 : 0 : showTitle ? 4 : 2,
10511
- children: preformatted ? /* @__PURE__ */ jsx(Text, { children: line.text }) : /* @__PURE__ */ jsx(Text, { children: theme.color("text", plainToolText(line.text)) })
10512
- },
10513
- `${line.kind}:${index}:${stripAnsi5(line.text)}`
10514
- )),
10515
- hiddenLineCount > 0 ? /* @__PURE__ */ jsx(Box, { marginLeft: showTitle ? 4 : 2, children: /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(`... ${hiddenLineCount} more line(s)`)) }) }) : null
10512
+ visibleLines.map((line, index) => /* @__PURE__ */ jsxs(Box, { marginLeft: contentIndent, children: [
10513
+ /* @__PURE__ */ jsx(Text, { children: theme.dim(contentConnector(index === 0)) }),
10514
+ preformatted ? /* @__PURE__ */ jsx(Text, { children: line.text }) : /* @__PURE__ */ jsx(Text, { children: theme.color("text", plainToolText(line.text)) })
10515
+ ] }, `${line.kind}:${index}:${stripAnsi5(line.text)}`)),
10516
+ hiddenLineCount > 0 ? /* @__PURE__ */ jsxs(Box, { marginLeft: contentIndent, children: [
10517
+ /* @__PURE__ */ jsx(Text, { children: theme.dim(contentConnector(visibleLines.length === 0)) }),
10518
+ /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(`\u2026 ${hiddenLineCount} more line(s)`)) }),
10519
+ moreHint ? /* @__PURE__ */ jsx(Text, { children: theme.dim(plainToolText(` \xB7 ${moreHint}`)) }) : null
10520
+ ] }) : null
10516
10521
  ] });
10517
10522
  }
10518
10523
 
@@ -10608,7 +10613,7 @@ function ToolResultBlock({ expanded = false, message, nested = false, showImages
10608
10613
  emptyText: descriptor.emptyText,
10609
10614
  indent,
10610
10615
  marginBottom: 0,
10611
- maxContentLines: 0,
10616
+ maxContentLines: 1,
10612
10617
  showSummaryInline: false,
10613
10618
  showTitle: !nested,
10614
10619
  status: message.isError ? "error" : "success",
@@ -10627,7 +10632,8 @@ function ToolResultBlock({ expanded = false, message, nested = false, showImages
10627
10632
  emptyText: descriptor.emptyText,
10628
10633
  indent,
10629
10634
  marginBottom: 0,
10630
- maxContentLines: expanded ? Number.MAX_SAFE_INTEGER : 10,
10635
+ maxContentLines: expanded ? EXPANDED_CONTENT_LINES : COLLAPSED_CONTENT_LINES,
10636
+ moreHint: expanded ? "ctrl+o to collapse" : "ctrl+o to expand",
10631
10637
  preformatted: descriptor.preformatted,
10632
10638
  showSummaryInline: false,
10633
10639
  showTitle: !nested,
@@ -10892,7 +10898,7 @@ function TaskPanel({ expandToolOutputs = false, pendingMessages = [], snapshot,
10892
10898
  return null;
10893
10899
  }
10894
10900
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, marginTop: 1, children: [
10895
- /* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Tool Activity${recent.length > 0 ? ` ${recent.length}` : ""}`) }),
10901
+ recent.length > 0 ? /* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Tool Activity ${recent.length}`) }) : null,
10896
10902
  recent.map((tool) => {
10897
10903
  const descriptor = describeToolExecution(tool);
10898
10904
  return /* @__PURE__ */ jsx(
@@ -10902,7 +10908,8 @@ function TaskPanel({ expandToolOutputs = false, pendingMessages = [], snapshot,
10902
10908
  emptyText: descriptor.emptyText,
10903
10909
  indent: 1,
10904
10910
  marginBottom: 0,
10905
- maxContentLines: expandToolOutputs ? Number.MAX_SAFE_INTEGER : 10,
10911
+ maxContentLines: expandToolOutputs ? EXPANDED_CONTENT_LINES : COLLAPSED_CONTENT_LINES,
10912
+ moreHint: expandToolOutputs ? "ctrl+o to collapse" : "ctrl+o to expand",
10906
10913
  showSummaryInline: true,
10907
10914
  status: tool.status,
10908
10915
  summary: descriptor.summary,
package/dist/index.js CHANGED
@@ -14759,19 +14759,22 @@ function describeToolResult(message, showImages, args, theme) {
14759
14759
 
14760
14760
  // src/react-ink/components/ToolEventBlock.tsx
14761
14761
  import stripAnsi5 from "strip-ansi";
14762
- function statusMarker(status) {
14762
+ var STATUS_DOT = "\u25CF";
14763
+ var COLLAPSED_CONTENT_LINES = 2;
14764
+ var EXPANDED_CONTENT_LINES = 20;
14765
+ function contentConnector(isFirst) {
14766
+ return isFirst ? "\u2514 " : " ";
14767
+ }
14768
+ function statusColorKey(status) {
14763
14769
  switch (status) {
14764
14770
  case "error":
14765
- return "!";
14771
+ return "error";
14766
14772
  case "success":
14767
- return "=";
14773
+ return "success";
14768
14774
  default:
14769
- return ">";
14775
+ return "accent";
14770
14776
  }
14771
14777
  }
14772
- function statusColorKey(status) {
14773
- return status === "error" ? "error" : "text";
14774
- }
14775
14778
  function plainToolText(text) {
14776
14779
  return stripAnsi5(text);
14777
14780
  }
@@ -14807,7 +14810,8 @@ function ToolEventBlock({
14807
14810
  emptyText,
14808
14811
  indent = 0,
14809
14812
  marginBottom = 1,
14810
- maxContentLines = 10,
14813
+ maxContentLines = COLLAPSED_CONTENT_LINES,
14814
+ moreHint,
14811
14815
  preformatted = false,
14812
14816
  showSummaryInline = false,
14813
14817
  showTitle = true,
@@ -14827,21 +14831,22 @@ function ToolEventBlock({
14827
14831
  ...detailLines.map((text) => ({ kind: "detail", text }))
14828
14832
  ];
14829
14833
  const { visibleLines, hiddenLineCount } = clampContentLines(combinedLines, maxContentLines);
14834
+ const contentIndent = showTitle ? 2 : 0;
14830
14835
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom, marginLeft: indent, children: [
14831
14836
  showTitle ? /* @__PURE__ */ jsxs(Box, { children: [
14832
- /* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), plainToolText(`${statusMarker(status)} `)) }),
14833
- /* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), plainToolText(title)) }),
14837
+ /* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), `${STATUS_DOT} `) }),
14838
+ /* @__PURE__ */ jsx(Text, { bold: true, children: theme.color("text", plainToolText(title)) }),
14834
14839
  showSummaryInline && normalizedSummary ? /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(` (${normalizedSummary})`)) }) : null
14835
14840
  ] }) : null,
14836
- visibleLines.map((line4, index) => /* @__PURE__ */ jsx(
14837
- Box,
14838
- {
14839
- marginLeft: line4.kind === "response" ? showTitle ? 2 : 0 : showTitle ? 4 : 2,
14840
- children: preformatted ? /* @__PURE__ */ jsx(Text, { children: line4.text }) : /* @__PURE__ */ jsx(Text, { children: theme.color("text", plainToolText(line4.text)) })
14841
- },
14842
- `${line4.kind}:${index}:${stripAnsi5(line4.text)}`
14843
- )),
14844
- hiddenLineCount > 0 ? /* @__PURE__ */ jsx(Box, { marginLeft: showTitle ? 4 : 2, children: /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(`... ${hiddenLineCount} more line(s)`)) }) }) : null
14841
+ visibleLines.map((line4, index) => /* @__PURE__ */ jsxs(Box, { marginLeft: contentIndent, children: [
14842
+ /* @__PURE__ */ jsx(Text, { children: theme.dim(contentConnector(index === 0)) }),
14843
+ preformatted ? /* @__PURE__ */ jsx(Text, { children: line4.text }) : /* @__PURE__ */ jsx(Text, { children: theme.color("text", plainToolText(line4.text)) })
14844
+ ] }, `${line4.kind}:${index}:${stripAnsi5(line4.text)}`)),
14845
+ hiddenLineCount > 0 ? /* @__PURE__ */ jsxs(Box, { marginLeft: contentIndent, children: [
14846
+ /* @__PURE__ */ jsx(Text, { children: theme.dim(contentConnector(visibleLines.length === 0)) }),
14847
+ /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(`\u2026 ${hiddenLineCount} more line(s)`)) }),
14848
+ moreHint ? /* @__PURE__ */ jsx(Text, { children: theme.dim(plainToolText(` \xB7 ${moreHint}`)) }) : null
14849
+ ] }) : null
14845
14850
  ] });
14846
14851
  }
14847
14852
 
@@ -14937,7 +14942,7 @@ function ToolResultBlock({ expanded = false, message, nested = false, showImages
14937
14942
  emptyText: descriptor.emptyText,
14938
14943
  indent,
14939
14944
  marginBottom: 0,
14940
- maxContentLines: 0,
14945
+ maxContentLines: 1,
14941
14946
  showSummaryInline: false,
14942
14947
  showTitle: !nested,
14943
14948
  status: message.isError ? "error" : "success",
@@ -14956,7 +14961,8 @@ function ToolResultBlock({ expanded = false, message, nested = false, showImages
14956
14961
  emptyText: descriptor.emptyText,
14957
14962
  indent,
14958
14963
  marginBottom: 0,
14959
- maxContentLines: expanded ? Number.MAX_SAFE_INTEGER : 10,
14964
+ maxContentLines: expanded ? EXPANDED_CONTENT_LINES : COLLAPSED_CONTENT_LINES,
14965
+ moreHint: expanded ? "ctrl+o to collapse" : "ctrl+o to expand",
14960
14966
  preformatted: descriptor.preformatted,
14961
14967
  showSummaryInline: false,
14962
14968
  showTitle: !nested,
@@ -15221,7 +15227,7 @@ function TaskPanel({ expandToolOutputs = false, pendingMessages = [], snapshot,
15221
15227
  return null;
15222
15228
  }
15223
15229
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, marginTop: 1, children: [
15224
- /* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Tool Activity${recent.length > 0 ? ` ${recent.length}` : ""}`) }),
15230
+ recent.length > 0 ? /* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Tool Activity ${recent.length}`) }) : null,
15225
15231
  recent.map((tool) => {
15226
15232
  const descriptor = describeToolExecution(tool);
15227
15233
  return /* @__PURE__ */ jsx(
@@ -15231,7 +15237,8 @@ function TaskPanel({ expandToolOutputs = false, pendingMessages = [], snapshot,
15231
15237
  emptyText: descriptor.emptyText,
15232
15238
  indent: 1,
15233
15239
  marginBottom: 0,
15234
- maxContentLines: expandToolOutputs ? Number.MAX_SAFE_INTEGER : 10,
15240
+ maxContentLines: expandToolOutputs ? EXPANDED_CONTENT_LINES : COLLAPSED_CONTENT_LINES,
15241
+ moreHint: expandToolOutputs ? "ctrl+o to collapse" : "ctrl+o to expand",
15235
15242
  showSummaryInline: true,
15236
15243
  status: tool.status,
15237
15244
  summary: descriptor.summary,
package/dist/react-ink.js CHANGED
@@ -2051,19 +2051,22 @@ function describeToolResult(message, showImages, args, theme) {
2051
2051
 
2052
2052
  // src/react-ink/components/ToolEventBlock.tsx
2053
2053
  import stripAnsi5 from "strip-ansi";
2054
- function statusMarker(status) {
2054
+ var STATUS_DOT = "\u25CF";
2055
+ var COLLAPSED_CONTENT_LINES = 2;
2056
+ var EXPANDED_CONTENT_LINES = 20;
2057
+ function contentConnector(isFirst) {
2058
+ return isFirst ? "\u2514 " : " ";
2059
+ }
2060
+ function statusColorKey(status) {
2055
2061
  switch (status) {
2056
2062
  case "error":
2057
- return "!";
2063
+ return "error";
2058
2064
  case "success":
2059
- return "=";
2065
+ return "success";
2060
2066
  default:
2061
- return ">";
2067
+ return "accent";
2062
2068
  }
2063
2069
  }
2064
- function statusColorKey(status) {
2065
- return status === "error" ? "error" : "text";
2066
- }
2067
2070
  function plainToolText(text) {
2068
2071
  return stripAnsi5(text);
2069
2072
  }
@@ -2099,7 +2102,8 @@ function ToolEventBlock({
2099
2102
  emptyText,
2100
2103
  indent = 0,
2101
2104
  marginBottom = 1,
2102
- maxContentLines = 10,
2105
+ maxContentLines = COLLAPSED_CONTENT_LINES,
2106
+ moreHint,
2103
2107
  preformatted = false,
2104
2108
  showSummaryInline = false,
2105
2109
  showTitle = true,
@@ -2119,21 +2123,22 @@ function ToolEventBlock({
2119
2123
  ...detailLines.map((text) => ({ kind: "detail", text }))
2120
2124
  ];
2121
2125
  const { visibleLines, hiddenLineCount } = clampContentLines(combinedLines, maxContentLines);
2126
+ const contentIndent = showTitle ? 2 : 0;
2122
2127
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom, marginLeft: indent, children: [
2123
2128
  showTitle ? /* @__PURE__ */ jsxs(Box, { children: [
2124
- /* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), plainToolText(`${statusMarker(status)} `)) }),
2125
- /* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), plainToolText(title)) }),
2129
+ /* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), `${STATUS_DOT} `) }),
2130
+ /* @__PURE__ */ jsx(Text, { bold: true, children: theme.color("text", plainToolText(title)) }),
2126
2131
  showSummaryInline && normalizedSummary ? /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(` (${normalizedSummary})`)) }) : null
2127
2132
  ] }) : null,
2128
- visibleLines.map((line, index) => /* @__PURE__ */ jsx(
2129
- Box,
2130
- {
2131
- marginLeft: line.kind === "response" ? showTitle ? 2 : 0 : showTitle ? 4 : 2,
2132
- children: preformatted ? /* @__PURE__ */ jsx(Text, { children: line.text }) : /* @__PURE__ */ jsx(Text, { children: theme.color("text", plainToolText(line.text)) })
2133
- },
2134
- `${line.kind}:${index}:${stripAnsi5(line.text)}`
2135
- )),
2136
- hiddenLineCount > 0 ? /* @__PURE__ */ jsx(Box, { marginLeft: showTitle ? 4 : 2, children: /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(`... ${hiddenLineCount} more line(s)`)) }) }) : null
2133
+ visibleLines.map((line, index) => /* @__PURE__ */ jsxs(Box, { marginLeft: contentIndent, children: [
2134
+ /* @__PURE__ */ jsx(Text, { children: theme.dim(contentConnector(index === 0)) }),
2135
+ preformatted ? /* @__PURE__ */ jsx(Text, { children: line.text }) : /* @__PURE__ */ jsx(Text, { children: theme.color("text", plainToolText(line.text)) })
2136
+ ] }, `${line.kind}:${index}:${stripAnsi5(line.text)}`)),
2137
+ hiddenLineCount > 0 ? /* @__PURE__ */ jsxs(Box, { marginLeft: contentIndent, children: [
2138
+ /* @__PURE__ */ jsx(Text, { children: theme.dim(contentConnector(visibleLines.length === 0)) }),
2139
+ /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(`\u2026 ${hiddenLineCount} more line(s)`)) }),
2140
+ moreHint ? /* @__PURE__ */ jsx(Text, { children: theme.dim(plainToolText(` \xB7 ${moreHint}`)) }) : null
2141
+ ] }) : null
2137
2142
  ] });
2138
2143
  }
2139
2144
 
@@ -2229,7 +2234,7 @@ function ToolResultBlock({ expanded = false, message, nested = false, showImages
2229
2234
  emptyText: descriptor.emptyText,
2230
2235
  indent,
2231
2236
  marginBottom: 0,
2232
- maxContentLines: 0,
2237
+ maxContentLines: 1,
2233
2238
  showSummaryInline: false,
2234
2239
  showTitle: !nested,
2235
2240
  status: message.isError ? "error" : "success",
@@ -2248,7 +2253,8 @@ function ToolResultBlock({ expanded = false, message, nested = false, showImages
2248
2253
  emptyText: descriptor.emptyText,
2249
2254
  indent,
2250
2255
  marginBottom: 0,
2251
- maxContentLines: expanded ? Number.MAX_SAFE_INTEGER : 10,
2256
+ maxContentLines: expanded ? EXPANDED_CONTENT_LINES : COLLAPSED_CONTENT_LINES,
2257
+ moreHint: expanded ? "ctrl+o to collapse" : "ctrl+o to expand",
2252
2258
  preformatted: descriptor.preformatted,
2253
2259
  showSummaryInline: false,
2254
2260
  showTitle: !nested,
@@ -2513,7 +2519,7 @@ function TaskPanel({ expandToolOutputs = false, pendingMessages = [], snapshot,
2513
2519
  return null;
2514
2520
  }
2515
2521
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, marginTop: 1, children: [
2516
- /* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Tool Activity${recent.length > 0 ? ` ${recent.length}` : ""}`) }),
2522
+ recent.length > 0 ? /* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Tool Activity ${recent.length}`) }) : null,
2517
2523
  recent.map((tool) => {
2518
2524
  const descriptor = describeToolExecution(tool);
2519
2525
  return /* @__PURE__ */ jsx(
@@ -2523,7 +2529,8 @@ function TaskPanel({ expandToolOutputs = false, pendingMessages = [], snapshot,
2523
2529
  emptyText: descriptor.emptyText,
2524
2530
  indent: 1,
2525
2531
  marginBottom: 0,
2526
- maxContentLines: expandToolOutputs ? Number.MAX_SAFE_INTEGER : 10,
2532
+ maxContentLines: expandToolOutputs ? EXPANDED_CONTENT_LINES : COLLAPSED_CONTENT_LINES,
2533
+ moreHint: expandToolOutputs ? "ctrl+o to collapse" : "ctrl+o to expand",
2527
2534
  showSummaryInline: true,
2528
2535
  status: tool.status,
2529
2536
  summary: descriptor.summary,
@@ -3759,6 +3766,7 @@ export {
3759
3766
  BashMessageView,
3760
3767
  BranchSummaryMessageView,
3761
3768
  CHANGE_THRESHOLD,
3769
+ COLLAPSED_CONTENT_LINES,
3762
3770
  CONTEXT_LINES,
3763
3771
  ChangelogBlock,
3764
3772
  CompactionMessageView,
@@ -3766,6 +3774,7 @@ export {
3766
3774
  DialogFrame,
3767
3775
  Diff,
3768
3776
  DisplayBlockView,
3777
+ EXPANDED_CONTENT_LINES,
3769
3778
  Footer,
3770
3779
  LoginDialog,
3771
3780
  Markdown,
package/dist/shell-app.js CHANGED
@@ -10438,19 +10438,22 @@ function describeToolResult(message, showImages, args, theme) {
10438
10438
 
10439
10439
  // src/react-ink/components/ToolEventBlock.tsx
10440
10440
  import stripAnsi5 from "strip-ansi";
10441
- function statusMarker(status) {
10441
+ var STATUS_DOT = "\u25CF";
10442
+ var COLLAPSED_CONTENT_LINES = 2;
10443
+ var EXPANDED_CONTENT_LINES = 20;
10444
+ function contentConnector(isFirst) {
10445
+ return isFirst ? "\u2514 " : " ";
10446
+ }
10447
+ function statusColorKey(status) {
10442
10448
  switch (status) {
10443
10449
  case "error":
10444
- return "!";
10450
+ return "error";
10445
10451
  case "success":
10446
- return "=";
10452
+ return "success";
10447
10453
  default:
10448
- return ">";
10454
+ return "accent";
10449
10455
  }
10450
10456
  }
10451
- function statusColorKey(status) {
10452
- return status === "error" ? "error" : "text";
10453
- }
10454
10457
  function plainToolText(text) {
10455
10458
  return stripAnsi5(text);
10456
10459
  }
@@ -10486,7 +10489,8 @@ function ToolEventBlock({
10486
10489
  emptyText,
10487
10490
  indent = 0,
10488
10491
  marginBottom = 1,
10489
- maxContentLines = 10,
10492
+ maxContentLines = COLLAPSED_CONTENT_LINES,
10493
+ moreHint,
10490
10494
  preformatted = false,
10491
10495
  showSummaryInline = false,
10492
10496
  showTitle = true,
@@ -10506,21 +10510,22 @@ function ToolEventBlock({
10506
10510
  ...detailLines.map((text) => ({ kind: "detail", text }))
10507
10511
  ];
10508
10512
  const { visibleLines, hiddenLineCount } = clampContentLines(combinedLines, maxContentLines);
10513
+ const contentIndent = showTitle ? 2 : 0;
10509
10514
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom, marginLeft: indent, children: [
10510
10515
  showTitle ? /* @__PURE__ */ jsxs(Box, { children: [
10511
- /* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), plainToolText(`${statusMarker(status)} `)) }),
10512
- /* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), plainToolText(title)) }),
10516
+ /* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), `${STATUS_DOT} `) }),
10517
+ /* @__PURE__ */ jsx(Text, { bold: true, children: theme.color("text", plainToolText(title)) }),
10513
10518
  showSummaryInline && normalizedSummary ? /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(` (${normalizedSummary})`)) }) : null
10514
10519
  ] }) : null,
10515
- visibleLines.map((line, index) => /* @__PURE__ */ jsx(
10516
- Box,
10517
- {
10518
- marginLeft: line.kind === "response" ? showTitle ? 2 : 0 : showTitle ? 4 : 2,
10519
- children: preformatted ? /* @__PURE__ */ jsx(Text, { children: line.text }) : /* @__PURE__ */ jsx(Text, { children: theme.color("text", plainToolText(line.text)) })
10520
- },
10521
- `${line.kind}:${index}:${stripAnsi5(line.text)}`
10522
- )),
10523
- hiddenLineCount > 0 ? /* @__PURE__ */ jsx(Box, { marginLeft: showTitle ? 4 : 2, children: /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(`... ${hiddenLineCount} more line(s)`)) }) }) : null
10520
+ visibleLines.map((line, index) => /* @__PURE__ */ jsxs(Box, { marginLeft: contentIndent, children: [
10521
+ /* @__PURE__ */ jsx(Text, { children: theme.dim(contentConnector(index === 0)) }),
10522
+ preformatted ? /* @__PURE__ */ jsx(Text, { children: line.text }) : /* @__PURE__ */ jsx(Text, { children: theme.color("text", plainToolText(line.text)) })
10523
+ ] }, `${line.kind}:${index}:${stripAnsi5(line.text)}`)),
10524
+ hiddenLineCount > 0 ? /* @__PURE__ */ jsxs(Box, { marginLeft: contentIndent, children: [
10525
+ /* @__PURE__ */ jsx(Text, { children: theme.dim(contentConnector(visibleLines.length === 0)) }),
10526
+ /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(`\u2026 ${hiddenLineCount} more line(s)`)) }),
10527
+ moreHint ? /* @__PURE__ */ jsx(Text, { children: theme.dim(plainToolText(` \xB7 ${moreHint}`)) }) : null
10528
+ ] }) : null
10524
10529
  ] });
10525
10530
  }
10526
10531
 
@@ -10616,7 +10621,7 @@ function ToolResultBlock({ expanded = false, message, nested = false, showImages
10616
10621
  emptyText: descriptor.emptyText,
10617
10622
  indent,
10618
10623
  marginBottom: 0,
10619
- maxContentLines: 0,
10624
+ maxContentLines: 1,
10620
10625
  showSummaryInline: false,
10621
10626
  showTitle: !nested,
10622
10627
  status: message.isError ? "error" : "success",
@@ -10635,7 +10640,8 @@ function ToolResultBlock({ expanded = false, message, nested = false, showImages
10635
10640
  emptyText: descriptor.emptyText,
10636
10641
  indent,
10637
10642
  marginBottom: 0,
10638
- maxContentLines: expanded ? Number.MAX_SAFE_INTEGER : 10,
10643
+ maxContentLines: expanded ? EXPANDED_CONTENT_LINES : COLLAPSED_CONTENT_LINES,
10644
+ moreHint: expanded ? "ctrl+o to collapse" : "ctrl+o to expand",
10639
10645
  preformatted: descriptor.preformatted,
10640
10646
  showSummaryInline: false,
10641
10647
  showTitle: !nested,
@@ -10900,7 +10906,7 @@ function TaskPanel({ expandToolOutputs = false, pendingMessages = [], snapshot,
10900
10906
  return null;
10901
10907
  }
10902
10908
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, marginTop: 1, children: [
10903
- /* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Tool Activity${recent.length > 0 ? ` ${recent.length}` : ""}`) }),
10909
+ recent.length > 0 ? /* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Tool Activity ${recent.length}`) }) : null,
10904
10910
  recent.map((tool) => {
10905
10911
  const descriptor = describeToolExecution(tool);
10906
10912
  return /* @__PURE__ */ jsx(
@@ -10910,7 +10916,8 @@ function TaskPanel({ expandToolOutputs = false, pendingMessages = [], snapshot,
10910
10916
  emptyText: descriptor.emptyText,
10911
10917
  indent: 1,
10912
10918
  marginBottom: 0,
10913
- maxContentLines: expandToolOutputs ? Number.MAX_SAFE_INTEGER : 10,
10919
+ maxContentLines: expandToolOutputs ? EXPANDED_CONTENT_LINES : COLLAPSED_CONTENT_LINES,
10920
+ moreHint: expandToolOutputs ? "ctrl+o to collapse" : "ctrl+o to expand",
10914
10921
  showSummaryInline: true,
10915
10922
  status: tool.status,
10916
10923
  summary: descriptor.summary,
@@ -12,6 +12,12 @@ interface ToolEventBlockProps {
12
12
  showTitle?: boolean;
13
13
  showSummaryInline?: boolean;
14
14
  maxContentLines?: number;
15
+ /**
16
+ * Appended to the "… N more line(s)" overflow marker (e.g. "ctrl+o to
17
+ * expand"), so the user can discover how to reveal the folded output. Omitted
18
+ * → the bare count is shown.
19
+ */
20
+ moreHint?: string;
15
21
  /**
16
22
  * When true the detail body already carries syntax-highlight ANSI; render it
17
23
  * verbatim instead of stripping the escapes. stripAnsi is still used for the
@@ -20,6 +26,23 @@ interface ToolEventBlockProps {
20
26
  */
21
27
  preformatted?: boolean;
22
28
  }
29
+ /**
30
+ * How many content lines a collapsed tool event shows before the rest is folded
31
+ * behind a "… N more line(s)" affordance. Kept deliberately small so a tool reads
32
+ * as a tight two-to-three-line block (the ● action header plus a summary line),
33
+ * not a multi-line output dump; expanding a tool lifts this cap. Callers that
34
+ * render tool bodies (ToolResultBlock, TaskPanel) share this so the collapsed
35
+ * height is consistent everywhere.
36
+ */
37
+ export declare const COLLAPSED_CONTENT_LINES = 2;
38
+ /**
39
+ * How many content lines an *expanded* tool event shows (Ctrl+O). A bounded
40
+ * reveal — enough to actually read what a tool read/wrote/ran (10–20 lines)
41
+ * without flooding the transcript with a whole file; anything past it stays
42
+ * folded behind the "… N more" marker. Toggling Ctrl+O again collapses back to
43
+ * {@link COLLAPSED_CONTENT_LINES}.
44
+ */
45
+ export declare const EXPANDED_CONTENT_LINES = 20;
23
46
  export declare function statusColorKey(status: ToolEventStatus): string;
24
- export declare function ToolEventBlock({ detail, emptyText, indent, marginBottom, maxContentLines, preformatted, showSummaryInline, showTitle, status, summary, theme, title, }: ToolEventBlockProps): JSX.Element;
47
+ export declare function ToolEventBlock({ detail, emptyText, indent, marginBottom, maxContentLines, moreHint, preformatted, showSummaryInline, showTitle, status, summary, theme, title, }: ToolEventBlockProps): JSX.Element;
25
48
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "indusagi",
3
- "version": "0.13.1",
3
+ "version": "0.13.2",
4
4
  "description": "Indusagi — a terminal-first AI coding agent framework. Clean-room implementation.",
5
5
  "author": "Varun Israni",
6
6
  "license": "MIT",