@linxiraos/pi-tui 1.2.0 → 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 -120
- 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 +22 -26
- 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 +35 -43
- 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/agent-hub.ts +2 -2
- 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/plugin-settings.ts +8 -2
- 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 +4 -6
- package/src/prompt/composer.ts +196 -96
- 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 +256 -423
- 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 +137 -60
- 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/bash.ts
CHANGED
|
@@ -62,6 +62,8 @@ export interface BashToolDetails {
|
|
|
62
62
|
requestedTimeoutSeconds?: number;
|
|
63
63
|
timeoutDisabled?: boolean;
|
|
64
64
|
wallTimeMs?: number;
|
|
65
|
+
/** False when no wall-time footer was emitted; absent on older results. */
|
|
66
|
+
wallTimeNoticeEmitted?: boolean;
|
|
65
67
|
/** Exit code of a command that ran to completion but failed (non-zero). */
|
|
66
68
|
exitCode?: number;
|
|
67
69
|
/** True when the command was killed by its timeout deadline (not a failure). */
|
|
@@ -75,8 +77,9 @@ export interface BashToolDetails {
|
|
|
75
77
|
timedOut: boolean;
|
|
76
78
|
pid?: number;
|
|
77
79
|
};
|
|
80
|
+
/** Background job behind the call; `cancelled`: killed (`proc://<id>/kill`) before it finished. */
|
|
78
81
|
async?: {
|
|
79
|
-
state: "running" | "completed" | "failed";
|
|
82
|
+
state: "running" | "completed" | "failed" | "cancelled";
|
|
80
83
|
jobId: string;
|
|
81
84
|
type: "bash";
|
|
82
85
|
};
|
|
@@ -208,6 +211,9 @@ function formatWallTimeSeconds(wallTimeMs: number): string {
|
|
|
208
211
|
return (wallTimeMs / 1000).toFixed(2);
|
|
209
212
|
}
|
|
210
213
|
|
|
214
|
+
/** Minimum duration for a model-facing wall-time notice; shorter runs keep timing only in details. */
|
|
215
|
+
export const WALL_TIME_NOTICE_MIN_MS = 1000;
|
|
216
|
+
|
|
211
217
|
/** Formats the model-facing command duration notice. */
|
|
212
218
|
export function formatWallTimeNotice(wallTimeMs: number): string {
|
|
213
219
|
return `Wall time: ${formatWallTimeSeconds(wallTimeMs)} seconds`;
|
|
@@ -318,7 +324,7 @@ function stripBashNotices(
|
|
|
318
324
|
? strippedOutput
|
|
319
325
|
: stripTrailingNotice(strippedOutput, formatExitCodeNotice(details.exitCode));
|
|
320
326
|
const withoutWall =
|
|
321
|
-
details?.wallTimeMs === undefined
|
|
327
|
+
details?.wallTimeMs === undefined || details.wallTimeNoticeEmitted === false
|
|
322
328
|
? withoutExit
|
|
323
329
|
: stripTrailingNotice(withoutExit, formatWallTimeNotice(details.wallTimeMs));
|
|
324
330
|
return stripRawOutputArtifactNotice(withoutWall);
|
|
@@ -426,9 +432,9 @@ function shellRunState(
|
|
|
426
432
|
cancelled: boolean,
|
|
427
433
|
): RunState {
|
|
428
434
|
if (cancelled) return "cancelled";
|
|
435
|
+
if (details?.async?.state === "running") return "background";
|
|
429
436
|
if (isPartial) return "running";
|
|
430
437
|
if (details?.timedOut === true) return "timed-out";
|
|
431
|
-
if (details?.async?.state === "running") return "background";
|
|
432
438
|
if (isError || (details?.exitCode !== undefined && details.exitCode !== 0)) return "failed";
|
|
433
439
|
return "done";
|
|
434
440
|
}
|
|
@@ -677,13 +683,13 @@ export function createShellRenderer<TArgs>(config: ShellRendererConfig<TArgs>) {
|
|
|
677
683
|
const command = formatBashCommandText(toBashRenderArgs(args, config));
|
|
678
684
|
const previewLines = renderContext?.previewLines ?? BASH_DEFAULT_PREVIEW_LINES;
|
|
679
685
|
const state = shellRunState(details, isError, isPartial, options.cancelled === true);
|
|
680
|
-
//
|
|
681
|
-
|
|
682
|
-
|
|
686
|
+
// Live (a running call, or a parked job still streaming): the call's clock. Settled: the
|
|
687
|
+
// measured wall time wins. A frozen background snapshot's run time is unknown here.
|
|
688
|
+
const elapsedMs = isPartial
|
|
689
|
+
? options.elapsedMs
|
|
690
|
+
: state === "background"
|
|
683
691
|
? undefined
|
|
684
|
-
:
|
|
685
|
-
? options.elapsedMs
|
|
686
|
-
: (details?.wallTimeMs ?? options.elapsedMs);
|
|
692
|
+
: (details?.wallTimeMs ?? options.elapsedMs);
|
|
687
693
|
const meta = details?.meta;
|
|
688
694
|
const box = runBox(
|
|
689
695
|
[
|
package/src/tools/debug.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
replaceTabs,
|
|
11
11
|
TRUNCATE_LENGTHS,
|
|
12
12
|
truncateToWidth,
|
|
13
|
+
clipCollapsed,
|
|
13
14
|
} from "../render/render-utils";
|
|
14
15
|
import type { NativeToolView, RenderResultOptions, ToolRenderer, ToolRenderResult } from "./renderer";
|
|
15
16
|
import { ansi, kv } from "../native/describe";
|
|
@@ -210,7 +211,7 @@ export const debugToolRenderer = {
|
|
|
210
211
|
const previewLimit = options.expanded ? PREVIEW_LIMITS.EXPANDED_LINES : PREVIEW_LIMITS.COLLAPSED_LINES;
|
|
211
212
|
const displayedLines = rawLines
|
|
212
213
|
.slice(0, previewLimit)
|
|
213
|
-
.map(line =>
|
|
214
|
+
.map(line => clipCollapsed(line, TRUNCATE_LENGTHS.LINE, options.expanded));
|
|
214
215
|
const remaining = rawLines.length - displayedLines.length;
|
|
215
216
|
if (remaining > 0) {
|
|
216
217
|
displayedLines.push(
|
|
@@ -7,7 +7,7 @@ import type { Theme } from "../theme/theme";
|
|
|
7
7
|
import { formatOutputPaneLines, styleToolOutputLine } from "../render/output-pane";
|
|
8
8
|
import { renderStatusLine, type StatusLineOptions } from "../render/status-line";
|
|
9
9
|
import { plainToolCard, type ToolCardPhase } from "../render/tool-card";
|
|
10
|
-
import {
|
|
10
|
+
import { clipCollapsed } from "../render/render-utils";
|
|
11
11
|
import {
|
|
12
12
|
describeJsonTree,
|
|
13
13
|
formatArgsInline,
|
|
@@ -133,7 +133,8 @@ function buildDefaultToolBody(input: DefaultToolRenderInput, uiTheme: Theme, con
|
|
|
133
133
|
expanded: options.expanded,
|
|
134
134
|
collapsedMaxLines: 4,
|
|
135
135
|
expandedMaxLines: 12,
|
|
136
|
-
styleLine: line =>
|
|
136
|
+
styleLine: line =>
|
|
137
|
+
clipCollapsed(styleToolOutputLine(line, uiTheme), contentWidth, options.expanded),
|
|
137
138
|
showExpandHintWhenUncapped: true,
|
|
138
139
|
},
|
|
139
140
|
uiTheme,
|
package/src/tools/edit.d.ts
CHANGED
|
@@ -133,6 +133,8 @@ export interface EditRenderContext {
|
|
|
133
133
|
renderDiff?: (diffText: string, options?: {
|
|
134
134
|
filePath?: string;
|
|
135
135
|
}) => string;
|
|
136
|
+
/** Unsanitized result metadata, used only for filesystem link targets. */
|
|
137
|
+
rawDetails?: unknown;
|
|
136
138
|
}
|
|
137
139
|
/** Render replacement text until a computed diff preview is available. */
|
|
138
140
|
export declare function renderStreamingFallback(editMode: EditMode, args: unknown, theme: Theme): string;
|
package/src/tools/edit.ts
CHANGED
|
@@ -198,6 +198,8 @@ export interface EditRenderContext {
|
|
|
198
198
|
editStreamingFallback?: string;
|
|
199
199
|
/** Function to render diff text with syntax highlighting */
|
|
200
200
|
renderDiff?: (diffText: string, options?: { filePath?: string }) => string;
|
|
201
|
+
/** Unsanitized result metadata, used only for filesystem link targets. */
|
|
202
|
+
rawDetails?: unknown;
|
|
201
203
|
}
|
|
202
204
|
|
|
203
205
|
/**
|
|
@@ -297,7 +299,7 @@ function truncateEditTitlePath(displayPath: string, maxWidth: number | undefined
|
|
|
297
299
|
}
|
|
298
300
|
|
|
299
301
|
function formatEditTitlePath(pathValue: string, maxWidth?: number): string {
|
|
300
|
-
return truncateEditTitlePath(replaceTabs(shortenPath(pathValue)), maxWidth);
|
|
302
|
+
return truncateEditTitlePath(replaceTabs(shortenPath(sanitizeText(pathValue))), maxWidth);
|
|
301
303
|
}
|
|
302
304
|
|
|
303
305
|
function formatEditPathDisplay(
|
|
@@ -357,6 +359,7 @@ function renderEditHeader(
|
|
|
357
359
|
rename?: string;
|
|
358
360
|
firstChangedLine?: number;
|
|
359
361
|
linkPath?: string;
|
|
362
|
+
renameLinkPath?: string;
|
|
360
363
|
statsSuffix?: string;
|
|
361
364
|
extraSuffix?: string;
|
|
362
365
|
title?: string;
|
|
@@ -367,6 +370,7 @@ function renderEditHeader(
|
|
|
367
370
|
rename: options.rename,
|
|
368
371
|
firstChangedLine: options.firstChangedLine,
|
|
369
372
|
linkPath: options.linkPath,
|
|
373
|
+
renameLinkPath: options.renameLinkPath,
|
|
370
374
|
};
|
|
371
375
|
const formatted = formatEditDescription(options.rawPath, uiTheme, descriptionOptions);
|
|
372
376
|
const suffix = `${options.statsSuffix ?? ""}${options.extraSuffix ?? ""}`;
|
|
@@ -402,7 +406,14 @@ function renderEditHeader(
|
|
|
402
406
|
*/
|
|
403
407
|
function renderInlineEditRow(
|
|
404
408
|
uiTheme: Theme,
|
|
405
|
-
opts: {
|
|
409
|
+
opts: {
|
|
410
|
+
op?: Operation;
|
|
411
|
+
rename?: string;
|
|
412
|
+
rawPath: string;
|
|
413
|
+
linkPath?: string;
|
|
414
|
+
renameLinkPath?: string;
|
|
415
|
+
pending: boolean;
|
|
416
|
+
},
|
|
406
417
|
): Component {
|
|
407
418
|
const isDelete = opts.op === "delete";
|
|
408
419
|
return new WidthAwareText(
|
|
@@ -417,6 +428,7 @@ function renderInlineEditRow(
|
|
|
417
428
|
rawPath: opts.rawPath,
|
|
418
429
|
rename: opts.rename,
|
|
419
430
|
linkPath: opts.linkPath,
|
|
431
|
+
renameLinkPath: opts.renameLinkPath,
|
|
420
432
|
}),
|
|
421
433
|
0,
|
|
422
434
|
0,
|
|
@@ -481,6 +493,21 @@ interface StreamingDiffTail {
|
|
|
481
493
|
hidden: boolean;
|
|
482
494
|
}
|
|
483
495
|
|
|
496
|
+
/**
|
|
497
|
+
* Visual rows a raw diff line occupies once `renderDiff` gives it a code-frame
|
|
498
|
+
* gutter and `wrapEditRendererLine` hangs its continuations beneath it.
|
|
499
|
+
* Canonical `+12|` rows render a padded `max(3, digits) + 1` gutter plus `│`;
|
|
500
|
+
* rows already carrying a `│` rail keep their own prefix. Content wraps at the
|
|
501
|
+
* width left after that gutter; unnumbered rows wrap whole.
|
|
502
|
+
*/
|
|
503
|
+
function streamingDiffLineRows(rawLine: string, innerWidth: number): number {
|
|
504
|
+
const numbered = /^([+\-\s]\s*(\d+)[|│])(.*)$/s.exec(rawLine) ?? /^([+\-\s]\s*(\d+)\s)(.*)$/s.exec(rawLine);
|
|
505
|
+
if (!numbered) return Math.max(1, wrapTextWithAnsi(replaceTabs(rawLine), innerWidth).length);
|
|
506
|
+
const gutterWidth = Math.max(visibleWidth(numbered[1]!), Math.max(3, numbered[2]!.length) + 2);
|
|
507
|
+
const contentWidth = Math.max(1, innerWidth - gutterWidth);
|
|
508
|
+
return Math.max(1, wrapTextWithAnsi(replaceTabs(numbered[3] ?? ""), contentWidth).length);
|
|
509
|
+
}
|
|
510
|
+
|
|
484
511
|
/**
|
|
485
512
|
* Select the trailing physical lines that fit the live preview budget.
|
|
486
513
|
*
|
|
@@ -500,7 +527,7 @@ function sliceStreamingDiffTail(diff: string, innerWidth: number, budget: number
|
|
|
500
527
|
while (cursor >= 0) {
|
|
501
528
|
const newline = cursor > 0 ? diff.lastIndexOf("\n", cursor - 1) : -1;
|
|
502
529
|
const lineStart = newline + 1;
|
|
503
|
-
const lineRows =
|
|
530
|
+
const lineRows = streamingDiffLineRows(diff.slice(lineStart, cursor), innerWidth);
|
|
504
531
|
if (visualRows > 0 && visualRows + lineRows > rowLimit) break;
|
|
505
532
|
visualRows += lineRows;
|
|
506
533
|
start = lineStart;
|
|
@@ -1142,7 +1169,10 @@ export const editToolRenderer = {
|
|
|
1142
1169
|
while (bodyLines.length > 0 && bodyLines[0].trim() === "") bodyLines.shift();
|
|
1143
1170
|
return {
|
|
1144
1171
|
header,
|
|
1145
|
-
sections:
|
|
1172
|
+
sections:
|
|
1173
|
+
bodyLines.length > 0
|
|
1174
|
+
? [{ content: bodyLines.flatMap(line => wrapEditRendererLine(line, Math.max(1, width - 2))) }]
|
|
1175
|
+
: [],
|
|
1146
1176
|
phase: applyPatchError ? "error" : "pending",
|
|
1147
1177
|
borderColor: applyPatchError ? "error" : "borderMuted",
|
|
1148
1178
|
contentPaddingLeft: 0,
|
|
@@ -1192,7 +1222,7 @@ export const editToolRenderer = {
|
|
|
1192
1222
|
diffText = args.previewDiff ?? args.diff ?? "";
|
|
1193
1223
|
body.push(editDiff(diffText, rawPath));
|
|
1194
1224
|
} else if (args.diff || args.newText || args.patch) {
|
|
1195
|
-
body.push(code(args.diff ?? args.newText ?? args.patch ?? "", {
|
|
1225
|
+
body.push(code(args.diff ?? args.newText ?? args.patch ?? "", { path: rawPath || undefined }));
|
|
1196
1226
|
} else if (renderContext?.editDiffPreview) {
|
|
1197
1227
|
const preview = renderContext.editDiffPreview;
|
|
1198
1228
|
if ("error" in preview && preview.error) body.push(errorText(preview.error));
|
|
@@ -1230,8 +1260,18 @@ export const editToolRenderer = {
|
|
|
1230
1260
|
let added = 0;
|
|
1231
1261
|
let removed = 0;
|
|
1232
1262
|
// Files are borderless sections inside the one tool frame.
|
|
1233
|
-
const body: NativeChild[] = perFileResults.map(fileResult => {
|
|
1234
|
-
const
|
|
1263
|
+
const body: NativeChild[] = perFileResults.map((fileResult, index) => {
|
|
1264
|
+
const rawDetails = options.renderContext?.rawDetails;
|
|
1265
|
+
const rawPerFile =
|
|
1266
|
+
rawDetails && typeof rawDetails === "object" && "perFileResults" in rawDetails
|
|
1267
|
+
? rawDetails.perFileResults
|
|
1268
|
+
: undefined;
|
|
1269
|
+
const file = editFileParts(
|
|
1270
|
+
{ content: [], details: fileResult, isError: fileResult.isError },
|
|
1271
|
+
options,
|
|
1272
|
+
undefined,
|
|
1273
|
+
Array.isArray(rawPerFile) ? rawPerFile[index] : undefined,
|
|
1274
|
+
);
|
|
1235
1275
|
added += file.added;
|
|
1236
1276
|
removed += file.removed;
|
|
1237
1277
|
return fileDiffSection(file, file.body, {
|
|
@@ -1304,13 +1344,13 @@ function editToolHead(facts: EditHeadFacts): NativeToolHead {
|
|
|
1304
1344
|
const multi = (facts.files ?? 0) > 1;
|
|
1305
1345
|
const meta = compact([
|
|
1306
1346
|
diffStatsMeta(facts.added, facts.removed),
|
|
1307
|
-
!multi && facts.rename ? `→ ${displayPath(facts.rename)}` : undefined,
|
|
1347
|
+
!multi && facts.rename ? `→ ${displayPath(sanitizeText(facts.rename))}` : undefined,
|
|
1308
1348
|
]);
|
|
1309
1349
|
const badge = facts.diagnostics && diagnosticsBadge(facts.diagnostics);
|
|
1310
1350
|
const target = multi
|
|
1311
1351
|
? `${facts.files} files`
|
|
1312
1352
|
: facts.path
|
|
1313
|
-
? `${displayPath(facts.path)}${facts.line ? `:${facts.line}` : ""}`
|
|
1353
|
+
? `${displayPath(sanitizeText(facts.path))}${facts.line ? `:${facts.line}` : ""}`
|
|
1314
1354
|
: undefined;
|
|
1315
1355
|
return {
|
|
1316
1356
|
title: multi ? "Edit" : getOperationTitle(facts.op),
|
|
@@ -1322,9 +1362,9 @@ function editToolHead(facts: EditHeadFacts): NativeToolHead {
|
|
|
1322
1362
|
};
|
|
1323
1363
|
}
|
|
1324
1364
|
|
|
1325
|
-
/** A file's diff: hunks
|
|
1365
|
+
/** A file's diff: Tern highlights the hunks by the file's grammar and draws no path header (the head or section names the file). */
|
|
1326
1366
|
function editDiff(diffText: string, filePath: string): NativeNode {
|
|
1327
|
-
return nativeDiff(diffText, {
|
|
1367
|
+
return nativeDiff(diffText, { path: filePath || undefined });
|
|
1328
1368
|
}
|
|
1329
1369
|
|
|
1330
1370
|
/** One file's edit result for native views: head facts plus its body (diff or error, then diagnostics). */
|
|
@@ -1337,6 +1377,15 @@ interface EditFileParts extends Omit<EditHeadFacts, "diagnostics"> {
|
|
|
1337
1377
|
body: NativeChild[];
|
|
1338
1378
|
}
|
|
1339
1379
|
|
|
1380
|
+
/** Raw metadata paths are reserved for link targets; visible content comes from sanitized details. */
|
|
1381
|
+
function rawEditPaths(value: unknown): { path?: string; sourcePath?: string } {
|
|
1382
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return {};
|
|
1383
|
+
return {
|
|
1384
|
+
path: "path" in value && typeof value.path === "string" ? value.path : undefined,
|
|
1385
|
+
sourcePath: "sourcePath" in value && typeof value.sourcePath === "string" ? value.sourcePath : undefined,
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1340
1389
|
function editFileParts(
|
|
1341
1390
|
result: {
|
|
1342
1391
|
content: Array<{ type: string; text?: string }>;
|
|
@@ -1345,8 +1394,10 @@ function editFileParts(
|
|
|
1345
1394
|
},
|
|
1346
1395
|
options: RenderResultOptions & { renderContext?: EditRenderContext },
|
|
1347
1396
|
args?: EditRenderArgs,
|
|
1397
|
+
rawFileDetails?: unknown,
|
|
1348
1398
|
): EditFileParts {
|
|
1349
1399
|
const details = result.details;
|
|
1400
|
+
const rawPaths = rawEditPaths(rawFileDetails ?? options.renderContext?.rawDetails);
|
|
1350
1401
|
const isError = result.isError ?? (details && "isError" in details ? details.isError : false) ?? false;
|
|
1351
1402
|
const firstEdit = Array.isArray(args?.edits) ? args.edits[0] : undefined;
|
|
1352
1403
|
const firstHashlineInputEntry = getHashlineInputRenderSummary(args ?? {}, options.renderContext?.editMode)
|
|
@@ -1373,7 +1424,7 @@ function editFileParts(
|
|
|
1373
1424
|
const firstChangedLine =
|
|
1374
1425
|
(editDiffPreview && "firstChangedLine" in editDiffPreview ? editDiffPreview.firstChangedLine : undefined) ||
|
|
1375
1426
|
(details && !isError ? details.firstChangedLine : undefined);
|
|
1376
|
-
const shownPath = displayPath(detailPath ?? rawPath);
|
|
1427
|
+
const shownPath = displayPath(sanitizeText(detailPath ?? rawPath));
|
|
1377
1428
|
const body: NativeChild[] = [];
|
|
1378
1429
|
if (isError) {
|
|
1379
1430
|
const displayErrorText = details && "displayErrorText" in details ? details.displayErrorText : undefined;
|
|
@@ -1392,10 +1443,10 @@ function editFileParts(
|
|
|
1392
1443
|
const stats = diffText ? getDiffStats(diffText) : undefined;
|
|
1393
1444
|
return {
|
|
1394
1445
|
op,
|
|
1395
|
-
path: rawPath,
|
|
1446
|
+
path: sanitizeText(rawPath),
|
|
1396
1447
|
line: firstChangedLine,
|
|
1397
|
-
rename,
|
|
1398
|
-
resolvedPath: detailPath,
|
|
1448
|
+
rename: rename === undefined ? undefined : sanitizeText(rename),
|
|
1449
|
+
resolvedPath: rawPaths.path ?? detailPath,
|
|
1399
1450
|
added: stats?.added ?? 0,
|
|
1400
1451
|
removed: stats?.removed ?? 0,
|
|
1401
1452
|
isError: Boolean(isError),
|
|
@@ -1415,6 +1466,7 @@ function renderSingleFileResult(
|
|
|
1415
1466
|
args?: EditRenderArgs,
|
|
1416
1467
|
): Component {
|
|
1417
1468
|
const details = result.details;
|
|
1469
|
+
const rawPaths = rawEditPaths(options.renderContext?.rawDetails);
|
|
1418
1470
|
const isError = result.isError ?? (details && "isError" in details ? details.isError : false);
|
|
1419
1471
|
const edits = Array.isArray(args?.edits) ? args.edits : undefined;
|
|
1420
1472
|
const firstEdit = edits?.[0];
|
|
@@ -1449,8 +1501,17 @@ function renderSingleFileResult(
|
|
|
1449
1501
|
// container. Errors, no-ops, creates, move-with-edits, and anything with
|
|
1450
1502
|
// diagnostics keep the framed block below.
|
|
1451
1503
|
if (!isError && !details?.diff && !details?.diagnostics && (op === "delete" || rename)) {
|
|
1452
|
-
const linkPath =
|
|
1453
|
-
|
|
1504
|
+
const linkPath = rename
|
|
1505
|
+
? (rawPaths.sourcePath ?? moveSource ?? rawPaths.path ?? detailPath)
|
|
1506
|
+
: (rawPaths.path ?? detailPath);
|
|
1507
|
+
return renderInlineEditRow(uiTheme, {
|
|
1508
|
+
op,
|
|
1509
|
+
rename,
|
|
1510
|
+
rawPath,
|
|
1511
|
+
linkPath,
|
|
1512
|
+
renameLinkPath: rename ? (rawPaths.path ?? detailPath) : undefined,
|
|
1513
|
+
pending: false,
|
|
1514
|
+
});
|
|
1454
1515
|
}
|
|
1455
1516
|
|
|
1456
1517
|
const renderFallbackDiff = (diffText: string, diffOptions?: { filePath?: string }): string =>
|
|
@@ -1481,7 +1542,9 @@ function renderSingleFileResult(
|
|
|
1481
1542
|
const firstChangedLine =
|
|
1482
1543
|
(editDiffPreview && "firstChangedLine" in editDiffPreview ? editDiffPreview.firstChangedLine : undefined) ||
|
|
1483
1544
|
(details && !isError ? details.firstChangedLine : undefined);
|
|
1484
|
-
const linkPath =
|
|
1545
|
+
const linkPath = rename
|
|
1546
|
+
? (rawPaths.sourcePath ?? moveSource ?? rawPaths.path ?? detailPath)
|
|
1547
|
+
: (rawPaths.path ?? detailPath);
|
|
1485
1548
|
|
|
1486
1549
|
// Change stats ride inline on the header bar next to the path.
|
|
1487
1550
|
const previewDiff = editDiffPreview && !("error" in editDiffPreview) ? editDiffPreview.diff : undefined;
|
|
@@ -1499,6 +1562,7 @@ function renderSingleFileResult(
|
|
|
1499
1562
|
rename,
|
|
1500
1563
|
firstChangedLine,
|
|
1501
1564
|
linkPath,
|
|
1565
|
+
renameLinkPath: rename ? (rawPaths.path ?? detailPath) : undefined,
|
|
1502
1566
|
statsSuffix,
|
|
1503
1567
|
});
|
|
1504
1568
|
const innerWidth = Math.max(1, width - 2);
|
|
@@ -1523,7 +1587,11 @@ function renderSingleFileResult(
|
|
|
1523
1587
|
// (Delete / `src → dst`); only a true no-op needs an explanatory
|
|
1524
1588
|
// body so an empty card isn't mistaken for a stalled edit.
|
|
1525
1589
|
if (op !== "delete" && op !== "create" && !rename) {
|
|
1526
|
-
const noChangePath =
|
|
1590
|
+
const noChangePath = detailPath
|
|
1591
|
+
? shortenPath(detailPath)
|
|
1592
|
+
: rawPath
|
|
1593
|
+
? shortenPath(sanitizeText(rawPath))
|
|
1594
|
+
: "";
|
|
1527
1595
|
body = uiTheme.fg("dim", `No changes were made${noChangePath ? ` to ${noChangePath}` : ""}.`);
|
|
1528
1596
|
}
|
|
1529
1597
|
} else if (editDiffPreview) {
|
|
@@ -1575,8 +1643,19 @@ function renderMultiFileResult(
|
|
|
1575
1643
|
options: RenderResultOptions & { renderContext?: EditRenderContext },
|
|
1576
1644
|
uiTheme: Theme,
|
|
1577
1645
|
): Component {
|
|
1578
|
-
const
|
|
1579
|
-
|
|
1646
|
+
const rawDetails = options.renderContext?.rawDetails;
|
|
1647
|
+
const rawPerFile =
|
|
1648
|
+
rawDetails && typeof rawDetails === "object" && "perFileResults" in rawDetails
|
|
1649
|
+
? rawDetails.perFileResults
|
|
1650
|
+
: undefined;
|
|
1651
|
+
const fileComponents = perFileResults.map((fileResult, index) =>
|
|
1652
|
+
renderSingleFileResult(
|
|
1653
|
+
{ content: [], details: fileResult, isError: fileResult.isError },
|
|
1654
|
+
Array.isArray(rawPerFile)
|
|
1655
|
+
? { ...options, renderContext: { ...options.renderContext, rawDetails: rawPerFile[index] } }
|
|
1656
|
+
: options,
|
|
1657
|
+
uiTheme,
|
|
1658
|
+
),
|
|
1580
1659
|
);
|
|
1581
1660
|
const remaining = Math.max(0, totalFiles - perFileResults.length);
|
|
1582
1661
|
|
package/src/tools/eval.d.ts
CHANGED
|
@@ -13,25 +13,60 @@ export interface EvalStatusEvent {
|
|
|
13
13
|
resolvedThinkingLevel?: ConfiguredThinkingLevel;
|
|
14
14
|
[key: string]: unknown;
|
|
15
15
|
}
|
|
16
|
+
/** One column of a table view. */
|
|
17
|
+
export interface EvalTableColumn {
|
|
18
|
+
head: string;
|
|
19
|
+
/** Numeric values: renderers right-align the column. */
|
|
20
|
+
numeric?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A pretty rendering of something a cell printed, shown to the user in place
|
|
24
|
+
* of its text; the model only ever sees the text.
|
|
25
|
+
* - `table`: a data frame or `console.table`; leading index columns are plain
|
|
26
|
+
* columns, and a truncated frame's elided rows/columns are `…` cells.
|
|
27
|
+
* - `json`: a structured value (dict/list, object/array) as a collapsible tree.
|
|
28
|
+
* - `markdown`: an object's Markdown representation.
|
|
29
|
+
*/
|
|
30
|
+
export type EvalView = {
|
|
31
|
+
kind: "table";
|
|
32
|
+
columns: EvalTableColumn[];
|
|
33
|
+
rows: string[][];
|
|
34
|
+
} | {
|
|
35
|
+
kind: "json";
|
|
36
|
+
value: unknown;
|
|
37
|
+
} | {
|
|
38
|
+
kind: "markdown";
|
|
39
|
+
text: string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* A view and the exact printed text it stands for. Renderers locate `text` in
|
|
43
|
+
* the cell's `output` (entries in print order) and show the view there; an
|
|
44
|
+
* entry whose text is no longer in the output (truncated) is skipped.
|
|
45
|
+
*/
|
|
46
|
+
export interface EvalViewEntry {
|
|
47
|
+
text: string;
|
|
48
|
+
view: EvalView;
|
|
49
|
+
}
|
|
16
50
|
/** Per-cell execution result for transcript rendering. */
|
|
17
51
|
export interface EvalCellResult {
|
|
18
52
|
index: number;
|
|
19
53
|
title?: string;
|
|
20
54
|
code: string;
|
|
21
55
|
language?: EvalLanguage;
|
|
56
|
+
/** What the model saw: the cell's printed text plus image notes. */
|
|
22
57
|
output: string;
|
|
58
|
+
/** Pretty views of spans of `output`, in print order. */
|
|
59
|
+
views?: EvalViewEntry[];
|
|
23
60
|
status: "pending" | "running" | "complete" | "error";
|
|
24
61
|
durationMs?: number;
|
|
25
62
|
exitCode?: number;
|
|
26
63
|
statusEvents?: EvalStatusEvent[];
|
|
27
64
|
/** Discrete events dropped from the front of `statusEvents` (see {@link recordStatusEvent}). */
|
|
28
65
|
statusEventsElided?: number;
|
|
29
|
-
hasMarkdown?: boolean;
|
|
30
66
|
}
|
|
31
67
|
/** Tool result detail object surfaced to the UI/transcript. */
|
|
32
68
|
export interface EvalToolDetails {
|
|
33
69
|
cells?: EvalCellResult[];
|
|
34
|
-
jsonOutputs?: unknown[];
|
|
35
70
|
images?: ImageContent[];
|
|
36
71
|
statusEvents?: EvalStatusEvent[];
|
|
37
72
|
/** Discrete events dropped from the front of `statusEvents` (see {@link recordStatusEvent}). */
|
|
@@ -44,9 +79,9 @@ export interface EvalToolDetails {
|
|
|
44
79
|
languages?: EvalLanguage[];
|
|
45
80
|
/** Optional human-readable notice (e.g. fallback explanation). */
|
|
46
81
|
notice?: string;
|
|
47
|
-
/** Present when the cell was auto-backgrounded as an async job. */
|
|
82
|
+
/** Present when the cell was auto-backgrounded as an async job; `cancelled`: killed before it finished. */
|
|
48
83
|
async?: {
|
|
49
|
-
state: "running" | "completed" | "failed";
|
|
84
|
+
state: "running" | "completed" | "failed" | "cancelled";
|
|
50
85
|
jobId: string;
|
|
51
86
|
type: "eval";
|
|
52
87
|
};
|
|
@@ -100,6 +135,20 @@ export declare function upsertStatusEvent(events: EvalStatusEvent[], event: Eval
|
|
|
100
135
|
* events behind an "… N earlier" row.
|
|
101
136
|
*/
|
|
102
137
|
export declare function recordStatusEvent(log: StatusEventLog, event: EvalStatusEvent): void;
|
|
138
|
+
/** One ordered piece of a cell's output: printed text, or a view shown in place of the text it matched. */
|
|
139
|
+
export type EvalOutputPart = {
|
|
140
|
+
kind: "text";
|
|
141
|
+
text: string;
|
|
142
|
+
} | {
|
|
143
|
+
kind: "view";
|
|
144
|
+
view: EvalView;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Split `output` around its views, in order: each view's `text` is searched
|
|
148
|
+
* from the end of the previous match, unmatched entries are skipped, and
|
|
149
|
+
* blank text between views is dropped (newlines bordering a view trimmed).
|
|
150
|
+
*/
|
|
151
|
+
export declare function splitEvalOutput(output: string, views: readonly EvalViewEntry[] | undefined): EvalOutputPart[];
|
|
103
152
|
/** Render eval code cells, structured display output, and progress events. */
|
|
104
153
|
export declare const evalToolRenderer: {
|
|
105
154
|
animatedPendingPreview: true;
|