@pi-kaush/pi-tool-call-markers 0.3.4 → 0.3.5
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.md +18 -12
- package/package.json +1 -1
- package/src/index.ts +99 -95
- package/src/muted.ts +4 -8
package/README.md
CHANGED
|
@@ -15,19 +15,16 @@ Restart Pi or run `/reload`.
|
|
|
15
15
|
Collapsed tool rows use semantic theme colors with no gear, background fill, box padding, or filled blank rows:
|
|
16
16
|
|
|
17
17
|
```text
|
|
18
|
-
│
|
|
19
|
-
│
|
|
20
|
-
│
|
|
21
|
-
│
|
|
22
|
-
│ Bash
|
|
23
|
-
│ $: npm test → done
|
|
18
|
+
│ ●: src/a.ts 42 lines
|
|
19
|
+
│ ●: src/b.ts 18 lines
|
|
20
|
+
│ $: npm test → done
|
|
24
21
|
```
|
|
25
22
|
|
|
26
23
|
- **Two-column outer inset.** Tool markers and image output align with an inset conversation surface. Very narrow terminals reduce the decoration before useful content.
|
|
27
|
-
- **`│` tool-call rail.**
|
|
28
|
-
- **Semantic, low-contrast status.**
|
|
24
|
+
- **`│` tool-call rail.** Every collapsed call anchors on a glyph instead of its tool name: `●` read, `+` write, `±` edit, `○` local search, `≡` ls, `↗` web search and fetch, and `$` bash; unmapped tools fall back to `*`. Grouped rows flow directly across tool types.
|
|
25
|
+
- **Semantic, low-contrast status.** The anchor and the call content share the collapsed mute, pending state is warning-colored, and failures remain error-colored. Ordinary tool states have no background.
|
|
29
26
|
- **Width-safe outcome tails.** Long summaries truncate before useful tails such as `→ done`, `→ 42 lines`, `→ +2/-1`, or a `bash` duration.
|
|
30
|
-
- **Stable running groups.** Adjacent calls group as they appear. Pending state and elapsed `bash` time settle into the final outcome without changing the row count.
|
|
27
|
+
- **Stable running groups.** Adjacent calls group as they appear, including settled failures, which stay error-colored inside the group. Pending state and elapsed `bash` time settle into the final outcome without changing the row count.
|
|
31
28
|
- **Quiet-turn grouping.** Sequential calls can join across an assistant row with no visible prose or thinking. Visible assistant content remains a boundary.
|
|
32
29
|
- **MCP and self-rendered tools.** Their stable call labels, compact arguments, pending state, success, and first error line use the same collapsed shell. Native self-rendered details return when expanded.
|
|
33
30
|
- **Images remain visible.** Image fallback text and terminal image components render below the corresponding marker with the same inset.
|
|
@@ -36,7 +33,7 @@ Collapsed tool rows use semantic theme colors with no gear, background fill, box
|
|
|
36
33
|
|
|
37
34
|
## Subagent plans
|
|
38
35
|
|
|
39
|
-
A recognized `subagent` call renders as an unboxed plan in the shared tool aesthetic, marked with `↪` instead of the ordinary
|
|
36
|
+
A recognized `subagent` call renders as an unboxed plan in the shared tool aesthetic, marked with `↪` instead of the ordinary `│` tool-call rail:
|
|
40
37
|
|
|
41
38
|
```text
|
|
42
39
|
↪ subagent chain (3 steps) [repo-review]
|
|
@@ -52,7 +49,7 @@ Malformed, ambiguous, future, or too-narrow shapes fall back to the generic `↪
|
|
|
52
49
|
|
|
53
50
|
## Edit diffs
|
|
54
51
|
|
|
55
|
-
Settled `edit` calls
|
|
52
|
+
Settled `edit` calls collapse like every other row: the call line keeps its path and a `+added/-removed` outcome stat, and the hunk itself stays out of the collapsed row. `Ctrl+O` restores Pi's full native diff, including line numbers and intra-line word highlights. To keep edits expanded without pressing `Ctrl+O`, list `edit` in `PI_ALWAYS_EXPANDED_TOOL_CALL_MARKERS` (see Configuration).
|
|
56
53
|
|
|
57
54
|
Files and paths in collapsed rows are preserved as displayed by Pi: hyperlink-wrapped paths (Pi wraps `read` call paths in OSC 8 hyperlinks) keep their visible text when sanitized for one-line rows.
|
|
58
55
|
|
|
@@ -102,9 +99,18 @@ pi
|
|
|
102
99
|
|
|
103
100
|
`0`, `false`, `no`, and `off` disable parallel grouping. `1`, `true`, `yes`, and `on` enable it. The value is read when the extension loads.
|
|
104
101
|
|
|
102
|
+
To render chosen tools as Pi's native expanded block by default — full result and diff without `Ctrl+O` — list their names:
|
|
103
|
+
|
|
104
|
+
```fish
|
|
105
|
+
set -lx PI_ALWAYS_EXPANDED_TOOL_CALL_MARKERS edit,write
|
|
106
|
+
pi
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Names are comma-separated and matched exactly. Listed rows never join a group, and the list stays authoritative: collapsing the transcript with `Ctrl+O` re-expands them. The value is read when the extension loads.
|
|
110
|
+
|
|
105
111
|
### Collapsed-row colors
|
|
106
112
|
|
|
107
|
-
Collapsed rows (tool calls, `+ Thought`, subagents) default to the theme's `syntaxComment` color — it ships with every Pi theme and reads as a muted tone — with the
|
|
113
|
+
Collapsed rows (tool calls, `+ Thought`, subagents) default to the theme's `syntaxComment` color — it ships with every Pi theme and reads as a muted tone — with the row's anchor and the call content sharing it. Failures stay error-colored and live spinners keep their existing tints.
|
|
108
114
|
|
|
109
115
|
A theme can override each collapsed kind independently with optional color tokens:
|
|
110
116
|
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -21,11 +21,28 @@ import { fgCollapsed, fgCollapsedRail } from "./muted.ts";
|
|
|
21
21
|
const OUTER_INSET = 2;
|
|
22
22
|
const SUBAGENT_MARKER = "↪";
|
|
23
23
|
const GROUP_CALL_MARKER = "│";
|
|
24
|
+
// Collapsed rows anchor with a glyph instead of repeating the tool name;
|
|
25
|
+
// tools that read as one family share a glyph, and unmapped tools fall back
|
|
26
|
+
// to `*`.
|
|
27
|
+
const TOOL_CALL_GLYPHS: ReadonlyMap<string, string> = new Map([
|
|
28
|
+
["read", "●"],
|
|
29
|
+
["write", "+"],
|
|
30
|
+
["edit", "±"],
|
|
31
|
+
["grep", "○"],
|
|
32
|
+
["ffgrep", "○"],
|
|
33
|
+
["find", "○"],
|
|
34
|
+
["fffind", "○"],
|
|
35
|
+
["ls", "≡"],
|
|
36
|
+
["web_search", "↗"],
|
|
37
|
+
["fetch_content", "↗"],
|
|
38
|
+
["get_search_content", "↗"],
|
|
39
|
+
]);
|
|
24
40
|
const PRESENTATION_PATCHED = Symbol.for("kg.pi.toolPresentation.v3");
|
|
25
41
|
const LEGACY_PRESENTATION_PATCHED = Symbol.for("kg.pi.toolPresentation.v2");
|
|
26
42
|
const GROUPING_PATCHED = Symbol.for("kg.pi.toolGrouping.v1");
|
|
27
43
|
const ANSI_RE = /\u001b\[[0-9;]*m/g;
|
|
28
44
|
const COLLAPSE_PARALLEL_ENV = "PI_TOOL_CALL_MARKERS_COLLAPSE_PARALLEL";
|
|
45
|
+
const EXPANDED_TOOLS_ENV = "PI_ALWAYS_EXPANDED_TOOL_CALL_MARKERS";
|
|
29
46
|
|
|
30
47
|
type ThemeLike = {
|
|
31
48
|
bold(text: string): string;
|
|
@@ -72,6 +89,7 @@ type PresentationPatchState = {
|
|
|
72
89
|
owners: number;
|
|
73
90
|
theme?: ThemeLike;
|
|
74
91
|
collapseParallel: boolean;
|
|
92
|
+
expandedTools: ReadonlySet<string>;
|
|
75
93
|
groupCache: WeakMap<ToolExecutionRow, GroupRenderCache>;
|
|
76
94
|
collapsedCache: WeakMap<ToolExecutionRow, CollapsedRenderCache>;
|
|
77
95
|
rowVersions: WeakMap<ToolExecutionRow, number>;
|
|
@@ -94,9 +112,7 @@ type GroupingPatchState = {
|
|
|
94
112
|
|
|
95
113
|
type GroupRenderCache = {
|
|
96
114
|
lines: string[];
|
|
97
|
-
//
|
|
98
|
-
// member absorbs the leading blank and the tool-name header, later
|
|
99
|
-
// members carry their own line (plus edit diffs).
|
|
115
|
+
// The first member absorbs the leading blank; each member owns its line.
|
|
100
116
|
heights: Array<{ component: ToolExecutionRow; height: number }>;
|
|
101
117
|
members: ToolExecutionRow[];
|
|
102
118
|
memberVersions: number[];
|
|
@@ -120,6 +136,19 @@ function envEnabled(name: string, defaultValue: boolean): boolean {
|
|
|
120
136
|
return defaultValue;
|
|
121
137
|
}
|
|
122
138
|
|
|
139
|
+
// Comma-separated tool names, e.g. `edit,write`. Blank entries and padding
|
|
140
|
+
// are ignored; an unset or empty variable yields no names.
|
|
141
|
+
function envToolNames(name: string): ReadonlySet<string> {
|
|
142
|
+
const value = process.env[name]?.trim();
|
|
143
|
+
if (!value) return new Set();
|
|
144
|
+
return new Set(
|
|
145
|
+
value
|
|
146
|
+
.split(",")
|
|
147
|
+
.map((entry) => entry.trim())
|
|
148
|
+
.filter(Boolean),
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
123
152
|
function stripAnsi(text: string): string {
|
|
124
153
|
return text.replace(ANSI_RE, "");
|
|
125
154
|
}
|
|
@@ -497,6 +526,18 @@ function isCollapsibleSuccess(row: ToolExecutionRow): boolean {
|
|
|
497
526
|
);
|
|
498
527
|
}
|
|
499
528
|
|
|
529
|
+
// Settled failures join groups like settled successes; the row's error
|
|
530
|
+
// color carries the failure, so the group stays visually unbroken.
|
|
531
|
+
function isCollapsibleFailure(row: ToolExecutionRow): boolean {
|
|
532
|
+
return (
|
|
533
|
+
row.expanded === false &&
|
|
534
|
+
row.isPartial === false &&
|
|
535
|
+
!!row.result &&
|
|
536
|
+
rowHasFailed(row) &&
|
|
537
|
+
!hasImageResult(row)
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
|
|
500
541
|
function hasToolSiblingInAssistantBatch(
|
|
501
542
|
children: unknown[],
|
|
502
543
|
index: number,
|
|
@@ -525,7 +566,12 @@ function isGroupableToolRow(
|
|
|
525
566
|
state: PresentationPatchState,
|
|
526
567
|
): boolean {
|
|
527
568
|
if (row.toolName === "subagent") return false;
|
|
528
|
-
if (
|
|
569
|
+
if (
|
|
570
|
+
!isLiveRow(row) &&
|
|
571
|
+
!isCollapsibleSuccess(row) &&
|
|
572
|
+
!isCollapsibleFailure(row)
|
|
573
|
+
)
|
|
574
|
+
return false;
|
|
529
575
|
return (
|
|
530
576
|
state.collapseParallel ||
|
|
531
577
|
!hasToolSiblingInAssistantBatch(children, index, renderAt)
|
|
@@ -612,15 +658,8 @@ function diffCounts(diff: string): { added: number; removed: number } {
|
|
|
612
658
|
}
|
|
613
659
|
|
|
614
660
|
// Pi's edit tool (renderShell "self") stores its display diff in
|
|
615
|
-
// result.details.diff
|
|
616
|
-
//
|
|
617
|
-
// normally keep only their one-line call label; edits additionally show
|
|
618
|
-
// the change as a bounded diff block under the summary and a +a/-b stat in
|
|
619
|
-
// the outcome tail, so the hunk stays visible without Ctrl+O while
|
|
620
|
-
// expanded rows keep Pi's native rendering.
|
|
621
|
-
const EDIT_DIFF_LINE_RE = /^([+\-\s])(\s*\d*)(.*)$/;
|
|
622
|
-
const MAX_EDIT_DIFF_LINES = 12;
|
|
623
|
-
|
|
661
|
+
// result.details.diff; collapsed rows show only its +a/-b stat, while the
|
|
662
|
+
// full hunk returns with Ctrl+O.
|
|
624
663
|
function editDiffText(row: ToolExecutionRow): string | undefined {
|
|
625
664
|
if (row.toolName !== "edit") return undefined;
|
|
626
665
|
if (!row.result || row.isPartial !== false || rowHasFailed(row))
|
|
@@ -636,43 +675,6 @@ function renderedEditDiffStat(row: ToolExecutionRow): string | undefined {
|
|
|
636
675
|
return added + removed === 0 ? "applied" : `+${added}/-${removed}`;
|
|
637
676
|
}
|
|
638
677
|
|
|
639
|
-
function renderedEditDiffLines(
|
|
640
|
-
row: ToolExecutionRow,
|
|
641
|
-
theme: ThemeLike,
|
|
642
|
-
): string[] {
|
|
643
|
-
const diff = editDiffText(row);
|
|
644
|
-
if (diff === undefined) return [];
|
|
645
|
-
const raw = diff.split("\n");
|
|
646
|
-
if (raw[raw.length - 1] === "") raw.pop();
|
|
647
|
-
const lines: string[] = [];
|
|
648
|
-
for (const line of raw.slice(0, MAX_EDIT_DIFF_LINES)) {
|
|
649
|
-
const clean = sanitizeInline(line).trimEnd();
|
|
650
|
-
if (clean.trim() === "...") {
|
|
651
|
-
lines.push(fgCollapsed(theme, "muted", " ..."));
|
|
652
|
-
continue;
|
|
653
|
-
}
|
|
654
|
-
const match = EDIT_DIFF_LINE_RE.exec(clean);
|
|
655
|
-
if (!match) continue;
|
|
656
|
-
const color =
|
|
657
|
-
match[1] === "+"
|
|
658
|
-
? "toolDiffAdded"
|
|
659
|
-
: match[1] === "-"
|
|
660
|
-
? "toolDiffRemoved"
|
|
661
|
-
: "toolDiffContext";
|
|
662
|
-
lines.push(theme.fg(color, ` ${match[1]}${match[2]}${match[3]}`));
|
|
663
|
-
}
|
|
664
|
-
if (raw.length > MAX_EDIT_DIFF_LINES) {
|
|
665
|
-
lines.push(
|
|
666
|
-
fgCollapsed(
|
|
667
|
-
theme,
|
|
668
|
-
"muted",
|
|
669
|
-
` ... +${raw.length - MAX_EDIT_DIFF_LINES} more`,
|
|
670
|
-
),
|
|
671
|
-
);
|
|
672
|
-
}
|
|
673
|
-
return lines;
|
|
674
|
-
}
|
|
675
|
-
|
|
676
678
|
function outcomeSummary(row: ToolExecutionRow): string | undefined {
|
|
677
679
|
// Self-rendered tools own their result framing; the built-in heuristics
|
|
678
680
|
// (line counts, diff stats) describe default-shell rows only, so their
|
|
@@ -724,22 +726,6 @@ function renderedOutcome(
|
|
|
724
726
|
return fgCollapsed(theme, "toolOutput", `→ ${summary}`);
|
|
725
727
|
}
|
|
726
728
|
|
|
727
|
-
function renderedGroupedOutcome(
|
|
728
|
-
row: ToolExecutionRow,
|
|
729
|
-
theme: ThemeLike,
|
|
730
|
-
): string | undefined {
|
|
731
|
-
const outcome = renderedOutcome(row, theme);
|
|
732
|
-
if (outcome) return outcome;
|
|
733
|
-
if (isLiveRow(row)) {
|
|
734
|
-
const elapsed = liveElapsedText(row);
|
|
735
|
-
return theme.fg("warning", elapsed ? `… · ${elapsed}` : "…");
|
|
736
|
-
}
|
|
737
|
-
// Self-rendered tools have no per-tool outcome summary; keep the group's
|
|
738
|
-
// settled tail consistent with collapsed singletons.
|
|
739
|
-
if (row.getRenderShell?.() === "self") return renderedGenericOutcome(theme);
|
|
740
|
-
return undefined;
|
|
741
|
-
}
|
|
742
|
-
|
|
743
729
|
// A budget too small for the suffix keeps literal styled text instead, so a
|
|
744
730
|
// one-column label never collapses into a bare ellipsis or loses its status.
|
|
745
731
|
function truncateStyled(text: string, width: number, suffix = "…"): string {
|
|
@@ -900,6 +886,23 @@ function collapsedCallLabel(
|
|
|
900
886
|
return styledCallLabel(label, theme, color);
|
|
901
887
|
}
|
|
902
888
|
|
|
889
|
+
// Collapsed rows anchor their call text with a glyph instead of repeating
|
|
890
|
+
// the tool name, grouped or not. Bash carries `$:` inside its own label and
|
|
891
|
+
// the subagent fallback keeps its `↪ subagent` heading, so neither takes a
|
|
892
|
+
// glyph.
|
|
893
|
+
function collapsedCallMarker(
|
|
894
|
+
row: ToolExecutionRow,
|
|
895
|
+
theme: ThemeLike,
|
|
896
|
+
color: string,
|
|
897
|
+
): string {
|
|
898
|
+
if (row.toolName === "bash" || row.toolName === "subagent") return "";
|
|
899
|
+
return fgCollapsed(
|
|
900
|
+
theme,
|
|
901
|
+
color,
|
|
902
|
+
`${TOOL_CALL_GLYPHS.get(row.toolName ?? "") ?? "*"}: `,
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
|
|
903
906
|
function collapsedOutcome(
|
|
904
907
|
row: ToolExecutionRow,
|
|
905
908
|
width: number,
|
|
@@ -930,14 +933,15 @@ function collapsedHeadline(
|
|
|
930
933
|
theme: ThemeLike,
|
|
931
934
|
): string {
|
|
932
935
|
// Failed rows render entirely in error so the row reads as the one that
|
|
933
|
-
// failed, not just its outcome tail. Only the
|
|
936
|
+
// failed, not just its outcome tail. Only the row's anchor stays bold.
|
|
934
937
|
const tone = rowHasFailed(row) ? "error" : "muted";
|
|
935
938
|
const marker =
|
|
936
939
|
row.toolName === "subagent"
|
|
937
940
|
? `${fgCollapsed(theme, tone, SUBAGENT_MARKER)} `
|
|
938
|
-
: `${fgCollapsedRail(theme,
|
|
941
|
+
: `${fgCollapsedRail(theme, GROUP_CALL_MARKER)} `;
|
|
942
|
+
const glyph = collapsedCallMarker(row, theme, tone);
|
|
939
943
|
const budget = Math.max(1, width - visibleWidth(marker));
|
|
940
|
-
const label =
|
|
944
|
+
const label = glyph + collapsedChildLabel(row, budget, theme, tone);
|
|
941
945
|
const outcome = collapsedOutcome(row, budget, theme);
|
|
942
946
|
// The truncation suffix inherits the row tone; pi-tui's truncation resets
|
|
943
947
|
// around a plain suffix, which would render it in the terminal default
|
|
@@ -1248,20 +1252,20 @@ function renderCollapsedToolRow(
|
|
|
1248
1252
|
? renderSubagentPlan(row, layout.contentWidth, theme)
|
|
1249
1253
|
: undefined;
|
|
1250
1254
|
const body = plan ?? [collapsedHeadline(row, layout.contentWidth, theme)];
|
|
1251
|
-
if (row.toolName === "edit") {
|
|
1252
|
-
body.push(...renderedEditDiffLines(row, theme));
|
|
1253
|
-
}
|
|
1254
1255
|
body.push(...imageResultLines(row, layout.contentWidth, theme));
|
|
1255
1256
|
return ["", ...insetLines(body, width)];
|
|
1256
1257
|
}
|
|
1257
1258
|
|
|
1258
|
-
|
|
1259
|
+
// Drops the call label's tool-name token: the row's glyph anchors the call
|
|
1260
|
+
// instead. The `↪` subagent fallback keeps its own heading.
|
|
1261
|
+
function collapsedChildLabel(
|
|
1259
1262
|
row: ToolExecutionRow,
|
|
1260
1263
|
width: number,
|
|
1261
1264
|
theme: ThemeLike,
|
|
1262
1265
|
color: string = "muted",
|
|
1263
1266
|
): string {
|
|
1264
1267
|
const label = collapsedCallLabel(row, width, theme, color);
|
|
1268
|
+
if (row.toolName === "subagent") return label;
|
|
1265
1269
|
const plain = stripAnsi(label);
|
|
1266
1270
|
const toolName = row.toolName ?? "tool";
|
|
1267
1271
|
let prefix = "";
|
|
@@ -1287,37 +1291,26 @@ function renderGroupedCallLines(
|
|
|
1287
1291
|
theme: ThemeLike,
|
|
1288
1292
|
): Array<{ row: ToolExecutionRow; lines: string[] }> {
|
|
1289
1293
|
const segments: Array<{ row: ToolExecutionRow; lines: string[] }> = [];
|
|
1290
|
-
let previousToolName: string | undefined;
|
|
1291
1294
|
for (const row of rows) {
|
|
1292
1295
|
const lines: string[] = [];
|
|
1293
|
-
const toolName = row.toolName ?? "tool";
|
|
1294
|
-
if (toolName !== previousToolName) {
|
|
1295
|
-
// Keep the rail unbroken across subgroup spacing and put each bold
|
|
1296
|
-
// tool name beside it. The separator belongs to the new row so
|
|
1297
|
-
// click-routing heights stay aligned with the rendered lines.
|
|
1298
|
-
if (previousToolName !== undefined) {
|
|
1299
|
-
lines.push(fgCollapsedRail(theme, "muted", GROUP_CALL_MARKER));
|
|
1300
|
-
}
|
|
1301
|
-
lines.push(
|
|
1302
|
-
`${fgCollapsedRail(theme, "muted", GROUP_CALL_MARKER)} ${fgCollapsed(theme, "toolTitle", toolName, true)}`,
|
|
1303
|
-
);
|
|
1304
|
-
previousToolName = toolName;
|
|
1305
|
-
}
|
|
1306
1296
|
|
|
1307
1297
|
const color = rowHasFailed(row) ? "error" : "muted";
|
|
1308
|
-
const prefix = `${fgCollapsedRail(theme,
|
|
1309
|
-
const
|
|
1310
|
-
const
|
|
1298
|
+
const prefix = `${fgCollapsedRail(theme, GROUP_CALL_MARKER)} `;
|
|
1299
|
+
const marker = collapsedCallMarker(row, theme, color);
|
|
1300
|
+
const budget = Math.max(
|
|
1301
|
+
1,
|
|
1302
|
+
width - visibleWidth(prefix) - visibleWidth(marker),
|
|
1303
|
+
);
|
|
1304
|
+
const label = collapsedChildLabel(row, budget, theme, color);
|
|
1311
1305
|
const outcome = collapsedOutcome(row, budget, theme);
|
|
1312
1306
|
const suffix = fgCollapsed(theme, color, "…");
|
|
1313
1307
|
lines.push(
|
|
1314
1308
|
prefix +
|
|
1309
|
+
marker +
|
|
1315
1310
|
(outcome
|
|
1316
1311
|
? fitSummaryTail(label, outcome, budget, suffix)
|
|
1317
1312
|
: fitSummary(label, budget, suffix)),
|
|
1318
1313
|
);
|
|
1319
|
-
if (row.toolName === "edit")
|
|
1320
|
-
lines.push(...renderedEditDiffLines(row, theme));
|
|
1321
1314
|
segments.push({ row, lines });
|
|
1322
1315
|
}
|
|
1323
1316
|
return segments;
|
|
@@ -1387,8 +1380,7 @@ function renderGroupedToolRows(
|
|
|
1387
1380
|
width,
|
|
1388
1381
|
),
|
|
1389
1382
|
];
|
|
1390
|
-
// The
|
|
1391
|
-
// both belong to the first member; every later member owns its lines.
|
|
1383
|
+
// The first member owns the leading blank; every member owns its call line.
|
|
1392
1384
|
const heights = segments.map((segment, index) => ({
|
|
1393
1385
|
component: segment.row,
|
|
1394
1386
|
height: index === 0 ? segment.lines.length + 1 : segment.lines.length,
|
|
@@ -1616,6 +1608,7 @@ function installPresentationPatch(): PresentationPatchState | undefined {
|
|
|
1616
1608
|
const state: PresentationPatchState = {
|
|
1617
1609
|
owners: 1,
|
|
1618
1610
|
collapseParallel: envEnabled(COLLAPSE_PARALLEL_ENV, true),
|
|
1611
|
+
expandedTools: envToolNames(EXPANDED_TOOLS_ENV),
|
|
1619
1612
|
groupCache: new WeakMap(),
|
|
1620
1613
|
collapsedCache: new WeakMap(),
|
|
1621
1614
|
rowVersions: new WeakMap(),
|
|
@@ -1623,7 +1616,7 @@ function installPresentationPatch(): PresentationPatchState | undefined {
|
|
|
1623
1616
|
originalRender: proto.render,
|
|
1624
1617
|
originalUpdateDisplay: proto.updateDisplay,
|
|
1625
1618
|
};
|
|
1626
|
-
const patchedUpdateDisplay = function
|
|
1619
|
+
const patchedUpdateDisplay = function updateDisplayWithToolPresentation(
|
|
1627
1620
|
this: ToolExecutionRow,
|
|
1628
1621
|
): void {
|
|
1629
1622
|
// Transcript rerenders reuse settled caches, but a real component
|
|
@@ -1633,6 +1626,17 @@ function installPresentationPatch(): PresentationPatchState | undefined {
|
|
|
1633
1626
|
state.groupCache.delete(this);
|
|
1634
1627
|
state.collapsedCache.delete(this);
|
|
1635
1628
|
state.originalUpdateDisplay.call(this);
|
|
1629
|
+
// Rows for an always-expanded tool skip the collapsed presentation.
|
|
1630
|
+
// Forcing the flag here, before grouping decides whether the row is
|
|
1631
|
+
// eligible, keeps Pi's native expanded block authoritative; it also
|
|
1632
|
+
// re-expands the row after a global collapse.
|
|
1633
|
+
if (
|
|
1634
|
+
this.expanded === false &&
|
|
1635
|
+
state.expandedTools.has(this.toolName ?? "") &&
|
|
1636
|
+
typeof this.setExpanded === "function"
|
|
1637
|
+
) {
|
|
1638
|
+
this.setExpanded(true);
|
|
1639
|
+
}
|
|
1636
1640
|
};
|
|
1637
1641
|
// Pi 0.85 wraps settled tool results in a click-to-expand MouseRegion.
|
|
1638
1642
|
// The custom collapsed row replaces those lines with a single summary, so
|
package/src/muted.ts
CHANGED
|
@@ -83,12 +83,8 @@ export function fgCollapsed(
|
|
|
83
83
|
// guaranteed lighter than the collapsed color (e.g. catppuccin-latte's `dim`
|
|
84
84
|
// resolves to the same overlay0 as syntaxComment), so apply the terminal's
|
|
85
85
|
// faint attribute: it lightens toward the background on light themes and
|
|
86
|
-
// darkens on dark ones.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
text: string,
|
|
91
|
-
): string {
|
|
92
|
-
const styled = fgCollapsed(theme, color, text);
|
|
93
|
-
return color === "error" ? styled : `\x1b[2m${styled}\x1b[22m`;
|
|
86
|
+
// darkens on dark ones. The rail keeps this muted weight even on failed
|
|
87
|
+
// rows, where only the row's text turns error-colored.
|
|
88
|
+
export function fgCollapsedRail(theme: CollapsedTheme, text: string): string {
|
|
89
|
+
return `\x1b[2m${fgCollapsed(theme, "muted", text)}\x1b[22m`;
|
|
94
90
|
}
|