pi-compact-tools 0.5.6 → 0.5.9

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
@@ -149,7 +149,7 @@ The escaped code points remain readable on GitHub and are decoded to Nerd Font i
149
149
 
150
150
  ## Controls
151
151
 
152
- Every tool's complete invocation is always visible, including paths, patterns, shell commands, and auxiliary arguments. Large payloads represented as results, such as write content and edit diffs, follow the result toggle.
152
+ Relevant invocation details stay visible, including paths, patterns, shell commands, and auxiliary arguments. Read calls omit offset and limit noise, then report the number of lines read after completion. Large payloads represented as results, such as write content and edit diffs, follow the result toggle.
153
153
 
154
154
  A mouse click toggles one row's result:
155
155
 
@@ -7,16 +7,9 @@ function pathFrom(args: ToolArgs): string {
7
7
  return typeof value === "string" ? normalizeLineEndings(value) : "";
8
8
  }
9
9
 
10
- export function formatReadCallDetails(path: string, args: ToolArgs): string {
11
- const options: string[] = [];
12
- if (typeof args.offset === "number") options.push(`offset: ${args.offset}`);
13
- if (typeof args.limit === "number") options.push(`limit: ${args.limit}`);
14
- return options.length === 0 ? path : `${path} (${options.join(", ")})`;
15
- }
16
-
17
10
  export function getCallDetails(name: string, args: ToolArgs): string {
18
11
  const path = pathFrom(args) || (name === "grep" || name === "find" || name === "ls" ? "." : "");
19
- if (name === "read") return formatReadCallDetails(path, args);
12
+ if (name === "read") return path;
20
13
  if (name !== "grep" && name !== "find") return path;
21
14
  const pattern = typeof args.pattern === "string" ? normalizeLineEndings(args.pattern) : "…";
22
15
  return name === "grep" ? `/${pattern}/ in ${path}` : `${pattern} in ${path}`;
@@ -46,6 +39,23 @@ export function getTextResult(result: AgentToolResult<unknown>): string {
46
39
  return normalizeLineEndings(parts.join("\n")).trimEnd();
47
40
  }
48
41
 
42
+ export function formatReadResultSummary(result: AgentToolResult<unknown>): string | undefined {
43
+ if (!result.content.some((item) => item.type === "text")) return undefined;
44
+ const truncation = (result.details as {
45
+ truncation?: { firstLineExceedsLimit?: boolean; outputLines?: number };
46
+ } | undefined)?.truncation;
47
+ if (truncation?.firstLineExceedsLimit) return undefined;
48
+ let lineCount = truncation?.outputLines;
49
+ if (!Number.isInteger(lineCount) || lineCount === undefined || lineCount < 0) {
50
+ const content = getTextResult(result).replace(
51
+ /\n\n\[(?:Showing lines |\d+ more lines in file\.)[^\n]*\]$/u,
52
+ "",
53
+ );
54
+ lineCount = content.length === 0 ? 0 : content.split("\n").length;
55
+ }
56
+ return `${lineCount} ${lineCount === 1 ? "line" : "lines"}`;
57
+ }
58
+
49
59
  export function getFileOutput(
50
60
  name: string,
51
61
  args: ToolArgs,
@@ -47,8 +47,16 @@ export function hardWrapTextWithAnsi(text: string, width: number): string[] {
47
47
  wrapped.push("");
48
48
  continue;
49
49
  }
50
- for (let offset = 0; offset < lineWidth; offset += safeWidth) {
50
+ let offset = 0;
51
+ while (offset < lineWidth) {
52
+ if (offset > 0) {
53
+ const remainder = sliceByColumn(logicalLine, offset, lineWidth - offset, true);
54
+ const whitespace = stripTerminalSequences(remainder).match(/^\s+/u)?.[0] ?? "";
55
+ offset += visibleWidth(whitespace);
56
+ if (offset >= lineWidth) break;
57
+ }
51
58
  wrapped.push(sliceByColumn(logicalLine, offset, safeWidth, true));
59
+ offset += safeWidth;
52
60
  }
53
61
  }
54
62
  return wrapped;
@@ -34,6 +34,7 @@ import {
34
34
  import { isFullscreenMode, loadConfig } from "./compact-tools-config.ts";
35
35
  import { classifyToggleInput } from "./compact-tools-input.ts";
36
36
  import {
37
+ formatReadResultSummary,
37
38
  getArgumentDetails,
38
39
  getCallDetails,
39
40
  getFileOutput,
@@ -118,7 +119,13 @@ function styleDurationIcon(theme: Theme, indicator: DurationIndicatorConfig): st
118
119
  return `${ansi}${indicator.icon}\x1b[39m`;
119
120
  }
120
121
 
121
- function renderControls(theme: Theme, state: RowState, running: boolean, isError: boolean): Component {
122
+ function renderControls(
123
+ theme: Theme,
124
+ state: RowState,
125
+ running: boolean,
126
+ isError: boolean,
127
+ summary?: string,
128
+ ): Component {
122
129
  const duration = running && !runtime.animatesRows ? undefined : formatDuration(state);
123
130
  const indicator = !running && !isError ? durationIndicator(state) : undefined;
124
131
  const status = running
@@ -127,6 +134,7 @@ function renderControls(theme: Theme, state: RowState, running: boolean, isError
127
134
  let details = indicator
128
135
  ? `${styleDurationIcon(theme, indicator)} ${theme.fg("borderAccent", status)}`
129
136
  : theme.fg("borderAccent", status);
137
+ if (summary) details += theme.fg("borderAccent", ` • ${summary}`);
130
138
  if (state.hasResult) {
131
139
  const clickAction = state.expanded ? "to hide" : "for result";
132
140
  details += theme.fg(
@@ -211,7 +219,8 @@ function renderFileResult(
211
219
  updateEditResult(definition, result, options, theme, ctx, state);
212
220
  const container = new Container();
213
221
  appendFileResult(container, definition, state, output, theme, ctx.isError);
214
- container.addChild(renderControls(theme, state, options.isPartial, ctx.isError));
222
+ const summary = name === "read" && !ctx.isError ? formatReadResultSummary(result) : undefined;
223
+ container.addChild(renderControls(theme, state, options.isPartial, ctx.isError, summary));
215
224
  return container;
216
225
  }
217
226
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-compact-tools",
3
- "version": "0.5.6",
3
+ "version": "0.5.9",
4
4
  "description": "Compact, expandable UI for pi's built-in tools, bundled with a polished GitHub Dark theme.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -56,7 +56,7 @@
56
56
  "typescript": "^5.9.0"
57
57
  },
58
58
  "engines": {
59
- "node": ">=20"
59
+ "node": ">=22.19.0"
60
60
  },
61
61
  "publishConfig": {
62
62
  "access": "public"