@oh-my-pi/pi-coding-agent 9.6.0 → 9.6.3
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 +17 -0
- package/docs/theme.md +9 -12
- package/package.json +7 -7
- package/src/exa/render.ts +12 -12
- package/src/ipy/gateway-coordinator.ts +1 -1
- package/src/ipy/kernel.ts +5 -0
- package/src/ipy/runtime.ts +2 -6
- package/src/lsp/render.ts +16 -30
- package/src/modes/components/bash-execution.ts +2 -4
- package/src/modes/components/custom-message.ts +1 -1
- package/src/modes/components/footer.ts +1 -1
- package/src/modes/components/history-search.ts +3 -2
- package/src/modes/components/hook-message.ts +1 -1
- package/src/modes/components/python-execution.ts +2 -4
- package/src/modes/components/read-tool-group.ts +1 -1
- package/src/modes/components/session-selector.ts +7 -11
- package/src/modes/components/status-line/segments.ts +1 -1
- package/src/modes/components/status-line.ts +1 -1
- package/src/modes/components/tool-execution.ts +3 -3
- package/src/modes/components/ttsr-notification.ts +1 -1
- package/src/modes/components/welcome.ts +2 -2
- package/src/modes/controllers/event-controller.ts +3 -3
- package/src/modes/interactive-mode.ts +1 -1
- package/src/modes/theme/theme.ts +0 -11
- package/src/patch/shared.ts +7 -10
- package/src/task/executor.ts +1 -1
- package/src/task/render.ts +31 -33
- package/src/tools/bash.ts +3 -3
- package/src/tools/calculator.ts +3 -3
- package/src/tools/fetch.ts +4 -6
- package/src/tools/python.ts +22 -31
- package/src/tools/read.ts +1 -1
- package/src/tools/render-utils.ts +12 -21
- package/src/tools/review.ts +1 -7
- package/src/tools/ssh.ts +6 -8
- package/src/tools/write.ts +5 -5
- package/src/tui/code-cell.ts +2 -2
- package/src/tui/output-block.ts +2 -2
- package/src/tui/tree-list.ts +1 -3
- package/src/tui/utils.ts +3 -5
- package/src/web/search/render.ts +14 -24
|
@@ -66,7 +66,7 @@ export class EventController {
|
|
|
66
66
|
this.ctx.ui,
|
|
67
67
|
spinner => theme.fg("accent", spinner),
|
|
68
68
|
text => theme.fg("muted", text),
|
|
69
|
-
`Working
|
|
69
|
+
`Working… (esc to interrupt)`,
|
|
70
70
|
getSymbolTheme().spinnerFrames,
|
|
71
71
|
);
|
|
72
72
|
this.ctx.statusContainer.addChild(this.ctx.loadingAnimation);
|
|
@@ -286,7 +286,7 @@ export class EventController {
|
|
|
286
286
|
this.ctx.ui,
|
|
287
287
|
spinner => theme.fg("accent", spinner),
|
|
288
288
|
text => theme.fg("muted", text),
|
|
289
|
-
`${reasonText}Auto-compacting
|
|
289
|
+
`${reasonText}Auto-compacting… (esc to cancel)`,
|
|
290
290
|
getSymbolTheme().spinnerFrames,
|
|
291
291
|
);
|
|
292
292
|
this.ctx.statusContainer.addChild(this.ctx.autoCompactionLoader);
|
|
@@ -337,7 +337,7 @@ export class EventController {
|
|
|
337
337
|
this.ctx.ui,
|
|
338
338
|
spinner => theme.fg("warning", spinner),
|
|
339
339
|
text => theme.fg("muted", text),
|
|
340
|
-
`Retrying (${event.attempt}/${event.maxAttempts}) in ${delaySeconds}s
|
|
340
|
+
`Retrying (${event.attempt}/${event.maxAttempts}) in ${delaySeconds}s… (esc to cancel)`,
|
|
341
341
|
getSymbolTheme().spinnerFrames,
|
|
342
342
|
);
|
|
343
343
|
this.ctx.statusContainer.addChild(this.ctx.retryLoader);
|
|
@@ -110,7 +110,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
110
110
|
public autoCompactionLoader: Loader | undefined = undefined;
|
|
111
111
|
public retryLoader: Loader | undefined = undefined;
|
|
112
112
|
private pendingWorkingMessage: string | undefined;
|
|
113
|
-
private readonly defaultWorkingMessage = `Working
|
|
113
|
+
private readonly defaultWorkingMessage = `Working… (esc to interrupt)`;
|
|
114
114
|
public autoCompactionEscapeHandler?: () => void;
|
|
115
115
|
public retryEscapeHandler?: () => void;
|
|
116
116
|
public unsubscribe?: () => void;
|
package/src/modes/theme/theme.ts
CHANGED
|
@@ -124,7 +124,6 @@ export type SymbolKey =
|
|
|
124
124
|
| "checkbox.checked"
|
|
125
125
|
| "checkbox.unchecked"
|
|
126
126
|
// Text Formatting
|
|
127
|
-
| "format.ellipsis"
|
|
128
127
|
| "format.bullet"
|
|
129
128
|
| "format.dash"
|
|
130
129
|
| "format.bracketLeft"
|
|
@@ -357,9 +356,6 @@ const UNICODE_SYMBOLS: SymbolMap = {
|
|
|
357
356
|
"checkbox.checked": "☑",
|
|
358
357
|
// pick: ☐ | alt: □ ▢
|
|
359
358
|
"checkbox.unchecked": "☐",
|
|
360
|
-
// Text Formatting
|
|
361
|
-
// pick: … | alt: ⋯ ...
|
|
362
|
-
"format.ellipsis": "…",
|
|
363
359
|
// pick: • | alt: · ▪ ◦
|
|
364
360
|
"format.bullet": "•",
|
|
365
361
|
// pick: – | alt: — ― -
|
|
@@ -598,9 +594,6 @@ const NERD_SYMBOLS: SymbolMap = {
|
|
|
598
594
|
"checkbox.checked": "\uf14a",
|
|
599
595
|
// pick: | alt:
|
|
600
596
|
"checkbox.unchecked": "\uf096",
|
|
601
|
-
// Text Formatting
|
|
602
|
-
// pick: … | alt: ⋯ ...
|
|
603
|
-
"format.ellipsis": "\u2026",
|
|
604
597
|
// pick: | alt: •
|
|
605
598
|
"format.bullet": "\uf111",
|
|
606
599
|
// pick: – | alt: — ― -
|
|
@@ -752,8 +745,6 @@ const ASCII_SYMBOLS: SymbolMap = {
|
|
|
752
745
|
// Checkboxes
|
|
753
746
|
"checkbox.checked": "[x]",
|
|
754
747
|
"checkbox.unchecked": "[ ]",
|
|
755
|
-
// Text Formatting
|
|
756
|
-
"format.ellipsis": "...",
|
|
757
748
|
"format.bullet": "*",
|
|
758
749
|
"format.dash": "-",
|
|
759
750
|
"format.bracketLeft": "[",
|
|
@@ -1458,7 +1449,6 @@ export class Theme {
|
|
|
1458
1449
|
|
|
1459
1450
|
get format() {
|
|
1460
1451
|
return {
|
|
1461
|
-
ellipsis: this.symbols["format.ellipsis"],
|
|
1462
1452
|
bullet: this.symbols["format.bullet"],
|
|
1463
1453
|
dash: this.symbols["format.dash"],
|
|
1464
1454
|
bracketLeft: this.symbols["format.bracketLeft"],
|
|
@@ -2171,7 +2161,6 @@ export function getSymbolTheme(): SymbolTheme {
|
|
|
2171
2161
|
return {
|
|
2172
2162
|
cursor: theme.nav.cursor,
|
|
2173
2163
|
inputCursor: preset === "ascii" ? "|" : "▏",
|
|
2174
|
-
ellipsis: theme.format.ellipsis,
|
|
2175
2164
|
boxRound: theme.boxRound,
|
|
2176
2165
|
boxSharp: theme.boxSharp,
|
|
2177
2166
|
table: theme.boxSharp,
|
package/src/patch/shared.ts
CHANGED
|
@@ -103,10 +103,10 @@ function formatStreamingDiff(diff: string, rawPath: string, uiTheme: Theme): str
|
|
|
103
103
|
|
|
104
104
|
let text = "\n\n";
|
|
105
105
|
if (hidden > 0) {
|
|
106
|
-
text += uiTheme.fg("dim",
|
|
106
|
+
text += uiTheme.fg("dim", `… (${hidden} earlier lines)\n`);
|
|
107
107
|
}
|
|
108
108
|
text += renderDiffColored(displayLines.join("\n"), { filePath: rawPath });
|
|
109
|
-
text += uiTheme.fg("dim", `\n
|
|
109
|
+
text += uiTheme.fg("dim", `\n… (streaming)`);
|
|
110
110
|
return text;
|
|
111
111
|
}
|
|
112
112
|
|
|
@@ -147,10 +147,7 @@ function renderDiffSection(
|
|
|
147
147
|
const remainder: string[] = [];
|
|
148
148
|
if (hiddenHunks > 0) remainder.push(`${hiddenHunks} more hunks`);
|
|
149
149
|
if (hiddenLines > 0) remainder.push(`${hiddenLines} more lines`);
|
|
150
|
-
text += uiTheme.fg(
|
|
151
|
-
"toolOutput",
|
|
152
|
-
`\n${uiTheme.format.ellipsis} (${remainder.join(", ")}) ${formatExpandHint(uiTheme)}`,
|
|
153
|
-
);
|
|
150
|
+
text += uiTheme.fg("toolOutput", `\n… (${remainder.join(", ")}) ${formatExpandHint(uiTheme)}`);
|
|
154
151
|
}
|
|
155
152
|
return text;
|
|
156
153
|
}
|
|
@@ -164,7 +161,7 @@ export const editToolRenderer = {
|
|
|
164
161
|
const filePath = shortenPath(rawPath);
|
|
165
162
|
const editLanguage = getLanguageFromPath(rawPath) ?? "text";
|
|
166
163
|
const editIcon = uiTheme.fg("muted", uiTheme.getLangIcon(editLanguage));
|
|
167
|
-
let pathDisplay = filePath ? uiTheme.fg("accent", filePath) : uiTheme.fg("toolOutput",
|
|
164
|
+
let pathDisplay = filePath ? uiTheme.fg("accent", filePath) : uiTheme.fg("toolOutput", "…");
|
|
168
165
|
|
|
169
166
|
// Add arrow for move/rename operations
|
|
170
167
|
if (args.rename) {
|
|
@@ -188,7 +185,7 @@ export const editToolRenderer = {
|
|
|
188
185
|
text += `${uiTheme.fg("toolOutput", ui.truncate(line, 80))}\n`;
|
|
189
186
|
}
|
|
190
187
|
if (previewLines.length > maxLines) {
|
|
191
|
-
text += uiTheme.fg("dim",
|
|
188
|
+
text += uiTheme.fg("dim", `… ${previewLines.length - maxLines} more lines`);
|
|
192
189
|
}
|
|
193
190
|
} else if (args.newText || args.patch) {
|
|
194
191
|
const previewLines = (args.newText ?? args.patch ?? "").split("\n");
|
|
@@ -198,7 +195,7 @@ export const editToolRenderer = {
|
|
|
198
195
|
text += `${uiTheme.fg("toolOutput", ui.truncate(line, 80))}\n`;
|
|
199
196
|
}
|
|
200
197
|
if (previewLines.length > maxLines) {
|
|
201
|
-
text += uiTheme.fg("dim",
|
|
198
|
+
text += uiTheme.fg("dim", `… ${previewLines.length - maxLines} more lines`);
|
|
202
199
|
}
|
|
203
200
|
}
|
|
204
201
|
|
|
@@ -225,7 +222,7 @@ export const editToolRenderer = {
|
|
|
225
222
|
const rename = args?.rename || result.details?.rename;
|
|
226
223
|
|
|
227
224
|
// Build path display with line number if available
|
|
228
|
-
let pathDisplay = filePath ? uiTheme.fg("accent", filePath) : uiTheme.fg("toolOutput",
|
|
225
|
+
let pathDisplay = filePath ? uiTheme.fg("accent", filePath) : uiTheme.fg("toolOutput", "…");
|
|
229
226
|
const firstChangedLine =
|
|
230
227
|
(editDiffPreview && "firstChangedLine" in editDiffPreview ? editDiffPreview.firstChangedLine : undefined) ||
|
|
231
228
|
(result.details && !result.isError ? result.details.firstChangedLine : undefined);
|
package/src/task/executor.ts
CHANGED
|
@@ -135,7 +135,7 @@ function resolveModelOverride(
|
|
|
135
135
|
): { model?: Model<Api>; thinkingLevel?: ThinkingLevel } {
|
|
136
136
|
if (modelPatterns.length === 0) return {};
|
|
137
137
|
const matchPreferences = { usageOrder: settings?.getStorage()?.getModelUsageOrder() };
|
|
138
|
-
const roles = settings?.
|
|
138
|
+
const roles = settings?.getGroup("modelRoles");
|
|
139
139
|
for (const pattern of modelPatterns) {
|
|
140
140
|
const normalized = pattern.trim().toLowerCase();
|
|
141
141
|
if (!normalized || DEFAULT_MODEL_ALIASES.has(normalized)) {
|
package/src/task/render.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
formatMoreItems,
|
|
16
16
|
formatStatusIcon,
|
|
17
17
|
formatTokens,
|
|
18
|
-
|
|
18
|
+
truncateToWidth,
|
|
19
19
|
} from "../tools/render-utils";
|
|
20
20
|
import {
|
|
21
21
|
type FindingPriority,
|
|
@@ -67,10 +67,10 @@ function formatFindingSummary(findings: ReportFindingDetails[], theme: Theme): s
|
|
|
67
67
|
return `${theme.fg("dim", "Findings:")} ${parts.join(theme.sep.dot)}`;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
function formatJsonScalar(value: unknown,
|
|
70
|
+
function formatJsonScalar(value: unknown, _theme: Theme): string {
|
|
71
71
|
if (value === null) return "null";
|
|
72
72
|
if (typeof value === "string") {
|
|
73
|
-
const trimmed =
|
|
73
|
+
const trimmed = truncateToWidth(value, 70);
|
|
74
74
|
return `"${trimmed}"`;
|
|
75
75
|
}
|
|
76
76
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
@@ -150,7 +150,7 @@ function renderJsonTreeLines(
|
|
|
150
150
|
pushLine(
|
|
151
151
|
`${buildTreePrefix([...ancestors, !isLast], theme)}${theme.fg("dim", theme.tree.last)} ${theme.fg(
|
|
152
152
|
"dim",
|
|
153
|
-
|
|
153
|
+
"…",
|
|
154
154
|
)}`,
|
|
155
155
|
);
|
|
156
156
|
return;
|
|
@@ -183,7 +183,7 @@ function renderJsonTreeLines(
|
|
|
183
183
|
pushLine(
|
|
184
184
|
`${buildTreePrefix([...ancestors, !isLast], theme)}${theme.fg("dim", theme.tree.last)} ${theme.fg(
|
|
185
185
|
"dim",
|
|
186
|
-
|
|
186
|
+
"…",
|
|
187
187
|
)}`,
|
|
188
188
|
);
|
|
189
189
|
return;
|
|
@@ -253,7 +253,7 @@ function renderOutputSection(
|
|
|
253
253
|
lines.push(
|
|
254
254
|
`${continuePrefix} ${theme.fg("warning", theme.status.warning)} ${theme.fg(
|
|
255
255
|
"dim",
|
|
256
|
-
|
|
256
|
+
truncateToWidth(warning, 80),
|
|
257
257
|
)}`,
|
|
258
258
|
);
|
|
259
259
|
|
|
@@ -276,7 +276,7 @@ function renderOutputSection(
|
|
|
276
276
|
lines.push(`${continuePrefix} ${line}`);
|
|
277
277
|
}
|
|
278
278
|
if (tree.truncated) {
|
|
279
|
-
lines.push(`${continuePrefix} ${theme.fg("dim",
|
|
279
|
+
lines.push(`${continuePrefix} ${theme.fg("dim", "…")}`);
|
|
280
280
|
}
|
|
281
281
|
return lines;
|
|
282
282
|
}
|
|
@@ -288,12 +288,12 @@ function renderOutputSection(
|
|
|
288
288
|
const outputLines = output.trimEnd().split("\n");
|
|
289
289
|
const previewCount = expanded ? maxExpanded : maxCollapsed;
|
|
290
290
|
for (const line of outputLines.slice(0, previewCount)) {
|
|
291
|
-
lines.push(`${continuePrefix} ${theme.fg("dim",
|
|
291
|
+
lines.push(`${continuePrefix} ${theme.fg("dim", truncateToWidth(line, 70))}`);
|
|
292
292
|
}
|
|
293
293
|
|
|
294
294
|
if (outputLines.length > previewCount) {
|
|
295
295
|
lines.push(
|
|
296
|
-
`${continuePrefix} ${theme.fg("dim", formatMoreItems(outputLines.length - previewCount, "line"
|
|
296
|
+
`${continuePrefix} ${theme.fg("dim", formatMoreItems(outputLines.length - previewCount, "line"))}`,
|
|
297
297
|
);
|
|
298
298
|
}
|
|
299
299
|
|
|
@@ -318,7 +318,7 @@ function renderOutputSection(
|
|
|
318
318
|
lines.push(`${continuePrefix} ${line}`);
|
|
319
319
|
}
|
|
320
320
|
if (tree.truncated) {
|
|
321
|
-
lines.push(`${continuePrefix} ${theme.fg("dim",
|
|
321
|
+
lines.push(`${continuePrefix} ${theme.fg("dim", "…")}`);
|
|
322
322
|
}
|
|
323
323
|
return lines;
|
|
324
324
|
}
|
|
@@ -332,19 +332,17 @@ function renderOutputSection(
|
|
|
332
332
|
const outputLines = output.trimEnd().split("\n");
|
|
333
333
|
const previewCount = expanded ? maxExpanded : maxCollapsed;
|
|
334
334
|
for (const line of outputLines.slice(0, previewCount)) {
|
|
335
|
-
lines.push(`${continuePrefix} ${theme.fg("dim",
|
|
335
|
+
lines.push(`${continuePrefix} ${theme.fg("dim", truncateToWidth(line, 70))}`);
|
|
336
336
|
}
|
|
337
337
|
|
|
338
338
|
if (outputLines.length > previewCount) {
|
|
339
|
-
lines.push(
|
|
340
|
-
`${continuePrefix} ${theme.fg("dim", formatMoreItems(outputLines.length - previewCount, "line", theme))}`,
|
|
341
|
-
);
|
|
339
|
+
lines.push(`${continuePrefix} ${theme.fg("dim", formatMoreItems(outputLines.length - previewCount, "line"))}`);
|
|
342
340
|
}
|
|
343
341
|
|
|
344
342
|
return lines;
|
|
345
343
|
}
|
|
346
344
|
|
|
347
|
-
function formatArgsInline(args: Record<string, string>,
|
|
345
|
+
function formatArgsInline(args: Record<string, string>, _theme: Theme): string {
|
|
348
346
|
const entries = Object.entries(args);
|
|
349
347
|
if (entries.length === 0) return "No arguments";
|
|
350
348
|
|
|
@@ -352,11 +350,11 @@ function formatArgsInline(args: Record<string, string>, theme: Theme): string {
|
|
|
352
350
|
if (entries.length === 1) {
|
|
353
351
|
const [key, value] = entries[0];
|
|
354
352
|
const humanKey = humanizeKey(key);
|
|
355
|
-
const displayValue = `"${
|
|
353
|
+
const displayValue = `"${truncateToWidth(value, 32)}"`;
|
|
356
354
|
return `${humanKey}: ${displayValue}`;
|
|
357
355
|
}
|
|
358
356
|
|
|
359
|
-
const pairs = entries.map(([key, value]) => `${key}=${
|
|
357
|
+
const pairs = entries.map(([key, value]) => `${key}=${truncateToWidth(value, 24)}`);
|
|
360
358
|
return `Args: ${pairs.join(", ")}`;
|
|
361
359
|
}
|
|
362
360
|
|
|
@@ -365,12 +363,12 @@ function humanizeKey(key: string): string {
|
|
|
365
363
|
return key.replace(/[-_]/g, " ").replace(/\b\w/g, c => c.toUpperCase());
|
|
366
364
|
}
|
|
367
365
|
|
|
368
|
-
function formatScalarInline(value: unknown, maxLen: number,
|
|
366
|
+
function formatScalarInline(value: unknown, maxLen: number, _theme: Theme): string {
|
|
369
367
|
if (value === null) return "null";
|
|
370
368
|
if (value === undefined) return "undefined";
|
|
371
369
|
if (typeof value === "boolean") return String(value);
|
|
372
370
|
if (typeof value === "number") return String(value);
|
|
373
|
-
if (typeof value === "string") return `"${
|
|
371
|
+
if (typeof value === "string") return `"${truncateToWidth(value, maxLen)}"`;
|
|
374
372
|
if (Array.isArray(value)) return `[${value.length} items]`;
|
|
375
373
|
if (typeof value === "object") {
|
|
376
374
|
const keys = Object.keys(value);
|
|
@@ -391,7 +389,7 @@ function formatOutputInline(data: unknown, theme: Theme, maxWidth = 80): string
|
|
|
391
389
|
if (Array.isArray(data)) {
|
|
392
390
|
if (data.length === 0) return "Output: []";
|
|
393
391
|
const preview = formatScalarInline(data[0], 40, theme);
|
|
394
|
-
return `Output: [${data.length} items] ${preview}${data.length > 1 ?
|
|
392
|
+
return `Output: [${data.length} items] ${preview}${data.length > 1 ? "…" : ""}`;
|
|
395
393
|
}
|
|
396
394
|
|
|
397
395
|
// For objects, show key=value pairs inline
|
|
@@ -407,7 +405,7 @@ function formatOutputInline(data: unknown, theme: Theme, maxWidth = 80): string
|
|
|
407
405
|
const addLen = pairs.length > 0 ? pairStr.length + 2 : pairStr.length; // +2 for ", "
|
|
408
406
|
|
|
409
407
|
if (totalLen + addLen > maxWidth && pairs.length > 0) {
|
|
410
|
-
pairs.push(
|
|
408
|
+
pairs.push("…");
|
|
411
409
|
break;
|
|
412
410
|
}
|
|
413
411
|
|
|
@@ -442,7 +440,7 @@ function renderArgsSection(
|
|
|
442
440
|
if (entries.length === 1) {
|
|
443
441
|
const [key, value] = entries[0];
|
|
444
442
|
const humanKey = humanizeKey(key);
|
|
445
|
-
const displayValue = `"${
|
|
443
|
+
const displayValue = `"${truncateToWidth(value, 60)}"`;
|
|
446
444
|
lines.push(`${continuePrefix}${theme.fg("dim", `${humanKey}: ${displayValue}`)}`);
|
|
447
445
|
return lines;
|
|
448
446
|
}
|
|
@@ -453,7 +451,7 @@ function renderArgsSection(
|
|
|
453
451
|
lines.push(`${continuePrefix} ${line}`);
|
|
454
452
|
}
|
|
455
453
|
if (tree.truncated) {
|
|
456
|
-
lines.push(`${continuePrefix} ${theme.fg("dim",
|
|
454
|
+
lines.push(`${continuePrefix} ${theme.fg("dim", "…")}`);
|
|
457
455
|
}
|
|
458
456
|
|
|
459
457
|
return lines;
|
|
@@ -531,7 +529,7 @@ function renderAgentProgress(
|
|
|
531
529
|
|
|
532
530
|
if (progress.status === "running") {
|
|
533
531
|
if (!description) {
|
|
534
|
-
const taskPreview =
|
|
532
|
+
const taskPreview = truncateToWidth(progress.task, 40);
|
|
535
533
|
statusLine += ` ${theme.fg("muted", taskPreview)}`;
|
|
536
534
|
}
|
|
537
535
|
statusLine += `${theme.sep.dot}${theme.fg("dim", `${progress.toolCount} tools`)}`;
|
|
@@ -552,7 +550,7 @@ function renderAgentProgress(
|
|
|
552
550
|
if (progress.currentTool) {
|
|
553
551
|
let toolLine = `${continuePrefix}${theme.tree.hook} ${theme.fg("muted", progress.currentTool)}`;
|
|
554
552
|
if (progress.currentToolArgs) {
|
|
555
|
-
toolLine += `: ${theme.fg("dim",
|
|
553
|
+
toolLine += `: ${theme.fg("dim", truncateToWidth(progress.currentToolArgs, 40))}`;
|
|
556
554
|
}
|
|
557
555
|
if (progress.currentToolStartMs) {
|
|
558
556
|
const elapsed = Date.now() - progress.currentToolStartMs;
|
|
@@ -566,7 +564,7 @@ function renderAgentProgress(
|
|
|
566
564
|
const recent = progress.recentTools[0];
|
|
567
565
|
let toolLine = `${continuePrefix}${theme.tree.hook} ${theme.fg("dim", recent.tool)}`;
|
|
568
566
|
if (recent.args) {
|
|
569
|
-
toolLine += `: ${theme.fg("dim",
|
|
567
|
+
toolLine += `: ${theme.fg("dim", truncateToWidth(recent.args, 40))}`;
|
|
570
568
|
}
|
|
571
569
|
lines.push(toolLine);
|
|
572
570
|
}
|
|
@@ -612,7 +610,7 @@ function renderAgentProgress(
|
|
|
612
610
|
lines.push(
|
|
613
611
|
`${continuePrefix}${theme.fg(
|
|
614
612
|
"dim",
|
|
615
|
-
formatMoreItems((dataArray as unknown[]).length - displayCount, "item"
|
|
613
|
+
formatMoreItems((dataArray as unknown[]).length - displayCount, "item"),
|
|
616
614
|
)}`,
|
|
617
615
|
);
|
|
618
616
|
}
|
|
@@ -661,7 +659,7 @@ function renderReviewResult(
|
|
|
661
659
|
}
|
|
662
660
|
} else {
|
|
663
661
|
// Preview: first sentence or ~100 chars
|
|
664
|
-
const preview =
|
|
662
|
+
const preview = truncateToWidth(`${summary.explanation.split(/[.!?]/)[0]}.`, 100);
|
|
665
663
|
lines.push(`${continuePrefix}${theme.fg("dim", preview)}`);
|
|
666
664
|
}
|
|
667
665
|
}
|
|
@@ -718,7 +716,7 @@ function renderFindings(
|
|
|
718
716
|
}
|
|
719
717
|
|
|
720
718
|
if (!expanded && findings.length > 3) {
|
|
721
|
-
lines.push(`${continuePrefix}${theme.fg("dim", formatMoreItems(findings.length - 3, "finding"
|
|
719
|
+
lines.push(`${continuePrefix}${theme.fg("dim", formatMoreItems(findings.length - 3, "finding"))}`);
|
|
722
720
|
}
|
|
723
721
|
|
|
724
722
|
return lines;
|
|
@@ -830,7 +828,7 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool
|
|
|
830
828
|
lines.push(
|
|
831
829
|
`${continuePrefix}${theme.fg("warning", theme.status.warning)} ${theme.fg(
|
|
832
830
|
"dim",
|
|
833
|
-
|
|
831
|
+
truncateToWidth(missingCompleteWarning, 80),
|
|
834
832
|
)}`,
|
|
835
833
|
);
|
|
836
834
|
}
|
|
@@ -848,7 +846,7 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool
|
|
|
848
846
|
|
|
849
847
|
// Error message
|
|
850
848
|
if (result.error && !success) {
|
|
851
|
-
lines.push(`${continuePrefix}${theme.fg("error",
|
|
849
|
+
lines.push(`${continuePrefix}${theme.fg("error", truncateToWidth(result.error, 70))}`);
|
|
852
850
|
}
|
|
853
851
|
|
|
854
852
|
return lines;
|
|
@@ -869,7 +867,7 @@ export function renderResult(
|
|
|
869
867
|
if (!details) {
|
|
870
868
|
// Fallback to simple text
|
|
871
869
|
const text = result.content.find(c => c.type === "text")?.text || "";
|
|
872
|
-
return new Text(theme.fg("dim",
|
|
870
|
+
return new Text(theme.fg("dim", truncateToWidth(text, 100)), 0, 0);
|
|
873
871
|
}
|
|
874
872
|
|
|
875
873
|
const lines: string[] = [];
|
|
@@ -911,7 +909,7 @@ export function renderResult(
|
|
|
911
909
|
|
|
912
910
|
if (lines.length === 0) {
|
|
913
911
|
const text = fallbackText.trim() ? fallbackText : "No results";
|
|
914
|
-
return new Text(theme.fg("dim",
|
|
912
|
+
return new Text(theme.fg("dim", truncateToWidth(text, 140)), 0, 0);
|
|
915
913
|
}
|
|
916
914
|
|
|
917
915
|
if (fallbackText.trim()) {
|
package/src/tools/bash.ts
CHANGED
|
@@ -182,8 +182,8 @@ interface BashRenderContext {
|
|
|
182
182
|
timeout?: number;
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
function formatBashCommand(args: BashRenderArgs,
|
|
186
|
-
const command = args.command ||
|
|
185
|
+
function formatBashCommand(args: BashRenderArgs, _uiTheme: Theme): string {
|
|
186
|
+
const command = args.command || "…";
|
|
187
187
|
const prompt = "$";
|
|
188
188
|
const cwd = process.cwd();
|
|
189
189
|
let displayWorkdir = args.cwd;
|
|
@@ -285,7 +285,7 @@ export const bashToolRenderer = {
|
|
|
285
285
|
outputLines.push(
|
|
286
286
|
uiTheme.fg(
|
|
287
287
|
"dim",
|
|
288
|
-
|
|
288
|
+
`… (${result.skippedCount} earlier lines, showing ${result.visualLines.length} of ${result.skippedCount + result.visualLines.length}) (ctrl+o to expand)`,
|
|
289
289
|
),
|
|
290
290
|
);
|
|
291
291
|
}
|
package/src/tools/calculator.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
formatErrorMessage,
|
|
16
16
|
PREVIEW_LIMITS,
|
|
17
17
|
TRUNCATE_LENGTHS,
|
|
18
|
-
|
|
18
|
+
truncateToWidth,
|
|
19
19
|
} from "./render-utils";
|
|
20
20
|
|
|
21
21
|
// =============================================================================
|
|
@@ -454,7 +454,7 @@ export const calculatorToolRenderer = {
|
|
|
454
454
|
renderCall(args: CalculatorRenderArgs, uiTheme: Theme): Component {
|
|
455
455
|
const count = args.calculations?.length ?? 0;
|
|
456
456
|
const firstExpression = args.calculations?.[0]?.expression;
|
|
457
|
-
const description = firstExpression ?
|
|
457
|
+
const description = firstExpression ? truncateToWidth(firstExpression, TRUNCATE_LENGTHS.TITLE) : undefined;
|
|
458
458
|
const meta = count > 0 ? [formatCount("calc", count)] : [];
|
|
459
459
|
const text = renderStatusLine({ icon: "pending", title: "Calc", description, meta }, uiTheme);
|
|
460
460
|
return new Text(text, 0, 0);
|
|
@@ -495,7 +495,7 @@ export const calculatorToolRenderer = {
|
|
|
495
495
|
}
|
|
496
496
|
|
|
497
497
|
const description = args?.calculations?.[0]?.expression
|
|
498
|
-
?
|
|
498
|
+
? truncateToWidth(args.calculations[0].expression, TRUNCATE_LENGTHS.TITLE)
|
|
499
499
|
: undefined;
|
|
500
500
|
const header = renderStatusLine(
|
|
501
501
|
{ icon: "success", title: "Calc", description, meta: [formatCount("result", outputs.length)] },
|
package/src/tools/fetch.ts
CHANGED
|
@@ -967,7 +967,7 @@ export function renderFetchCall(
|
|
|
967
967
|
uiTheme: Theme = theme,
|
|
968
968
|
): Component {
|
|
969
969
|
const domain = getDomain(args.url);
|
|
970
|
-
const path = truncate(args.url.replace(/^https?:\/\/[^/]+/, ""), 50,
|
|
970
|
+
const path = truncate(args.url.replace(/^https?:\/\/[^/]+/, ""), 50, "…");
|
|
971
971
|
const description = `${domain}${path ? ` ${path}` : ""}`.trim();
|
|
972
972
|
const meta: string[] = [];
|
|
973
973
|
if (args.raw) meta.push("raw");
|
|
@@ -990,7 +990,7 @@ export function renderFetchResult(
|
|
|
990
990
|
}
|
|
991
991
|
|
|
992
992
|
const domain = getDomain(details.finalUrl);
|
|
993
|
-
const path = truncate(details.finalUrl.replace(/^https?:\/\/[^/]+/, ""), 50,
|
|
993
|
+
const path = truncate(details.finalUrl.replace(/^https?:\/\/[^/]+/, ""), 50, "…");
|
|
994
994
|
const hasRedirect = details.url !== details.finalUrl;
|
|
995
995
|
const hasNotes = details.notes.length > 0;
|
|
996
996
|
const truncation = details.meta?.truncation;
|
|
@@ -1035,15 +1035,13 @@ export function renderFetchResult(
|
|
|
1035
1035
|
|
|
1036
1036
|
const previewLimit = expanded ? 12 : 3;
|
|
1037
1037
|
const previewList = applyListLimit(contentLines, { headLimit: previewLimit });
|
|
1038
|
-
const previewLines = previewList.items.map(line => truncate(line.trimEnd(), 120,
|
|
1038
|
+
const previewLines = previewList.items.map(line => truncate(line.trimEnd(), 120, "…"));
|
|
1039
1039
|
const remaining = Math.max(0, contentLines.length - previewLines.length);
|
|
1040
1040
|
const contentPreviewLines =
|
|
1041
1041
|
previewLines.length > 0 ? previewLines.map(line => uiTheme.fg("dim", line)) : [uiTheme.fg("dim", "(no content)")];
|
|
1042
1042
|
if (remaining > 0) {
|
|
1043
1043
|
const hint = formatExpandHint(uiTheme, expanded, true);
|
|
1044
|
-
contentPreviewLines.push(
|
|
1045
|
-
uiTheme.fg("muted", `${uiTheme.format.ellipsis} ${remaining} more lines${hint ? ` ${hint}` : ""}`),
|
|
1046
|
-
);
|
|
1044
|
+
contentPreviewLines.push(uiTheme.fg("muted", `… ${remaining} more lines${hint ? ` ${hint}` : ""}`));
|
|
1047
1045
|
}
|
|
1048
1046
|
|
|
1049
1047
|
return {
|
package/src/tools/python.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as path from "node:path";
|
|
|
2
2
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
3
3
|
import type { ImageContent } from "@oh-my-pi/pi-ai";
|
|
4
4
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
5
|
-
import { Text
|
|
5
|
+
import { Text } from "@oh-my-pi/pi-tui";
|
|
6
6
|
import { type Static, Type } from "@sinclair/typebox";
|
|
7
7
|
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
8
8
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
@@ -17,7 +17,7 @@ import type { ToolSession } from ".";
|
|
|
17
17
|
import type { OutputMeta } from "./output-meta";
|
|
18
18
|
import { allocateOutputArtifact, createTailBuffer } from "./output-utils";
|
|
19
19
|
import { resolveToCwd } from "./path-utils";
|
|
20
|
-
import { shortenPath, ToolUIKit,
|
|
20
|
+
import { shortenPath, ToolUIKit, truncateToWidth } from "./render-utils";
|
|
21
21
|
import { ToolAbortError, ToolError } from "./tool-errors";
|
|
22
22
|
import { toolResult } from "./tool-result";
|
|
23
23
|
import { DEFAULT_MAX_BYTES } from "./truncate";
|
|
@@ -494,7 +494,7 @@ function formatStatusEvent(event: PythonStatusEvent, theme: Theme): string {
|
|
|
494
494
|
case "find":
|
|
495
495
|
case "glob":
|
|
496
496
|
parts.push(`${data.count} match${(data.count as number) !== 1 ? "es" : ""}`);
|
|
497
|
-
if (data.pattern) parts.push(`for "${
|
|
497
|
+
if (data.pattern) parts.push(`for "${truncateToWidth(String(data.pattern), 20)}"`);
|
|
498
498
|
break;
|
|
499
499
|
case "grep":
|
|
500
500
|
parts.push(`${data.count} match${(data.count as number) !== 1 ? "es" : ""}`);
|
|
@@ -502,16 +502,16 @@ function formatStatusEvent(event: PythonStatusEvent, theme: Theme): string {
|
|
|
502
502
|
break;
|
|
503
503
|
case "rgrep":
|
|
504
504
|
parts.push(`${data.count} match${(data.count as number) !== 1 ? "es" : ""}`);
|
|
505
|
-
if (data.pattern) parts.push(`for "${
|
|
505
|
+
if (data.pattern) parts.push(`for "${truncateToWidth(String(data.pattern), 20)}"`);
|
|
506
506
|
break;
|
|
507
507
|
case "ls":
|
|
508
508
|
parts.push(`${data.count} entr${(data.count as number) !== 1 ? "ies" : "y"}`);
|
|
509
509
|
break;
|
|
510
510
|
case "env":
|
|
511
511
|
if (data.action === "set") {
|
|
512
|
-
parts.push(`set ${data.key}=${
|
|
512
|
+
parts.push(`set ${data.key}=${truncateToWidth(String(data.value ?? ""), 30)}`);
|
|
513
513
|
} else if (data.action === "get") {
|
|
514
|
-
parts.push(`${data.key}=${
|
|
514
|
+
parts.push(`${data.key}=${truncateToWidth(String(data.value ?? ""), 30)}`);
|
|
515
515
|
} else {
|
|
516
516
|
parts.push(`${data.count} variable${(data.count as number) !== 1 ? "s" : ""}`);
|
|
517
517
|
}
|
|
@@ -617,7 +617,7 @@ function formatStatusEventExpanded(event: PythonStatusEvent, theme: Theme): stri
|
|
|
617
617
|
lines.push(` ${theme.fg("dim", formatter(arr[i]))}`);
|
|
618
618
|
}
|
|
619
619
|
if (arr.length > max) {
|
|
620
|
-
lines.push(` ${theme.fg("dim",
|
|
620
|
+
lines.push(` ${theme.fg("dim", `… ${arr.length - max} more`)}`);
|
|
621
621
|
}
|
|
622
622
|
};
|
|
623
623
|
|
|
@@ -625,11 +625,11 @@ function formatStatusEventExpanded(event: PythonStatusEvent, theme: Theme): stri
|
|
|
625
625
|
const addPreview = (preview: string, maxLines = 3) => {
|
|
626
626
|
const previewLines = String(preview).split("\n").slice(0, maxLines);
|
|
627
627
|
for (const line of previewLines) {
|
|
628
|
-
lines.push(` ${theme.fg("toolOutput",
|
|
628
|
+
lines.push(` ${theme.fg("toolOutput", truncateToWidth(line, 80))}`);
|
|
629
629
|
}
|
|
630
630
|
const totalLines = String(preview).split("\n").length;
|
|
631
631
|
if (totalLines > maxLines) {
|
|
632
|
-
lines.push(` ${theme.fg("dim",
|
|
632
|
+
lines.push(` ${theme.fg("dim", `… ${totalLines - maxLines} more lines`)}`);
|
|
633
633
|
}
|
|
634
634
|
};
|
|
635
635
|
|
|
@@ -645,7 +645,7 @@ function formatStatusEventExpanded(event: PythonStatusEvent, theme: Theme): stri
|
|
|
645
645
|
if (data.hits) {
|
|
646
646
|
addItems(data.hits as unknown[], h => {
|
|
647
647
|
const hit = h as { line: number; text: string };
|
|
648
|
-
return `${hit.line}: ${
|
|
648
|
+
return `${hit.line}: ${truncateToWidth(hit.text, 60)}`;
|
|
649
649
|
});
|
|
650
650
|
}
|
|
651
651
|
break;
|
|
@@ -653,7 +653,7 @@ function formatStatusEventExpanded(event: PythonStatusEvent, theme: Theme): stri
|
|
|
653
653
|
if (data.hits) {
|
|
654
654
|
addItems(data.hits as unknown[], h => {
|
|
655
655
|
const hit = h as { file: string; line: number; text: string };
|
|
656
|
-
return `${shortenPath(hit.file)}:${hit.line}: ${
|
|
656
|
+
return `${shortenPath(hit.file)}:${hit.line}: ${truncateToWidth(hit.text, 50)}`;
|
|
657
657
|
});
|
|
658
658
|
}
|
|
659
659
|
break;
|
|
@@ -672,7 +672,7 @@ function formatStatusEventExpanded(event: PythonStatusEvent, theme: Theme): stri
|
|
|
672
672
|
if (data.entries) {
|
|
673
673
|
addItems(data.entries as unknown[], e => {
|
|
674
674
|
const entry = e as { sha: string; subject: string };
|
|
675
|
-
return `${entry.sha} ${
|
|
675
|
+
return `${entry.sha} ${truncateToWidth(entry.subject, 50)}`;
|
|
676
676
|
});
|
|
677
677
|
}
|
|
678
678
|
break;
|
|
@@ -725,13 +725,9 @@ function renderStatusEvents(events: PythonStatusEvent[], theme: Theme, expanded:
|
|
|
725
725
|
}
|
|
726
726
|
|
|
727
727
|
if (!expanded && events.length > maxCollapsed) {
|
|
728
|
-
lines.push(
|
|
729
|
-
`${theme.fg("dim", theme.tree.last)} ${theme.fg("dim", `${theme.format.ellipsis} ${events.length - maxCollapsed} more`)}`,
|
|
730
|
-
);
|
|
728
|
+
lines.push(`${theme.fg("dim", theme.tree.last)} ${theme.fg("dim", `… ${events.length - maxCollapsed} more`)}`);
|
|
731
729
|
} else if (expanded && events.length > maxExpanded) {
|
|
732
|
-
lines.push(
|
|
733
|
-
`${theme.fg("dim", theme.tree.last)} ${theme.fg("dim", `${theme.format.ellipsis} ${events.length - maxExpanded} more`)}`,
|
|
734
|
-
);
|
|
730
|
+
lines.push(`${theme.fg("dim", theme.tree.last)} ${theme.fg("dim", `… ${events.length - maxExpanded} more`)}`);
|
|
735
731
|
}
|
|
736
732
|
|
|
737
733
|
return lines;
|
|
@@ -781,7 +777,7 @@ export const pythonToolRenderer = {
|
|
|
781
777
|
if (cells.length === 0) {
|
|
782
778
|
const prompt = uiTheme.fg("accent", ">>>");
|
|
783
779
|
const prefix = workdirLabel ? `${uiTheme.fg("dim", `${workdirLabel} && `)}` : "";
|
|
784
|
-
const text = ui.title(`${prompt} ${prefix}
|
|
780
|
+
const text = ui.title(`${prompt} ${prefix}…`);
|
|
785
781
|
return new Text(text, 0, 0);
|
|
786
782
|
}
|
|
787
783
|
|
|
@@ -896,10 +892,7 @@ export const pythonToolRenderer = {
|
|
|
896
892
|
const outputLines = [...outputContent.lines];
|
|
897
893
|
if (!expanded && outputContent.hiddenCount > 0) {
|
|
898
894
|
outputLines.push(
|
|
899
|
-
uiTheme.fg(
|
|
900
|
-
"dim",
|
|
901
|
-
`${uiTheme.format.ellipsis} ${outputContent.hiddenCount} more lines (ctrl+o to expand)`,
|
|
902
|
-
),
|
|
895
|
+
uiTheme.fg("dim", `… ${outputContent.hiddenCount} more lines (ctrl+o to expand)`),
|
|
903
896
|
);
|
|
904
897
|
}
|
|
905
898
|
if (statusLines.length > 0) {
|
|
@@ -1007,24 +1000,22 @@ export const pythonToolRenderer = {
|
|
|
1007
1000
|
outputLines.push("");
|
|
1008
1001
|
const skippedLine = uiTheme.fg(
|
|
1009
1002
|
"dim",
|
|
1010
|
-
|
|
1003
|
+
`… (${cachedSkipped} earlier lines, showing ${cachedLines.length} of ${cachedSkipped + cachedLines.length}) (ctrl+o to expand)`,
|
|
1011
1004
|
);
|
|
1012
|
-
outputLines.push(truncateToWidth(skippedLine, width
|
|
1005
|
+
outputLines.push(truncateToWidth(skippedLine, width));
|
|
1013
1006
|
}
|
|
1014
1007
|
outputLines.push(...cachedLines);
|
|
1015
1008
|
if (statusLines.length > 0) {
|
|
1016
|
-
outputLines.push(
|
|
1017
|
-
truncateToWidth(uiTheme.fg("dim", "Status"), width, uiTheme.fg("dim", uiTheme.format.ellipsis)),
|
|
1018
|
-
);
|
|
1009
|
+
outputLines.push(truncateToWidth(uiTheme.fg("dim", "Status"), width));
|
|
1019
1010
|
for (const statusLine of statusLines) {
|
|
1020
|
-
outputLines.push(truncateToWidth(statusLine, width
|
|
1011
|
+
outputLines.push(truncateToWidth(statusLine, width));
|
|
1021
1012
|
}
|
|
1022
1013
|
}
|
|
1023
1014
|
if (timeoutLine) {
|
|
1024
|
-
outputLines.push(truncateToWidth(timeoutLine, width
|
|
1015
|
+
outputLines.push(truncateToWidth(timeoutLine, width));
|
|
1025
1016
|
}
|
|
1026
1017
|
if (warningLine) {
|
|
1027
|
-
outputLines.push(truncateToWidth(warningLine, width
|
|
1018
|
+
outputLines.push(truncateToWidth(warningLine, width));
|
|
1028
1019
|
}
|
|
1029
1020
|
return outputLines;
|
|
1030
1021
|
},
|