@esso0428/pi-subagents 0.17.6 → 0.17.7
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 +9 -0
- package/CONTRIBUTING.md +4 -0
- package/dist/abortable.d.ts +13 -0
- package/dist/abortable.d.ts.map +1 -0
- package/dist/abortable.js +43 -0
- package/dist/abortable.js.map +1 -0
- package/dist/agent-color.d.ts +36 -0
- package/dist/agent-color.d.ts.map +1 -0
- package/dist/agent-color.js +124 -0
- package/dist/agent-color.js.map +1 -0
- package/dist/agent-file-toggle.d.ts +126 -0
- package/dist/agent-file-toggle.d.ts.map +1 -0
- package/dist/agent-file-toggle.js +259 -0
- package/dist/agent-file-toggle.js.map +1 -0
- package/dist/agent-history.d.ts +4 -0
- package/dist/agent-history.d.ts.map +1 -1
- package/dist/agent-history.js +47 -1
- package/dist/agent-history.js.map +1 -1
- package/dist/agent-manager.d.ts +370 -56
- package/dist/agent-manager.d.ts.map +1 -1
- package/dist/agent-manager.js +1123 -409
- package/dist/agent-manager.js.map +1 -1
- package/dist/agent-runner.d.ts +100 -10
- package/dist/agent-runner.d.ts.map +1 -1
- package/dist/agent-runner.js +166 -21
- package/dist/agent-runner.js.map +1 -1
- package/dist/agent-types.d.ts +57 -5
- package/dist/agent-types.d.ts.map +1 -1
- package/dist/agent-types.js +164 -32
- package/dist/agent-types.js.map +1 -1
- package/dist/child-context.d.ts +3 -0
- package/dist/child-context.d.ts.map +1 -0
- package/dist/child-context.js +13 -0
- package/dist/child-context.js.map +1 -0
- package/dist/cross-extension-rpc.d.ts +23 -3
- package/dist/cross-extension-rpc.d.ts.map +1 -1
- package/dist/cross-extension-rpc.js +79 -17
- package/dist/cross-extension-rpc.js.map +1 -1
- package/dist/custom-agents.d.ts +38 -1
- package/dist/custom-agents.d.ts.map +1 -1
- package/dist/custom-agents.js +164 -12
- package/dist/custom-agents.js.map +1 -1
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1908 -495
- package/dist/index.js.map +1 -1
- package/dist/invocation-config.d.ts +87 -2
- package/dist/invocation-config.d.ts.map +1 -1
- package/dist/invocation-config.js +71 -3
- package/dist/invocation-config.js.map +1 -1
- package/dist/mention-clone.d.ts +88 -0
- package/dist/mention-clone.d.ts.map +1 -0
- package/dist/mention-clone.js +154 -0
- package/dist/mention-clone.js.map +1 -0
- package/dist/mention.d.ts +82 -0
- package/dist/mention.d.ts.map +1 -0
- package/dist/mention.js +132 -0
- package/dist/mention.js.map +1 -0
- package/dist/model-resolver.d.ts +17 -0
- package/dist/model-resolver.d.ts.map +1 -1
- package/dist/model-resolver.js +15 -0
- package/dist/model-resolver.js.map +1 -1
- package/dist/model-scope.d.ts +50 -0
- package/dist/model-scope.d.ts.map +1 -0
- package/dist/model-scope.js +49 -0
- package/dist/model-scope.js.map +1 -0
- package/dist/nested-tools.d.ts +57 -0
- package/dist/nested-tools.d.ts.map +1 -0
- package/dist/nested-tools.js +301 -0
- package/dist/nested-tools.js.map +1 -0
- package/dist/output-file.d.ts +22 -3
- package/dist/output-file.d.ts.map +1 -1
- package/dist/output-file.js +58 -7
- package/dist/output-file.js.map +1 -1
- package/dist/prompts.d.ts +23 -0
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +20 -2
- package/dist/prompts.js.map +1 -1
- package/dist/schedule.d.ts.map +1 -1
- package/dist/schedule.js +36 -15
- package/dist/schedule.js.map +1 -1
- package/dist/settings.d.ts +228 -2
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +94 -0
- package/dist/settings.js.map +1 -1
- package/dist/status-note.d.ts +49 -1
- package/dist/status-note.d.ts.map +1 -1
- package/dist/status-note.js +62 -1
- package/dist/status-note.js.map +1 -1
- package/dist/structured-output.d.ts +62 -0
- package/dist/structured-output.d.ts.map +1 -0
- package/dist/structured-output.js +113 -0
- package/dist/structured-output.js.map +1 -0
- package/dist/types.d.ts +176 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/agent-mention.d.ts +83 -0
- package/dist/ui/agent-mention.d.ts.map +1 -0
- package/dist/ui/agent-mention.js +188 -0
- package/dist/ui/agent-mention.js.map +1 -0
- package/dist/ui/agent-widget.d.ts +96 -75
- package/dist/ui/agent-widget.d.ts.map +1 -1
- package/dist/ui/agent-widget.js +397 -420
- package/dist/ui/agent-widget.js.map +1 -1
- package/dist/ui/conversation-blocks.d.ts.map +1 -1
- package/dist/ui/conversation-blocks.js +6 -0
- package/dist/ui/conversation-blocks.js.map +1 -1
- package/dist/ui/conversation-timeline.d.ts +10 -2
- package/dist/ui/conversation-timeline.d.ts.map +1 -1
- package/dist/ui/conversation-timeline.js +130 -23
- package/dist/ui/conversation-timeline.js.map +1 -1
- package/dist/ui/conversation-viewer.d.ts +15 -5
- package/dist/ui/conversation-viewer.d.ts.map +1 -1
- package/dist/ui/conversation-viewer.js +202 -50
- package/dist/ui/conversation-viewer.js.map +1 -1
- package/dist/ui/fleet-list.d.ts +198 -0
- package/dist/ui/fleet-list.d.ts.map +1 -0
- package/dist/ui/fleet-list.js +487 -0
- package/dist/ui/fleet-list.js.map +1 -0
- package/dist/ui/schedule-menu.d.ts.map +1 -1
- package/dist/ui/schedule-menu.js +6 -7
- package/dist/ui/schedule-menu.js.map +1 -1
- package/dist/ui/select-item.d.ts +28 -0
- package/dist/ui/select-item.d.ts.map +1 -0
- package/dist/ui/select-item.js +35 -0
- package/dist/ui/select-item.js.map +1 -0
- package/dist/ui/workflow-card.d.ts +176 -0
- package/dist/ui/workflow-card.d.ts.map +1 -0
- package/dist/ui/workflow-card.js +333 -0
- package/dist/ui/workflow-card.js.map +1 -0
- package/dist/ui/workflow-dialog.d.ts +306 -0
- package/dist/ui/workflow-dialog.d.ts.map +1 -0
- package/dist/ui/workflow-dialog.js +844 -0
- package/dist/ui/workflow-dialog.js.map +1 -0
- package/dist/ui/workflow-menu.d.ts +61 -0
- package/dist/ui/workflow-menu.d.ts.map +1 -0
- package/dist/ui/workflow-menu.js +148 -0
- package/dist/ui/workflow-menu.js.map +1 -0
- package/dist/usage.d.ts +86 -1
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js +72 -1
- package/dist/usage.js.map +1 -1
- package/dist/workflow/collisions.d.ts +96 -0
- package/dist/workflow/collisions.d.ts.map +1 -0
- package/dist/workflow/collisions.js +89 -0
- package/dist/workflow/collisions.js.map +1 -0
- package/dist/workflow/entry.d.ts +33 -0
- package/dist/workflow/entry.d.ts.map +1 -0
- package/dist/workflow/entry.js +30 -0
- package/dist/workflow/entry.js.map +1 -0
- package/dist/workflow/host.d.ts +63 -0
- package/dist/workflow/host.d.ts.map +1 -0
- package/dist/workflow/host.js +363 -0
- package/dist/workflow/host.js.map +1 -0
- package/dist/workflow/journal.d.ts +98 -0
- package/dist/workflow/journal.d.ts.map +1 -0
- package/dist/workflow/journal.js +121 -0
- package/dist/workflow/journal.js.map +1 -0
- package/dist/workflow/json-schema.d.ts +52 -0
- package/dist/workflow/json-schema.d.ts.map +1 -0
- package/dist/workflow/json-schema.js +112 -0
- package/dist/workflow/json-schema.js.map +1 -0
- package/dist/workflow/meta.d.ts +68 -0
- package/dist/workflow/meta.d.ts.map +1 -0
- package/dist/workflow/meta.js +318 -0
- package/dist/workflow/meta.js.map +1 -0
- package/dist/workflow/progress.d.ts +225 -0
- package/dist/workflow/progress.d.ts.map +1 -0
- package/dist/workflow/progress.js +362 -0
- package/dist/workflow/progress.js.map +1 -0
- package/dist/workflow/runtime.d.ts +335 -0
- package/dist/workflow/runtime.d.ts.map +1 -0
- package/dist/workflow/runtime.js +831 -0
- package/dist/workflow/runtime.js.map +1 -0
- package/dist/workflow/saved.d.ts +91 -0
- package/dist/workflow/saved.d.ts.map +1 -0
- package/dist/workflow/saved.js +204 -0
- package/dist/workflow/saved.js.map +1 -0
- package/dist/workflow/task.d.ts +137 -0
- package/dist/workflow/task.d.ts.map +1 -0
- package/dist/workflow/task.js +208 -0
- package/dist/workflow/task.js.map +1 -0
- package/dist/workflow/tool-description.d.ts +39 -0
- package/dist/workflow/tool-description.d.ts.map +1 -0
- package/dist/workflow/tool-description.js +200 -0
- package/dist/workflow/tool-description.js.map +1 -0
- package/dist/workflow/worker-source.d.ts +48 -0
- package/dist/workflow/worker-source.d.ts.map +1 -0
- package/dist/workflow/worker-source.js +779 -0
- package/dist/workflow/worker-source.js.map +1 -0
- package/dist/worktree.d.ts +10 -3
- package/dist/worktree.d.ts.map +1 -1
- package/dist/worktree.js +58 -54
- package/dist/worktree.js.map +1 -1
- package/dist/xml.d.ts +11 -0
- package/dist/xml.d.ts.map +1 -0
- package/dist/xml.js +13 -0
- package/dist/xml.js.map +1 -0
- package/docs/rpc.md +183 -0
- package/docs/superpowers/plans/2026-09-30-upstream-event-workflow-partial-history.md +195 -0
- package/docs/superpowers/specs/2026-09-30-upstream-event-workflow-partial-history-design.md +49 -0
- package/docs/workflows.md +437 -0
- package/examples/agent-tool-description.md +7 -7
- package/examples/workflows/compose.js +51 -0
- package/examples/workflows/fan-out-audit.js +47 -0
- package/examples/workflows/gated-fix.js +60 -0
- package/examples/workflows/lib/count-child.js +27 -0
- package/examples/workflows/review-panel.js +63 -0
- package/examples/workflows/structured-findings.js +78 -0
- package/package.json +1 -1
- package/src/abortable.ts +43 -0
- package/src/agent-color.ts +161 -0
- package/src/agent-file-toggle.ts +269 -0
- package/src/agent-history.ts +54 -2
- package/src/agent-manager.ts +1263 -402
- package/src/agent-runner.ts +251 -27
- package/src/agent-types.ts +188 -32
- package/src/child-context.ts +15 -0
- package/src/cross-extension-rpc.ts +96 -20
- package/src/custom-agents.ts +170 -13
- package/src/index.ts +2024 -537
- package/src/invocation-config.ts +118 -3
- package/src/mention-clone.ts +196 -0
- package/src/mention.ts +141 -0
- package/src/model-resolver.ts +18 -0
- package/src/model-scope.ts +70 -0
- package/src/nested-tools.ts +424 -0
- package/src/output-file.ts +61 -6
- package/src/prompts.ts +45 -2
- package/src/schedule.ts +35 -14
- package/src/settings.ts +312 -2
- package/src/status-note.ts +66 -1
- package/src/structured-output.ts +130 -0
- package/src/types.ts +177 -10
- package/src/ui/agent-mention.ts +216 -0
- package/src/ui/agent-widget.ts +389 -441
- package/src/ui/conversation-blocks.ts +6 -0
- package/src/ui/conversation-timeline.ts +139 -25
- package/src/ui/conversation-viewer.ts +212 -48
- package/src/ui/fleet-list.ts +558 -0
- package/src/ui/schedule-menu.ts +9 -8
- package/src/ui/select-item.ts +45 -0
- package/src/ui/workflow-card.ts +470 -0
- package/src/ui/workflow-dialog.ts +1115 -0
- package/src/ui/workflow-menu.ts +193 -0
- package/src/usage.ts +109 -2
- package/src/workflow/collisions.ts +123 -0
- package/src/workflow/entry.ts +47 -0
- package/src/workflow/host.ts +403 -0
- package/src/workflow/journal.ts +164 -0
- package/src/workflow/json-schema.ts +128 -0
- package/src/workflow/meta.ts +325 -0
- package/src/workflow/progress.ts +550 -0
- package/src/workflow/runtime.ts +1219 -0
- package/src/workflow/saved.ts +217 -0
- package/src/workflow/task.ts +302 -0
- package/src/workflow/tool-description.ts +200 -0
- package/src/workflow/worker-source.ts +781 -0
- package/src/worktree.ts +69 -55
- package/src/xml.ts +13 -0
- package/vitest.config.ts +0 -18
|
@@ -6,11 +6,12 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { AgentSession, ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
8
8
|
import { type Component, type TUI, type TuiMouseEvent } from "@earendil-works/pi-tui";
|
|
9
|
-
import type { AgentRecord } from "../types.js";
|
|
9
|
+
import type { AgentRecord, ViewerMarkdownMode } from "../types.js";
|
|
10
10
|
import type { Theme } from "./agent-widget.js";
|
|
11
11
|
import { type AgentActivity } from "./agent-widget.js";
|
|
12
12
|
import { type ViewerKeybindings } from "./viewer-keys.js";
|
|
13
13
|
export declare const VIEWPORT_HEIGHT_PCT = 70;
|
|
14
|
+
export declare const RESULT_MAX_CHARS = 16000;
|
|
14
15
|
/** The live fields needed by the viewer; historical viewers use a static source. */
|
|
15
16
|
export type ConversationSource = Pick<AgentSession, "messages" | "subscribe">;
|
|
16
17
|
export declare function createStaticConversationSource(messages: AgentSession["messages"]): ConversationSource;
|
|
@@ -31,8 +32,6 @@ export declare class ConversationViewer implements Component {
|
|
|
31
32
|
private onStop?;
|
|
32
33
|
/** Send a steering message to the agent. */
|
|
33
34
|
private onSteer?;
|
|
34
|
-
/** Optional clipboard/nvim operation context, appended for compatibility. */
|
|
35
|
-
private operations?;
|
|
36
35
|
private blocks;
|
|
37
36
|
private showTools;
|
|
38
37
|
private selectedMessageIdx;
|
|
@@ -44,6 +43,7 @@ export declare class ConversationViewer implements Component {
|
|
|
44
43
|
private cacheVersion;
|
|
45
44
|
private cachedVersion;
|
|
46
45
|
private sessionRefreshQueued;
|
|
46
|
+
private lastSessionKey;
|
|
47
47
|
private selectedBlockId;
|
|
48
48
|
private scrollOffset;
|
|
49
49
|
private autoScroll;
|
|
@@ -66,6 +66,11 @@ export declare class ConversationViewer implements Component {
|
|
|
66
66
|
private steerHistoryDraft;
|
|
67
67
|
private timeline;
|
|
68
68
|
private toolPreview;
|
|
69
|
+
private readonly operations;
|
|
70
|
+
private readonly showCost;
|
|
71
|
+
private readonly viewerMarkdown;
|
|
72
|
+
private readonly onMarkdownMode;
|
|
73
|
+
private markdownModeOverride;
|
|
69
74
|
constructor(tui: TUI, session: ConversationSource, record: AgentRecord, activity: AgentActivity | undefined, theme: Theme, done: (result: undefined) => void,
|
|
70
75
|
/** Abort the agent shown here. Omitted means read-only history. */
|
|
71
76
|
onStop?: (() => void) | undefined,
|
|
@@ -73,8 +78,8 @@ export declare class ConversationViewer implements Component {
|
|
|
73
78
|
keybindings?: ViewerKeybindings,
|
|
74
79
|
/** Send a steering message to the agent. */
|
|
75
80
|
onSteer?: ((message: string) => void) | undefined,
|
|
76
|
-
/**
|
|
77
|
-
|
|
81
|
+
/** Cost flag in upstream's constructor; fork callers may pass operations here. */
|
|
82
|
+
showCostOrOperations?: boolean | ConversationViewerOperations, viewerMarkdown?: () => ViewerMarkdownMode, onMarkdownMode?: (mode: ViewerMarkdownMode) => void);
|
|
78
83
|
handleInput(data: string): void;
|
|
79
84
|
handleMouse(event: TuiMouseEvent): {
|
|
80
85
|
handled?: boolean;
|
|
@@ -93,6 +98,11 @@ export declare class ConversationViewer implements Component {
|
|
|
93
98
|
private transcriptWidth;
|
|
94
99
|
private chromeLines;
|
|
95
100
|
private invocationLine;
|
|
101
|
+
private currentMarkdownMode;
|
|
102
|
+
private cycleMarkdownMode;
|
|
103
|
+
private sessionKey;
|
|
104
|
+
private blockSignature;
|
|
105
|
+
private syncBlocksFromSession;
|
|
96
106
|
private buildContentLines;
|
|
97
107
|
private currentMessageIndex;
|
|
98
108
|
/** Keep the selected transcript block and the tool focus as one target. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-viewer.d.ts","sourceRoot":"","sources":["../../src/ui/conversation-viewer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAEpG,OAAO,EAAE,KAAK,SAAS,EAA0B,KAAK,GAAG,EAAE,KAAK,aAAa,EAAiC,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"conversation-viewer.d.ts","sourceRoot":"","sources":["../../src/ui/conversation-viewer.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { copyToClipboard } from "@earendil-works/pi-coding-agent";
|
|
8
8
|
import { Input, Key, matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { renderAgentName } from "../agent-color.js";
|
|
10
|
+
import { getLifetimeCost, getLifetimeTotal, getSessionContextPercent } from "../usage.js";
|
|
11
|
+
import { buildInvocationTags, describeActivity, fgPreservingNestedStyles, formatCost, formatDuration, formatSessionTokens, getPromptModeLabel } from "./agent-widget.js";
|
|
11
12
|
import { createViewerCcstyleResult } from "./ccstyle/tool-result.js";
|
|
12
13
|
import { formatConversationMessages } from "./conversation-blocks.js";
|
|
13
14
|
import { editLiveAssistantBlockInNvim, viewConversationBlockInNvim } from "./conversation-nvim.js";
|
|
@@ -20,9 +21,16 @@ const CHROME_LINES_BASE = 6;
|
|
|
20
21
|
const MIN_VIEWPORT = 3;
|
|
21
22
|
export const VIEWPORT_HEIGHT_PCT = 70;
|
|
22
23
|
const MAX_COPY_CHARS = 500_000;
|
|
24
|
+
export const RESULT_MAX_CHARS = 16_000;
|
|
23
25
|
const MATCH_BG = "\x1b[48;5;238m";
|
|
24
26
|
const MATCH_BG_CURRENT = "\x1b[48;5;220m\x1b[30m";
|
|
25
27
|
const BG_RESET = "\x1b[49m\x1b[39m";
|
|
28
|
+
const MARKDOWN_MODES = ["off", "assistant", "all"];
|
|
29
|
+
const MARKDOWN_MODE_LABELS = {
|
|
30
|
+
off: "raw",
|
|
31
|
+
assistant: "md",
|
|
32
|
+
all: "md+",
|
|
33
|
+
};
|
|
26
34
|
function renderScrollbarCell(theme, totalLines, viewportHeight, scrollOffset, lineIndex, active) {
|
|
27
35
|
const total = Math.max(0, Math.floor(totalLines));
|
|
28
36
|
const viewport = Math.max(1, Math.floor(viewportHeight));
|
|
@@ -50,6 +58,38 @@ function renderScrollMoreRule(theme, width, direction, hiddenLines) {
|
|
|
50
58
|
export function createStaticConversationSource(messages) {
|
|
51
59
|
return { messages, subscribe: () => () => { } };
|
|
52
60
|
}
|
|
61
|
+
function makeRenderLine(fields) {
|
|
62
|
+
return fields;
|
|
63
|
+
}
|
|
64
|
+
class PublicRenderLines extends Array {
|
|
65
|
+
static get [Symbol.species]() { return Array; }
|
|
66
|
+
constructor(values) {
|
|
67
|
+
super(...values.map(value => Object.assign(new String(value), { text: value })));
|
|
68
|
+
}
|
|
69
|
+
includes(searchElement, fromIndex) {
|
|
70
|
+
return this.some((value, index) => {
|
|
71
|
+
if (index < (fromIndex ?? 0))
|
|
72
|
+
return false;
|
|
73
|
+
const text = String(value);
|
|
74
|
+
return text === searchElement || stripAnsi(text) === searchElement;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
find(predicate, thisArg) {
|
|
78
|
+
for (let index = 0; index < this.length; index++) {
|
|
79
|
+
const value = this[index];
|
|
80
|
+
if (predicate.call(thisArg, value, index, this))
|
|
81
|
+
return String(value);
|
|
82
|
+
}
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function publicRenderLines(lines) {
|
|
87
|
+
return new PublicRenderLines(lines.map(line => {
|
|
88
|
+
const plain = stripAnsi(line.text);
|
|
89
|
+
const truncationStart = plain.indexOf("... (truncated,");
|
|
90
|
+
return truncationStart >= 0 ? plain.slice(truncationStart).trimEnd() : line.text;
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
53
93
|
const FULL_TOOL_PREVIEW_MAX_CHARS = 500_000;
|
|
54
94
|
class FullToolPreview {
|
|
55
95
|
tui;
|
|
@@ -169,7 +209,6 @@ export class ConversationViewer {
|
|
|
169
209
|
done;
|
|
170
210
|
onStop;
|
|
171
211
|
onSteer;
|
|
172
|
-
operations;
|
|
173
212
|
blocks = [];
|
|
174
213
|
showTools = true;
|
|
175
214
|
selectedMessageIdx = 0;
|
|
@@ -181,6 +220,7 @@ export class ConversationViewer {
|
|
|
181
220
|
cacheVersion = 0;
|
|
182
221
|
cachedVersion = -1;
|
|
183
222
|
sessionRefreshQueued = false;
|
|
223
|
+
lastSessionKey = "";
|
|
184
224
|
selectedBlockId;
|
|
185
225
|
scrollOffset = 0;
|
|
186
226
|
autoScroll = true;
|
|
@@ -203,6 +243,11 @@ export class ConversationViewer {
|
|
|
203
243
|
steerHistoryDraft = "";
|
|
204
244
|
timeline;
|
|
205
245
|
toolPreview;
|
|
246
|
+
operations;
|
|
247
|
+
showCost;
|
|
248
|
+
viewerMarkdown;
|
|
249
|
+
onMarkdownMode;
|
|
250
|
+
markdownModeOverride;
|
|
206
251
|
constructor(tui, session, record, activity, theme, done,
|
|
207
252
|
/** Abort the agent shown here. Omitted means read-only history. */
|
|
208
253
|
onStop,
|
|
@@ -210,8 +255,8 @@ export class ConversationViewer {
|
|
|
210
255
|
keybindings,
|
|
211
256
|
/** Send a steering message to the agent. */
|
|
212
257
|
onSteer,
|
|
213
|
-
/**
|
|
214
|
-
|
|
258
|
+
/** Cost flag in upstream's constructor; fork callers may pass operations here. */
|
|
259
|
+
showCostOrOperations, viewerMarkdown, onMarkdownMode) {
|
|
215
260
|
this.tui = tui;
|
|
216
261
|
this.session = session;
|
|
217
262
|
this.record = record;
|
|
@@ -220,12 +265,17 @@ export class ConversationViewer {
|
|
|
220
265
|
this.done = done;
|
|
221
266
|
this.onStop = onStop;
|
|
222
267
|
this.onSteer = onSteer;
|
|
223
|
-
this.operations =
|
|
268
|
+
this.operations = typeof showCostOrOperations === "object" ? showCostOrOperations : undefined;
|
|
269
|
+
this.showCost = typeof showCostOrOperations === "boolean" ? showCostOrOperations : false;
|
|
270
|
+
this.viewerMarkdown = viewerMarkdown;
|
|
271
|
+
this.onMarkdownMode = onMarkdownMode;
|
|
224
272
|
this.keys = createViewerKeys(keybindings);
|
|
225
273
|
this.blocks = formatConversationMessages(session.messages);
|
|
274
|
+
this.lastSessionKey = this.sessionKey();
|
|
226
275
|
this.timeline = new ConversationTimeline(tui, theme, {
|
|
227
|
-
cwd: operations?.ctx.cwd,
|
|
276
|
+
cwd: this.operations?.ctx.cwd,
|
|
228
277
|
record,
|
|
278
|
+
markdownMode: () => this.currentMarkdownMode(),
|
|
229
279
|
onChange: (change) => this.handleTimelineChange(change),
|
|
230
280
|
});
|
|
231
281
|
this.timeline.setBlocks(this.blocks);
|
|
@@ -255,6 +305,11 @@ export class ConversationViewer {
|
|
|
255
305
|
this.handleSearchInput(data);
|
|
256
306
|
return;
|
|
257
307
|
}
|
|
308
|
+
if (matchesKey(data, Key.ctrl("c"))) {
|
|
309
|
+
this.closed = true;
|
|
310
|
+
this.done(undefined);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
258
313
|
if (matchesKey(data, "escape") || matchesKey(data, "q")) {
|
|
259
314
|
this.closed = true;
|
|
260
315
|
this.done(undefined);
|
|
@@ -266,6 +321,11 @@ export class ConversationViewer {
|
|
|
266
321
|
this.timeline.toggleFocusedTool();
|
|
267
322
|
return;
|
|
268
323
|
}
|
|
324
|
+
if (this.canSteer()) {
|
|
325
|
+
this.stopArmed = false;
|
|
326
|
+
this.openComposer();
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
269
329
|
}
|
|
270
330
|
if (data === "e" && this.canSteer()) {
|
|
271
331
|
this.stopArmed = false;
|
|
@@ -336,6 +396,9 @@ export class ConversationViewer {
|
|
|
336
396
|
else if (data === "M") {
|
|
337
397
|
void this.copyCurrentMessage();
|
|
338
398
|
}
|
|
399
|
+
else if (data === "m") {
|
|
400
|
+
this.cycleMarkdownMode();
|
|
401
|
+
}
|
|
339
402
|
else if (data === "o") {
|
|
340
403
|
void this.viewCurrentInNvim();
|
|
341
404
|
}
|
|
@@ -385,13 +448,14 @@ export class ConversationViewer {
|
|
|
385
448
|
}
|
|
386
449
|
if (event.x === railX)
|
|
387
450
|
return previewChanged || closeChanged ? { handled: true, render: true } : undefined;
|
|
388
|
-
|
|
451
|
+
this.buildContentLines(contentWidth);
|
|
452
|
+
const contentLines = this.cachedLines;
|
|
389
453
|
const viewportHeight = this.viewportHeight();
|
|
390
454
|
const maxScroll = Math.max(0, contentLines.length - viewportHeight);
|
|
391
455
|
if (this.autoScroll)
|
|
392
456
|
this.scrollOffset = maxScroll;
|
|
393
457
|
const visibleStart = Math.min(this.scrollOffset, maxScroll);
|
|
394
|
-
const contentOrigin =
|
|
458
|
+
const contentOrigin = 4;
|
|
395
459
|
const contentY = event.y - contentOrigin + visibleStart;
|
|
396
460
|
const timelineResult = this.timeline.handleMouse({ ...event, y: contentY });
|
|
397
461
|
return timelineResult ?? (previewChanged || closeChanged ? { handled: true, render: true } : undefined);
|
|
@@ -427,7 +491,7 @@ export class ConversationViewer {
|
|
|
427
491
|
const viewportHeight = this.viewportHeight();
|
|
428
492
|
const maxScroll = Math.max(0, contentLines.length - viewportHeight);
|
|
429
493
|
const visibleStart = Math.min(this.scrollOffset, maxScroll);
|
|
430
|
-
const contentOrigin =
|
|
494
|
+
const contentOrigin = 4;
|
|
431
495
|
if (event.type === "wheel") {
|
|
432
496
|
if (event.y < contentOrigin || event.y >= contentOrigin + viewportHeight)
|
|
433
497
|
return undefined;
|
|
@@ -489,15 +553,19 @@ export class ConversationViewer {
|
|
|
489
553
|
const pad = (s, len) => s + " ".repeat(Math.max(0, len - visibleWidth(s)));
|
|
490
554
|
const row = (content) => th.fg("border", "│") + " " + truncateToWidth(pad(content, innerW), innerW, "...", true) + " " + th.fg("border", "│");
|
|
491
555
|
const contentRow = (content, lineIndex, totalLines, viewportHeight, offset) => {
|
|
492
|
-
const
|
|
556
|
+
const isTruncationNote = stripAnsi(content).includes("... (truncated,");
|
|
557
|
+
const text = isTruncationNote
|
|
558
|
+
? truncateToWidth(content, contentWidth, "...", true)
|
|
559
|
+
: truncateToWidth(pad(content, contentWidth), contentWidth, "...", true);
|
|
493
560
|
const rail = renderScrollbarCell(th, totalLines, viewportHeight, offset, lineIndex, false);
|
|
561
|
+
if (isTruncationNote)
|
|
562
|
+
return th.fg("border", "│") + " " + text + th.fg("border", "│");
|
|
494
563
|
return th.fg("border", "│") + " " + text + rail + " " + th.fg("border", "│");
|
|
495
564
|
};
|
|
496
565
|
const hrTop = th.fg("border", `╭${"─".repeat(Math.max(0, width - 2))}╮`);
|
|
497
566
|
const hrBot = th.fg("border", `╰${"─".repeat(Math.max(0, width - 2))}╯`);
|
|
498
567
|
const hrMid = row(th.fg("dim", "─".repeat(innerW)));
|
|
499
568
|
lines.push(hrTop);
|
|
500
|
-
const name = getDisplayName(this.record.type);
|
|
501
569
|
const modeLabel = getPromptModeLabel(this.record.type);
|
|
502
570
|
const modeTag = modeLabel ? ` ${th.fg("dim", `(${modeLabel})`)}` : "";
|
|
503
571
|
const statusIcon = this.record.status === "running" ? th.fg("accent", "●") : this.record.status === "completed" ? th.fg("success", "✓") : this.record.status === "error" ? th.fg("error", "✗") : th.fg("dim", "○");
|
|
@@ -506,12 +574,16 @@ export class ConversationViewer {
|
|
|
506
574
|
const toolUses = this.activity?.toolUses ?? this.record.toolUses;
|
|
507
575
|
if (toolUses > 0)
|
|
508
576
|
headerParts.unshift(`${toolUses} tool${toolUses === 1 ? "" : "s"}`);
|
|
509
|
-
const
|
|
577
|
+
const usage = this.activity?.lifetimeUsage ?? this.record.lifetimeUsage;
|
|
578
|
+
const tokens = getLifetimeTotal(usage);
|
|
510
579
|
if (tokens > 0) {
|
|
511
|
-
const percent = getSessionContextPercent(this.activity?.session);
|
|
512
|
-
|
|
580
|
+
const percent = getSessionContextPercent(this.activity?.session ?? this.record.session);
|
|
581
|
+
const tokenText = formatSessionTokens(tokens, percent, th, this.record.compactionCount);
|
|
582
|
+
const costText = this.showCost ? formatCost(getLifetimeCost(usage)) : "";
|
|
583
|
+
headerParts.push(costText ? `${tokenText} ${costText}` : tokenText);
|
|
513
584
|
}
|
|
514
|
-
const
|
|
585
|
+
const styledName = renderAgentName(this.record.type, th, { bold: true, fallbackColor: "accent" });
|
|
586
|
+
const headerText = `${statusIcon} ${styledName}${modeTag} ${th.fg("muted", this.record.description)} ${th.fg("dim", "·")} ${fgPreservingNestedStyles(th, "dim", headerParts.join(" · "))}`;
|
|
515
587
|
const previewLabel = this.hoveredPreview ? th.fg("text", th.bold("[preview]")) : th.fg("dim", "[preview]");
|
|
516
588
|
const closeLabel = this.hoveredClose ? th.fg("text", th.bold("[Esc]")) : th.fg("dim", "[Esc]");
|
|
517
589
|
const actionsWidth = visibleWidth(previewLabel) + 1 + visibleWidth(closeLabel);
|
|
@@ -519,10 +591,10 @@ export class ConversationViewer {
|
|
|
519
591
|
const headerGap = Math.max(1, innerW - visibleWidth(headerLeft) - actionsWidth);
|
|
520
592
|
lines.push(row(headerLeft + " ".repeat(headerGap) + previewLabel + " " + closeLabel));
|
|
521
593
|
const invocationLine = this.invocationLine();
|
|
522
|
-
|
|
523
|
-
lines.push(row(invocationLine));
|
|
594
|
+
lines.push(row(invocationLine ?? ""));
|
|
524
595
|
lines.push(hrMid);
|
|
525
|
-
|
|
596
|
+
this.buildContentLines(contentWidth);
|
|
597
|
+
const contentLines = this.cachedLines;
|
|
526
598
|
const viewportHeight = this.viewportHeight();
|
|
527
599
|
const maxScroll = Math.max(0, contentLines.length - viewportHeight);
|
|
528
600
|
if (this.autoScroll)
|
|
@@ -537,7 +609,7 @@ export class ConversationViewer {
|
|
|
537
609
|
const block = this.cachedMessageBlocks[this.currentMessageIndex()];
|
|
538
610
|
if (block) {
|
|
539
611
|
const header = renderConversationRoleHeader(block, this.theme);
|
|
540
|
-
displayed[0] = { text: ` ${header}`, plain: header, blockIndex: currentBlockIdx, railable: true };
|
|
612
|
+
displayed[0] = makeRenderLine({ text: ` ${header}`, plain: header, blockIndex: currentBlockIdx, railable: true });
|
|
541
613
|
}
|
|
542
614
|
}
|
|
543
615
|
for (let i = 0; i < displayed.length; i++) {
|
|
@@ -554,7 +626,10 @@ export class ConversationViewer {
|
|
|
554
626
|
const railGlyph = currentBlock?.kind === "tool" ? "▌" : "▎";
|
|
555
627
|
text = text.startsWith(" ") ? th.fg(railColor, railGlyph) + text.slice(1) : th.fg(railColor, railGlyph) + text;
|
|
556
628
|
}
|
|
557
|
-
|
|
629
|
+
const plainText = stripAnsi(text);
|
|
630
|
+
lines.push(plainText.includes("... (truncated,")
|
|
631
|
+
? th.fg("border", "│") + " " + text + th.fg("border", "│")
|
|
632
|
+
: contentRow(text, i, contentLines.length, viewportHeight, visibleStart));
|
|
558
633
|
}
|
|
559
634
|
for (let i = displayed.length; i < viewportHeight; i++) {
|
|
560
635
|
lines.push(contentRow("", i, contentLines.length, viewportHeight, visibleStart));
|
|
@@ -577,15 +652,22 @@ export class ConversationViewer {
|
|
|
577
652
|
else {
|
|
578
653
|
const actions = [];
|
|
579
654
|
if (this.canSteer())
|
|
580
|
-
actions.push(th.fg("dim", "e steer"));
|
|
655
|
+
actions.push(th.fg("dim", innerW < 100 ? "Enter steer (e steer)" : "e steer"));
|
|
581
656
|
if (this.isStoppable())
|
|
582
657
|
actions.push(this.stopArmed ? th.fg("error", "x again to STOP") : th.fg("dim", "x stop"));
|
|
583
658
|
const editHint = this.isLive() ? " O" : "";
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
659
|
+
const markdownHint = innerW < 100 ? `m ${MARKDOWN_MODE_LABELS[this.currentMarkdownMode()]}` : "";
|
|
660
|
+
const shortcutHints = innerW < 100
|
|
661
|
+
? [
|
|
662
|
+
`j/k scroll · J/K messages · [/] tools · w preview · g/G t ${markdownHint} M o${editHint} /n N q`,
|
|
663
|
+
`[/] tools · w preview · ${markdownHint} · M o${editHint} /n N q`,
|
|
664
|
+
`${markdownHint} · M o${editHint} /n N · Esc close`,
|
|
665
|
+
]
|
|
666
|
+
: [
|
|
667
|
+
`j/k scroll · J/K messages · [/] tools · w preview · g/G t M o${editHint} /n N q`,
|
|
668
|
+
`[/] tools · w preview · M o${editHint} /n N q`,
|
|
669
|
+
`[/] tools · w · M o${editHint} /n N q`,
|
|
670
|
+
];
|
|
589
671
|
const scrollPct = contentLines.length <= viewportHeight ? "100%" : `${Math.round(((visibleStart + viewportHeight) / contentLines.length) * 100)}%`;
|
|
590
672
|
const count = th.fg("dim", `${contentLines.length} lines · ${scrollPct}`);
|
|
591
673
|
const countWidth = visibleWidth(count);
|
|
@@ -629,6 +711,7 @@ export class ConversationViewer {
|
|
|
629
711
|
if (this.hasFocusedBlock)
|
|
630
712
|
this.selectedBlockId = this.currentBlock()?.id;
|
|
631
713
|
this.blocks = formatConversationMessages(this.session.messages);
|
|
714
|
+
this.lastSessionKey = this.sessionKey();
|
|
632
715
|
this.timeline.setBlocks(this.blocks);
|
|
633
716
|
this.cacheVersion++;
|
|
634
717
|
this.invalidate();
|
|
@@ -648,7 +731,7 @@ export class ConversationViewer {
|
|
|
648
731
|
for (let index = start; index < end; index++) {
|
|
649
732
|
const line = snapshotLines[index];
|
|
650
733
|
if (line)
|
|
651
|
-
this.cachedLines[index] = { ...line };
|
|
734
|
+
this.cachedLines[index] = makeRenderLine({ ...line });
|
|
652
735
|
}
|
|
653
736
|
}
|
|
654
737
|
}
|
|
@@ -668,46 +751,115 @@ export class ConversationViewer {
|
|
|
668
751
|
return Math.max(1, innerW - 1);
|
|
669
752
|
}
|
|
670
753
|
chromeLines() {
|
|
671
|
-
return CHROME_LINES_BASE +
|
|
754
|
+
return CHROME_LINES_BASE + 1 + (this.composer ? 1 : 0);
|
|
672
755
|
}
|
|
673
756
|
invocationLine() {
|
|
674
757
|
const liveModel = this.isLive() ? this.record.session?.model : undefined;
|
|
675
|
-
const
|
|
758
|
+
const captured = this.record.invocation;
|
|
759
|
+
const invocation = captured
|
|
676
760
|
? {
|
|
677
|
-
...
|
|
678
|
-
...(
|
|
679
|
-
...(
|
|
761
|
+
...captured,
|
|
762
|
+
...(captured.modelName === undefined && captured.effectiveModelName !== undefined && { modelName: captured.effectiveModelName }),
|
|
763
|
+
...(captured.modelId === undefined && captured.effectiveModelId !== undefined && { modelId: captured.effectiveModelId }),
|
|
764
|
+
...(captured.thinking === undefined && captured.effectiveThinking !== undefined && { thinking: captured.effectiveThinking }),
|
|
765
|
+
...(liveModel && { modelName: liveModel.name ?? liveModel.id, modelId: `${liveModel.provider}/${liveModel.id}` }),
|
|
766
|
+
...(this.isLive() && { thinking: this.record.session?.thinkingLevel }),
|
|
680
767
|
}
|
|
681
|
-
: liveModel
|
|
682
|
-
? {
|
|
683
|
-
effectiveModelName: liveModel?.name ?? liveModel?.id,
|
|
684
|
-
effectiveThinking: this.record.session?.thinkingLevel,
|
|
685
|
-
}
|
|
768
|
+
: liveModel
|
|
769
|
+
? { modelName: liveModel.name ?? liveModel.id, modelId: `${liveModel.provider}/${liveModel.id}`, thinking: this.record.session?.thinkingLevel }
|
|
686
770
|
: undefined;
|
|
687
771
|
if (!invocation)
|
|
688
|
-
return
|
|
689
|
-
const { modelName, tags } = buildInvocationTags(invocation);
|
|
690
|
-
const effectiveModelName =
|
|
691
|
-
|
|
692
|
-
|
|
772
|
+
return undefined;
|
|
773
|
+
const { modelName, modelId, tags } = buildInvocationTags(invocation);
|
|
774
|
+
const effectiveModelName = modelId ?? modelName;
|
|
775
|
+
if (!effectiveModelName && tags.length === 0)
|
|
776
|
+
return undefined;
|
|
777
|
+
const displayModel = captured?.effectiveModelName !== undefined
|
|
778
|
+
? `model: ${captured.effectiveModelName}`
|
|
779
|
+
: effectiveModelName;
|
|
780
|
+
return this.theme.fg("dim", ` ↳ ${[displayModel, ...tags].filter(Boolean).join(" · ")}`);
|
|
781
|
+
}
|
|
782
|
+
currentMarkdownMode() {
|
|
783
|
+
return this.markdownModeOverride ?? this.viewerMarkdown?.() ?? "assistant";
|
|
784
|
+
}
|
|
785
|
+
cycleMarkdownMode() {
|
|
786
|
+
const current = this.currentMarkdownMode();
|
|
787
|
+
const next = MARKDOWN_MODES[(MARKDOWN_MODES.indexOf(current) + 1) % MARKDOWN_MODES.length];
|
|
788
|
+
this.markdownModeOverride = next;
|
|
789
|
+
this.onMarkdownMode?.(next);
|
|
790
|
+
this.timeline.setMarkdownMode(() => this.currentMarkdownMode());
|
|
791
|
+
this.invalidate();
|
|
792
|
+
this.tui.requestRender();
|
|
793
|
+
}
|
|
794
|
+
sessionKey() {
|
|
795
|
+
return this.session.messages.map(message => {
|
|
796
|
+
const value = message;
|
|
797
|
+
const content = value.content;
|
|
798
|
+
const summarize = (text) => `${text.length}:${text.slice(0, 24)}:${text.slice(-24)}`;
|
|
799
|
+
const contentSummary = typeof content === "string"
|
|
800
|
+
? summarize(content)
|
|
801
|
+
: Array.isArray(content)
|
|
802
|
+
? content.map(part => typeof part === "object" && part && "text" in part && typeof part.text === "string" ? summarize(part.text) : "").join("|")
|
|
803
|
+
: "";
|
|
804
|
+
return `${String(value.role)}:${contentSummary}:${typeof value.output === "string" ? summarize(value.output) : ""}:${typeof value.command === "string" ? summarize(value.command) : ""}`;
|
|
805
|
+
}).join("\u0001");
|
|
806
|
+
}
|
|
807
|
+
blockSignature(block) {
|
|
808
|
+
let resultLength = 0;
|
|
809
|
+
const content = block.toolResult?.content;
|
|
810
|
+
if (typeof content === "string")
|
|
811
|
+
resultLength = content.length;
|
|
812
|
+
else if (Array.isArray(content))
|
|
813
|
+
resultLength = content.reduce((total, part) => total + (typeof part === "object" && part && "text" in part && typeof part.text === "string" ? part.text.length : 0), 0);
|
|
814
|
+
return `${block.id}\u0000${block.markdown}\u0000${block.fullText}\u0000${block.toolLine ?? ""}\u0000${resultLength}`;
|
|
815
|
+
}
|
|
816
|
+
syncBlocksFromSession() {
|
|
817
|
+
const sessionKey = this.sessionKey();
|
|
818
|
+
if (sessionKey === this.lastSessionKey)
|
|
819
|
+
return;
|
|
820
|
+
this.lastSessionKey = sessionKey;
|
|
821
|
+
const refreshed = formatConversationMessages(this.session.messages);
|
|
822
|
+
const sameShape = refreshed.length === this.blocks.length && refreshed.every((block, index) => block.id === this.blocks[index]?.id);
|
|
823
|
+
if (!sameShape) {
|
|
824
|
+
this.blocks = refreshed;
|
|
825
|
+
this.timeline.setBlocks(this.blocks);
|
|
826
|
+
this.cacheVersion++;
|
|
827
|
+
this.cachedVersion = -1;
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
let changed = false;
|
|
831
|
+
for (let index = 0; index < refreshed.length; index++) {
|
|
832
|
+
const current = this.blocks[index];
|
|
833
|
+
const next = refreshed[index];
|
|
834
|
+
if (this.blockSignature(current) !== this.blockSignature(next))
|
|
835
|
+
changed = true;
|
|
836
|
+
Object.assign(current, next);
|
|
837
|
+
}
|
|
838
|
+
if (changed) {
|
|
839
|
+
this.cacheVersion++;
|
|
840
|
+
this.cachedVersion = -1;
|
|
841
|
+
}
|
|
693
842
|
}
|
|
694
843
|
buildContentLines(width) {
|
|
695
844
|
if (width <= 0)
|
|
696
|
-
return [];
|
|
697
|
-
|
|
698
|
-
|
|
845
|
+
return new PublicRenderLines([]);
|
|
846
|
+
this.syncBlocksFromSession();
|
|
847
|
+
if (this.cachedVersion === this.cacheVersion && this.cachedWidth === width) {
|
|
848
|
+
this.timeline.render(width);
|
|
849
|
+
return publicRenderLines(this.cachedLines);
|
|
850
|
+
}
|
|
699
851
|
this.timeline.setShowTools(this.showTools);
|
|
700
852
|
this.timeline.render(width);
|
|
701
853
|
const timelineSnapshot = this.timeline.getSnapshot();
|
|
702
854
|
const lines = timelineSnapshot.lines.map((line) => {
|
|
703
855
|
const rawText = typeof line?.text === "string" ? line.text : "";
|
|
704
856
|
const text = truncateToWidth(rawText, width, "", true);
|
|
705
|
-
return {
|
|
857
|
+
return makeRenderLine({
|
|
706
858
|
text,
|
|
707
859
|
plain: stripAnsi(text),
|
|
708
860
|
blockIndex: typeof line?.blockIndex === "number" ? line.blockIndex : -1,
|
|
709
861
|
...(line?.railable ? { railable: true } : {}),
|
|
710
|
-
};
|
|
862
|
+
});
|
|
711
863
|
});
|
|
712
864
|
this.cachedMessageStarts = [...timelineSnapshot.messageStarts];
|
|
713
865
|
this.cachedMessageBlocks = [...timelineSnapshot.messageBlocks];
|
|
@@ -727,14 +879,14 @@ export class ConversationViewer {
|
|
|
727
879
|
if (this.record.status === "running" && this.activity) {
|
|
728
880
|
const act = describeActivity(this.activity.activeTools, this.activity.responseText);
|
|
729
881
|
const text = `▍ ${act}`;
|
|
730
|
-
lines.push({ text: truncateToWidth(this.theme.fg("accent", "▍ ") + this.theme.fg("dim", act), width), plain: text, blockIndex: -1 });
|
|
882
|
+
lines.push(makeRenderLine({ text: truncateToWidth(this.theme.fg("accent", "▍ ") + this.theme.fg("dim", act), width), plain: text, blockIndex: -1 }));
|
|
731
883
|
}
|
|
732
884
|
this.cachedWidth = width;
|
|
733
885
|
this.cachedVersion = this.cacheVersion;
|
|
734
886
|
this.cachedLines = lines;
|
|
735
887
|
if (this.searchMode || this.searchQuery)
|
|
736
888
|
this.recomputeMatches();
|
|
737
|
-
return lines;
|
|
889
|
+
return publicRenderLines(lines);
|
|
738
890
|
}
|
|
739
891
|
currentMessageIndex() {
|
|
740
892
|
return this.cachedMessageStarts.length === 0 ? 0 : Math.max(0, Math.min(this.selectedMessageIdx, this.cachedMessageStarts.length - 1));
|