@pi-kaush/pi-tool-call-markers 0.3.4 → 0.3.6
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 +56 -0
- package/README.md +26 -14
- package/package.json +1 -1
- package/src/bash-block.ts +22 -3
- package/src/container-hooks.ts +6 -0
- package/src/index.ts +168 -209
- package/src/info-visibility-state.ts +16 -2
- package/src/info-visibility.ts +15 -3
- package/src/muted.ts +29 -24
- package/src/thinking-block-merger.ts +141 -64
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,62 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- Read colors from the live palette instead of caching them against the
|
|
6
|
+
theme object. Pi swaps the palette behind a stable theme Proxy, so every
|
|
7
|
+
identity-keyed cache survived a theme switch: collapsed rows, the `+ Thought`
|
|
8
|
+
label, and user `!` blocks kept the old colors until their content changed.
|
|
9
|
+
Probes are map lookups, so the render caches now key on the resolved colors
|
|
10
|
+
(`paletteSample`, including the bash-block line cache) and the label
|
|
11
|
+
resolves its style per call.
|
|
12
|
+
|
|
13
|
+
- Stop grouping from resurrecting a tool that opted out of the transcript. A
|
|
14
|
+
self-rendered tool that draws no lines stays hidden whether it renders alone
|
|
15
|
+
or beside another call: the singleton and grouped paths share one
|
|
16
|
+
draws-nothing rule.
|
|
17
|
+
|
|
18
|
+
- Go inert at the final owner's shutdown. Every prototype wrapper — tool
|
|
19
|
+
presentation, container grouping, user bash blocks, thinking — delegates to
|
|
20
|
+
the original when another extension's wrapper has buried it and removal is
|
|
21
|
+
impossible, so collapsed rows and restyled labels cannot outlive their owner.
|
|
22
|
+
A later install re-enables the same wrappers.
|
|
23
|
+
|
|
24
|
+
- Roll back a container hook that mutates the child list and then throws.
|
|
25
|
+
Its edit used to stick, dropping those rows from every later render. Both
|
|
26
|
+
copies of the shared hook contract changed together.
|
|
27
|
+
|
|
28
|
+
- Own and release `/toggle-info` with the rest of the extension: the
|
|
29
|
+
process-global filter hook and the hidden flag now leave with the last owner
|
|
30
|
+
instead of filtering a transcript this package no longer renders.
|
|
31
|
+
|
|
32
|
+
- Track thinking rows for the `/toggle-info` replay instead of every assistant
|
|
33
|
+
row, capped at 400 entries, so a long session or an abandoned branch cannot
|
|
34
|
+
pin every message the transcript ever showed.
|
|
35
|
+
|
|
36
|
+
- Delete state nothing reads (the row→group map) and the duplicate
|
|
37
|
+
`session_start` handler that applied the collapsed default twice.
|
|
38
|
+
|
|
39
|
+
- Drop the colon after every collapsed-row anchor: glyph rows read
|
|
40
|
+
`│ ● src/a.ts` and bash rows `│ $ npm test`. The anchor runs bold with a
|
|
41
|
+
single space before the call text, so the anchor alone separates the two.
|
|
42
|
+
The whole seam — glyph map, `$` prompt, subagent fallback heading, and the
|
|
43
|
+
tool-token drop — now lives in one function that both the singleton and
|
|
44
|
+
grouped render paths call, and self-rendered labels no longer leak their
|
|
45
|
+
tool name into the row under themes that tag instead of color.
|
|
46
|
+
|
|
47
|
+
- Drop the italics Pi puts on thinking. The hidden `+ Thought` label renders
|
|
48
|
+
plain in every theme — the live spinner keeps its level tint, the settled
|
|
49
|
+
row its muted tone, and a theme that resolves no color still loses the
|
|
50
|
+
italics — and the visible trace stays italic only while it streams, then
|
|
51
|
+
renders as ordinary transcript text once the row settles. The live/settled
|
|
52
|
+
rule is shared with the label, so un-flagged row rebuilds (resize, theme
|
|
53
|
+
switch) keep a live trace italic and a finished one plain.
|
|
54
|
+
`PI_TOOL_CALL_MARKERS_THOUGHT_COLOR=inherit` remains the only opt-out that
|
|
55
|
+
keeps Pi's native italic styling.
|
|
56
|
+
|
|
57
|
+
- Fail open when a theme rejects a thinking token. Pi's Theme throws on
|
|
58
|
+
tokens it does not know, so the label probe now falls back to the plain
|
|
59
|
+
treatment instead of throwing out of the row's update pass.
|
|
60
|
+
|
|
5
61
|
- Restore Pi 0.85's click-to-expand under the custom collapsed rows. Pi routes
|
|
6
62
|
mouse clicks by per-child rendered line heights, and the grouping render
|
|
7
63
|
bypassed the native render that refreshes that cache, so clicks on anything
|
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 bold glyph instead of its tool name — `●` read, `+` write, `±` edit, `○` local search, `≡` ls, `↗` web search and fetch, and `$` bash; unmapped tools fall back to `*` — with a single space between the anchor and the call text, no joining colon. 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
|
|
|
@@ -81,7 +78,9 @@ When Pi exposes its per-row hidden-thinking and streaming fields, hidden reasoni
|
|
|
81
78
|
+ Thought · 2.5s
|
|
82
79
|
```
|
|
83
80
|
|
|
84
|
-
The live label samples Pi's native braille spinner sequence from the content updates Pi already renders; it does not add a timer. The adapter stores the first local streaming timestamp per assistant row in a `WeakMap`. A restored message or an older runtime with no streaming argument uses `+ Thought`.
|
|
81
|
+
The live label samples Pi's native braille spinner sequence from the content updates Pi already renders; it does not add a timer. The adapter stores the first local streaming timestamp per assistant row in a `WeakMap`. A restored message or an older runtime with no streaming argument uses `+ Thought`. There is no interval, timeout, render request, model call, or network work.
|
|
82
|
+
|
|
83
|
+
Pi renders thinking labels and traces italic. This package drops those italics: both labels read as plain collapsed rows (the live spinner keeps its thinking-level tint, the settled row the muted tone, and a theme that resolves no color still loses the italics), and a visible trace stays italic only while it streams, then settles into ordinary transcript text. `PI_TOOL_CALL_MARKERS_THOUGHT_COLOR=inherit` is the opt-out that keeps Pi's native italic `thinkingText` styling.
|
|
85
84
|
|
|
86
85
|
## Local development
|
|
87
86
|
|
|
@@ -102,9 +101,18 @@ pi
|
|
|
102
101
|
|
|
103
102
|
`0`, `false`, `no`, and `off` disable parallel grouping. `1`, `true`, `yes`, and `on` enable it. The value is read when the extension loads.
|
|
104
103
|
|
|
104
|
+
To render chosen tools as Pi's native expanded block by default — full result and diff without `Ctrl+O` — list their names:
|
|
105
|
+
|
|
106
|
+
```fish
|
|
107
|
+
set -lx PI_ALWAYS_EXPANDED_TOOL_CALL_MARKERS edit,write
|
|
108
|
+
pi
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
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.
|
|
112
|
+
|
|
105
113
|
### Collapsed-row colors
|
|
106
114
|
|
|
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
|
|
115
|
+
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
116
|
|
|
109
117
|
A theme can override each collapsed kind independently with optional color tokens:
|
|
110
118
|
|
|
@@ -125,10 +133,14 @@ Pi has no public hook for native tool rows, transcript grouping, or per-message
|
|
|
125
133
|
|
|
126
134
|
- `ToolExecutionComponent` for collapsed presentation;
|
|
127
135
|
- `Container` for adjacent grouping; and
|
|
128
|
-
- `AssistantMessageComponent.updateContent` for display-only thinking merging and
|
|
136
|
+
- `AssistantMessageComponent.updateContent` for display-only thinking merging, lifecycle labels, and the settled trace's italics.
|
|
129
137
|
|
|
130
138
|
Each adapter feature-detects the fields and methods it needs, keeps the original method, uses an idempotency symbol, catches cosmetic failures, and restores the original on `session_shutdown` when it still owns the patch. Unsupported shapes fail open to Pi's native rendering. The thinking adapter continues adjacent merging even when the private label shape is unavailable.
|
|
131
139
|
|
|
140
|
+
Teardown is owner-counted and inert: when another extension's wrapper sits above one of these, removal is impossible, so the buried wrapper delegates to the original instead of leaving collapsed rows or restyled labels behind after its owner shuts down. A later install re-enables it. The shared chat-container hook contract applies the same fail-open rule to hooks: a hook that throws after editing the child list has its edit rolled back, so a failed hook cannot drop rows from the transcript.
|
|
141
|
+
|
|
142
|
+
Colors are read live from the theme, so a mid-session theme switch repaints collapsed rows, labels, and `!` blocks; cached render output keys on the resolved palette rather than on the theme object, which Pi keeps stable across a switch.
|
|
143
|
+
|
|
132
144
|
Expanded tools always use Pi's native renderer. The collapsed tool shell owns its two-column inset directly; transcript layout extensions should leave tool rows unchanged, preventing load-order-dependent double padding.
|
|
133
145
|
|
|
134
146
|
> TODO: migrate these adapters to public Pi transcript and tool-rendering APIs when available.
|
package/package.json
CHANGED
package/src/bash-block.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BashExecutionComponent } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
3
|
+
import { paletteSample } from "./muted.ts";
|
|
3
4
|
|
|
4
5
|
type ThemeLike = {
|
|
5
6
|
bold(text: string): string;
|
|
@@ -199,8 +200,15 @@ type BashRow = { status?: unknown };
|
|
|
199
200
|
|
|
200
201
|
type BashBlockPatchState = {
|
|
201
202
|
owners: number;
|
|
203
|
+
// Set at the final owner's shutdown. A wrapper another extension has buried
|
|
204
|
+
// cannot be uninstalled, so it delegates instead of outliving its owner; a
|
|
205
|
+
// later install re-enables it.
|
|
206
|
+
disabled?: boolean;
|
|
202
207
|
theme?: ThemeLike;
|
|
203
|
-
cache: WeakMap<
|
|
208
|
+
cache: WeakMap<
|
|
209
|
+
object,
|
|
210
|
+
{ width: number; src: string[]; lines: string[]; palette: string }
|
|
211
|
+
>;
|
|
204
212
|
originalRender: (width: number) => string[];
|
|
205
213
|
patchedRender?: (width: number) => string[];
|
|
206
214
|
};
|
|
@@ -213,6 +221,7 @@ type BashBlockPatchState = {
|
|
|
213
221
|
// TODO: Replace prototype patching with a public Pi rendering API when available.
|
|
214
222
|
function installBashBlockPatch(): BashBlockPatchState | undefined {
|
|
215
223
|
try {
|
|
224
|
+
console.error("BB new state");
|
|
216
225
|
const proto = BashExecutionComponent?.prototype as unknown as BashRow & {
|
|
217
226
|
[BASH_BLOCK_PATCHED]?: BashBlockPatchState;
|
|
218
227
|
render?: (width: number) => string[];
|
|
@@ -222,6 +231,8 @@ function installBashBlockPatch(): BashBlockPatchState | undefined {
|
|
|
222
231
|
const existing = proto[BASH_BLOCK_PATCHED];
|
|
223
232
|
if (existing) {
|
|
224
233
|
existing.owners++;
|
|
234
|
+
console.error("BB reuse owners", existing.owners);
|
|
235
|
+
existing.disabled = false;
|
|
225
236
|
return existing;
|
|
226
237
|
}
|
|
227
238
|
|
|
@@ -235,17 +246,24 @@ function installBashBlockPatch(): BashBlockPatchState | undefined {
|
|
|
235
246
|
width: number,
|
|
236
247
|
): string[] {
|
|
237
248
|
const theme = state.theme;
|
|
238
|
-
if (!theme)
|
|
249
|
+
if (state.disabled || !theme) {
|
|
250
|
+
return state.originalRender.call(this, width);
|
|
251
|
+
}
|
|
239
252
|
const inset = bashBlockInset(width);
|
|
240
253
|
const bodyWidth = width - inset * 2 - visibleWidth(PROMPT_RAIL);
|
|
241
254
|
if (inset === 0 || bodyWidth < 8) {
|
|
242
255
|
return state.originalRender.call(this, width);
|
|
243
256
|
}
|
|
244
257
|
const lines = state.originalRender.call(this, Math.max(1, bodyWidth));
|
|
258
|
+
// Decorated lines carry resolved colors, so the cache keys on the
|
|
259
|
+
// palette too: Pi swaps the colors behind a stable theme Proxy, which a
|
|
260
|
+
// theme-identity check would never notice.
|
|
261
|
+
const palette = paletteSample(theme);
|
|
245
262
|
const entry = state.cache.get(this);
|
|
246
263
|
if (
|
|
247
264
|
entry &&
|
|
248
265
|
entry.width === width &&
|
|
266
|
+
entry.palette === palette &&
|
|
249
267
|
entry.src.length === lines.length &&
|
|
250
268
|
entry.src.every((line, index) => line === lines[index])
|
|
251
269
|
) {
|
|
@@ -259,7 +277,7 @@ function installBashBlockPatch(): BashBlockPatchState | undefined {
|
|
|
259
277
|
typeof status === "string" ? status : undefined,
|
|
260
278
|
inset,
|
|
261
279
|
);
|
|
262
|
-
state.cache.set(this, { width, src: lines, lines: decorated });
|
|
280
|
+
state.cache.set(this, { width, src: lines, lines: decorated, palette });
|
|
263
281
|
return decorated;
|
|
264
282
|
};
|
|
265
283
|
|
|
@@ -285,6 +303,7 @@ function uninstallBashBlockPatch(state: BashBlockPatchState | undefined): void {
|
|
|
285
303
|
if (!state || state.owners <= 0) return;
|
|
286
304
|
state.owners--;
|
|
287
305
|
if (state.owners > 0) return;
|
|
306
|
+
state.disabled = true;
|
|
288
307
|
const proto = BashExecutionComponent?.prototype as unknown as BashRow & {
|
|
289
308
|
[BASH_BLOCK_PATCHED]?: BashBlockPatchState;
|
|
290
309
|
render?: (width: number) => string[];
|
package/src/container-hooks.ts
CHANGED
|
@@ -37,11 +37,17 @@ export function runChatContainerHooks(
|
|
|
37
37
|
const restores: Array<() => void> = [];
|
|
38
38
|
if (Array.isArray(children)) {
|
|
39
39
|
for (const hook of chatContainerHooks()) {
|
|
40
|
+
// A hook rewrites `children` and hands back its own undo. Snapshot first:
|
|
41
|
+
// a hook that throws after splicing rows out would otherwise leave them
|
|
42
|
+
// missing from every later render, with nothing left to restore them.
|
|
43
|
+
const before = [...children];
|
|
40
44
|
try {
|
|
41
45
|
const restore = hook(container, children, width);
|
|
42
46
|
if (typeof restore === "function") restores.push(restore);
|
|
43
47
|
} catch {
|
|
44
48
|
// Hooks are cosmetic; one failing hook must not break rendering.
|
|
49
|
+
children.length = 0;
|
|
50
|
+
children.push(...before);
|
|
45
51
|
}
|
|
46
52
|
}
|
|
47
53
|
}
|