@linxiraos/pi-tui 1.2.1 → 1.3.0
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 +188 -125
- package/README.md +36 -0
- package/THIRD-PARTY-NOTICES.txt +55 -5
- package/dist/types/app-keybindings.d.ts +18 -8
- package/dist/types/apps/git/diff-pane.d.ts +5 -0
- package/dist/types/apps/git/git-tui.d.ts +16 -2
- package/dist/types/apps/git/state.d.ts +11 -0
- package/dist/types/autocomplete.d.ts +2 -0
- package/dist/types/charts/chart-svg.d.ts +7 -13
- package/dist/types/chat/advisor-message.d.ts +4 -1
- package/dist/types/chat/assistant-message.d.ts +9 -4
- package/dist/types/chat/figure-markdown.d.ts +7 -2
- package/dist/types/chat/messages.d.ts +3 -1
- package/dist/types/chat/read-tool-group.d.ts +2 -2
- package/dist/types/chat/table-chart.d.ts +11 -15
- package/dist/types/chat/tool-execution.d.ts +32 -20
- package/dist/types/chat/user-message.d.ts +3 -2
- package/dist/types/chrome/countdown-timer.d.ts +3 -2
- package/dist/types/chrome/diff.d.ts +2 -3
- package/dist/types/chrome/transcript-container.d.ts +2 -0
- package/dist/types/components/image.d.ts +2 -0
- package/dist/types/components/markdown.d.ts +49 -3
- package/dist/types/components/text.d.ts +2 -0
- package/dist/types/debug-server.d.ts +2 -0
- package/dist/types/keybinding-matchers.d.ts +6 -0
- package/dist/types/multiplexers/tmux.d.ts +1 -0
- package/dist/types/multiplexers/types.d.ts +6 -0
- package/dist/types/native/backend.d.ts +5 -4
- package/dist/types/native/blobs.d.ts +24 -12
- package/dist/types/overlays/agent-hub-projection.d.ts +10 -5
- package/dist/types/overlays/annotation-overlay.d.ts +19 -0
- package/dist/types/overlays/approval-dialog.d.ts +79 -0
- package/dist/types/overlays/ask-dialog.d.ts +11 -6
- package/dist/types/overlays/btw-history-panel.d.ts +2 -6
- package/dist/types/overlays/hook-editor.d.ts +7 -2
- package/dist/types/overlays/hook-input.d.ts +12 -4
- package/dist/types/overlays/job-tree.d.ts +50 -0
- package/dist/types/overlays/jobs-panel.d.ts +25 -11
- package/dist/types/overlays/login-dialog.d.ts +8 -3
- package/dist/types/overlays/mcp-add-wizard.d.ts +9 -1
- package/dist/types/overlays/model-browser.d.ts +6 -1
- package/dist/types/overlays/model-picker.d.ts +2 -0
- package/dist/types/overlays/pause-screen.d.ts +5 -0
- package/dist/types/overlays/plan-review-overlay.d.ts +4 -0
- package/dist/types/overlays/report-panel.d.ts +5 -1
- package/dist/types/overlays/reset-usage-selector.d.ts +7 -5
- package/dist/types/overlays/session-account-selector.d.ts +4 -0
- package/dist/types/overlays/session-info-overlay.d.ts +7 -3
- package/dist/types/overlays/session-selector.d.ts +3 -1
- package/dist/types/overlays/usage-dashboard.d.ts +6 -6
- package/dist/types/prompt/composer.d.ts +21 -20
- package/dist/types/prompt/custom-editor.d.ts +20 -10
- package/dist/types/prompt/image-references.d.ts +22 -0
- package/dist/types/prompt/internal-url-autocomplete.d.ts +1 -0
- package/dist/types/prompt/macos-spelling.d.ts +2 -1
- package/dist/types/prompt/prose-gate.d.ts +3 -0
- package/dist/types/prompt/queued-messages.d.ts +1 -1
- package/dist/types/prompt/typing-word.d.ts +25 -0
- package/dist/types/prompt/welcome.d.ts +26 -6
- package/dist/types/render/hanging-wrap.d.ts +7 -0
- package/dist/types/render/hyperlink.d.ts +2 -0
- package/dist/types/render/render-utils.d.ts +9 -1
- package/dist/types/render/utils.d.ts +1 -1
- package/dist/types/setup/scenes/splash.d.ts +6 -5
- package/dist/types/status-line/context-usage.d.ts +4 -1
- package/dist/types/status-line/host.d.ts +6 -4
- package/dist/types/status-line/startup.d.ts +6 -6
- package/dist/types/status-line/types.d.ts +3 -0
- package/dist/types/stdin-buffer.d.ts +7 -0
- package/dist/types/terminal-capabilities.d.ts +16 -1
- package/dist/types/terminal-multiplexer.d.ts +7 -0
- package/dist/types/terminal.d.ts +8 -4
- package/dist/types/theme/symbols.d.ts +1 -1
- package/dist/types/theme/theme.d.ts +11 -0
- package/dist/types/thinking.d.ts +5 -0
- package/dist/types/tmux.d.ts +39 -4
- package/dist/types/tools/ast-edit.d.ts +2 -2
- package/dist/types/tools/ast-grep.d.ts +2 -2
- package/dist/types/tools/bash.d.ts +6 -1
- package/dist/types/tools/edit.d.ts +2 -0
- package/dist/types/tools/eval.d.ts +53 -4
- package/dist/types/tools/find.d.ts +14 -4
- package/dist/types/tools/glob.d.ts +3 -3
- package/dist/types/tools/grep.d.ts +2 -2
- package/dist/types/tools/grouped-file-output.d.ts +9 -4
- package/dist/types/tools/native-view.d.ts +1 -1
- package/dist/types/tools/read.d.ts +32 -10
- package/dist/types/tools/renderer.d.ts +2 -0
- package/dist/types/tools/task.d.ts +31 -0
- package/dist/types/tools/write.d.ts +2 -0
- package/dist/types/tui.d.ts +20 -3
- package/package.json +10 -10
- package/src/app-keybindings.d.ts +18 -8
- package/src/app-keybindings.ts +20 -8
- package/src/apps/autoresearch-dashboard.ts +444 -27
- package/src/apps/debug/raw-sse.ts +2 -2
- package/src/apps/git/diff-pane.ts +39 -41
- package/src/apps/git/git-tui.ts +80 -14
- package/src/apps/git/sidebar.ts +10 -1
- package/src/apps/git/state.ts +12 -0
- package/src/autocomplete.d.ts +2 -0
- package/src/autocomplete.ts +21 -19
- package/src/bracketed-paste.ts +9 -2
- package/src/charts/chart-svg.d.ts +7 -13
- package/src/charts/chart-svg.ts +19 -22
- package/src/chat/advisor-message.d.ts +4 -1
- package/src/chat/advisor-message.ts +77 -24
- package/src/chat/assistant-message.d.ts +9 -4
- package/src/chat/assistant-message.ts +127 -31
- package/src/chat/bash-execution.ts +7 -2
- package/src/chat/figure-markdown.d.ts +7 -2
- package/src/chat/figure-markdown.ts +10 -3
- package/src/chat/image-loading.ts +9 -6
- package/src/chat/messages.d.ts +3 -1
- package/src/chat/messages.ts +4 -1
- package/src/chat/read-tool-group.d.ts +2 -2
- package/src/chat/read-tool-group.ts +97 -42
- package/src/chat/svg-figure.ts +3 -1
- package/src/chat/svg-source.ts +6 -3
- package/src/chat/table-chart.d.ts +11 -15
- package/src/chat/table-chart.ts +24 -57
- package/src/chat/tool-execution.d.ts +32 -20
- package/src/chat/tool-execution.ts +103 -36
- package/src/chat/user-message.d.ts +3 -2
- package/src/chat/user-message.ts +54 -34
- package/src/chrome/countdown-timer.ts +3 -3
- package/src/chrome/diff.d.ts +2 -3
- package/src/chrome/diff.ts +4 -9
- package/src/chrome/transcript-container.d.ts +2 -0
- package/src/chrome/transcript-container.ts +212 -28
- package/src/components/editor.ts +12 -12
- package/src/components/image.d.ts +2 -0
- package/src/components/image.ts +54 -20
- package/src/components/markdown.d.ts +49 -3
- package/src/components/markdown.ts +461 -11
- package/src/components/settings-list.ts +2 -4
- package/src/components/text.d.ts +2 -0
- package/src/components/text.ts +11 -1
- package/src/debug-server.d.ts +2 -0
- package/src/debug-server.ts +51 -69
- package/src/hotkeys-markdown.ts +2 -0
- package/src/keybinding-matchers.d.ts +6 -0
- package/src/keybinding-matchers.ts +19 -0
- package/src/multiplexers/tmux.d.ts +1 -0
- package/src/multiplexers/tmux.ts +3 -0
- package/src/multiplexers/types.d.ts +6 -0
- package/src/multiplexers/types.ts +6 -0
- package/src/native/backend.d.ts +5 -4
- package/src/native/backend.ts +13 -5
- package/src/native/blobs.d.ts +24 -12
- package/src/native/blobs.ts +56 -7
- package/src/native/reconcile.ts +43 -21
- package/src/overlays/advisor-config.ts +259 -8
- package/src/overlays/agent-hub-projection.d.ts +10 -5
- package/src/overlays/agent-hub-projection.ts +63 -12
- package/src/overlays/annotation-overlay.ts +422 -168
- package/src/overlays/approval-dialog.ts +389 -0
- package/src/overlays/ask-dialog.ts +244 -105
- package/src/overlays/btw-history-panel.ts +208 -147
- package/src/overlays/extensions/extension-list.ts +4 -6
- package/src/overlays/hook-editor.ts +90 -32
- package/src/overlays/hook-input.ts +105 -19
- package/src/overlays/job-tree.ts +177 -0
- package/src/overlays/jobs-panel.ts +222 -142
- package/src/overlays/login-dialog.ts +201 -91
- package/src/overlays/mcp-add-wizard.ts +562 -279
- package/src/overlays/model-browser.ts +32 -7
- package/src/overlays/model-hub.ts +4 -10
- package/src/overlays/model-picker.ts +58 -21
- package/src/overlays/pause-screen.ts +81 -23
- package/src/overlays/plan-review-overlay.ts +16 -0
- package/src/overlays/plugin-selector.ts +17 -1
- package/src/overlays/queue-mode-selector.ts +10 -0
- package/src/overlays/report-panel.ts +6 -2
- package/src/overlays/reset-usage-selector.ts +130 -21
- package/src/overlays/session-account-selector.ts +36 -0
- package/src/overlays/session-info-overlay.ts +199 -76
- package/src/overlays/session-selector.ts +15 -10
- package/src/overlays/settings-selector.ts +3 -0
- package/src/overlays/show-images-selector.ts +1 -0
- package/src/overlays/snapcompact-shape-preview.ts +13 -6
- package/src/overlays/theme-selector.ts +6 -1
- package/src/overlays/thinking-selector.ts +8 -4
- package/src/overlays/tree-selector.ts +117 -2
- package/src/overlays/usage-dashboard.ts +498 -144
- package/src/prompt/composer-cache.ts +1 -1
- package/src/prompt/composer.ts +194 -74
- package/src/prompt/custom-editor.ts +168 -65
- package/src/prompt/image-references.d.ts +22 -0
- package/src/prompt/image-references.ts +79 -2
- package/src/prompt/internal-url-autocomplete.ts +1 -0
- package/src/prompt/macos-spelling.ts +28 -5
- package/src/prompt/prose-gate.ts +3 -0
- package/src/prompt/queued-messages.ts +9 -2
- package/src/prompt/tips.txt +1 -2
- package/src/prompt/typing-word.ts +59 -0
- package/src/prompt/welcome.ts +97 -45
- package/src/render/code-cell.ts +18 -5
- package/src/render/hanging-wrap.d.ts +7 -0
- package/src/render/hanging-wrap.ts +58 -0
- package/src/render/hyperlink.d.ts +2 -0
- package/src/render/hyperlink.ts +5 -0
- package/src/render/render-utils.d.ts +9 -1
- package/src/render/render-utils.ts +16 -2
- package/src/render/utils.d.ts +1 -1
- package/src/render/utils.ts +1 -1
- package/src/render/width-aware-text.ts +6 -5
- package/src/setup/scenes/splash.ts +22 -8
- package/src/status-line/component.ts +23 -10
- package/src/status-line/context-usage.ts +176 -73
- package/src/status-line/footer.ts +18 -35
- package/src/status-line/host.ts +6 -1
- package/src/status-line/segments.ts +16 -5
- package/src/status-line/startup.ts +6 -6
- package/src/status-line/types.ts +1 -0
- package/src/stdin-buffer.d.ts +7 -0
- package/src/stdin-buffer.ts +11 -1
- package/src/terminal-capabilities.d.ts +16 -1
- package/src/terminal-capabilities.ts +66 -28
- package/src/terminal-multiplexer.d.ts +7 -0
- package/src/terminal-multiplexer.ts +14 -0
- package/src/terminal.d.ts +8 -4
- package/src/terminal.ts +160 -46
- package/src/theme/symbols.d.ts +1 -1
- package/src/theme/symbols.ts +1 -0
- package/src/theme/theme-class.ts +1 -0
- package/src/theme/theme.d.ts +11 -0
- package/src/theme/theme.ts +46 -14
- package/src/thinking.d.ts +5 -0
- package/src/thinking.ts +9 -1
- package/src/tmux.d.ts +39 -4
- package/src/tmux.ts +110 -16
- package/src/tools/ask.ts +20 -9
- package/src/tools/ast-edit.d.ts +2 -2
- package/src/tools/ast-edit.ts +30 -7
- package/src/tools/ast-grep.d.ts +2 -2
- package/src/tools/ast-grep.ts +39 -35
- package/src/tools/bash.d.ts +6 -1
- package/src/tools/bash.ts +15 -9
- package/src/tools/debug.ts +2 -1
- package/src/tools/default-renderer.ts +3 -2
- package/src/tools/edit.d.ts +2 -0
- package/src/tools/edit.ts +100 -21
- package/src/tools/eval.d.ts +53 -4
- package/src/tools/eval.ts +173 -137
- package/src/tools/find.d.ts +14 -4
- package/src/tools/find.ts +71 -18
- package/src/tools/glob.d.ts +3 -3
- package/src/tools/glob.ts +51 -17
- package/src/tools/grep.d.ts +2 -2
- package/src/tools/grep.ts +99 -22
- package/src/tools/grouped-file-output.d.ts +9 -4
- package/src/tools/grouped-file-output.ts +21 -6
- package/src/tools/lsp.ts +30 -18
- package/src/tools/mcp.ts +2 -2
- package/src/tools/native-view.d.ts +1 -1
- package/src/tools/native-view.ts +2 -2
- package/src/tools/read.d.ts +32 -10
- package/src/tools/read.ts +89 -43
- package/src/tools/renderer.d.ts +2 -0
- package/src/tools/renderer.ts +2 -0
- package/src/tools/task.d.ts +31 -0
- package/src/tools/task.ts +40 -7
- package/src/tools/todo.ts +3 -2
- package/src/tools/wait.ts +16 -30
- package/src/tools/web-search.ts +2 -1
- package/src/tools/write.d.ts +2 -0
- package/src/tools/write.ts +36 -12
- package/src/tools/yield.ts +2 -2
- package/src/tui.d.ts +20 -3
- package/src/tui.ts +140 -36
- package/src/utils.ts +5 -3
- package/dist/types/tools/eval-format/code-mode-declarations.d.ts +0 -5
- package/src/tools/eval-format/code-mode-declarations.ts +0 -61
package/src/tools/eval.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
ToolRenderer,
|
|
10
10
|
} from "./renderer";
|
|
11
11
|
import type { TspSpan } from "@linxiraos/pi-wire";
|
|
12
|
-
import { compact, keyed, md, node, span, text } from "../native/describe";
|
|
12
|
+
import { code, compact, keyed, md, node, span, text } from "../native/describe";
|
|
13
13
|
import type { NativeChild, NativeNode } from "../native/node";
|
|
14
14
|
import { plainText } from "../native/spans";
|
|
15
15
|
import { resultText, runBox, runFoot, type RunFootInput, runInput, runOutput, type RunState } from "./native-view";
|
|
@@ -35,12 +35,16 @@ import {
|
|
|
35
35
|
renderJsonTreeLines,
|
|
36
36
|
} from "./json-tree";
|
|
37
37
|
import { formatStyledTruncationWarning, stripOutputNotice } from "./output-meta";
|
|
38
|
+
import { splitPathAndSel } from "./read";
|
|
38
39
|
import {
|
|
39
40
|
DEFAULT_TERMINAL_PREVIEW_LINES,
|
|
41
|
+
PREVIEW_LIMITS,
|
|
40
42
|
cappedHeadLines,
|
|
41
43
|
formatTitle,
|
|
44
|
+
previewLine,
|
|
42
45
|
previewWindowRows,
|
|
43
46
|
replaceTabs,
|
|
47
|
+
sanitizeDisplayLines,
|
|
44
48
|
shortenPath,
|
|
45
49
|
truncateToWidth,
|
|
46
50
|
wrapBrackets,
|
|
@@ -60,26 +64,57 @@ export interface EvalStatusEvent {
|
|
|
60
64
|
[key: string]: unknown;
|
|
61
65
|
}
|
|
62
66
|
|
|
67
|
+
/** One column of a table view. */
|
|
68
|
+
export interface EvalTableColumn {
|
|
69
|
+
head: string;
|
|
70
|
+
/** Numeric values: renderers right-align the column. */
|
|
71
|
+
numeric?: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* A pretty rendering of something a cell printed, shown to the user in place
|
|
76
|
+
* of its text; the model only ever sees the text.
|
|
77
|
+
* - `table`: a data frame or `console.table`; leading index columns are plain
|
|
78
|
+
* columns, and a truncated frame's elided rows/columns are `…` cells.
|
|
79
|
+
* - `json`: a structured value (dict/list, object/array) as a collapsible tree.
|
|
80
|
+
* - `markdown`: an object's Markdown representation.
|
|
81
|
+
*/
|
|
82
|
+
export type EvalView =
|
|
83
|
+
| { kind: "table"; columns: EvalTableColumn[]; rows: string[][] }
|
|
84
|
+
| { kind: "json"; value: unknown }
|
|
85
|
+
| { kind: "markdown"; text: string };
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* A view and the exact printed text it stands for. Renderers locate `text` in
|
|
89
|
+
* the cell's `output` (entries in print order) and show the view there; an
|
|
90
|
+
* entry whose text is no longer in the output (truncated) is skipped.
|
|
91
|
+
*/
|
|
92
|
+
export interface EvalViewEntry {
|
|
93
|
+
text: string;
|
|
94
|
+
view: EvalView;
|
|
95
|
+
}
|
|
96
|
+
|
|
63
97
|
/** Per-cell execution result for transcript rendering. */
|
|
64
98
|
export interface EvalCellResult {
|
|
65
99
|
index: number;
|
|
66
100
|
title?: string;
|
|
67
101
|
code: string;
|
|
68
102
|
language?: EvalLanguage;
|
|
103
|
+
/** What the model saw: the cell's printed text plus image notes. */
|
|
69
104
|
output: string;
|
|
105
|
+
/** Pretty views of spans of `output`, in print order. */
|
|
106
|
+
views?: EvalViewEntry[];
|
|
70
107
|
status: "pending" | "running" | "complete" | "error";
|
|
71
108
|
durationMs?: number;
|
|
72
109
|
exitCode?: number;
|
|
73
110
|
statusEvents?: EvalStatusEvent[];
|
|
74
111
|
/** Discrete events dropped from the front of `statusEvents` (see {@link recordStatusEvent}). */
|
|
75
112
|
statusEventsElided?: number;
|
|
76
|
-
hasMarkdown?: boolean;
|
|
77
113
|
}
|
|
78
114
|
|
|
79
115
|
/** Tool result detail object surfaced to the UI/transcript. */
|
|
80
116
|
export interface EvalToolDetails {
|
|
81
117
|
cells?: EvalCellResult[];
|
|
82
|
-
jsonOutputs?: unknown[];
|
|
83
118
|
images?: ImageContent[];
|
|
84
119
|
statusEvents?: EvalStatusEvent[];
|
|
85
120
|
/** Discrete events dropped from the front of `statusEvents` (see {@link recordStatusEvent}). */
|
|
@@ -92,9 +127,9 @@ export interface EvalToolDetails {
|
|
|
92
127
|
languages?: EvalLanguage[];
|
|
93
128
|
/** Optional human-readable notice (e.g. fallback explanation). */
|
|
94
129
|
notice?: string;
|
|
95
|
-
/** Present when the cell was auto-backgrounded as an async job. */
|
|
130
|
+
/** Present when the cell was auto-backgrounded as an async job; `cancelled`: killed before it finished. */
|
|
96
131
|
async?: {
|
|
97
|
-
state: "running" | "completed" | "failed";
|
|
132
|
+
state: "running" | "completed" | "failed" | "cancelled";
|
|
98
133
|
jobId: string;
|
|
99
134
|
type: "eval";
|
|
100
135
|
};
|
|
@@ -583,7 +618,8 @@ function formatCellOutputLines(
|
|
|
583
618
|
theme: Theme,
|
|
584
619
|
width: number,
|
|
585
620
|
): { lines: readonly string[]; hiddenCount: number } {
|
|
586
|
-
|
|
621
|
+
const output = cell.output;
|
|
622
|
+
if (!output) {
|
|
587
623
|
return { lines: [], hiddenCount: 0 };
|
|
588
624
|
}
|
|
589
625
|
|
|
@@ -595,32 +631,56 @@ function formatCellOutputLines(
|
|
|
595
631
|
// exact hidden-count row, so the pane marker stays off here.
|
|
596
632
|
const innerWidth = outputBlockContentWidth(width);
|
|
597
633
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
634
|
+
const isError = cell.status === "error";
|
|
635
|
+
const styleText = (line: string): string => theme.fg(isError ? "error" : "toolOutput", replaceTabs(line));
|
|
636
|
+
// A table's printed text is already a terminal table, aligned to the line it starts on: keep it as text.
|
|
637
|
+
const parts = splitEvalOutput(
|
|
638
|
+
output,
|
|
639
|
+
cell.views?.filter(entry => entry.view.kind !== "table"),
|
|
640
|
+
);
|
|
641
|
+
if (parts.some(part => part.kind === "view")) {
|
|
642
|
+
// Printed text keeps its place; json and markdown views replace theirs with a tree / rendered Markdown.
|
|
643
|
+
const treeDepth = expanded ? JSON_TREE_MAX_DEPTH_EXPANDED : JSON_TREE_MAX_DEPTH_COLLAPSED;
|
|
644
|
+
const treeLineCap = expanded ? JSON_TREE_MAX_LINES_EXPANDED : JSON_TREE_MAX_LINES_COLLAPSED;
|
|
645
|
+
const treeScalarLen = expanded ? JSON_TREE_SCALAR_LEN_EXPANDED : JSON_TREE_SCALAR_LEN_COLLAPSED;
|
|
646
|
+
const allLines: string[] = [];
|
|
647
|
+
for (const part of parts) {
|
|
648
|
+
if (part.kind === "text") {
|
|
649
|
+
for (const line of part.text.split("\n")) allLines.push(styleText(line));
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
const view = part.view;
|
|
653
|
+
if (view.kind === "json") {
|
|
654
|
+
const tree = renderJsonTreeLines(view.value, theme, treeDepth, treeLineCap, treeScalarLen);
|
|
655
|
+
allLines.push(...tree.lines);
|
|
656
|
+
if (tree.truncated) allLines.push(theme.fg("dim", "…"));
|
|
657
|
+
} else if (view.kind === "markdown") {
|
|
658
|
+
allLines.push(...new Markdown(view.text, 0, 0, getMarkdownTheme()).render(innerWidth));
|
|
659
|
+
}
|
|
660
|
+
}
|
|
601
661
|
const formatted = formatOutputPaneLines(
|
|
602
662
|
{
|
|
603
663
|
lines: allLines,
|
|
604
664
|
expanded,
|
|
605
665
|
collapsedMaxLines: previewLines,
|
|
606
666
|
edge: "tail",
|
|
667
|
+
visual: true,
|
|
668
|
+
width: innerWidth,
|
|
607
669
|
showHiddenMarker: false,
|
|
608
670
|
},
|
|
609
671
|
theme,
|
|
610
672
|
);
|
|
611
673
|
return { lines: formatted.lines, hiddenCount: formatted.hiddenCount };
|
|
612
674
|
}
|
|
613
|
-
|
|
614
|
-
const isError = cell.status === "error";
|
|
615
675
|
const formatted = formatOutputPaneLines(
|
|
616
676
|
{
|
|
617
|
-
lines:
|
|
677
|
+
lines: output.split("\n"),
|
|
618
678
|
expanded,
|
|
619
679
|
collapsedMaxLines: previewLines,
|
|
620
680
|
edge: "tail",
|
|
621
681
|
visual: true,
|
|
622
682
|
width: innerWidth,
|
|
623
|
-
styleLine:
|
|
683
|
+
styleLine: styleText,
|
|
624
684
|
showHiddenMarker: false,
|
|
625
685
|
},
|
|
626
686
|
theme,
|
|
@@ -628,17 +688,42 @@ function formatCellOutputLines(
|
|
|
628
688
|
return { lines: formatted.lines, hiddenCount: formatted.hiddenCount };
|
|
629
689
|
}
|
|
630
690
|
|
|
631
|
-
/**
|
|
632
|
-
|
|
691
|
+
/** Display cells a status field value keeps on its one-line summary. */
|
|
692
|
+
const STATUS_VALUE_WIDTH = 200;
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Plain one-line summary of a status event: op plus its scalar fields, each
|
|
696
|
+
* collapsed to one line. A `preview` (file or command text a helper returned)
|
|
697
|
+
* never joins the line: an expanded cell shows it under the line as a code
|
|
698
|
+
* block holding its first {@link PREVIEW_LIMITS.OUTPUT_EXPANDED} lines, folded
|
|
699
|
+
* to {@link PREVIEW_LIMITS.COLLAPSED_LINES}.
|
|
700
|
+
*/
|
|
701
|
+
function describeStatusEvent(event: EvalStatusEvent, expanded: boolean): NativeNode {
|
|
633
702
|
const spans: TspSpan[] = [span(event.op, "accent")];
|
|
634
703
|
for (const key in event) {
|
|
635
|
-
if (key === "op" || key === "resolvedThinkingLevel") continue;
|
|
704
|
+
if (key === "op" || key === "preview" || key === "resolvedThinkingLevel") continue;
|
|
636
705
|
const value = event[key];
|
|
637
706
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
638
|
-
spans.push(span(` ${key}=`, "muted"), span(sanitizeText(String(value))));
|
|
707
|
+
spans.push(span(` ${key}=`, "muted"), span(previewLine(sanitizeText(String(value)), STATUS_VALUE_WIDTH)));
|
|
639
708
|
}
|
|
640
709
|
}
|
|
641
|
-
|
|
710
|
+
const line = text(spans, { truncate: "end", role: "zeta.tool.eval.status" });
|
|
711
|
+
const preview = expanded ? eventString(event.preview)?.trimEnd() : undefined;
|
|
712
|
+
if (!preview) return line;
|
|
713
|
+
const head = cappedHeadLines(sanitizeDisplayLines(preview), PREVIEW_LIMITS.OUTPUT_EXPANDED).lines;
|
|
714
|
+
const path = eventString(event.path);
|
|
715
|
+
return node("col", { role: "zeta.tool.eval.status.event", gap: "none" }, [
|
|
716
|
+
keyed(line, "line"),
|
|
717
|
+
keyed(
|
|
718
|
+
code(head.join("\n"), {
|
|
719
|
+
role: "zeta.tool.eval.status.preview",
|
|
720
|
+
path: path ? splitPathAndSel(path).path : undefined,
|
|
721
|
+
wrap: false,
|
|
722
|
+
preview: { lines: PREVIEW_LIMITS.COLLAPSED_LINES },
|
|
723
|
+
}),
|
|
724
|
+
"preview",
|
|
725
|
+
),
|
|
726
|
+
]);
|
|
642
727
|
}
|
|
643
728
|
|
|
644
729
|
/**
|
|
@@ -664,100 +749,79 @@ function evalToolHead(
|
|
|
664
749
|
};
|
|
665
750
|
}
|
|
666
751
|
|
|
667
|
-
/**
|
|
668
|
-
type EvalOutputPart =
|
|
669
|
-
| { readonly kind: "text"; readonly text: string }
|
|
670
|
-
| { readonly kind: "table"; readonly head: readonly string[]; readonly rows: readonly string[][] };
|
|
671
|
-
|
|
672
|
-
/** The cells of a `│ a │ b │` row, trimmed; undefined when the line is not a table row. */
|
|
673
|
-
function tableRowCells(line: string): string[] | undefined {
|
|
674
|
-
const plain = plainText(line).trim();
|
|
675
|
-
if (plain.length < 2 || !plain.startsWith("│") || !plain.endsWith("│")) return undefined;
|
|
676
|
-
return plain
|
|
677
|
-
.slice(1, -1)
|
|
678
|
-
.split("│")
|
|
679
|
-
.map(cell => cell.trim());
|
|
680
|
-
}
|
|
752
|
+
/** One ordered piece of a cell's output: printed text, or a view shown in place of the text it matched. */
|
|
753
|
+
export type EvalOutputPart = { kind: "text"; text: string } | { kind: "view"; view: EvalView };
|
|
681
754
|
|
|
682
755
|
/**
|
|
683
|
-
* Split `
|
|
684
|
-
*
|
|
685
|
-
*
|
|
756
|
+
* Split `output` around its views, in order: each view's `text` is searched
|
|
757
|
+
* from the end of the previous match, unmatched entries are skipped, and
|
|
758
|
+
* blank text between views is dropped (newlines bordering a view trimmed).
|
|
686
759
|
*/
|
|
687
|
-
function
|
|
688
|
-
const lines = output.split("\n");
|
|
760
|
+
export function splitEvalOutput(output: string, views: readonly EvalViewEntry[] | undefined): EvalOutputPart[] {
|
|
689
761
|
const parts: EvalOutputPart[] = [];
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
.replace(/^\n+|\s+$/g, "");
|
|
696
|
-
if (chunk.length > 0) parts.push({ kind: "text", text: chunk });
|
|
762
|
+
const pushText = (chunk: string, trimStart: boolean, trimEnd: boolean): void => {
|
|
763
|
+
let text = chunk;
|
|
764
|
+
if (trimStart) text = text.replace(/^\n+/, "");
|
|
765
|
+
if (trimEnd) text = text.replace(/\n+$/, "");
|
|
766
|
+
if (text.trim().length > 0) parts.push({ kind: "text", text });
|
|
697
767
|
};
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
)
|
|
707
|
-
continue;
|
|
708
|
-
const rows: string[][] = [];
|
|
709
|
-
let end = i + 3;
|
|
710
|
-
for (; end < lines.length; end++) {
|
|
711
|
-
const cells = tableRowCells(lines[end]!);
|
|
712
|
-
if (!cells) break;
|
|
713
|
-
rows.push(cells);
|
|
714
|
-
}
|
|
715
|
-
if (
|
|
716
|
-
!plainText(lines[end] ?? "")
|
|
717
|
-
.trimStart()
|
|
718
|
-
.startsWith("└")
|
|
719
|
-
)
|
|
720
|
-
continue;
|
|
721
|
-
if (rows.some(row => row.length !== head.length)) continue;
|
|
722
|
-
flushText(i);
|
|
723
|
-
parts.push({ kind: "table", head, rows });
|
|
724
|
-
i = end;
|
|
725
|
-
textStart = end + 1;
|
|
768
|
+
let cursor = 0;
|
|
769
|
+
for (const entry of views ?? []) {
|
|
770
|
+
if (!entry.text) continue;
|
|
771
|
+
const at = output.indexOf(entry.text, cursor);
|
|
772
|
+
if (at < 0) continue;
|
|
773
|
+
pushText(output.slice(cursor, at), cursor > 0, true);
|
|
774
|
+
parts.push({ kind: "view", view: entry.view });
|
|
775
|
+
cursor = at + entry.text.length;
|
|
726
776
|
}
|
|
727
|
-
|
|
777
|
+
pushText(output.slice(cursor), cursor > 0, cursor > 0);
|
|
728
778
|
return parts;
|
|
729
779
|
}
|
|
730
780
|
|
|
781
|
+
/** A table view as a native `table`; numeric columns align to the end. */
|
|
782
|
+
function evalTableNode(view: Extract<EvalView, { kind: "table" }>, key: string): NativeNode {
|
|
783
|
+
return node(
|
|
784
|
+
"table",
|
|
785
|
+
{
|
|
786
|
+
cols: view.columns.map((column, c) => ({
|
|
787
|
+
id: `c${c}`,
|
|
788
|
+
head: column.head,
|
|
789
|
+
align: column.numeric ? "end" : undefined,
|
|
790
|
+
})),
|
|
791
|
+
rows: view.rows.map((cells, r) => ({
|
|
792
|
+
id: `r${r}`,
|
|
793
|
+
cells: Object.fromEntries(cells.map((cell, c) => [`c${c}`, cell])),
|
|
794
|
+
})),
|
|
795
|
+
role: "zeta.tool.eval.table",
|
|
796
|
+
},
|
|
797
|
+
undefined,
|
|
798
|
+
key,
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
|
|
731
802
|
/**
|
|
732
|
-
* One cell's outputs
|
|
733
|
-
*
|
|
734
|
-
* blocks as tables.
|
|
803
|
+
* One cell's outputs in order: printed text (following its tail, clamped to
|
|
804
|
+
* the last `previewLines` while folded) with each view in place of its text.
|
|
735
805
|
*/
|
|
736
|
-
function evalOutputNodes(
|
|
806
|
+
function evalOutputNodes(
|
|
807
|
+
output: string,
|
|
808
|
+
views: readonly EvalViewEntry[] | undefined,
|
|
809
|
+
previewLines: number,
|
|
810
|
+
): NativeNode[] {
|
|
737
811
|
if (output.trim().length === 0) return [];
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
rows: part.rows.map((cells, r) => ({
|
|
752
|
-
id: `r${r}`,
|
|
753
|
-
cells: Object.fromEntries(cells.map((cell, c) => [`c${c}`, cell])),
|
|
754
|
-
})),
|
|
755
|
-
role: "zeta.tool.eval.table",
|
|
756
|
-
},
|
|
757
|
-
undefined,
|
|
758
|
-
`table-${i}`,
|
|
759
|
-
),
|
|
760
|
-
);
|
|
812
|
+
return splitEvalOutput(output, views).map((part, i) => {
|
|
813
|
+
if (part.kind === "text") {
|
|
814
|
+
return runOutput(part.text, {
|
|
815
|
+
role: "zeta.tool.eval.output",
|
|
816
|
+
previewLines,
|
|
817
|
+
key: i === 0 ? "output" : `output-${i}`,
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
const view = part.view;
|
|
821
|
+
if (view.kind === "table") return evalTableNode(view, `table-${i}`);
|
|
822
|
+
if (view.kind === "json") return keyed(describeJsonTree(view.value, { hiddenRootKeys: [] }), `json-${i}`);
|
|
823
|
+
return keyed(md(view.text), `markdown-${i}`);
|
|
824
|
+
});
|
|
761
825
|
}
|
|
762
826
|
|
|
763
827
|
/** Status lines a folded cell keeps: the newest ones. */
|
|
@@ -774,7 +838,9 @@ function evalStatusSection(log: StatusEventLog, expanded: boolean): NativeNode |
|
|
|
774
838
|
if (events.length === 0 && elided === 0) return undefined;
|
|
775
839
|
const shownFrom = expanded ? 0 : Math.max(0, events.length - RUN_STATUS_TAIL);
|
|
776
840
|
const hidden = shownFrom + elided;
|
|
777
|
-
const lines = events
|
|
841
|
+
const lines = events
|
|
842
|
+
.slice(shownFrom)
|
|
843
|
+
.map((event, i) => keyed(describeStatusEvent(event, expanded), `s${hidden + i}`));
|
|
778
844
|
return node(
|
|
779
845
|
"col",
|
|
780
846
|
{ role: "zeta.run.status", gap: "none" },
|
|
@@ -922,18 +988,6 @@ export const evalToolRenderer = {
|
|
|
922
988
|
// the styled `warningLine` below carries the same text in ⟨…⟩ form.
|
|
923
989
|
const output = stripOutputNotice(rawOutput, details?.meta).trimEnd();
|
|
924
990
|
|
|
925
|
-
const jsonOutputs = details?.jsonOutputs ?? [];
|
|
926
|
-
const treeExpanded = options.renderContext?.expanded ?? options.expanded;
|
|
927
|
-
const treeDepth = treeExpanded ? JSON_TREE_MAX_DEPTH_EXPANDED : JSON_TREE_MAX_DEPTH_COLLAPSED;
|
|
928
|
-
const treeLineCap = treeExpanded ? JSON_TREE_MAX_LINES_EXPANDED : JSON_TREE_MAX_LINES_COLLAPSED;
|
|
929
|
-
const treeScalarLen = treeExpanded ? JSON_TREE_SCALAR_LEN_EXPANDED : JSON_TREE_SCALAR_LEN_COLLAPSED;
|
|
930
|
-
const labelOutputs = jsonOutputs.length > 1;
|
|
931
|
-
const jsonLines = jsonOutputs.flatMap((value, index) => {
|
|
932
|
-
const tree = renderJsonTreeLines(value, uiTheme, treeDepth, treeLineCap, treeScalarLen);
|
|
933
|
-
const body = tree.truncated ? [...tree.lines, uiTheme.fg("dim", "…")] : tree.lines;
|
|
934
|
-
return labelOutputs ? [uiTheme.fg("dim", `display[${index + 1}]`), ...body] : body;
|
|
935
|
-
});
|
|
936
|
-
|
|
937
991
|
const timeoutSeconds = options.renderContext?.timeout;
|
|
938
992
|
const timeoutLine =
|
|
939
993
|
typeof timeoutSeconds === "number"
|
|
@@ -1057,7 +1111,6 @@ export const evalToolRenderer = {
|
|
|
1057
1111
|
lines.push("");
|
|
1058
1112
|
}
|
|
1059
1113
|
}
|
|
1060
|
-
lines.push(...jsonLines);
|
|
1061
1114
|
if (timeoutLine) {
|
|
1062
1115
|
lines.push(timeoutLine);
|
|
1063
1116
|
}
|
|
@@ -1080,9 +1133,6 @@ export const evalToolRenderer = {
|
|
|
1080
1133
|
});
|
|
1081
1134
|
}
|
|
1082
1135
|
|
|
1083
|
-
const displayOutput = output;
|
|
1084
|
-
const combinedOutput = [displayOutput, ...jsonLines].filter(Boolean).join("\n");
|
|
1085
|
-
|
|
1086
1136
|
const statusEvents = details?.statusEvents ?? [];
|
|
1087
1137
|
const statusLines = renderStatusEvents(
|
|
1088
1138
|
statusEvents,
|
|
@@ -1091,12 +1141,12 @@ export const evalToolRenderer = {
|
|
|
1091
1141
|
details?.statusEventsElided,
|
|
1092
1142
|
);
|
|
1093
1143
|
|
|
1094
|
-
if (!
|
|
1144
|
+
if (!output && statusLines.length === 0) {
|
|
1095
1145
|
const lines = [timeoutLine, noticeLine, asyncLine, warningLine].filter(Boolean) as string[];
|
|
1096
1146
|
return new Text(lines.join("\n"), 0, 0);
|
|
1097
1147
|
}
|
|
1098
1148
|
|
|
1099
|
-
if (!
|
|
1149
|
+
if (!output && statusLines.length > 0) {
|
|
1100
1150
|
const lines = [
|
|
1101
1151
|
uiTheme.fg("dim", "Status"),
|
|
1102
1152
|
...statusLines,
|
|
@@ -1109,7 +1159,7 @@ export const evalToolRenderer = {
|
|
|
1109
1159
|
}
|
|
1110
1160
|
|
|
1111
1161
|
if (options.renderContext?.expanded ?? options.expanded) {
|
|
1112
|
-
const styledOutput =
|
|
1162
|
+
const styledOutput = output
|
|
1113
1163
|
.split("\n")
|
|
1114
1164
|
.map(line => uiTheme.fg("toolOutput", line))
|
|
1115
1165
|
.join("\n");
|
|
@@ -1124,7 +1174,7 @@ export const evalToolRenderer = {
|
|
|
1124
1174
|
return new Text(lines.join("\n"), 0, 0);
|
|
1125
1175
|
}
|
|
1126
1176
|
|
|
1127
|
-
const styledOutput =
|
|
1177
|
+
const styledOutput = output
|
|
1128
1178
|
.split("\n")
|
|
1129
1179
|
.map(line => uiTheme.fg("toolOutput", line))
|
|
1130
1180
|
.join("\n");
|
|
@@ -1214,9 +1264,6 @@ export const evalToolRenderer = {
|
|
|
1214
1264
|
const cancelled = options.cancelled === true;
|
|
1215
1265
|
const expanded = options.renderContext?.expanded ?? options.expanded;
|
|
1216
1266
|
const previewLines = options.renderContext?.previewLines ?? EVAL_DEFAULT_PREVIEW_LINES;
|
|
1217
|
-
const jsonNodes = (details?.jsonOutputs ?? []).map((value, index) =>
|
|
1218
|
-
keyed(describeJsonTree(value, { hiddenRootKeys: [] }), `display-${index}`),
|
|
1219
|
-
);
|
|
1220
1267
|
// The call's notice and truncation join the last run's foot facts (a background job is a head badge).
|
|
1221
1268
|
const callFacts = { facts: compact([details?.notice]), meta: details?.meta };
|
|
1222
1269
|
const cellResults = details?.cells;
|
|
@@ -1242,15 +1289,7 @@ export const evalToolRenderer = {
|
|
|
1242
1289
|
language,
|
|
1243
1290
|
code: formatEvalCodeForDisplay(cell.code, language),
|
|
1244
1291
|
title: cell.title,
|
|
1245
|
-
outputs: [
|
|
1246
|
-
...evalOutputNodes(
|
|
1247
|
-
cell.output,
|
|
1248
|
-
cell.hasMarkdown === true && cell.status !== "error",
|
|
1249
|
-
previewLines,
|
|
1250
|
-
),
|
|
1251
|
-
|
|
1252
|
-
...(i === cellResults.length - 1 ? jsonNodes : []),
|
|
1253
|
-
],
|
|
1292
|
+
outputs: [...evalOutputNodes(cell.output, cell.views, previewLines)],
|
|
1254
1293
|
status: evalStatusSection(cell, expanded),
|
|
1255
1294
|
foot: state && {
|
|
1256
1295
|
state,
|
|
@@ -1275,10 +1314,7 @@ export const evalToolRenderer = {
|
|
|
1275
1314
|
const rawOutput = options.renderContext?.output ?? resultText(result).trimEnd();
|
|
1276
1315
|
const state: RunState = cancelled ? "cancelled" : isPartial ? "running" : result.isError ? "failed" : "done";
|
|
1277
1316
|
const last: Omit<EvalCellRun, "language" | "code" | "title"> = {
|
|
1278
|
-
outputs:
|
|
1279
|
-
...evalOutputNodes(stripOutputNotice(rawOutput, details?.meta).trimEnd(), false, previewLines),
|
|
1280
|
-
...jsonNodes,
|
|
1281
|
-
],
|
|
1317
|
+
outputs: evalOutputNodes(stripOutputNotice(rawOutput, details?.meta).trimEnd(), undefined, previewLines),
|
|
1282
1318
|
status: evalStatusSection(details ?? {}, expanded),
|
|
1283
1319
|
foot: { state, elapsedMs: options.elapsedMs, ...callFacts },
|
|
1284
1320
|
};
|
package/src/tools/find.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Theme } from "../theme/theme";
|
|
2
2
|
import type { Component } from "../tui";
|
|
3
3
|
import type { OutputMeta } from "./output-meta";
|
|
4
|
-
import type { NativeToolView, RenderResultOptions } from "./renderer";
|
|
4
|
+
import type { NativeToolView, RenderResultContextOptions, RenderResultOptions } from "./renderer";
|
|
5
5
|
/** A verified line range with its yes-probability and a one-line preview. */
|
|
6
6
|
export interface FindRange {
|
|
7
7
|
start: number;
|
|
@@ -22,12 +22,21 @@ export interface FindHit {
|
|
|
22
22
|
linesSeen: number;
|
|
23
23
|
truncated: boolean;
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* How much of a search the judge actually covered. `unavailable`: every judge
|
|
27
|
+
* request failed, so an empty result is not evidence of absence. `partial`:
|
|
28
|
+
* some requests failed. `complete`: none failed (or none were needed).
|
|
29
|
+
*/
|
|
30
|
+
export type FindCoverage = "complete" | "partial" | "unavailable";
|
|
25
31
|
/** Search accounting reported alongside the hits. */
|
|
26
32
|
export interface FindStats {
|
|
27
33
|
/** Eligible files under the root. */
|
|
28
34
|
listed: number;
|
|
29
35
|
requests: number;
|
|
30
|
-
|
|
36
|
+
/** Judge requests that failed outright; decides {@link FindCoverage}. */
|
|
37
|
+
failed: number;
|
|
38
|
+
/** Questions a successful response left without a usable answer. */
|
|
39
|
+
unanswered: number;
|
|
31
40
|
/** Entries judged by name. */
|
|
32
41
|
judged: number;
|
|
33
42
|
/** Files whose content was read and sent. */
|
|
@@ -51,6 +60,7 @@ export interface FindToolDetails {
|
|
|
51
60
|
/** Verified-passage probability at or above which a file is a hit. */
|
|
52
61
|
threshold: number;
|
|
53
62
|
hits: FindHit[];
|
|
63
|
+
coverage: FindCoverage;
|
|
54
64
|
stats: FindStats;
|
|
55
65
|
elapsedMs: number;
|
|
56
66
|
/** Session cwd; hit paths are relative to it. */
|
|
@@ -74,7 +84,7 @@ export declare const findToolRenderer: {
|
|
|
74
84
|
}>;
|
|
75
85
|
details?: FindToolDetails;
|
|
76
86
|
isError?: boolean;
|
|
77
|
-
}, options:
|
|
87
|
+
}, options: RenderResultContextOptions, uiTheme: Theme, args?: FindRenderArgs): Component;
|
|
78
88
|
describeCall(args: FindRenderArgs): NativeToolView;
|
|
79
89
|
/**
|
|
80
90
|
* Inline (§7.3 find): `Find “query” 2 hits · 8 files`, then per hit its
|
|
@@ -88,7 +98,7 @@ export declare const findToolRenderer: {
|
|
|
88
98
|
}>;
|
|
89
99
|
details?: FindToolDetails;
|
|
90
100
|
isError?: boolean;
|
|
91
|
-
}, options:
|
|
101
|
+
}, options: RenderResultContextOptions, args?: FindRenderArgs): NativeToolView;
|
|
92
102
|
mergeCallAndResult: true;
|
|
93
103
|
animatedPendingPreview: true;
|
|
94
104
|
animatedPartialResult: true;
|