@esso0428/pi-subagents 0.15.13 → 0.15.15

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +6 -31
  2. package/dist/ui/agent-widget.d.ts +8 -0
  3. package/dist/ui/agent-widget.d.ts.map +1 -1
  4. package/dist/ui/agent-widget.js +40 -12
  5. package/dist/ui/agent-widget.js.map +1 -1
  6. package/dist/ui/ccstyle/diff/diff-renderer.d.ts.map +1 -1
  7. package/dist/ui/ccstyle/diff/diff-renderer.js +2 -4
  8. package/dist/ui/ccstyle/diff/diff-renderer.js.map +1 -1
  9. package/dist/ui/ccstyle/tool-renderer.d.ts.map +1 -1
  10. package/dist/ui/ccstyle/tool-renderer.js +17 -11
  11. package/dist/ui/ccstyle/tool-renderer.js.map +1 -1
  12. package/dist/ui/ccstyle/tool-result.d.ts +22 -10
  13. package/dist/ui/ccstyle/tool-result.d.ts.map +1 -1
  14. package/dist/ui/ccstyle/tool-result.js +160 -73
  15. package/dist/ui/ccstyle/tool-result.js.map +1 -1
  16. package/dist/ui/conversation-timeline.d.ts +16 -9
  17. package/dist/ui/conversation-timeline.d.ts.map +1 -1
  18. package/dist/ui/conversation-timeline.js +85 -61
  19. package/dist/ui/conversation-timeline.js.map +1 -1
  20. package/dist/ui/conversation-viewer.d.ts +4 -1
  21. package/dist/ui/conversation-viewer.d.ts.map +1 -1
  22. package/dist/ui/conversation-viewer.js +107 -110
  23. package/dist/ui/conversation-viewer.js.map +1 -1
  24. package/dist/write-execution.d.ts +0 -2
  25. package/dist/write-execution.d.ts.map +1 -1
  26. package/dist/write-execution.js +1 -5
  27. package/dist/write-execution.js.map +1 -1
  28. package/package.json +1 -1
  29. package/src/ui/agent-widget.ts +38 -12
  30. package/src/ui/ccstyle/diff/diff-renderer.ts +2 -7
  31. package/src/ui/ccstyle/tool-renderer.ts +23 -24
  32. package/src/ui/ccstyle/tool-result.ts +167 -107
  33. package/src/ui/conversation-timeline.ts +103 -62
  34. package/src/ui/conversation-viewer.ts +119 -124
  35. package/src/write-execution.ts +1 -7
  36. package/test/ui/agent-widget.test.ts +123 -0
  37. package/test/ui/conversation-diff.test.ts +1 -28
  38. package/test/ui/conversation-viewer.test.ts +181 -112
  39. package/test/write-execution.test.ts +0 -2
  40. package/.pi/tasks/tasks-01a09263-0ac6-77be-97f5-664b3ffea76b.json +0 -53
  41. package/.pi/workflows/index.json +0 -5
@@ -81,10 +81,7 @@ async function capturePreviousContent(absolutePath) {
81
81
  }
82
82
  function durableDetails(metadata, path, content) {
83
83
  if (metadata.diffUnavailableReason) {
84
- return {
85
- fileExistedBeforeWrite: metadata.fileExistedBeforeWrite,
86
- diffUnavailableReason: metadata.diffUnavailableReason,
87
- };
84
+ return { diffUnavailableReason: metadata.diffUnavailableReason };
88
85
  }
89
86
  const previousContent = metadata.previousContent ?? "";
90
87
  const diffResult = generateDiffString(previousContent, content);
@@ -94,7 +91,6 @@ function durableDetails(metadata, path, content) {
94
91
  return { diffUnavailableReason: `durable diff exceeds ${MAX_DURABLE_DIFF_BYTES} bytes` };
95
92
  }
96
93
  return {
97
- fileExistedBeforeWrite: metadata.fileExistedBeforeWrite,
98
94
  diff: diffResult.diff,
99
95
  patch,
100
96
  firstChangedLine: diffResult.firstChangedLine,
@@ -1 +1 @@
1
- {"version":3,"file":"write-execution.js","sourceRoot":"","sources":["../src/write-execution.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"write-execution.js","sourceRoot":"","sources":["../src/write-execution.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@esso0428/pi-subagents",
3
- "version": "0.15.13",
3
+ "version": "0.15.15",
4
4
  "description": "A pi extension that brings smart Claude Code-style autonomous sub-agents to pi, with npm:pi-subagents-style JSON agent overrides.",
5
5
  "author": "ESSO0428",
6
6
  "repository": {
@@ -14,7 +14,19 @@ import { getLifetimeTotal, getSessionContextPercent, type LifetimeUsage, type Se
14
14
  // ---- Constants ----
15
15
 
16
16
  /** Maximum number of rendered lines before overflow collapse kicks in. */
17
- const MAX_WIDGET_LINES = 12;
17
+ export const MAX_WIDGET_LINES = 12;
18
+ /** Keep a small editor/input area visible below the above-editor widget. */
19
+ const MIN_EDITOR_LINES = 4;
20
+
21
+ /**
22
+ * Derive the widget ceiling from the terminal height while retaining the
23
+ * historical MAX_WIDGET_LINES ceiling. Very short terminals may have no room
24
+ * for the widget; that is preferable to consuming the editor/input area.
25
+ */
26
+ export function getWidgetLineBudget(rows: number): number {
27
+ if (!Number.isFinite(rows)) return MAX_WIDGET_LINES;
28
+ return Math.min(MAX_WIDGET_LINES, Math.max(0, Math.floor(rows) - MIN_EDITOR_LINES));
29
+ }
18
30
 
19
31
  /** Braille spinner frames for animated running indicator. */
20
32
  export const SPINNER = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
@@ -176,9 +188,9 @@ export function buildInvocationTags(
176
188
  return { modelName: invocation.modelName, tags };
177
189
  }
178
190
 
179
- /** Truncate text to a single line, max `len` chars. */
191
+ /** Normalize and truncate text so it can never add physical widget rows. */
180
192
  function truncateLine(text: string, len = 60): string {
181
- const line = text.split("\n").find(l => l.trim())?.trim() ?? "";
193
+ const line = text.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
182
194
  if (line.length <= len) return line;
183
195
  return line.slice(0, len) + "…";
184
196
  }
@@ -325,7 +337,7 @@ export class AgentWidget {
325
337
  statusText = theme.fg("dim", " stopped");
326
338
  } else if (a.status === "error") {
327
339
  icon = theme.fg("error", "✗");
328
- const errMsg = a.error ? `: ${a.error.slice(0, 60)}` : "";
340
+ const errMsg = a.error ? `: ${truncateLine(a.error)}` : "";
329
341
  statusText = theme.fg("error", ` error${errMsg}`);
330
342
  } else {
331
343
  // aborted
@@ -340,7 +352,7 @@ export class AgentWidget {
340
352
  parts.push(duration);
341
353
 
342
354
  const modeTag = modeLabel ? ` ${theme.fg("dim", `(${modeLabel})`)}` : "";
343
- return `${icon} ${theme.fg("dim", name)}${modeTag} ${theme.fg("dim", a.description)} ${theme.fg("dim", "·")} ${theme.fg("dim", parts.join(" · "))}${statusText}`;
355
+ return `${icon} ${theme.fg("dim", name)}${modeTag} ${theme.fg("dim", truncateLine(a.description))} ${theme.fg("dim", "·")} ${theme.fg("dim", parts.join(" · "))}${statusText}`;
344
356
  }
345
357
 
346
358
  /**
@@ -363,6 +375,8 @@ export class AgentWidget {
363
375
  if (!hasActive && !hasFinished) return [];
364
376
 
365
377
  const w = tui.terminal.columns;
378
+ const maxLines = getWidgetLineBudget(tui.terminal.rows);
379
+ if (maxLines === 0) return [];
366
380
  const truncate = (line: string) => truncateToWidth(line, w);
367
381
  const headingColor = hasActive ? "accent" : "dim";
368
382
  const headingIcon = hasActive ? "●" : "○";
@@ -399,7 +413,7 @@ export class AgentWidget {
399
413
  const activity = bg ? describeActivity(bg.activeTools, bg.responseText) : "thinking…";
400
414
 
401
415
  runningLines.push([
402
- truncate(theme.fg("dim", "├─") + ` ${theme.fg("accent", frame)} ${theme.bold(name)}${modeTag} ${theme.fg("muted", a.description)} ${theme.fg("dim", "·")} ${fgPreservingNestedStyles(theme, "dim", statsText)}`),
416
+ truncate(theme.fg("dim", "├─") + ` ${theme.fg("accent", frame)} ${theme.bold(name)}${modeTag} ${theme.fg("muted", truncateLine(a.description))} ${theme.fg("dim", "·")} ${fgPreservingNestedStyles(theme, "dim", statsText)}`),
403
417
  truncate(theme.fg("dim", "│ ") + theme.fg("dim", ` ⎿ ${activity}`)),
404
418
  ]);
405
419
  }
@@ -408,12 +422,18 @@ export class AgentWidget {
408
422
  ? truncate(theme.fg("dim", "├─") + ` ${theme.fg("muted", "◦")} ${theme.fg("dim", `${queued.length} queued`)}`)
409
423
  : undefined;
410
424
 
411
- // Assemble with overflow cap (heading + overflow indicator = 2 reserved lines).
412
- const maxBody = MAX_WIDGET_LINES - 1; // heading takes 1 line
425
+ // Assemble with a responsive cap (heading + overflow indicator = 2
426
+ // reserved lines when content exceeds the available body budget).
427
+ const maxBody = maxLines - 1; // heading takes 1 line
413
428
  const totalBody = finishedLines.length + runningLines.length * 2 + (queuedLine ? 1 : 0);
414
429
 
415
430
  const lines: string[] = [truncate(theme.fg(headingColor, headingIcon) + " " + theme.fg(headingColor, "Agents"))];
416
431
 
432
+ if (maxLines === 1) {
433
+ // There is room only for the heading; do not consume the editor/input row.
434
+ return lines;
435
+ }
436
+
417
437
  if (totalBody <= maxBody) {
418
438
  // Everything fits — add all lines and fix up connectors for the last item.
419
439
  lines.push(...finishedLines);
@@ -439,6 +459,7 @@ export class AgentWidget {
439
459
  // Reserve 1 line for overflow indicator.
440
460
  let budget = maxBody - 1;
441
461
  let hiddenRunning = 0;
462
+ let hiddenQueued = 0;
442
463
  let hiddenFinished = 0;
443
464
 
444
465
  // 1. Running agents (2 lines each)
@@ -452,9 +473,13 @@ export class AgentWidget {
452
473
  }
453
474
 
454
475
  // 2. Queued line
455
- if (queuedLine && budget >= 1) {
456
- lines.push(queuedLine);
457
- budget--;
476
+ if (queuedLine) {
477
+ if (budget >= 1) {
478
+ lines.push(queuedLine);
479
+ budget--;
480
+ } else {
481
+ hiddenQueued = 1;
482
+ }
458
483
  }
459
484
 
460
485
  // 3. Finished agents
@@ -470,9 +495,10 @@ export class AgentWidget {
470
495
  // Overflow summary
471
496
  const overflowParts: string[] = [];
472
497
  if (hiddenRunning > 0) overflowParts.push(`${hiddenRunning} running`);
498
+ if (hiddenQueued > 0) overflowParts.push(`${hiddenQueued} queued`);
473
499
  if (hiddenFinished > 0) overflowParts.push(`${hiddenFinished} finished`);
474
500
  const overflowText = overflowParts.join(", ");
475
- lines.push(truncate(theme.fg("dim", "└─") + ` ${theme.fg("dim", `+${hiddenRunning + hiddenFinished} more (${overflowText})`)}`)
501
+ lines.push(truncate(theme.fg("dim", "└─") + ` ${theme.fg("dim", `+${hiddenRunning + hiddenQueued + hiddenFinished} more (${overflowText})`)}`)
476
502
  );
477
503
  }
478
504
 
@@ -2951,11 +2951,6 @@ export function renderWriteDiffResult(
2951
2951
  return new Text(theme.fg("warning", "↳ diff unavailable: durable diff has no displayable lines"), 0, 0);
2952
2952
  }
2953
2953
  }
2954
- const persistedWasOverwrite = persistedParsed?.entries.some(
2955
- (entry) => entry.kind === "line" && entry.lineKind === "remove",
2956
- ) ?? false;
2957
- const wasOverwrite = options.fileExistedBeforeWrite === true || persistedWasOverwrite;
2958
-
2959
2954
  if (typeof content !== "string" && !persistedParsed) {
2960
2955
  if (!safeFallbackText.trim()) {
2961
2956
  return new Text(theme.fg("muted", "↳ write completed"), 0, 0);
@@ -3036,7 +3031,7 @@ export function renderWriteDiffResult(
3036
3031
  hovered,
3037
3032
  clampDiffLinesToWidth(
3038
3033
  renderWriteCollapsedHintLine(
3039
- wasOverwrite,
3034
+ options.fileExistedBeforeWrite === true,
3040
3035
  safeWidth,
3041
3036
  theme,
3042
3037
  hovered,
@@ -3048,7 +3043,7 @@ export function renderWriteDiffResult(
3048
3043
  }
3049
3044
 
3050
3045
  const header = renderWriteHeader(
3051
- wasOverwrite,
3046
+ options.fileExistedBeforeWrite === true,
3052
3047
  safeWidth,
3053
3048
  theme,
3054
3049
  options.headerLabel,
@@ -17,13 +17,22 @@ function titleForTool(toolName: string): string {
17
17
  .replace(/\b\w/g, (character) => character.toUpperCase());
18
18
  }
19
19
 
20
- function summaryForCall(toolName: string, args: any): string {
21
- if (!args || typeof args !== "object") return titleForTool(toolName);
22
- const value =
23
- args.path ?? args.file_path ?? args.command ?? args.query ?? args.pattern ?? args.url ?? args.name;
24
- return value === undefined
25
- ? titleForTool(toolName)
26
- : `${titleForTool(toolName)} ${oneLine(value)}`;
20
+ function summaryForCall(toolName: string, args: any): { main: string; detail: string } {
21
+ const title = titleForTool(toolName);
22
+ if (!args || typeof args !== "object") return { main: title, detail: "" };
23
+ if (toolName.toLowerCase() === "read") {
24
+ const path = args.path ?? args.file_path;
25
+ const details = [
26
+ args.offset !== undefined ? `offset=${args.offset}` : "",
27
+ args.limit !== undefined ? `limit=${args.limit}` : "",
28
+ ].filter(Boolean);
29
+ return {
30
+ main: path === undefined ? title : `${title} ${oneLine(path)}`,
31
+ detail: details.length ? ` (${details.join(", ")})` : "",
32
+ };
33
+ }
34
+ const value = args.path ?? args.file_path ?? args.command ?? args.query ?? args.pattern ?? args.url ?? args.name;
35
+ return value === undefined ? { main: title, detail: "" } : { main: `${title} ${oneLine(value)}`, detail: "" };
27
36
  }
28
37
 
29
38
  function renderCallComponent(toolName: string, args: any, theme: any, context: any): Component {
@@ -34,7 +43,8 @@ function renderCallComponent(toolName: string, args: any, theme: any, context: a
34
43
  render(width: number): string[] {
35
44
  const safeWidth = Math.max(1, Math.floor(Number.isFinite(width) ? width : 1));
36
45
  const prefix = ` ${theme.fg(color, icon)} `;
37
- return [truncateToWidth(prefix + theme.fg("toolTitle", summaryForCall(toolName, args)), safeWidth, "")];
46
+ const summary = summaryForCall(toolName, args);
47
+ return [truncateToWidth(prefix + theme.fg("toolTitle", summary.main) + theme.fg("dim", summary.detail), safeWidth, "")];
38
48
  },
39
49
  invalidate() {},
40
50
  };
@@ -63,22 +73,11 @@ export function createViewerCcstyleTool(toolName: string, isHovered: () => boole
63
73
  },
64
74
  renderResult(result, options, theme, context) {
65
75
  settled = true;
66
- return createViewerCcstyleResult(
67
- name,
68
- result,
69
- { ...options, isHovered },
70
- theme,
71
- {
72
- ...context,
73
- isHovered,
74
- diffConfig: {
75
- ...DEFAULT_TOOL_DISPLAY_CONFIG,
76
- // The viewer itself is scrollable, so an expanded card should not
77
- // stop at the compact 40-line diff preview.
78
- expandedPreviewMaxLines: Number.MAX_SAFE_INTEGER,
79
- },
80
- },
81
- );
76
+ return createViewerCcstyleResult(name, result, { ...options, isHovered }, theme, {
77
+ ...context,
78
+ isHovered,
79
+ diffConfig: { ...DEFAULT_TOOL_DISPLAY_CONFIG },
80
+ });
82
81
  },
83
82
  };
84
83
  }
@@ -51,56 +51,159 @@ export function outputLineCount(result: any): number {
51
51
  }
52
52
 
53
53
  export function countLines(text: string): number {
54
- return text.trim() ? text.trim().split("\n").length : 0;
54
+ return text.trim() ? text.trim().split("\n").filter((line) => line.trim()).length : 0;
55
55
  }
56
56
 
57
+ /** Format arguments as stable, readable `key: value` rows for the Input rail. */
57
58
  export function formatToolInputArgs(args: unknown, maxChars = 8_000): string {
58
59
  if (args === undefined || args === null) return "";
59
- const rendered =
60
- typeof args === "object" ? safeJson(args) : sanitizeToolResultText(String(args));
61
- const bounded = sanitizeToolResultText(rendered, maxChars);
62
- return rendered.length > maxChars ? `${bounded}…` : bounded;
60
+ if (typeof args !== "object" || Array.isArray(args)) {
61
+ const rendered = typeof args === "string" ? sanitizeToolResultText(args) : safeJson(args);
62
+ return rendered.length > maxChars ? `${rendered.slice(0, maxChars)}…` : rendered;
63
+ }
64
+ const preferred = [
65
+ "path", "file_path", "command", "query", "pattern", "url", "name",
66
+ "message", "content", "old_string", "new_string",
67
+ ];
68
+ const entries = Object.entries(args as Record<string, unknown>)
69
+ .filter(([, value]) => value !== undefined)
70
+ .sort(([left], [right]) => {
71
+ const li = preferred.indexOf(left);
72
+ const ri = preferred.indexOf(right);
73
+ if (li < 0 && ri < 0) return left.localeCompare(right);
74
+ if (li < 0) return 1;
75
+ if (ri < 0) return -1;
76
+ return li - ri;
77
+ });
78
+ const lines: string[] = [];
79
+ for (const [key, value] of entries) {
80
+ const safeKey = sanitizeToolResultText(key);
81
+ if (typeof value === "string") {
82
+ const safeValue = sanitizeToolResultText(value);
83
+ if (safeValue.includes("\n")) {
84
+ lines.push(`${safeKey}:`);
85
+ lines.push(...safeValue.split("\n").map((line) => ` ${line}`));
86
+ } else lines.push(`${safeKey}: ${safeValue}`);
87
+ } else {
88
+ const rendered = safeJson(value);
89
+ if (rendered.includes("\n")) {
90
+ lines.push(`${safeKey}:`);
91
+ lines.push(...rendered.split("\n").map((line) => ` ${line}`));
92
+ } else lines.push(`${safeKey}: ${rendered}`);
93
+ }
94
+ }
95
+ const rendered = lines.join("\n");
96
+ return rendered.length > maxChars ? `${rendered.slice(0, maxChars)}…` : rendered;
63
97
  }
64
98
 
65
99
  function hasExpandableDetail(text: string, args: unknown): boolean {
66
100
  return countLines(text) > 1 || formatToolInputArgs(args).trim().length > 0;
67
101
  }
68
102
 
69
- /** Small Component used for the viewer-local Input/Output card. */
70
- class ExpandedToolIoView implements Component {
71
- private readonly input: string;
72
- private readonly output: string;
73
- private readonly isError: boolean;
103
+ export type ToolIoSection = "input" | "output";
104
+
105
+ /** Viewer-local adaptation of pi-cc's structured Input/Output tool card. */
106
+ export class ExpandedToolIoView implements Component {
107
+ private cachedWidth: number | undefined;
108
+ private cachedLines: string[] | undefined;
109
+ private lineSections: Array<ToolIoSection | null> = [];
110
+ private hoveredSection: ToolIoSection | null = null;
111
+ private showMoreRows: Partial<Record<ToolIoSection, number>> = {};
74
112
 
75
- constructor(input: string, output: string, isError: boolean) {
76
- this.input = input;
77
- this.output = output || "Done";
78
- this.isError = isError;
113
+ constructor(
114
+ private input: string,
115
+ private output: string,
116
+ private readonly isError: boolean,
117
+ private readonly maxOutputLines = DEFAULT_TOOL_DISPLAY_CONFIG.expandedPreviewMaxLines,
118
+ private readonly maxInputLines = DEFAULT_TOOL_DISPLAY_CONFIG.expandedPreviewMaxLines,
119
+ private readonly theme?: any,
120
+ ) {}
121
+
122
+ getInputBody(): string { return this.input; }
123
+ getOutputBody(): string { return this.output.trim() ? this.output : "Done"; }
124
+
125
+ setHoveredSection(section: ToolIoSection | null): void {
126
+ if (this.hoveredSection === section) return;
127
+ this.hoveredSection = section;
128
+ this.invalidate();
79
129
  }
80
130
 
131
+ sectionAtLine(line: number): ToolIoSection | null { return this.lineSections[line] ?? null; }
132
+ showMoreLine(section: ToolIoSection): number | undefined { return this.showMoreRows[section]; }
133
+
81
134
  render(width: number): string[] {
82
135
  const safeWidth = toolViewportWidth(width);
136
+ if (this.cachedLines && this.cachedWidth === safeWidth) return this.cachedLines;
137
+ const theme = this.theme;
138
+ const color = (name: string, value: string): string => typeof theme?.fg === "function" ? theme.fg(name, value) : value;
139
+ const bold = (value: string): string => typeof theme?.bold === "function" ? theme.bold(value) : value;
140
+ const rail = " │ ";
141
+ const contentWidth = Math.max(1, safeWidth - visibleWidth(rail));
142
+ const bodyColor = this.isError ? "error" : "toolOutput";
83
143
  const rows: string[] = [];
84
- const addSection = (title: string, body: string, last: boolean) => {
85
- rows.push(truncateToWidth(`${last ? "└" : "├"} ${title}`, safeWidth, ""));
86
- const source = body.replace(/\t/g, " ").replace(/\n+$/, "") || "(empty)";
87
- for (const line of source.split("\n")) {
88
- for (const wrapped of wrapTextWithAnsi(line, Math.max(1, safeWidth - 3))) {
89
- const prefix = last ? " " : "│ ";
90
- rows.push(truncateToWidth(`${prefix}${wrapped}`, safeWidth, ""));
91
- }
144
+ this.lineSections = [];
145
+ this.showMoreRows = {};
146
+ const push = (line: string, section: ToolIoSection | null) => {
147
+ rows.push(truncateToWidth(line, safeWidth, ""));
148
+ this.lineSections.push(section);
149
+ };
150
+ const pushHeader = (corner: "├" | "└", title: string) => {
151
+ push(color("dim", ` ${corner} `) + color("accent", bold(title)), null);
152
+ };
153
+ const pushRail = (line: string, section: ToolIoSection, continued: boolean) => {
154
+ push(color("dim", continued ? rail : " ") + line, section);
155
+ };
156
+ const pushBody = (body: string, section: ToolIoSection, limit: number, continued: boolean, input: boolean) => {
157
+ const raw = body.replace(/\t/g, " ").replace(/\n+$/, "");
158
+ if (!raw.trim()) {
159
+ pushRail(color("dim", "(empty)"), section, continued);
160
+ return;
161
+ }
162
+ const sources = raw.split("\n");
163
+ const wrapped: string[] = [];
164
+ const styleInput = (line: string): string => {
165
+ const match = line.match(/^([A-Za-z_][\w.-]*)(:\s*)(.*)$/);
166
+ return match
167
+ ? color("dim", `${match[1]}${match[2]}`) + color("muted", match[3] ?? "")
168
+ : color("muted", line);
169
+ };
170
+ for (const source of sources) {
171
+ const styled = input ? styleInput(source) : color(bodyColor, source);
172
+ const lines = wrapTextWithAnsi(styled, contentWidth);
173
+ wrapped.push(...(lines.length ? lines : [styled]));
174
+ }
175
+ const truncated = sources.length > limit || wrapped.length > limit;
176
+ const visible = truncated ? wrapped.slice(0, limit) : wrapped;
177
+ for (const line of visible) pushRail(line, section, continued);
178
+ if (truncated && wrapped.length > visible.length) {
179
+ const hidden = wrapped.length - visible.length;
180
+ const hintColor = this.hoveredSection === section ? "text" : "dim";
181
+ pushRail(
182
+ color("dim", `… +${hidden} more lines`) + color("dim", " •") + color(hintColor, ` ${showMoreHintText()}`),
183
+ section,
184
+ continued,
185
+ );
186
+ this.showMoreRows[section] = rows.length - 1;
92
187
  }
93
188
  };
94
- if (this.input.trim()) {
95
- addSection("Input", this.input, false);
96
- addSection("Output", this.output, true);
97
- } else {
98
- addSection("Output", this.output, true);
189
+
190
+ const hasInput = this.input.trim().length > 0;
191
+ if (hasInput) {
192
+ pushHeader("├", "Input");
193
+ pushBody(this.input, "input", Math.max(1, this.maxInputLines), true, true);
194
+ push(color("dim", " │"), null);
99
195
  }
100
- return rows.map((row) => (this.isError ? row : row));
196
+ pushHeader("└", "Output");
197
+ pushBody(this.getOutputBody(), "output", Math.max(1, this.maxOutputLines), false, false);
198
+ this.cachedWidth = safeWidth;
199
+ this.cachedLines = rows;
200
+ return rows;
101
201
  }
102
202
 
103
- invalidate(): void {}
203
+ invalidate(): void {
204
+ this.cachedWidth = undefined;
205
+ this.cachedLines = undefined;
206
+ }
104
207
  }
105
208
 
106
209
  function unavailableComponent(reason: string, theme: any): Component {
@@ -112,34 +215,24 @@ function unavailableComponent(reason: string, theme: any): Component {
112
215
  };
113
216
  }
114
217
 
115
- function resultText(result: any): string {
116
- return rawTextFromResult(result);
117
- }
218
+ function resultText(result: any): string { return rawTextFromResult(result); }
118
219
 
119
220
  function persistedFromDetails(details: any): PersistedDiff | undefined {
120
221
  if (!details || typeof details !== "object") return undefined;
121
222
  const persisted: PersistedDiff = {};
122
223
  if (typeof details.diff === "string") persisted.diff = details.diff;
123
224
  if (typeof details.patch === "string") persisted.patch = details.patch;
124
- if (typeof details.diffUnavailableReason === "string") {
125
- persisted.diffUnavailableReason = details.diffUnavailableReason;
126
- }
225
+ if (typeof details.diffUnavailableReason === "string") persisted.diffUnavailableReason = details.diffUnavailableReason;
127
226
  return Object.keys(persisted).length ? persisted : undefined;
128
227
  }
129
228
 
130
229
  function viewerConfig(context: any): ViewerDiffConfig {
131
230
  const candidate = context?.diffConfig;
132
- if (!candidate || typeof candidate !== "object") return DEFAULT_TOOL_DISPLAY_CONFIG;
133
- return {
134
- ...DEFAULT_TOOL_DISPLAY_CONFIG,
135
- ...candidate,
136
- };
231
+ return candidate && typeof candidate === "object"
232
+ ? { ...DEFAULT_TOOL_DISPLAY_CONFIG, ...candidate }
233
+ : DEFAULT_TOOL_DISPLAY_CONFIG;
137
234
  }
138
235
 
139
- /**
140
- * Rich edit/write rendering for the conversation viewer. Durable details are
141
- * passed through before any live/ephemeral context so history is deterministic.
142
- */
143
236
  export function renderRichToolResult(
144
237
  toolName: string,
145
238
  result: any,
@@ -150,100 +243,67 @@ export function renderRichToolResult(
150
243
  if (options?.isPartial || options?.isError || context?.isError) return undefined;
151
244
  const expanded = options?.expanded === true || context?.expanded === true;
152
245
  const args = context?.args ?? options?.args;
153
- const filePath = args?.file_path ?? args?.path;
154
246
  const details = result?.details;
155
247
  const persistedDiff = context?.persistedDiff ?? persistedFromDetails(details);
156
248
  const fileExistedBeforeWrite = typeof context?.fileExistedBeforeWrite === "boolean"
157
249
  ? context.fileExistedBeforeWrite
158
- : typeof details?.fileExistedBeforeWrite === "boolean"
159
- ? details.fileExistedBeforeWrite
160
- : undefined;
250
+ : typeof details?.fileExistedBeforeWrite === "boolean" ? details.fileExistedBeforeWrite : undefined;
161
251
 
162
252
  if (toolName === "edit") {
163
- return renderEditDiffResult(
164
- details,
165
- { expanded, filePath, persistedDiff, isHovered: options?.isHovered, invalidate: context?.invalidate },
166
- viewerConfig(context),
167
- theme,
168
- resultText(result),
169
- );
253
+ return renderEditDiffResult(details, {
254
+ expanded, filePath: args?.file_path ?? args?.path, persistedDiff,
255
+ isHovered: options?.isHovered, invalidate: context?.invalidate,
256
+ }, viewerConfig(context), theme, resultText(result));
170
257
  }
171
258
  if (toolName !== "write") return undefined;
172
259
  if (persistedDiff?.diffUnavailableReason && !persistedDiff.diff && !persistedDiff.patch) {
173
260
  return unavailableComponent(persistedDiff.diffUnavailableReason, theme);
174
261
  }
175
-
176
262
  const content = typeof args?.content === "string" ? args.content : undefined;
177
- if (!content && !persistedDiff?.diff && !persistedDiff?.patch) {
263
+ if (typeof content !== "string" && !persistedDiff?.diff && !persistedDiff?.patch) {
178
264
  return unavailableComponent("execution metadata is unavailable", theme);
179
265
  }
180
- return renderWriteDiffResult(
181
- content,
182
- {
183
- expanded,
184
- filePath,
185
- persistedDiff,
186
- previousContent: context?.previousContent,
187
- fileExistedBeforeWrite,
188
- isHovered: options?.isHovered,
189
- invalidate: context?.invalidate,
190
- },
191
- viewerConfig(context),
192
- theme,
193
- resultText(result),
194
- );
195
- }
196
-
197
- function renderCallSummary(toolName: string, args: any, theme: any): string {
198
- const title = toolName.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ");
199
- const value = args?.path ?? args?.file_path ?? args?.command ?? args?.query ?? args?.name;
200
- const summary = value === undefined ? title : `${title} ${oneLine(value)}`;
201
- return theme.fg("toolTitle", summary);
202
- }
203
-
204
- function settledIcon(context: any): string {
205
- if (context?.isError) return "✗";
206
- if (context?.isPartial || context?.executionStarted) return "●";
207
- return "✓";
266
+ return renderWriteDiffResult(content, {
267
+ expanded,
268
+ filePath: args?.file_path ?? args?.path,
269
+ persistedDiff,
270
+ previousContent: context?.previousContent,
271
+ fileExistedBeforeWrite,
272
+ isHovered: options?.isHovered,
273
+ invalidate: context?.invalidate,
274
+ }, viewerConfig(context), theme, resultText(result));
208
275
  }
209
276
 
210
277
  function renderFallbackResult(result: any, options: any, theme: any, context: any): Component {
211
278
  const error = options?.isError || context?.isError;
212
279
  const expanded = options?.expanded === true || context?.expanded === true;
213
- const text = textFromResult(result, expanded);
214
- if (expanded && (text.trim() || formatToolInputArgs(context?.args).trim())) {
215
- return new ExpandedToolIoView(formatToolInputArgs(context?.args), text, Boolean(error));
280
+ const maxChars = Number.isFinite(context?.maxChars) ? Math.max(0, Math.floor(context.maxChars)) : 16_384;
281
+ const text = textFromResult(result, expanded, maxChars);
282
+ const input = formatToolInputArgs(context?.args, maxChars);
283
+ if (expanded && (text.trim() || input.trim())) {
284
+ const maxLines = Number.isFinite(context?.diffConfig?.expandedPreviewMaxLines)
285
+ ? Math.max(1, Math.floor(context.diffConfig.expandedPreviewMaxLines))
286
+ : DEFAULT_TOOL_DISPLAY_CONFIG.expandedPreviewMaxLines;
287
+ return new ExpandedToolIoView(input, text, Boolean(error), maxLines, maxLines, theme);
216
288
  }
217
- const lines = text ? text.split("\n") : [];
218
- const count = lines.length;
289
+ const count = text ? text.split("\n").length : 0;
219
290
  const summary = error ? oneLine(text) || "Failed" : count ? `${count} ${count === 1 ? "line" : "lines"} returned` : "Done";
220
291
  const expandable = !expanded && hasExpandableDetail(text, context?.args);
221
292
  return {
222
293
  render(width: number): string[] {
223
294
  const hovered = options?.isHovered?.() ?? context?.isHovered?.() ?? false;
224
- const clickLabel = showMoreHintText();
225
- const hint = expandable ? ` • ${clickLabel}` : "";
226
- const color = error ? "error" : "muted";
295
+ const hint = expandable ? ` • ${showMoreHintText()}` : "";
227
296
  const line = expandable && hovered
228
- ? theme.fg(color, ` ↳ ${summary} • `) + theme.fg("text", clickLabel)
229
- : theme.fg(color, ` ↳ ${summary}${hint}`);
297
+ ? theme.fg(error ? "error" : "muted", ` ↳ ${summary} • `) + theme.fg("text", showMoreHintText())
298
+ : theme.fg(error ? "error" : "muted", ` ↳ ${summary}${hint}`);
230
299
  return [truncateToWidth(line, toolViewportWidth(width), "")];
231
300
  },
232
301
  invalidate() {},
233
302
  };
234
303
  }
235
304
 
236
- export function createViewerCcstyleResult(
237
- toolName: string,
238
- result: any,
239
- options: any,
240
- theme: any,
241
- context: any,
242
- ): Component {
243
- return (
244
- renderRichToolResult(toolName, result, options, theme, context) ??
245
- renderFallbackResult(result, options, theme, context)
246
- );
305
+ export function createViewerCcstyleResult(toolName: string, result: any, options: any, theme: any, context: any): Component {
306
+ return renderRichToolResult(toolName, result, options, theme, context) ?? renderFallbackResult(result, options, theme, context);
247
307
  }
248
308
 
249
- export { ExpandedToolIoView };
309
+ export type { DisplayConfigInput };