@pi-kaush/pi-tool-call-markers 0.3.12 → 0.3.14

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
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ - Anchor the settled thinking label like a collapsed tool call:
6
+ `│ * Thought · 2.5s` instead of `+ Thought · 2.5s`. The faint rail and
7
+ bold glyph match the tool rows around it, so a turn that alternates
8
+ thinking and calls reads as one column. The live `⠋ Thinking…` spinner is
9
+ unchanged.
10
+
5
11
  - Paint collapsed rows with the theme's `dim` token instead of
6
12
  `syntaxComment`. Pi's generated `system` theme solves `syntaxComment` to
7
13
  the same contrast as `muted` and `toolOutput`, so collapsed tool calls
package/README.md CHANGED
@@ -33,19 +33,19 @@ Collapsed tool rows use semantic theme colors with no gear, background fill, box
33
33
 
34
34
  ## Subagent plans
35
35
 
36
- A recognized `subagent` call renders as an unboxed plan in the shared tool aesthetic, marked with `↪` instead of the ordinary `│` tool-call rail:
36
+ A recognized `subagent` call renders as an unboxed plan in the shared tool aesthetic, using the same `│` tool-call rail:
37
37
 
38
38
  ```text
39
- ↪ subagent chain (3 steps) [repo-review]
39
+ │ subagent chain (3 steps) [repo-review]
40
40
  1. 🐝 bee [workhorse] Challenge the compatibility conclusion…
41
41
  2. 🐝 bee …
42
42
  ```
43
43
 
44
- Single calls stay on one `↪ [<emoji>] [<profile>][<agent>] <task preview>` row — no tool label; the `↪` marker identifies it. Chain calls get a heading with the kind, count, and scope followed by numbered steps (parallel tasks list without numbers), with each step ordered emoji, profile badge, name badge. Agent display names (emoji + name) are scraped from the native plan component — including the single-call heading — with an args fallback, and render in `accent`; everything else stays muted, and failed subagents go full red. Subagents never join ordinary tool groups.
44
+ Single calls stay on one `│ [<emoji>] [<profile>][<agent>] <task preview>` row — no tool label. Chain calls get a heading with the kind, count, and scope followed by numbered steps (parallel tasks list without numbers), with each step ordered emoji, profile badge, name badge. Agent display names (emoji + name) are scraped from the native plan component — including the single-call heading — with an args fallback, and render in `accent`; everything else stays muted, and failed subagents go full red. Subagents never join ordinary tool groups.
45
45
 
46
46
  While a subagent runs, the plan headline's tail shows live progress from the streamed result details — `→ 1 turn · provider/model` in the warning tone — and a settled call keeps the same `→ N turns · provider/model` summary in muted (turns aggregate across tasks; the model shows only when every task used the same one).
47
47
 
48
- Malformed, ambiguous, future, or too-narrow shapes fall back to the generic `↪ subagent …` collapsed row rather than dropping information, and `Ctrl+O` still exposes the native subagent renderer.
48
+ Malformed, ambiguous, future, or too-narrow shapes fall back to the generic `│ subagent …` collapsed row rather than dropping information, and `Ctrl+O` still exposes the native subagent renderer.
49
49
 
50
50
  ## Asked questions
51
51
 
@@ -98,10 +98,10 @@ When Pi exposes its per-row hidden-thinking and streaming fields, hidden reasoni
98
98
 
99
99
  ```text
100
100
  ⠋ Thinking… → ⠙ Thinking… → …
101
- + Thought · 2.5s
101
+ │ * Thought · 2.5s
102
102
  ```
103
103
 
104
- 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.
104
+ 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`. The settled label borrows the collapsed tool-row anchor — a faint `│` rail and a bold `*` — so finished reasoning reads like the tool calls around it. There is no interval, timeout, render request, model call, or network work.
105
105
 
106
106
  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.
107
107
 
@@ -135,7 +135,7 @@ Names are comma-separated and matched exactly. Listed rows never join a group, a
135
135
 
136
136
  ### Collapsed-row colors
137
137
 
138
- Collapsed rows (tool calls, `+ Thought`, subagents) default to the theme's `dim` color — it ships with every Pi theme and sits below `muted`, including in the generated `system` theme — with the row's anchor and the call content sharing it. Failures stay error-colored and live spinners keep their existing tints.
138
+ Collapsed rows (tool calls, `│ * Thought`, subagents) default to the theme's `dim` color — it ships with every Pi theme and sits below `muted`, including in the generated `system` theme — with the row's anchor and the call content sharing it. Failures stay error-colored and live spinners keep their existing tints.
139
139
 
140
140
  A theme can override each collapsed kind independently with optional color tokens:
141
141
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-kaush/pi-tool-call-markers",
3
- "version": "0.3.12",
3
+ "version": "0.3.14",
4
4
  "description": "Compact and group Pi tool calls, with a bundled extension for adjacent thinking blocks.",
5
5
  "license": "MIT",
6
6
  "author": "Kaushik Gopal",
package/src/index.ts CHANGED
@@ -24,7 +24,7 @@ import { isQuestionToolCall, renderQuestionBlock } from "./question-block.ts";
24
24
  import { sanitizeInline } from "./sanitize.ts";
25
25
 
26
26
  const OUTER_INSET = 2;
27
- const SUBAGENT_MARKER = "↪";
27
+ const SUBAGENT_MARKER = "│";
28
28
  const GROUP_CALL_MARKER = "│";
29
29
  // Collapsed rows anchor with a glyph instead of repeating the tool name;
30
30
  // tools that read as one family share a glyph, and unmapped tools fall back
@@ -901,7 +901,7 @@ function codemodeCallLabel(row: ToolExecutionRow): string | undefined {
901
901
  // The collapsed-row seam lives here and nowhere else: which anchor a row
902
902
  // takes, how that anchor is styled, and the call text that follows it.
903
903
  // Anchors always render bold and take no joining colon — `│ ● src/a.ts`,
904
- // `│ $ npm test` — and subagent fallbacks keep their `↪ subagent …`
904
+ // `│ $ npm test` — and subagent fallbacks keep their `│ subagent …`
905
905
  // reading instead of a glyph. Callers append the outcome tail.
906
906
  function collapsedSeam(
907
907
  row: ToolExecutionRow,
@@ -1173,10 +1173,10 @@ function subagentProgressText(row: ToolExecutionRow): string | undefined {
1173
1173
  return parts.length > 0 ? parts.join(" · ") : undefined;
1174
1174
  }
1175
1175
 
1176
- // Subagents render as an ordinary unboxed tool block: a `↪` heading with the
1176
+ // Subagents render as an ordinary unboxed tool block: a `│` heading with the
1177
1177
  // plan kind/count/scope, then the numbered chain steps or parallel tasks with
1178
1178
  // agent identities (emoji, profile badge, name badge) in accent. Single calls
1179
- // collapse to one row: `↪ <emoji> [<profile>][<name>] <task preview>`. Everything
1179
+ // collapse to one row: `│ <emoji> [<profile>][<name>] <task preview>`. Everything
1180
1180
  // else stays muted (or error on failure), matching the shared tool-row aesthetic.
1181
1181
  function renderSubagentPlan(
1182
1182
  row: ToolExecutionRow,
package/src/muted.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // Collapsed-row color policy.
2
2
  //
3
- // Collapsed blocks (tool calls, settled "+ Thought" labels, subagent rows)
3
+ // Collapsed blocks (tool calls, settled "│ * Thought" labels, subagent rows)
4
4
  // default to the theme's `dim` token — it ships with every Pi theme and sits
5
5
  // below `muted` — instead of the louder muted/toolTitle/toolOutput split.
6
6
  // Pi's generated `system` theme solves `syntaxComment` to the same contrast
@@ -10,7 +10,7 @@ const SPINNER_INTERVAL_MS = 80;
10
10
  // Visual treatment for the collapsed thinking label. The live "Thinking…"
11
11
  // spinner tints with the session's active thinking-level color
12
12
  // (thinkingOff…thinkingMax), so progress reads as activity; the settled
13
- // "+ Thought" row drops to the muted token collapsed tool calls use, so
13
+ // "│ * Thought" row drops to the muted token collapsed tool calls use, so
14
14
  // finished reasoning stops advertising the level. "inherit" keeps Pi's
15
15
  // native styling (italic + thinkingText) for both states, and "mdheading"
16
16
  // rides the theme's mdHeading token for both. The env var overrides the
@@ -105,21 +105,34 @@ function labelStyle(
105
105
  return styledWith(token, theme);
106
106
  }
107
107
 
108
- // The settled label is the finalized "+ Thought" row; every other label is
109
- // the live spinner.
108
+ // The settled label wears the collapsed tool-row anchor — faint rail, bold
109
+ // glyph — so finished reasoning reads like the tool calls around it. Every
110
+ // other label is the live spinner.
111
+ const THOUGHT_RAIL = "│";
112
+ const THOUGHT_GLYPH = "*";
113
+ const THOUGHT_ANCHOR = `${THOUGHT_RAIL} ${THOUGHT_GLYPH}`;
114
+ const SETTLED_THOUGHT = `${THOUGHT_ANCHOR} Thought`;
115
+
110
116
  function isSettledThoughtLabel(label: string): boolean {
111
- return label.startsWith("+ Thought");
117
+ return label.startsWith(SETTLED_THOUGHT);
118
+ }
119
+
120
+ function styledSettledThought(raw: string, style: LabelStyle): string {
121
+ const rest = raw.slice(THOUGHT_ANCHOR.length);
122
+ return `${style.prefix}\x1b[2m${THOUGHT_RAIL}\x1b[22m \x1b[1m${THOUGHT_GLYPH}\x1b[22m${rest}${style.suffix}`;
112
123
  }
113
124
 
114
125
  export function visibleThoughtLabel(label: string): string {
115
126
  if (!stylesThinkingLabels()) return label;
116
127
  const raw = label.replace(/\x1b\[[0-9;]*m/g, "");
117
128
  const theme = themeProvider?.();
118
- const style = theme
119
- ? labelStyle(isSettledThoughtLabel(label), theme)
120
- : undefined;
129
+ const settled = isSettledThoughtLabel(raw);
130
+ const style = theme ? labelStyle(settled, theme) : undefined;
121
131
  // A theme that cannot resolve a color still drops Pi's italics.
122
- return style ? `${style.prefix}${raw}${style.suffix}` : `${ITALIC_OFF}${raw}`;
132
+ if (!style) return `${ITALIC_OFF}${raw}`;
133
+ return settled
134
+ ? styledSettledThought(raw, style)
135
+ : `${style.prefix}${raw}${style.suffix}`;
123
136
  }
124
137
 
125
138
  type AssistantMessageLike = {
@@ -351,9 +364,9 @@ function lifecycleLabel(
351
364
 
352
365
  const settled = timings.get(row);
353
366
  if (settled?.finishedAt !== undefined) {
354
- return `+ Thought · ${formatThoughtDuration(settled.startedAt, settled.finishedAt)}`;
367
+ return `${SETTLED_THOUGHT} · ${formatThoughtDuration(settled.startedAt, settled.finishedAt)}`;
355
368
  }
356
- return "+ Thought";
369
+ return SETTLED_THOUGHT;
357
370
  }
358
371
 
359
372
  function stripThinkingBlocks(