@linxiraos/pi-tui 1.4.0 → 1.4.1
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 +178 -182
- package/dist/types/autocomplete.d.ts +6 -0
- package/dist/types/components/sparkline.d.ts +34 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/native/describe.d.ts +7 -1
- package/dist/types/native/overlay.d.ts +2 -0
- package/dist/types/native/tone.d.ts +2 -0
- package/dist/types/overlays/agent-hub.d.ts +3 -3
- package/dist/types/overlays/approval-dialog.d.ts +15 -1
- package/dist/types/overlays/jobs-panel.d.ts +3 -0
- package/dist/types/overlays/model-browser.d.ts +1 -1
- package/dist/types/render/output-block.d.ts +2 -0
- package/dist/types/render/tool-card.d.ts +2 -0
- package/dist/types/sixel.d.ts +28 -0
- package/dist/types/status-line/host.d.ts +3 -0
- package/dist/types/terminal-capabilities.d.ts +5 -0
- package/dist/types/tools/bash.d.ts +2 -0
- package/dist/types/tools/default-renderer.d.ts +3 -0
- package/dist/types/tools/eval.d.ts +9 -8
- package/dist/types/tools/irc.d.ts +6 -0
- package/dist/types/tools/job-widget.d.ts +226 -0
- package/dist/types/tools/json-tree.d.ts +2 -0
- package/dist/types/tools/line-ranges.d.ts +8 -1
- package/dist/types/tools/mcp.d.ts +23 -0
- package/dist/types/tools/output-meta.d.ts +1 -1
- package/dist/types/tools/read.d.ts +8 -2
- package/dist/types/tools/renderer.d.ts +8 -2
- package/dist/types/tools/result-card.d.ts +1 -1
- package/dist/types/tools/streaming-output.d.ts +1 -0
- package/dist/types/tools/task.d.ts +12 -0
- package/dist/types/tools/wait.d.ts +5 -0
- package/package.json +9 -9
- package/src/autocomplete.d.ts +6 -0
- package/src/autocomplete.ts +21 -6
- package/src/chat/skill-message.ts +16 -17
- package/src/chat/tool-execution.ts +35 -0
- package/src/chrome/transcript-container.ts +85 -13
- package/src/components/editor.ts +17 -7
- package/src/components/image.ts +5 -4
- package/src/components/markdown.ts +11 -3
- package/src/components/sparkline.d.ts +34 -0
- package/src/components/sparkline.ts +89 -0
- package/src/index.d.ts +1 -0
- package/src/index.ts +1 -0
- package/src/native/backend.ts +32 -6
- package/src/native/describe.d.ts +7 -1
- package/src/native/describe.ts +18 -1
- package/src/native/overlay.d.ts +2 -0
- package/src/native/overlay.ts +3 -0
- package/src/native/tone.d.ts +2 -0
- package/src/native/tone.ts +22 -0
- package/src/overlays/agent-hub.ts +14 -10
- package/src/overlays/agent-transcript-viewer.ts +2 -2
- package/src/overlays/agents-hub.ts +2 -1
- package/src/overlays/approval-dialog.ts +59 -13
- package/src/overlays/hub-frame.ts +2 -1
- package/src/overlays/jobs-panel.ts +24 -2
- package/src/overlays/model-browser.ts +3 -0
- package/src/overlays/model-hub.ts +2 -1
- package/src/prompt/attachment-chips.ts +1 -1
- package/src/render/output-block.d.ts +2 -0
- package/src/render/output-block.ts +25 -12
- package/src/render/tool-card.d.ts +2 -0
- package/src/render/tool-card.ts +6 -0
- package/src/sixel.d.ts +28 -0
- package/src/sixel.ts +185 -0
- package/src/status-line/component.ts +19 -2
- package/src/status-line/host.ts +3 -0
- package/src/terminal-capabilities.d.ts +5 -0
- package/src/terminal-capabilities.ts +43 -3
- package/src/theme/symbols.ts +5 -3
- package/src/tools/bash.d.ts +2 -0
- package/src/tools/bash.ts +25 -9
- package/src/tools/default-renderer.d.ts +3 -0
- package/src/tools/default-renderer.ts +54 -17
- package/src/tools/eval.d.ts +9 -8
- package/src/tools/eval.ts +32 -14
- package/src/tools/find.ts +4 -5
- package/src/tools/glob.ts +4 -6
- package/src/tools/grep.ts +2 -4
- package/src/tools/irc.d.ts +6 -0
- package/src/tools/irc.ts +6 -0
- package/src/tools/job-widget.d.ts +226 -0
- package/src/tools/job-widget.ts +1036 -0
- package/src/tools/json-tree.d.ts +2 -0
- package/src/tools/json-tree.ts +8 -0
- package/src/tools/line-ranges.d.ts +8 -1
- package/src/tools/line-ranges.ts +23 -13
- package/src/tools/mcp.d.ts +23 -0
- package/src/tools/mcp.ts +44 -1
- package/src/tools/output-meta.d.ts +1 -1
- package/src/tools/output-meta.ts +1 -1
- package/src/tools/read.d.ts +8 -2
- package/src/tools/read.ts +64 -21
- package/src/tools/renderer.d.ts +8 -2
- package/src/tools/renderer.ts +8 -2
- package/src/tools/result-card.d.ts +1 -1
- package/src/tools/result-card.ts +1 -2
- package/src/tools/streaming-output.d.ts +1 -0
- package/src/tools/streaming-output.ts +11 -9
- package/src/tools/task.d.ts +12 -0
- package/src/tools/task.ts +25 -1
- package/src/tools/wait.d.ts +5 -0
- package/src/tools/wait.ts +290 -147
- package/src/tui.ts +45 -5
|
@@ -104,21 +104,22 @@ function buildDefaultToolBody(input: DefaultToolRenderInput, uiTheme: Theme, con
|
|
|
104
104
|
body.push(uiTheme.fg("dim", "(no output)"));
|
|
105
105
|
} else {
|
|
106
106
|
let renderedAsJson = false;
|
|
107
|
-
if (
|
|
107
|
+
if (isTreeSafeJson(textContent)) {
|
|
108
108
|
try {
|
|
109
109
|
const parsed = JSON.parse(textContent);
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
110
|
+
const tree = renderJsonTreeLines(parsed, uiTheme, {
|
|
111
|
+
maxDepth: options.expanded ? JSON_TREE_MAX_DEPTH_EXPANDED : JSON_TREE_MAX_DEPTH_COLLAPSED,
|
|
112
|
+
maxLines: options.expanded ? JSON_TREE_MAX_LINES_EXPANDED : JSON_TREE_MAX_LINES_COLLAPSED,
|
|
113
|
+
maxScalarLen: options.expanded ? JSON_TREE_SCALAR_LEN_EXPANDED : JSON_TREE_SCALAR_LEN_COLLAPSED,
|
|
114
|
+
// A result's own `i` or `__partialJson` keys are data, not call metadata.
|
|
115
|
+
hiddenRootKeys: [],
|
|
116
|
+
});
|
|
114
117
|
|
|
115
|
-
|
|
118
|
+
// An expanded tree that hit a cap would show less than the raw output, so
|
|
119
|
+
// Ctrl+O falls through to the uncapped raw view instead.
|
|
120
|
+
if (tree.lines.length > 0 && !(options.expanded && tree.truncated)) {
|
|
116
121
|
body.push(...tree.lines);
|
|
117
|
-
if (!options.expanded)
|
|
118
|
-
body.push(formatExpandHint(uiTheme, options.expanded, true));
|
|
119
|
-
} else if (tree.truncated) {
|
|
120
|
-
body.push(uiTheme.fg("dim", "…"));
|
|
121
|
-
}
|
|
122
|
+
if (!options.expanded) body.push(formatExpandHint(uiTheme, options.expanded, true));
|
|
122
123
|
renderedAsJson = true;
|
|
123
124
|
}
|
|
124
125
|
} catch {
|
|
@@ -126,13 +127,14 @@ function buildDefaultToolBody(input: DefaultToolRenderInput, uiTheme: Theme, con
|
|
|
126
127
|
}
|
|
127
128
|
}
|
|
128
129
|
if (!renderedAsJson) {
|
|
130
|
+
// No expanded cap: the terminal's own disclosure clamp is the only
|
|
131
|
+
// bound, so Ctrl+O reveals every row the collapsed view promised.
|
|
129
132
|
body.push(
|
|
130
133
|
...formatOutputPaneLines(
|
|
131
134
|
{
|
|
132
135
|
lines: textContent.split("\n"),
|
|
133
136
|
expanded: options.expanded,
|
|
134
137
|
collapsedMaxLines: 4,
|
|
135
|
-
expandedMaxLines: 12,
|
|
136
138
|
styleLine: line =>
|
|
137
139
|
clipCollapsed(styleToolOutputLine(line, uiTheme), contentWidth, options.expanded),
|
|
138
140
|
showExpandHintWhenUncapped: true,
|
|
@@ -157,14 +159,37 @@ export function formatDefaultToolExecution(
|
|
|
157
159
|
return [renderStatusLine(status, uiTheme), ...buildDefaultToolBody(input, uiTheme, contentWidth)].join("\n");
|
|
158
160
|
}
|
|
159
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Serialized JSON past this size keeps the raw view: the tree caps out at a few
|
|
164
|
+
* hundred rows anyway, and parsing and indexing a huge payload only to discard
|
|
165
|
+
* the tree can stall the UI.
|
|
166
|
+
*/
|
|
167
|
+
const JSON_TREE_MAX_CHARS = 64 * 1024;
|
|
168
|
+
/** An integer literal of 16+ digits may exceed `Number.MAX_SAFE_INTEGER` and change when parsed. */
|
|
169
|
+
const UNSAFE_INTEGER_RE = /(?<![\w.])-?\d{16,}(?![\w.])/;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Whether a tool result can render as a JSON tree without losing anything the
|
|
173
|
+
* raw text shows: a bracketed payload small enough to index, with no integer a
|
|
174
|
+
* double would round (64-bit ids).
|
|
175
|
+
*/
|
|
176
|
+
function isTreeSafeJson(text: string): boolean {
|
|
177
|
+
return (
|
|
178
|
+
(text.startsWith("{") || text.startsWith("[")) &&
|
|
179
|
+
text.length <= JSON_TREE_MAX_CHARS &&
|
|
180
|
+
!UNSAFE_INTEGER_RE.test(text)
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
160
184
|
/** Inline args summary budget in characters (a data cap, not a width). */
|
|
161
185
|
const NATIVE_ARGS_SUMMARY_CHARS = 160;
|
|
162
|
-
/** Result text kept for the native card body. */
|
|
163
|
-
const NATIVE_RESULT_MAX_CHARS = 64 * 1024;
|
|
164
186
|
|
|
165
187
|
/**
|
|
166
188
|
* TSP view of the generic fallback card: the tool label with a one-line args
|
|
167
189
|
* summary as the head target; the result as a JSON tree or raw `ansi` output.
|
|
190
|
+
* The complete output goes over the wire — the card-level disclosure clamp the
|
|
191
|
+
* terminal applies is the only bound, so an expanded card keeps every row. JSON
|
|
192
|
+
* the tree's depth, node or scalar caps would cut keeps the raw path instead.
|
|
168
193
|
*/
|
|
169
194
|
export function describeDefaultToolExecution(input: DefaultToolRenderInput): NativeToolView {
|
|
170
195
|
const { result } = input;
|
|
@@ -175,15 +200,27 @@ export function describeDefaultToolExecution(input: DefaultToolRenderInput): Nat
|
|
|
175
200
|
: undefined;
|
|
176
201
|
const tool: NativeToolHead = { title: input.label, target: summary || undefined, targetKind: "text" };
|
|
177
202
|
if (!result) return { tool };
|
|
178
|
-
const output = result.output.trimEnd()
|
|
203
|
+
const output = result.output.trimEnd();
|
|
179
204
|
const tone = result.skipped ? "info" : result.isError ? "error" : undefined;
|
|
180
205
|
if (!output) return { tool, tone, body: [noteText("(no output)")] };
|
|
181
|
-
if (
|
|
206
|
+
if (isTreeSafeJson(output)) {
|
|
207
|
+
let parsed: unknown;
|
|
182
208
|
try {
|
|
183
|
-
|
|
209
|
+
parsed = JSON.parse(output);
|
|
184
210
|
} catch {
|
|
185
211
|
// Not JSON: shown as raw output below.
|
|
186
212
|
}
|
|
213
|
+
if (parsed !== undefined) {
|
|
214
|
+
let truncated = false;
|
|
215
|
+
const tree = describeJsonTree(parsed, {
|
|
216
|
+
// A result's own `i` or `__partialJson` keys are data, not call metadata.
|
|
217
|
+
hiddenRootKeys: [],
|
|
218
|
+
onTruncated: () => {
|
|
219
|
+
truncated = true;
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
if (!truncated) return { tool, tone, body: [tree] };
|
|
223
|
+
}
|
|
187
224
|
}
|
|
188
225
|
return { tool, tone, body: [ansi(output)] };
|
|
189
226
|
}
|
package/src/tools/eval.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ export interface EvalCellResult {
|
|
|
61
61
|
durationMs?: number;
|
|
62
62
|
exitCode?: number;
|
|
63
63
|
statusEvents?: EvalStatusEvent[];
|
|
64
|
-
/**
|
|
64
|
+
/** Evictable events dropped from the front of `statusEvents` (see {@link recordStatusEvent}). */
|
|
65
65
|
statusEventsElided?: number;
|
|
66
66
|
}
|
|
67
67
|
/** Tool result detail object surfaced to the UI/transcript. */
|
|
@@ -69,7 +69,7 @@ export interface EvalToolDetails {
|
|
|
69
69
|
cells?: EvalCellResult[];
|
|
70
70
|
images?: ImageContent[];
|
|
71
71
|
statusEvents?: EvalStatusEvent[];
|
|
72
|
-
/**
|
|
72
|
+
/** Evictable events dropped from the front of `statusEvents` (see {@link recordStatusEvent}). */
|
|
73
73
|
statusEventsElided?: number;
|
|
74
74
|
isError?: boolean;
|
|
75
75
|
meta?: OutputMeta;
|
|
@@ -104,7 +104,7 @@ interface EvalRenderContext {
|
|
|
104
104
|
timeout?: number;
|
|
105
105
|
}
|
|
106
106
|
/**
|
|
107
|
-
* Coalescing key of a progress-snapshot event: `agent` and `
|
|
107
|
+
* Coalescing key of a progress-snapshot event: `agent`, `judge_batch`, and `mcp_progress`
|
|
108
108
|
* events keyed by `id`, where only the newest snapshot matters. Discrete
|
|
109
109
|
* actions (everything else) have no key. Shared by {@link upsertStatusEvent}
|
|
110
110
|
* and the executors' display collectors so both coalesce identically.
|
|
@@ -114,12 +114,12 @@ export declare function statusEventKey(event: {
|
|
|
114
114
|
[key: string]: unknown;
|
|
115
115
|
}): string | undefined;
|
|
116
116
|
/**
|
|
117
|
-
*
|
|
117
|
+
* Evictable status events a log keeps. A cell polling a helper in a loop emits
|
|
118
118
|
* one event per call (hundreds of thousands), and every live update and the
|
|
119
119
|
* persisted tool result would otherwise carry them all.
|
|
120
120
|
*/
|
|
121
121
|
export declare const MAX_STATUS_EVENTS = 200;
|
|
122
|
-
/** A status event list plus the count of
|
|
122
|
+
/** A status event list plus the count of evictable events dropped from its front. */
|
|
123
123
|
export type StatusEventLog = Pick<EvalCellResult, "statusEvents" | "statusEventsElided">;
|
|
124
124
|
/**
|
|
125
125
|
* Append or replace a status event. Progress snapshots (see
|
|
@@ -129,9 +129,10 @@ export type StatusEventLog = Pick<EvalCellResult, "statusEvents" | "statusEvents
|
|
|
129
129
|
export declare function upsertStatusEvent(events: EvalStatusEvent[], event: EvalStatusEvent): void;
|
|
130
130
|
/**
|
|
131
131
|
* {@link upsertStatusEvent} into a bounded log. Past {@link MAX_STATUS_EVENTS},
|
|
132
|
-
* the oldest discrete event is dropped and counted.
|
|
133
|
-
* cards read them, and so does
|
|
134
|
-
*
|
|
132
|
+
* the oldest discrete event or MCP progress snapshot is dropped and counted.
|
|
133
|
+
* Agent/judgment-batch snapshots stay, since agent cards read them, and so does
|
|
134
|
+
* the newest committed `todo` result, which the session todo panel refreshes
|
|
135
|
+
* from. Renderers already show only the newest
|
|
135
136
|
* events behind an "… N earlier" row.
|
|
136
137
|
*/
|
|
137
138
|
export declare function recordStatusEvent(log: StatusEventLog, event: EvalStatusEvent): void;
|
package/src/tools/eval.ts
CHANGED
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
renderJsonTreeLines,
|
|
36
36
|
} from "./json-tree";
|
|
37
37
|
import { formatStyledTruncationWarning, stripOutputNotice } from "./output-meta";
|
|
38
|
+
import { formatMCPProgress, parseMCPProgress } from "./mcp";
|
|
38
39
|
import { splitPathAndSel } from "./read";
|
|
39
40
|
import {
|
|
40
41
|
DEFAULT_TERMINAL_PREVIEW_LINES,
|
|
@@ -108,7 +109,7 @@ export interface EvalCellResult {
|
|
|
108
109
|
durationMs?: number;
|
|
109
110
|
exitCode?: number;
|
|
110
111
|
statusEvents?: EvalStatusEvent[];
|
|
111
|
-
/**
|
|
112
|
+
/** Evictable events dropped from the front of `statusEvents` (see {@link recordStatusEvent}). */
|
|
112
113
|
statusEventsElided?: number;
|
|
113
114
|
}
|
|
114
115
|
|
|
@@ -117,7 +118,7 @@ export interface EvalToolDetails {
|
|
|
117
118
|
cells?: EvalCellResult[];
|
|
118
119
|
images?: ImageContent[];
|
|
119
120
|
statusEvents?: EvalStatusEvent[];
|
|
120
|
-
/**
|
|
121
|
+
/** Evictable events dropped from the front of `statusEvents` (see {@link recordStatusEvent}). */
|
|
121
122
|
statusEventsElided?: number;
|
|
122
123
|
isError?: boolean;
|
|
123
124
|
meta?: OutputMeta;
|
|
@@ -222,26 +223,29 @@ function pushCodeCellLines(
|
|
|
222
223
|
type AgentEventStatus = "pending" | "running" | "completed" | "failed" | "aborted";
|
|
223
224
|
|
|
224
225
|
/**
|
|
225
|
-
* Coalescing key of a progress-snapshot event: `agent` and `
|
|
226
|
+
* Coalescing key of a progress-snapshot event: `agent`, `judge_batch`, and `mcp_progress`
|
|
226
227
|
* events keyed by `id`, where only the newest snapshot matters. Discrete
|
|
227
228
|
* actions (everything else) have no key. Shared by {@link upsertStatusEvent}
|
|
228
229
|
* and the executors' display collectors so both coalesce identically.
|
|
229
230
|
*/
|
|
230
231
|
export function statusEventKey(event: { op: string; [key: string]: unknown }): string | undefined {
|
|
231
|
-
if (
|
|
232
|
+
if (
|
|
233
|
+
(event.op === "agent" || event.op === "judge_batch" || event.op === "mcp_progress") &&
|
|
234
|
+
typeof event.id === "string"
|
|
235
|
+
) {
|
|
232
236
|
return `${event.op}\0${event.id}`;
|
|
233
237
|
}
|
|
234
238
|
return undefined;
|
|
235
239
|
}
|
|
236
240
|
|
|
237
241
|
/**
|
|
238
|
-
*
|
|
242
|
+
* Evictable status events a log keeps. A cell polling a helper in a loop emits
|
|
239
243
|
* one event per call (hundreds of thousands), and every live update and the
|
|
240
244
|
* persisted tool result would otherwise carry them all.
|
|
241
245
|
*/
|
|
242
246
|
export const MAX_STATUS_EVENTS = 200;
|
|
243
247
|
|
|
244
|
-
/** A status event list plus the count of
|
|
248
|
+
/** A status event list plus the count of evictable events dropped from its front. */
|
|
245
249
|
export type StatusEventLog = Pick<EvalCellResult, "statusEvents" | "statusEventsElided">;
|
|
246
250
|
|
|
247
251
|
/**
|
|
@@ -263,9 +267,10 @@ export function upsertStatusEvent(events: EvalStatusEvent[], event: EvalStatusEv
|
|
|
263
267
|
|
|
264
268
|
/**
|
|
265
269
|
* {@link upsertStatusEvent} into a bounded log. Past {@link MAX_STATUS_EVENTS},
|
|
266
|
-
* the oldest discrete event is dropped and counted.
|
|
267
|
-
* cards read them, and so does
|
|
268
|
-
*
|
|
270
|
+
* the oldest discrete event or MCP progress snapshot is dropped and counted.
|
|
271
|
+
* Agent/judgment-batch snapshots stay, since agent cards read them, and so does
|
|
272
|
+
* the newest committed `todo` result, which the session todo panel refreshes
|
|
273
|
+
* from. Renderers already show only the newest
|
|
269
274
|
* events behind an "… N earlier" row.
|
|
270
275
|
*/
|
|
271
276
|
export function recordStatusEvent(log: StatusEventLog, event: EvalStatusEvent): void {
|
|
@@ -273,7 +278,9 @@ export function recordStatusEvent(log: StatusEventLog, event: EvalStatusEvent):
|
|
|
273
278
|
upsertStatusEvent(events, event);
|
|
274
279
|
if (events.length <= MAX_STATUS_EVENTS) return;
|
|
275
280
|
const keep = events.findLastIndex(e => e.op === "todo" && e.committed === true);
|
|
276
|
-
const oldest = events.findIndex(
|
|
281
|
+
const oldest = events.findIndex(
|
|
282
|
+
(e, i) => i !== keep && (e.op === "mcp_progress" || statusEventKey(e) === undefined),
|
|
283
|
+
);
|
|
277
284
|
if (oldest < 0) return;
|
|
278
285
|
events.splice(oldest, 1);
|
|
279
286
|
log.statusEventsElided = (log.statusEventsElided ?? 0) + 1;
|
|
@@ -414,6 +421,12 @@ function formatStatusEvent(event: EvalStatusEvent, theme: Theme): string {
|
|
|
414
421
|
}
|
|
415
422
|
|
|
416
423
|
switch (op) {
|
|
424
|
+
case "mcp_progress": {
|
|
425
|
+
if (data.tool) parts.push(previewLine(sanitizeText(String(data.tool)), STATUS_VALUE_WIDTH));
|
|
426
|
+
const progress = parseMCPProgress(data);
|
|
427
|
+
if (progress) parts.push(formatMCPProgress(progress, STATUS_VALUE_WIDTH));
|
|
428
|
+
break;
|
|
429
|
+
}
|
|
417
430
|
case "read":
|
|
418
431
|
parts.push(`${data.chars ?? data.bytes ?? 0} chars`);
|
|
419
432
|
if (data.path) parts.push(`from ${shortenPath(String(data.path))}`);
|
|
@@ -693,20 +706,25 @@ const STATUS_VALUE_WIDTH = 200;
|
|
|
693
706
|
|
|
694
707
|
/**
|
|
695
708
|
* Plain one-line summary of a status event: op plus its scalar fields, each
|
|
696
|
-
* collapsed to one line.
|
|
697
|
-
*
|
|
698
|
-
*
|
|
699
|
-
*
|
|
709
|
+
* collapsed to one line. MCP progress shows its tool and then the shared
|
|
710
|
+
* {@link formatMCPProgress} text; its call id is internal. A `preview` (file or
|
|
711
|
+
* command text a helper returned) never joins the line: an expanded cell shows
|
|
712
|
+
* it under the line as a code block holding its first
|
|
713
|
+
* {@link PREVIEW_LIMITS.OUTPUT_EXPANDED} lines, folded to
|
|
714
|
+
* {@link PREVIEW_LIMITS.COLLAPSED_LINES}.
|
|
700
715
|
*/
|
|
701
716
|
function describeStatusEvent(event: EvalStatusEvent, expanded: boolean): NativeNode {
|
|
702
717
|
const spans: TspSpan[] = [span(event.op, "accent")];
|
|
718
|
+
const mcpProgress = event.op === "mcp_progress" ? parseMCPProgress(event) : undefined;
|
|
703
719
|
for (const key in event) {
|
|
704
720
|
if (key === "op" || key === "preview" || key === "resolvedThinkingLevel") continue;
|
|
721
|
+
if (event.op === "mcp_progress" && key !== "tool") continue;
|
|
705
722
|
const value = event[key];
|
|
706
723
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
707
724
|
spans.push(span(` ${key}=`, "muted"), span(previewLine(sanitizeText(String(value)), STATUS_VALUE_WIDTH)));
|
|
708
725
|
}
|
|
709
726
|
}
|
|
727
|
+
if (mcpProgress) spans.push(span(` ${formatMCPProgress(mcpProgress, STATUS_VALUE_WIDTH)}`));
|
|
710
728
|
const line = text(spans, { truncate: "end", role: "zeta.tool.eval.status" });
|
|
711
729
|
const preview = expanded ? eventString(event.preview)?.trimEnd() : undefined;
|
|
712
730
|
if (!preview) return line;
|
package/src/tools/find.ts
CHANGED
|
@@ -256,7 +256,7 @@ export const findToolRenderer = {
|
|
|
256
256
|
},
|
|
257
257
|
uiTheme,
|
|
258
258
|
);
|
|
259
|
-
return new Text(text,
|
|
259
|
+
return new Text(text, 0, 0);
|
|
260
260
|
},
|
|
261
261
|
|
|
262
262
|
renderResult(
|
|
@@ -269,7 +269,7 @@ export const findToolRenderer = {
|
|
|
269
269
|
const text = result.content?.find(c => c.type === "text")?.text ?? "";
|
|
270
270
|
|
|
271
271
|
if (result.isError) {
|
|
272
|
-
return new Text(formatErrorMessage(text || "Unknown error", uiTheme),
|
|
272
|
+
return new Text(formatErrorMessage(text || "Unknown error", uiTheme), 0, 0);
|
|
273
273
|
}
|
|
274
274
|
|
|
275
275
|
// Streaming progress: the tool reports the phase it is in.
|
|
@@ -285,7 +285,7 @@ export const findToolRenderer = {
|
|
|
285
285
|
},
|
|
286
286
|
uiTheme,
|
|
287
287
|
);
|
|
288
|
-
return new Text(header,
|
|
288
|
+
return new Text(header, 0, 0);
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
const { hits, stats, threshold } = details;
|
|
@@ -317,7 +317,7 @@ export const findToolRenderer = {
|
|
|
317
317
|
: "No relevant passages found";
|
|
318
318
|
const lines = [header, formatEmptyMessage(empty, uiTheme)];
|
|
319
319
|
for (const failure of stats.failures) lines.push(uiTheme.fg("warning", failure));
|
|
320
|
-
return new Text(lines.join("\n"),
|
|
320
|
+
return new Text(lines.join("\n"), 0, 0);
|
|
321
321
|
}
|
|
322
322
|
|
|
323
323
|
const header = renderStatusLine(
|
|
@@ -359,7 +359,6 @@ export const findToolRenderer = {
|
|
|
359
359
|
}
|
|
360
360
|
return [header, ...hitLines, ...extra].map(line => truncateToWidth(line, width, Ellipsis.Omit));
|
|
361
361
|
},
|
|
362
|
-
{ paddingX: 1 },
|
|
363
362
|
);
|
|
364
363
|
},
|
|
365
364
|
describeCall(args: FindRenderArgs): NativeToolView {
|
package/src/tools/glob.ts
CHANGED
|
@@ -151,7 +151,7 @@ export const globToolRenderer = {
|
|
|
151
151
|
},
|
|
152
152
|
uiTheme,
|
|
153
153
|
);
|
|
154
|
-
return new Text(text,
|
|
154
|
+
return new Text(text, 0, 0);
|
|
155
155
|
},
|
|
156
156
|
|
|
157
157
|
renderResult(
|
|
@@ -165,7 +165,7 @@ export const globToolRenderer = {
|
|
|
165
165
|
|
|
166
166
|
if (result.isError || details?.error) {
|
|
167
167
|
const errorText = details?.error || result.content?.find(c => c.type === "text")?.text || "Unknown error";
|
|
168
|
-
return new Text(formatErrorMessage(errorText, uiTheme),
|
|
168
|
+
return new Text(formatErrorMessage(errorText, uiTheme), 0, 0);
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
const hasDetailedData = details?.fileCount !== undefined;
|
|
@@ -178,7 +178,7 @@ export const globToolRenderer = {
|
|
|
178
178
|
textContent.includes("No files found") ||
|
|
179
179
|
textContent.trim() === ""
|
|
180
180
|
) {
|
|
181
|
-
return new Text(formatEmptyMessage("No files found", uiTheme),
|
|
181
|
+
return new Text(formatEmptyMessage("No files found", uiTheme), 0, 0);
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
const lines = textContent.split("\n").filter(l => l.trim());
|
|
@@ -207,7 +207,6 @@ export const globToolRenderer = {
|
|
|
207
207
|
);
|
|
208
208
|
return [header, ...listLines].map(l => truncateToWidth(l, width, Ellipsis.Omit));
|
|
209
209
|
},
|
|
210
|
-
{ paddingX: 1 },
|
|
211
210
|
);
|
|
212
211
|
}
|
|
213
212
|
|
|
@@ -244,7 +243,7 @@ export const globToolRenderer = {
|
|
|
244
243
|
);
|
|
245
244
|
const lines = [header, formatEmptyMessage(emptyLabel, uiTheme)];
|
|
246
245
|
if (missingNote) lines.push(missingNote);
|
|
247
|
-
return new Text(lines.join("\n"),
|
|
246
|
+
return new Text(lines.join("\n"), 0, 0);
|
|
248
247
|
}
|
|
249
248
|
const meta: string[] = [formatCount("file", fileCount)];
|
|
250
249
|
if (details?.scopePath) meta.push(`in ${details.scopePath}`);
|
|
@@ -298,7 +297,6 @@ export const globToolRenderer = {
|
|
|
298
297
|
);
|
|
299
298
|
return [header, ...fileLines, ...extraLines].map(l => truncateToWidth(l, width, Ellipsis.Omit));
|
|
300
299
|
},
|
|
301
|
-
{ paddingX: 1 },
|
|
302
300
|
);
|
|
303
301
|
},
|
|
304
302
|
describeCall(args: GlobRenderArgs): NativeToolView {
|
package/src/tools/grep.ts
CHANGED
|
@@ -365,7 +365,7 @@ export const grepToolRenderer = {
|
|
|
365
365
|
{ icon: "pending", title: "Grep", titleColor: "toolTitle", description: args.pattern || "?", meta },
|
|
366
366
|
uiTheme,
|
|
367
367
|
);
|
|
368
|
-
return new Text(text,
|
|
368
|
+
return new Text(text, 0, 0);
|
|
369
369
|
},
|
|
370
370
|
|
|
371
371
|
renderResult(
|
|
@@ -422,7 +422,6 @@ export const grepToolRenderer = {
|
|
|
422
422
|
);
|
|
423
423
|
return [header, ...listLines].map(l => truncateToWidth(l, width, Ellipsis.Omit));
|
|
424
424
|
},
|
|
425
|
-
{ paddingX: 1 },
|
|
426
425
|
);
|
|
427
426
|
}
|
|
428
427
|
const linkTargets = grepLinkTargets(details, options.renderContext?.rawDetails);
|
|
@@ -456,7 +455,7 @@ export const grepToolRenderer = {
|
|
|
456
455
|
);
|
|
457
456
|
const lines = [header, formatEmptyMessage(tuiText("gpNoMatches", "No matches found"), uiTheme)];
|
|
458
457
|
if (missingNote) lines.push(missingNote);
|
|
459
|
-
return new Text(lines.join("\n"),
|
|
458
|
+
return new Text(lines.join("\n"), 0, 0);
|
|
460
459
|
}
|
|
461
460
|
|
|
462
461
|
const summaryParts = [formatCount("match", matchCount), formatCount("file", fileCount)];
|
|
@@ -514,7 +513,6 @@ export const grepToolRenderer = {
|
|
|
514
513
|
);
|
|
515
514
|
return [header, ...matchLines, ...extraLines].map(l => truncateToWidth(l, width, Ellipsis.Omit));
|
|
516
515
|
},
|
|
517
|
-
{ paddingX: 1 },
|
|
518
516
|
);
|
|
519
517
|
},
|
|
520
518
|
describeCall(args: GrepRenderArgs): NativeToolView {
|
package/src/tools/irc.d.ts
CHANGED
|
@@ -19,6 +19,12 @@ export interface IrcMessage {
|
|
|
19
19
|
* ping-pong forever.
|
|
20
20
|
*/
|
|
21
21
|
wakeRelay?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* One leg of an `all` broadcast. Like relays, broadcasts never draw an
|
|
24
|
+
* automatic wake-turn reply: every woken idle peer would otherwise answer
|
|
25
|
+
* the broadcaster, mostly to say the message was not for it.
|
|
26
|
+
*/
|
|
27
|
+
broadcast?: boolean;
|
|
22
28
|
}
|
|
23
29
|
/** Delivery outcome for one peer recipient. */
|
|
24
30
|
export interface IrcDeliveryReceipt {
|
package/src/tools/irc.ts
CHANGED
|
@@ -21,6 +21,12 @@ export interface IrcMessage {
|
|
|
21
21
|
* ping-pong forever.
|
|
22
22
|
*/
|
|
23
23
|
wakeRelay?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* One leg of an `all` broadcast. Like relays, broadcasts never draw an
|
|
26
|
+
* automatic wake-turn reply: every woken idle peer would otherwise answer
|
|
27
|
+
* the broadcaster, mostly to say the message was not for it.
|
|
28
|
+
*/
|
|
29
|
+
broadcast?: boolean;
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
/** Delivery outcome for one peer recipient. */
|