pi-bar 0.3.15 → 0.3.18

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 CHANGED
@@ -9,7 +9,7 @@
9
9
  claude-opus-4.7 ❯ think:med ❯ 2.6% / 1.0M ❯ Inspecting package structure ❯ plan:active
10
10
  ```
11
11
 
12
- ![pi-bar screenshot, three rows showing green, yellow, and red context usage](https://cdn.jsdelivr.net/npm/pi-bar@0.3.15/assets/screenshot.png)
12
+ ![pi-bar screenshot, three rows showing green, yellow, and red context usage](https://cdn.jsdelivr.net/npm/pi-bar@0.3.18/assets/screenshot.png)
13
13
 
14
14
  ## Why use it?
15
15
 
@@ -48,7 +48,7 @@ Allowed segments are `model`, `thinking`, `context`, `tldr`, and `extensions`. T
48
48
 
49
49
  ### Configure live TLDR
50
50
 
51
- pi-bar shows a concise live TLDR of the current task in the footer. It generates TLDRs from compacted recent prompt, assistant, tool, and result activity. It resets when you navigate the session tree so stale summaries do not follow you across branches. Set `PI_BAR_SHOW` without `tldr` to hide it.
51
+ pi-bar shows a concise live TLDR of the current task in the footer. It generates TLDRs from recent prompt, assistant, and deterministic code-compressed tool facts (for example `bash ... ok`, `grep ... 4 matches`, `edit file`, or `custom_tool key=value`). It resets when you navigate the session tree so stale summaries do not follow you across branches. Set `PI_BAR_SHOW` without `tldr` to hide it.
52
52
 
53
53
  Override the TLDR model with:
54
54
 
@@ -77,8 +77,8 @@ const SETTINGS_BAR_KEY = "bar";
77
77
  const MAX_ACTIVITY_TEXT_CHARS = 800;
78
78
  const MAX_USER_TEXT_CHARS = 700;
79
79
  const MAX_ASSISTANT_UPDATE_CHARS = 500;
80
- const MAX_TOOL_RESULT_OK_CHARS = 500;
81
- const MAX_TOOL_RESULT_ERROR_CHARS = 900;
80
+ const MAX_TOOL_RESULT_OK_CHARS = 160;
81
+ const MAX_TOOL_RESULT_ERROR_CHARS = 320;
82
82
  const MAX_FINAL_TEXT_CHARS = 700;
83
83
  const MAX_RETAINED_RAW_ACTIVITIES = 128;
84
84
  const ANSI_PATTERN = /\x1B\[[0-?]*[ -/]*[@-~]/g;
@@ -308,6 +308,24 @@ function compactValue(value: unknown, maxChars: number): string | undefined {
308
308
  return text ? truncateText(compactText(text), maxChars) : undefined;
309
309
  }
310
310
 
311
+ function compactInputArgs(input: Record<string, unknown>, maxChars: number): string | undefined {
312
+ const args = Object.entries(input)
313
+ .sort(([a], [b]) => a.localeCompare(b))
314
+ .map(([key, value]) => {
315
+ const formatted = compactValue(value, 80);
316
+ return formatted ? `${key}=${formatted}` : undefined;
317
+ })
318
+ .filter((arg): arg is string => Boolean(arg));
319
+
320
+ let result = "";
321
+ for (const arg of args) {
322
+ const next = result ? `${result} ${arg}` : arg;
323
+ if (next.length > maxChars) break;
324
+ result = next;
325
+ }
326
+ return result || undefined;
327
+ }
328
+
311
329
  function compactToolInput(toolName: string, input: Record<string, unknown> | undefined): string {
312
330
  if (!input) return toolName;
313
331
 
@@ -334,24 +352,56 @@ function compactToolInput(toolName: string, input: Record<string, unknown> | und
334
352
  case "ls":
335
353
  return path ? `ls ${path}` : "ls";
336
354
  default: {
337
- const args = Object.entries(input)
338
- .slice(0, 3)
339
- .map(([key, value]) => {
340
- const formatted = compactValue(value, 80);
341
- return formatted ? `${key}=${formatted}` : undefined;
342
- })
343
- .filter(Boolean)
344
- .join(" ");
355
+ const args = compactInputArgs(input, 240);
345
356
  return args ? `${toolName} ${args}` : toolName;
346
357
  }
347
358
  }
348
359
  }
349
360
 
350
- function compactToolResultText(text: string | undefined, isError: boolean): string | undefined {
361
+ function usefulLineCount(text: string): number {
362
+ return text
363
+ .split("\n")
364
+ .map((line) => line.trim())
365
+ .filter(Boolean).length;
366
+ }
367
+
368
+ function errorSummary(text: string | undefined): string | undefined {
351
369
  if (!text) return undefined;
352
370
  const compacted = compactText(text);
353
- const maxChars = isError ? MAX_TOOL_RESULT_ERROR_CHARS : MAX_TOOL_RESULT_OK_CHARS;
354
- return isError ? truncateText(compacted, maxChars) : tailText(compacted, maxChars);
371
+ const exitMatch = compacted.match(/Command exited with code \d+/);
372
+ if (exitMatch) return truncateText(exitMatch[0], MAX_TOOL_RESULT_ERROR_CHARS);
373
+ return truncateText(compacted, MAX_TOOL_RESULT_ERROR_CHARS);
374
+ }
375
+
376
+ function summarizeToolResult(
377
+ toolName: string,
378
+ input: Record<string, unknown> | undefined,
379
+ text: string | undefined,
380
+ isError: boolean,
381
+ ): string | undefined {
382
+ if (isError) return errorSummary(text);
383
+
384
+ const lineCount = text ? usefulLineCount(text) : 0;
385
+ const path = compactValue(input?.path ?? input?.filePath ?? input?.cwd, 120);
386
+
387
+ switch (toolName) {
388
+ case "bash":
389
+ return undefined;
390
+ case "read":
391
+ return path ? `${lineCount || "file"} lines from ${path}` : undefined;
392
+ case "edit":
393
+ return path ? `edited ${path}` : undefined;
394
+ case "write":
395
+ return path ? `wrote ${path}` : undefined;
396
+ case "grep":
397
+ return lineCount ? `${lineCount} matches` : "no matches";
398
+ case "find":
399
+ return lineCount ? `${lineCount} paths` : "no paths";
400
+ case "ls":
401
+ return lineCount ? `${lineCount} entries` : undefined;
402
+ default:
403
+ return lineCount ? `${lineCount} output lines` : undefined;
404
+ }
355
405
  }
356
406
 
357
407
  function extractTextContent(content: readonly unknown[] | undefined): string | undefined {
@@ -414,9 +464,15 @@ class TldrFactCollector {
414
464
  input?: Record<string, unknown>;
415
465
  isError?: boolean;
416
466
  content?: readonly unknown[];
467
+ details?: unknown;
417
468
  }): TldrActivity {
418
469
  const isError = Boolean(event.isError);
419
- const resultText = compactToolResultText(extractTextContent(event.content), isError);
470
+ const resultText = summarizeToolResult(
471
+ event.toolName,
472
+ event.input,
473
+ extractTextContent(event.content),
474
+ isError,
475
+ );
420
476
  const status = isError ? "error" : "ok";
421
477
  const tool = compactToolInput(event.toolName, event.input);
422
478
  return this.addActivity(
@@ -556,6 +612,7 @@ class FooterTldrEngine {
556
612
  input?: Record<string, unknown>;
557
613
  isError?: boolean;
558
614
  content?: readonly unknown[];
615
+ details?: unknown;
559
616
  },
560
617
  ): void {
561
618
  this.enqueue(ctx, this.facts.recordToolResult(event));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-bar",
3
- "version": "0.3.15",
3
+ "version": "0.3.18",
4
4
  "description": "Pi footer/statusline showing active model, thinking level, context pressure, live TLDR, and extension statuses.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -51,6 +51,6 @@
51
51
  "extensions": [
52
52
  "./extensions/status-footer.ts"
53
53
  ],
54
- "image": "https://cdn.jsdelivr.net/npm/pi-bar@0.3.15/assets/screenshot.png"
54
+ "image": "https://cdn.jsdelivr.net/npm/pi-bar@0.3.18/assets/screenshot.png"
55
55
  }
56
56
  }