@aragon-agent/cli 0.5.6 → 0.5.9
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 +356 -0
- package/README.md +1429 -1105
- package/dist/agent/coalesce.d.ts +13 -0
- package/dist/agent/coalesce.js +50 -11
- package/dist/agent/controller.d.ts +141 -2
- package/dist/agent/controller.js +396 -4
- package/dist/agent/entry-limits.d.ts +65 -0
- package/dist/agent/entry-limits.js +133 -0
- package/dist/agent/headless.d.ts +8 -0
- package/dist/agent/headless.js +40 -0
- package/dist/agent/reducer.d.ts +253 -3
- package/dist/agent/reducer.js +553 -28
- package/dist/agent/retry-view.d.ts +68 -0
- package/dist/agent/retry-view.js +95 -0
- package/dist/agent/system-prompt.d.ts +11 -0
- package/dist/agent/system-prompt.js +2 -0
- package/dist/cli.js +122 -4
- package/dist/commands/builtins.d.ts +1 -1
- package/dist/commands/builtins.js +313 -2
- package/dist/commands/perf.d.ts +45 -0
- package/dist/commands/perf.js +78 -0
- package/dist/config/cli-commands.d.ts +53 -2
- package/dist/config/cli-commands.js +136 -3
- package/dist/config/env.d.ts +6 -1
- package/dist/config/env.js +131 -1
- package/dist/config/load.d.ts +63 -0
- package/dist/config/load.js +125 -2
- package/dist/config/schema.d.ts +273 -10
- package/dist/config/schema.js +250 -7
- package/dist/config/store.js +20 -1
- package/dist/fast/critique.d.ts +43 -0
- package/dist/fast/critique.js +62 -0
- package/dist/fast/digest.d.ts +42 -0
- package/dist/fast/digest.js +85 -0
- package/dist/fast/frames.d.ts +99 -0
- package/dist/fast/frames.js +180 -0
- package/dist/fast/limits.d.ts +98 -0
- package/dist/fast/limits.js +98 -0
- package/dist/fast/prompt.d.ts +72 -0
- package/dist/fast/prompt.js +94 -0
- package/dist/fast/resolve.d.ts +43 -0
- package/dist/fast/resolve.js +105 -0
- package/dist/fast/review-call.d.ts +99 -0
- package/dist/fast/review-call.js +130 -0
- package/dist/fast/reviewer.d.ts +248 -0
- package/dist/fast/reviewer.js +664 -0
- package/dist/fast/types.d.ts +128 -0
- package/dist/fast/types.js +14 -0
- package/dist/fast/wiring.d.ts +170 -0
- package/dist/fast/wiring.js +316 -0
- package/dist/logging/install.d.ts +15 -1
- package/dist/logging/install.js +37 -4
- package/dist/logging/logger.d.ts +1 -1
- package/dist/session/persist.js +57 -1
- package/dist/team/normalize.d.ts +26 -1
- package/dist/team/normalize.js +23 -3
- package/dist/team/prompt.d.ts +11 -0
- package/dist/team/prompt.js +10 -0
- package/dist/team/report.d.ts +18 -0
- package/dist/team/report.js +27 -1
- package/dist/team/runtime.d.ts +13 -2
- package/dist/team/runtime.js +33 -6
- package/dist/team/subagent.d.ts +19 -1
- package/dist/team/subagent.js +72 -10
- package/dist/team/task-tool.d.ts +26 -0
- package/dist/team/task-tool.js +48 -4
- package/dist/team/types.d.ts +80 -1
- package/dist/tools/bash-tool.js +19 -3
- package/dist/tools/diff.d.ts +25 -5
- package/dist/tools/diff.js +72 -41
- package/dist/tools/file-change-store.d.ts +34 -0
- package/dist/tools/file-change-store.js +57 -0
- package/dist/tools/fs-tools.d.ts +26 -0
- package/dist/tools/fs-tools.js +62 -5
- package/dist/tools/index.d.ts +31 -0
- package/dist/tools/index.js +7 -1
- package/dist/tools/patch.d.ts +115 -0
- package/dist/tools/patch.js +453 -0
- package/dist/tools/terminal-output.d.ts +107 -0
- package/dist/tools/terminal-output.js +198 -0
- package/dist/tools/tool-output-store.d.ts +68 -0
- package/dist/tools/tool-output-store.js +102 -0
- package/dist/ui/ActivityLine.d.ts +48 -0
- package/dist/ui/ActivityLine.js +22 -0
- package/dist/ui/App.d.ts +1 -4
- package/dist/ui/App.js +357 -44
- package/dist/ui/BottomStatusRow.d.ts +43 -0
- package/dist/ui/BottomStatusRow.js +14 -0
- package/dist/ui/Composer.d.ts +1 -6
- package/dist/ui/Composer.js +2 -2
- package/dist/ui/Markdown.d.ts +7 -1
- package/dist/ui/Markdown.js +15 -48
- package/dist/ui/PromptInput.d.ts +1 -15
- package/dist/ui/PromptInput.js +1 -38
- package/dist/ui/StatusBar.d.ts +50 -0
- package/dist/ui/StatusBar.js +7 -3
- package/dist/ui/TeamPanel.d.ts +5 -4
- package/dist/ui/TeamPanel.js +1 -1
- package/dist/ui/TodoPanel.d.ts +5 -4
- package/dist/ui/Transcript.d.ts +80 -5
- package/dist/ui/Transcript.js +179 -11
- package/dist/ui/activity-phrases.d.ts +33 -0
- package/dist/ui/activity-phrases.js +50 -0
- package/dist/ui/entries/AssistantEntry.d.ts +38 -1
- package/dist/ui/entries/AssistantEntry.js +34 -3
- package/dist/ui/entries/DiffView.d.ts +67 -0
- package/dist/ui/entries/DiffView.js +103 -0
- package/dist/ui/entries/FastCard.d.ts +53 -0
- package/dist/ui/entries/FastCard.js +87 -0
- package/dist/ui/entries/RetryCard.d.ts +56 -0
- package/dist/ui/entries/RetryCard.js +60 -0
- package/dist/ui/entries/TeamCard.d.ts +9 -1
- package/dist/ui/entries/TeamCard.js +28 -2
- package/dist/ui/entries/TodoCard.d.ts +9 -1
- package/dist/ui/entries/TodoCard.js +23 -1
- package/dist/ui/entries/ToolCard.d.ts +50 -1
- package/dist/ui/entries/ToolCard.js +104 -7
- package/dist/ui/entries/ToolPreview.d.ts +2 -2
- package/dist/ui/entries/UserEntry.d.ts +9 -1
- package/dist/ui/entries/UserEntry.js +17 -1
- package/dist/ui/exit-snapshot.d.ts +7 -0
- package/dist/ui/glyphs.d.ts +9 -0
- package/dist/ui/glyphs.js +2 -0
- package/dist/ui/layout/AppShell.d.ts +13 -22
- package/dist/ui/layout/AppShell.js +3 -38
- package/dist/ui/layout/MeasuredEntry.d.ts +21 -0
- package/dist/ui/layout/MeasuredEntry.js +30 -0
- package/dist/ui/layout/ScrollViewport.js +8 -2
- package/dist/ui/layout/viewport-geometry.d.ts +28 -0
- package/dist/ui/layout/viewport-geometry.js +27 -0
- package/dist/ui/layout/virtual-window.d.ts +100 -0
- package/dist/ui/layout/virtual-window.js +308 -0
- package/dist/ui/live-clamp.d.ts +42 -0
- package/dist/ui/live-clamp.js +74 -0
- package/dist/ui/markdown-blocks.d.ts +25 -1
- package/dist/ui/markdown-blocks.js +43 -0
- package/dist/ui/overlays/HelpOverlay.js +16 -2
- package/dist/ui/overlays/SettingsScreen.d.ts +82 -1
- package/dist/ui/overlays/SettingsScreen.js +147 -1
- package/dist/ui/render-cache.d.ts +81 -0
- package/dist/ui/render-cache.js +195 -0
- package/dist/ui/render-governor.d.ts +54 -0
- package/dist/ui/render-governor.js +78 -0
- package/dist/ui/transcript-text.d.ts +11 -0
- package/dist/ui/transcript-text.js +32 -0
- package/dist/ui/use-height-store.d.ts +31 -0
- package/dist/ui/use-height-store.js +76 -0
- package/dist/ui/use-render-governor.d.ts +39 -0
- package/dist/ui/use-render-governor.js +57 -0
- package/dist/ui/use-startup-notices.d.ts +9 -1
- package/dist/ui/use-startup-notices.js +35 -1
- package/dist/ui/use-wheel-routing.d.ts +16 -32
- package/dist/ui/use-wheel-routing.js +21 -38
- package/package.json +2 -2
- package/dist/ui/layout/regions.d.ts +0 -55
- package/dist/ui/layout/regions.js +0 -52
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The bottom status row — the one already-budgeted row above the composer, now
|
|
3
|
+
* shared by two occupants (agent-activity-presentation §3.2.3 / D-17 / P0-1).
|
|
4
|
+
*
|
|
5
|
+
* THE ACTIVITY LINE IS NOT A NEW `AppShell` SLOT, AND THIS FILE IS WHY.
|
|
6
|
+
*
|
|
7
|
+
* `viewportRows()` (`layout/budget.ts`) is the ONE function that says how many
|
|
8
|
+
* rows the viewport gets, and it enumerates exactly `header + toast + composer +
|
|
9
|
+
* status`. In full-screen `AppShell`'s root is `height={frameHeight(rows)}` with
|
|
10
|
+
* `overflow="hidden"`, the bottom chrome box is `flexShrink={0}` and the viewport
|
|
11
|
+
* box is its only `flexShrink={1}` child — so an extra chrome row does not make
|
|
12
|
+
* the frame taller, Yoga takes the row out of the TRANSCRIPT. Meanwhile
|
|
13
|
+
* `viewportRows()` keeps returning the old number to `ScrollViewport`,
|
|
14
|
+
* `selectWindow`'s spacers, `overlayMaxRows`, `popupMaxRows` and `todoRailRows`.
|
|
15
|
+
* The transcript would draw one row shorter than every consumer believes, ONLY
|
|
16
|
+
* WHILE A RUN IS IN FLIGHT, so the layout would shift on submit and shift back on
|
|
17
|
+
* `agent_end`.
|
|
18
|
+
*
|
|
19
|
+
* `ToastStack.tsx` already legislates this for itself: *"in `fullscreen` this
|
|
20
|
+
* ALWAYS occupies exactly one row — an empty row when there is nothing to say.
|
|
21
|
+
* Rendering conditionally would make the viewport height (and therefore the whole
|
|
22
|
+
* transcript) jump every time a toast appears or expires."* A run starts and ends
|
|
23
|
+
* far more often than a toast appears and expires, so the activity line is the
|
|
24
|
+
* STRONGER case for that rule, not an exception to it.
|
|
25
|
+
*
|
|
26
|
+
* Sharing the row means `budget.ts` and `AppShell.tsx` come out of this round
|
|
27
|
+
* UNMODIFIED — and `budget.test.ts` asserts that they did (AC-8a, DoD #8).
|
|
28
|
+
*
|
|
29
|
+
* PRECEDENCE: a toast wins. A transient ack is a RESPONSE TO THE USER, and the
|
|
30
|
+
* row nearest the input belongs to it.
|
|
31
|
+
*/
|
|
32
|
+
import React from 'react';
|
|
33
|
+
import type { Theme } from './theme.js';
|
|
34
|
+
import type { Toast } from '../agent/reducer.js';
|
|
35
|
+
import type { RenderMode } from './layout/frame.js';
|
|
36
|
+
export interface BottomStatusRowProps {
|
|
37
|
+
mode: RenderMode;
|
|
38
|
+
toasts: Toast[];
|
|
39
|
+
/** `<ActivityLine>` while a run owns the screen, else `null`. */
|
|
40
|
+
activity: React.ReactNode;
|
|
41
|
+
theme: Theme;
|
|
42
|
+
}
|
|
43
|
+
export declare function BottomStatusRow({ mode, toasts, activity, theme, }: BottomStatusRowProps): React.ReactElement | null;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box } from 'ink';
|
|
3
|
+
import { ToastStack } from './ToastStack.js';
|
|
4
|
+
export function BottomStatusRow({ mode, toasts, activity, theme, }) {
|
|
5
|
+
// A toast wins the row; so does an empty toast stack in full-screen, whose
|
|
6
|
+
// blank `<Text> </Text>` IS the budgeted row and must keep being emitted.
|
|
7
|
+
if (toasts.length > 0 || !activity) {
|
|
8
|
+
return _jsx(ToastStack, { toasts: toasts, theme: theme, mode: mode });
|
|
9
|
+
}
|
|
10
|
+
// Inline has no frame and therefore nothing to protect: `ToastStack`'s inline
|
|
11
|
+
// branch is already a conditional 0-3 row stack, and this is simply one more
|
|
12
|
+
// conditional row above it.
|
|
13
|
+
return _jsx(Box, { flexShrink: 0, children: activity });
|
|
14
|
+
}
|
package/dist/ui/Composer.d.ts
CHANGED
|
@@ -35,14 +35,9 @@ export interface ComposerProps {
|
|
|
35
35
|
/** Mirror of the controller's effective mode; drives the chip and the border. */
|
|
36
36
|
agentMode: AgentMode;
|
|
37
37
|
popupMaxRows?: number;
|
|
38
|
-
/** Pure pass-through to `PromptInput` (mouse-wheel-region-routing §5.6). */
|
|
39
|
-
historyIntent?: {
|
|
40
|
-
dir: 'up' | 'down';
|
|
41
|
-
nonce: number;
|
|
42
|
-
};
|
|
43
38
|
theme: Theme;
|
|
44
39
|
caps: TermCapabilities;
|
|
45
40
|
onSubmit: (text: string) => void;
|
|
46
41
|
onHelp?: () => void;
|
|
47
42
|
}
|
|
48
|
-
export declare function Composer({ isActive, running, history, commands, cwd, showHint, submitCount, hintsEnabled, agentMode, popupMaxRows,
|
|
43
|
+
export declare function Composer({ isActive, running, history, commands, cwd, showHint, submitCount, hintsEnabled, agentMode, popupMaxRows, theme, caps, onSubmit, onHelp, }: ComposerProps): React.ReactElement;
|
package/dist/ui/Composer.js
CHANGED
|
@@ -56,7 +56,7 @@ function hintText(running, submitCount, glyphs, mode) {
|
|
|
56
56
|
'? help',
|
|
57
57
|
].join(dot);
|
|
58
58
|
}
|
|
59
|
-
export function Composer({ isActive, running, history, commands, cwd, showHint, submitCount, hintsEnabled, agentMode, popupMaxRows,
|
|
59
|
+
export function Composer({ isActive, running, history, commands, cwd, showHint, submitCount, hintsEnabled, agentMode, popupMaxRows, theme, caps, onSubmit, onHelp, }) {
|
|
60
60
|
const [hasDraft, setHasDraft] = useState(false);
|
|
61
61
|
const onDraftChange = useCallback((next) => setHasDraft(next), []);
|
|
62
62
|
// Plan mode inserts ONE branch, above `draft` and below `running`. The
|
|
@@ -73,7 +73,7 @@ export function Composer({ isActive, running, history, commands, cwd, showHint,
|
|
|
73
73
|
: theme.idleBorder ?? theme.border;
|
|
74
74
|
const glyphs = pickGlyphs(caps);
|
|
75
75
|
const visible = showHint && hintsEnabled;
|
|
76
|
-
return (_jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [_jsx(PromptInput, { isActive: isActive, running: running, history: history, commands: commands, cwd: cwd, theme: theme, caps: caps, popupMaxRows: popupMaxRows, onSubmit: onSubmit, onHelp: onHelp, agentMode: agentMode, bordered: { color: borderColor }, onDraftChange: onDraftChange
|
|
76
|
+
return (_jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [_jsx(PromptInput, { isActive: isActive, running: running, history: history, commands: commands, cwd: cwd, theme: theme, caps: caps, popupMaxRows: popupMaxRows, onSubmit: onSubmit, onHelp: onHelp, agentMode: agentMode, bordered: { color: borderColor }, onDraftChange: onDraftChange }), visible && (
|
|
77
77
|
// The chip rides the EXISTING hint row rather than adding one, so it
|
|
78
78
|
// costs zero rows on a 24-row terminal.
|
|
79
79
|
_jsxs(Box, { flexDirection: "row", flexShrink: 0, children: [_jsx(Text, { children: ' ' }), _jsx(ModeChip, { mode: agentMode, theme: theme, caps: caps }), _jsx(Text, { wrap: "truncate", color: theme.hintFg ?? theme.muted, children: hintText(running, submitCount, glyphs, agentMode) })] }))] }));
|
package/dist/ui/Markdown.d.ts
CHANGED
|
@@ -7,7 +7,13 @@
|
|
|
7
7
|
* *italic* / `code` / ~~strike~~. Anything else renders as plain text. Still
|
|
8
8
|
* intentionally small — not a CommonMark implementation.
|
|
9
9
|
*
|
|
10
|
-
* The grammar lives in `markdown-blocks.ts`; this file only renders.
|
|
10
|
+
* The grammar lives in `markdown-blocks.ts`; this file only renders. That was
|
|
11
|
+
* true of the file header long before it was true of the file
|
|
12
|
+
* (tui-render-performance R2): the block grammar used to run here, in the render
|
|
13
|
+
* body, on every frame. Both expensive halves are now memoised on the input
|
|
14
|
+
* string — `parseMarkdownCached` for the AST, `highlightCached` for the ANSI —
|
|
15
|
+
* while theme and glyphs stay render-time, so `/theme` still takes effect
|
|
16
|
+
* immediately (K-5).
|
|
11
17
|
*/
|
|
12
18
|
import React from 'react';
|
|
13
19
|
import type { Theme } from './theme.js';
|
package/dist/ui/Markdown.js
CHANGED
|
@@ -1,54 +1,27 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
|
-
import { highlight } from 'cli-highlight';
|
|
4
3
|
import { pickGlyphs } from './glyphs.js';
|
|
5
4
|
import { railBorderProps } from './layout/Gutter.js';
|
|
6
|
-
import {
|
|
7
|
-
|
|
5
|
+
import { highlightCached, parseMarkdownCached } from './render-cache.js';
|
|
6
|
+
import { formatTable, isRule, parseHeading, parseInline, } from './markdown-blocks.js';
|
|
8
7
|
/** Width of the `---` rule. Fixed so it cannot force a wrap on narrow frames. */
|
|
9
8
|
const RULE_WIDTH = 24;
|
|
10
9
|
export function Markdown({ text, theme, caps }) {
|
|
11
10
|
const glyphs = pickGlyphs(caps);
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
i += 1;
|
|
23
|
-
while (i < lines.length && !FENCE.test((lines[i] ?? '').trim())) {
|
|
24
|
-
codeLines.push(lines[i] ?? '');
|
|
25
|
-
i += 1;
|
|
26
|
-
}
|
|
27
|
-
i += 1; // skip closing fence
|
|
28
|
-
blocks.push(_jsx(CodeBlock, { code: codeLines.join('\n'), lang: lang, theme: theme, glyphs: glyphs }, `b${key++}`));
|
|
29
|
-
continue;
|
|
30
|
-
}
|
|
31
|
-
// A pipe row followed by a divider row starts a table; consume the run.
|
|
32
|
-
const headerCells = parseTableRow(line);
|
|
33
|
-
if (headerCells && i + 1 < lines.length && isTableDivider(lines[i + 1] ?? '')) {
|
|
34
|
-
const align = tableAlignments(lines[i + 1] ?? '');
|
|
35
|
-
const rows = [headerCells];
|
|
36
|
-
i += 2;
|
|
37
|
-
while (i < lines.length) {
|
|
38
|
-
const cells = parseTableRow(lines[i] ?? '');
|
|
39
|
-
if (!cells)
|
|
40
|
-
break;
|
|
41
|
-
rows.push(cells);
|
|
42
|
-
i += 1;
|
|
43
|
-
}
|
|
44
|
-
const formatted = formatTable(rows, align);
|
|
45
|
-
blocks.push(_jsx(Box, { flexDirection: "column", children: formatted.map((row, r) => (_jsx(Text, { wrap: "truncate", bold: r === 0, color: r === 0 ? theme.accent : undefined, children: row }, r))) }, `b${key++}`));
|
|
46
|
-
continue;
|
|
11
|
+
const blocks = parseMarkdownCached(text);
|
|
12
|
+
return (_jsx(Box, { flexDirection: "column", children: blocks.map((block, i) => renderBlock(block, i, theme, glyphs)) }));
|
|
13
|
+
}
|
|
14
|
+
function renderBlock(block, key, theme, glyphs) {
|
|
15
|
+
switch (block.kind) {
|
|
16
|
+
case 'code':
|
|
17
|
+
return (_jsx(CodeBlock, { code: block.code, lang: block.lang, theme: theme, glyphs: glyphs }, `b${key}`));
|
|
18
|
+
case 'table': {
|
|
19
|
+
const formatted = formatTable(block.rows, block.align);
|
|
20
|
+
return (_jsx(Box, { flexDirection: "column", children: formatted.map((row, r) => (_jsx(Text, { wrap: "truncate", bold: r === 0, color: r === 0 ? theme.accent : undefined, children: row }, r))) }, `b${key}`));
|
|
47
21
|
}
|
|
48
|
-
|
|
49
|
-
|
|
22
|
+
default:
|
|
23
|
+
return _jsx(InlineLine, { line: block.text, theme: theme, glyphs: glyphs }, `b${key}`);
|
|
50
24
|
}
|
|
51
|
-
return _jsx(Box, { flexDirection: "column", children: blocks });
|
|
52
25
|
}
|
|
53
26
|
/**
|
|
54
27
|
* Fenced code. The round border is gone (§4.3): nested inside a tool card it
|
|
@@ -57,13 +30,7 @@ export function Markdown({ text, theme, caps }) {
|
|
|
57
30
|
* code" boundary for 1 column and 0 rows.
|
|
58
31
|
*/
|
|
59
32
|
function CodeBlock({ code, lang, theme, glyphs, }) {
|
|
60
|
-
|
|
61
|
-
try {
|
|
62
|
-
rendered = highlight(code, { language: lang || undefined, ignoreIllegals: true });
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
rendered = code;
|
|
66
|
-
}
|
|
33
|
+
const rendered = highlightCached(code, lang);
|
|
67
34
|
return (_jsxs(Box, { flexDirection: "column", flexShrink: 0, paddingLeft: 1, ...railBorderProps(glyphs.railVertical, theme.border), children: [lang.length > 0 && (_jsx(Text, { color: theme.chip.fg, backgroundColor: theme.chip.bg, children: ` ${lang} ` })), _jsx(Text, { children: rendered })] }));
|
|
68
35
|
}
|
|
69
36
|
/** Six heading levels used to render identically; now they carry three weights. */
|
package/dist/ui/PromptInput.d.ts
CHANGED
|
@@ -55,20 +55,6 @@ interface PromptInputProps {
|
|
|
55
55
|
};
|
|
56
56
|
/** Fires only when the draft flips empty ⇄ non-empty, for the border color. */
|
|
57
57
|
onDraftChange?: (hasDraft: boolean) => void;
|
|
58
|
-
/**
|
|
59
|
-
* One prompt-history step, pushed by the wheel router when a notch lands on
|
|
60
|
-
* the composer band (mouse-wheel-region-routing §5.6). `nonce` is monotonic
|
|
61
|
-
* so two notches in the same direction are two steps.
|
|
62
|
-
*
|
|
63
|
-
* Applied through the SAME `verticalOrHistory` / popup-selection branches the
|
|
64
|
-
* keyboard uses, deliberately: it means the wheel and `↑`/`↓` cannot drift
|
|
65
|
-
* apart, and the "never clobber an in-progress draft" guard protects the
|
|
66
|
-
* wheel for free.
|
|
67
|
-
*/
|
|
68
|
-
historyIntent?: {
|
|
69
|
-
dir: 'up' | 'down';
|
|
70
|
-
nonce: number;
|
|
71
|
-
};
|
|
72
58
|
}
|
|
73
59
|
/** Apply an edit intent as a pure buffer/cursor transform. */
|
|
74
60
|
export declare function applyEdit(buffer: string, cursor: number, intent: EditIntent): {
|
|
@@ -98,5 +84,5 @@ export declare function fileTokenAt(buffer: string, cursor: number): {
|
|
|
98
84
|
end: number;
|
|
99
85
|
query: string;
|
|
100
86
|
} | null;
|
|
101
|
-
export declare function PromptInput({ isActive, running, history, commands, cwd, theme, caps, popupMaxRows, agentMode, onSubmit, onHelp, bordered, onDraftChange,
|
|
87
|
+
export declare function PromptInput({ isActive, running, history, commands, cwd, theme, caps, popupMaxRows, agentMode, onSubmit, onHelp, bordered, onDraftChange, }: PromptInputProps): React.ReactElement;
|
|
102
88
|
export {};
|
package/dist/ui/PromptInput.js
CHANGED
|
@@ -127,7 +127,7 @@ function isControlSeq(input) {
|
|
|
127
127
|
// ---------------------------------------------------------------------------
|
|
128
128
|
// Component
|
|
129
129
|
// ---------------------------------------------------------------------------
|
|
130
|
-
export function PromptInput({ isActive, running, history, commands, cwd, theme, caps, popupMaxRows, agentMode, onSubmit, onHelp, bordered, onDraftChange,
|
|
130
|
+
export function PromptInput({ isActive, running, history, commands, cwd, theme, caps, popupMaxRows, agentMode, onSubmit, onHelp, bordered, onDraftChange, }) {
|
|
131
131
|
const [buffer, setBuffer] = useState('');
|
|
132
132
|
const [cursor, setCursor] = useState(0);
|
|
133
133
|
const [historyIndex, setHistoryIndex] = useState(null);
|
|
@@ -261,43 +261,6 @@ export function PromptInput({ isActive, running, history, commands, cwd, theme,
|
|
|
261
261
|
recallDown();
|
|
262
262
|
}
|
|
263
263
|
};
|
|
264
|
-
// --- Wheel-driven history step (mouse-wheel-region-routing §5.6). ---------
|
|
265
|
-
// The applier closes over the buffer, the cursor and the popup state, so it
|
|
266
|
-
// is re-created on every render and reached through a ref: depending on it
|
|
267
|
-
// directly would re-fire the effect on every keystroke.
|
|
268
|
-
const applyHistoryIntent = useRef(() => { });
|
|
269
|
-
applyHistoryIntent.current = (dir) => {
|
|
270
|
-
// Mirrors the keyboard branch exactly — with the completion popup open,
|
|
271
|
-
// Up/Down move the selection rather than recalling history.
|
|
272
|
-
if (popupItems.length > 0) {
|
|
273
|
-
setSel(dir === 'up'
|
|
274
|
-
? Math.max(0, clampedSel - 1)
|
|
275
|
-
: Math.min(popupItems.length - 1, clampedSel + 1));
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
verticalOrHistory(dir);
|
|
279
|
-
};
|
|
280
|
-
const historyIntentRef = useRef(historyIntent);
|
|
281
|
-
historyIntentRef.current = historyIntent;
|
|
282
|
-
// I-9: seeded from the incoming nonce during the FIRST render, so a mount
|
|
283
|
-
// that inherits a nonce cannot replay it. This component really does remount
|
|
284
|
-
// — `App` returns the terminal-too-small placeholder before `AppShell` —
|
|
285
|
-
// so without the guard, shrinking the window mid-wheel and growing it back
|
|
286
|
-
// recalls a history entry with no gesture behind it.
|
|
287
|
-
const lastHistoryNonce = useRef(historyIntent?.nonce);
|
|
288
|
-
const historyNonce = historyIntent?.nonce ?? 0;
|
|
289
|
-
useEffect(() => {
|
|
290
|
-
const current = historyIntentRef.current;
|
|
291
|
-
if (!current || !isActive)
|
|
292
|
-
return;
|
|
293
|
-
if (current.nonce === lastHistoryNonce.current)
|
|
294
|
-
return;
|
|
295
|
-
lastHistoryNonce.current = current.nonce;
|
|
296
|
-
applyHistoryIntent.current(current.dir);
|
|
297
|
-
// Keyed on the nonce alone, same reasoning as `ScrollViewport`'s intent
|
|
298
|
-
// effect: `historyIntent` is a fresh object on every parent render.
|
|
299
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
300
|
-
}, [historyNonce]);
|
|
301
264
|
// --- Input handling. -----------------------------------------------------
|
|
302
265
|
useInput((input, key) => {
|
|
303
266
|
// FIRST STATEMENT, BEFORE THE POPUP BRANCH, AND IT HAS TO STAY THERE.
|
package/dist/ui/StatusBar.d.ts
CHANGED
|
@@ -88,6 +88,56 @@ interface StatusBarProps {
|
|
|
88
88
|
done: number;
|
|
89
89
|
total: number;
|
|
90
90
|
};
|
|
91
|
+
/**
|
|
92
|
+
* Live retry state (llm-api-retry-backoff §6.6), or absent when nothing is
|
|
93
|
+
* retrying — an ordinary session's bar is then unchanged.
|
|
94
|
+
*
|
|
95
|
+
* LEFT CLUSTER, after `teamActive`, and it DEGRADES. It is a run-state fact like
|
|
96
|
+
* `agents 3/5`, and the left cluster is `flexShrink={0}` so every column it takes
|
|
97
|
+
* comes out of the context gauge; below `RETRY_UI.statusCompactCols` it renders
|
|
98
|
+
* as `[r3]`.
|
|
99
|
+
*
|
|
100
|
+
* This does NOT contradict the "no `cols >= N` breakpoint" rule on `agentMode`
|
|
101
|
+
* above: that rule exists because the MODE must never be unreportable. The retry
|
|
102
|
+
* has a second, fuller home in the transcript card, which is exactly why it is
|
|
103
|
+
* the kind of readout that can afford to shrink.
|
|
104
|
+
*/
|
|
105
|
+
retryActive?: {
|
|
106
|
+
attempt: number;
|
|
107
|
+
max: number;
|
|
108
|
+
secondsLeft: number;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Render-governor rung (tui-render-performance L4). `> 0` renders a muted
|
|
112
|
+
* `eco` chip.
|
|
113
|
+
*
|
|
114
|
+
* I-L4-2 — THE GOVERNOR IS USER-VISIBLE, and this is where. A user who cannot
|
|
115
|
+
* see why the stream got chunkier will conclude the model got slower, and
|
|
116
|
+
* degrading silently is the one thing a claim of robustness cannot afford.
|
|
117
|
+
* It sits in the RIGHT cluster next to the other derived numbers and is
|
|
118
|
+
* suppressed on a narrow terminal, which is the `teamActive` treatment rather
|
|
119
|
+
* than the `agentMode` one: the mode must never be unreportable, whereas an
|
|
120
|
+
* eco chip on a 50-column terminal costs the context gauge more than it says.
|
|
121
|
+
*/
|
|
122
|
+
ecoRung?: number;
|
|
123
|
+
/**
|
|
124
|
+
* The live fast tier (fast-model-tier §6), or absent when it is off for this
|
|
125
|
+
* session — in which case an ordinary session's bar is byte-identical.
|
|
126
|
+
*
|
|
127
|
+
* RIGHT CLUSTER, next to `eco`, and it DEGRADES below
|
|
128
|
+
* `FAST_LIMITS.statusCompactCols`. This is the `teamActive` / `ecoRung`
|
|
129
|
+
* treatment rather than the `agentMode` one, and the distinction is the note
|
|
130
|
+
* on `agentMode` above: the mode must never be unreportable, whereas the fast
|
|
131
|
+
* tier has a fuller home in `/fast status` — which is the GUARANTEED reporting
|
|
132
|
+
* surface — and a chip on a 60-column terminal costs the context gauge more
|
|
133
|
+
* than it says.
|
|
134
|
+
*
|
|
135
|
+
* `inFlight` renders `fast*`, so a review that is taking a while is visible
|
|
136
|
+
* without a spinner competing with the run's own.
|
|
137
|
+
*/
|
|
138
|
+
fastActive?: {
|
|
139
|
+
inFlight: boolean;
|
|
140
|
+
};
|
|
91
141
|
}
|
|
92
142
|
export declare function StatusBar(props: StatusBarProps): React.ReactElement;
|
|
93
143
|
export {};
|
package/dist/ui/StatusBar.js
CHANGED
|
@@ -4,8 +4,12 @@ import { pickGlyphs } from './glyphs.js';
|
|
|
4
4
|
import { formatCost, formatTokens, formatDuration } from '../agent/usage.js';
|
|
5
5
|
import { buildGauge } from './gauge.js';
|
|
6
6
|
import { MODE_LABEL } from '../agent/agent-mode.js';
|
|
7
|
+
import { formatRetryChip } from '../agent/retry-view.js';
|
|
8
|
+
import { FAST_LIMITS } from '../fast/limits.js';
|
|
7
9
|
import { TEAM_LIMITS } from '../team/limits.js';
|
|
8
10
|
import { TODO_LIMITS } from '../todo/limits.js';
|
|
11
|
+
/** Below this the `eco` chip costs the context gauge more than it is worth. */
|
|
12
|
+
const ECO_MIN_COLS = 72;
|
|
9
13
|
/**
|
|
10
14
|
* I-5 — DO NOT "CLEAN THIS UP". Ink short-circuits identical output at TWO
|
|
11
15
|
* gates (`ink.js:132` and `log-update.js:13`), so a fixed frame whose React
|
|
@@ -25,7 +29,7 @@ function redrawChar(nonce) {
|
|
|
25
29
|
return nonce % 2 === 0 ? ' ' : NBSP;
|
|
26
30
|
}
|
|
27
31
|
export function StatusBar(props) {
|
|
28
|
-
const { model, provider, usageTotal, contextTokens, contextWindow, contextWindowKnown, status, elapsedMs, thinkingLevel, tokPerSec, theme, caps, scrolledLines = 0, redrawNonce = 0, agentMode = 'build', pendingAgentMode = null, teamActive, todoActive, } = props;
|
|
32
|
+
const { model, provider, usageTotal, contextTokens, contextWindow, contextWindowKnown, status, elapsedMs, thinkingLevel, tokPerSec, theme, caps, scrolledLines = 0, redrawNonce = 0, agentMode = 'build', pendingAgentMode = null, teamActive, todoActive, retryActive, ecoRung = 0, fastActive, } = props;
|
|
29
33
|
const { stdout } = useStdout();
|
|
30
34
|
const cols = stdout?.columns ?? 80;
|
|
31
35
|
const running = status === 'running';
|
|
@@ -51,7 +55,7 @@ export function StatusBar(props) {
|
|
|
51
55
|
// land in one predictable place.
|
|
52
56
|
_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", flexShrink: 0, children: [_jsxs(Box, { flexDirection: "row", flexShrink: 0, children: [_jsxs(Text, { color: running ? theme.toolRunning : theme.toolDone, children: [redrawChar(redrawNonce), statusGlyph, " ", running ? 'running' : 'idle'] }), modeWord && (_jsxs(Text, { color: theme.accent, bold: true, children: [' ', modeWord] })), teamActive && (_jsxs(Text, { color: theme.toolRunning, bold: true, children: [' ', cols >= TEAM_LIMITS.statusCompactCols
|
|
53
57
|
? `agents ${teamActive.running}/${teamActive.total}`
|
|
54
|
-
: `[${teamActive.running}]`] })), todoActive && (_jsxs(Text, { color: theme.accent, children: [' ', cols >= TODO_LIMITS.statusCompactCols
|
|
58
|
+
: `[${teamActive.running}]`] })), retryActive && (_jsxs(Text, { color: theme.noticeWarn, bold: true, children: [' ', formatRetryChip(retryActive, cols)] })), todoActive && (_jsxs(Text, { color: theme.accent, children: [' ', cols >= TODO_LIMITS.statusCompactCols
|
|
55
59
|
? `todo ${todoActive.done}/${todoActive.total}`
|
|
56
|
-
: `[${todoActive.done}/${todoActive.total}]`] })), cols >= 60 && (_jsxs(Text, { color: theme.muted, children: [' ', provider, ":", model] })), thinkingLevel !== 'off' && cols >= 72 && (_jsxs(Text, { color: theme.accent, children: [" think:", thinkingLevel] }))] }), _jsxs(Box, { flexDirection: "row", children: [scrolledLines > 0 && (_jsxs(Text, { color: theme.noticeWarn, children: [glyphs.arrowUp, scrolledLines, ' '] })), cols >= 60 && (_jsxs(Text, { children: [_jsx(Text, { color: theme.muted, children: "[" }), _jsx(Text, { color: gauge.fillColor, children: gauge.filled }), _jsx(Text, { color: gauge.trackColor, children: gauge.empty }), _jsx(Text, { color: theme.muted, children: "] " })] })), _jsx(Text, { color: theme.muted, children: pctLabel }), cols >= 72 && _jsxs(Text, { color: theme.muted, children: [" ", tokens] }), _jsxs(Text, { color: theme.muted, children: [" ", formatCost(usageTotal.costUsd)] }), running && (_jsxs(Text, { color: theme.muted, children: [tokPerSec > 0 && cols >= 72 ? ` ${tokPerSec} tok/s` : '', " ", formatDuration(elapsedMs)] }))] })] }));
|
|
60
|
+
: `[${todoActive.done}/${todoActive.total}]`] })), cols >= 60 && (_jsxs(Text, { color: theme.muted, children: [' ', provider, ":", model] })), thinkingLevel !== 'off' && cols >= 72 && (_jsxs(Text, { color: theme.accent, children: [" think:", thinkingLevel] }))] }), _jsxs(Box, { flexDirection: "row", children: [fastActive && cols >= FAST_LIMITS.statusCompactCols && (_jsxs(Text, { color: theme.muted, children: ["fast", fastActive.inFlight ? '*' : '', ' '] })), ecoRung > 0 && cols >= ECO_MIN_COLS && (_jsxs(Text, { color: theme.muted, children: ["eco", ' '] })), scrolledLines > 0 && (_jsxs(Text, { color: theme.noticeWarn, children: [glyphs.arrowUp, scrolledLines, ' '] })), cols >= 60 && (_jsxs(Text, { children: [_jsx(Text, { color: theme.muted, children: "[" }), _jsx(Text, { color: gauge.fillColor, children: gauge.filled }), _jsx(Text, { color: gauge.trackColor, children: gauge.empty }), _jsx(Text, { color: theme.muted, children: "] " })] })), _jsx(Text, { color: theme.muted, children: pctLabel }), cols >= 72 && _jsxs(Text, { color: theme.muted, children: [" ", tokens] }), _jsxs(Text, { color: theme.muted, children: [" ", formatCost(usageTotal.costUsd)] }), running && (_jsxs(Text, { color: theme.muted, children: [tokPerSec > 0 && cols >= 72 ? ` ${tokPerSec} tok/s` : '', " ", formatDuration(elapsedMs)] }))] })] }));
|
|
57
61
|
}
|
package/dist/ui/TeamPanel.d.ts
CHANGED
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
* not mounted at all, so a session that never delegates has zero rows and zero
|
|
11
11
|
* layout shift.
|
|
12
12
|
*
|
|
13
|
-
* IT MUST BE MOUNTED
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* IT MUST BE MOUNTED IN `AppShell`'s BOTTOM CHROME (I-10), not in the middle
|
|
14
|
+
* band. The roster is transient status about the run in progress, so it belongs
|
|
15
|
+
* with the other transient rows — toast, composer, status bar — rather than
|
|
16
|
+
* inside the scrolling transcript, where it would be interleaved with history
|
|
17
|
+
* and scroll out of sight exactly when the user wants to watch it.
|
|
17
18
|
*/
|
|
18
19
|
import React from 'react';
|
|
19
20
|
import type { Theme } from './theme.js';
|
package/dist/ui/TeamPanel.js
CHANGED
|
@@ -120,7 +120,7 @@ export function TeamPanel({ snapshot, rows, cols, reducedMotion, theme, caps, no
|
|
|
120
120
|
// `reducedMotion` and a non-Unicode terminal fall back to the same
|
|
121
121
|
// static marker, exactly as `AssistantEntry` and `ToolCard` already do.
|
|
122
122
|
const animate = isRunning(run) && !reducedMotion && caps.unicode;
|
|
123
|
-
return (_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: color, children: [' ', animate ? _jsx(Spinner, { type: "dots" }) : marker(run, glyphs), ' '] }), _jsx(Text, { color: theme.primary, children: run.label.padEnd(8).slice(0, 8) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, overflow: "hidden", children: _jsx(Text, { wrap: "truncate", color: theme.muted, children: run.description }) }), _jsx(Box, { flexShrink: 1, overflow: "hidden", children: _jsxs(Text, { wrap: "truncate", color: color, children: [' ', activityLine(run, cols)] }) }), _jsxs(Text, { wrap: "truncate", color: theme.muted, children: [' ', run.startedAt ? formatDuration(Math.max(0, (run.endedAt ?? at) - run.startedAt)) : ''] })] }, run.label));
|
|
123
|
+
return (_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: color, children: [' ', animate ? _jsx(Spinner, { type: "dots" }) : marker(run, glyphs), ' '] }), _jsx(Text, { color: theme.primary, children: `${run.label}${run.tier === 'fast' ? '~' : ''}`.padEnd(8).slice(0, 8) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, overflow: "hidden", children: _jsx(Text, { wrap: "truncate", color: theme.muted, children: run.description }) }), _jsx(Box, { flexShrink: 1, overflow: "hidden", children: _jsxs(Text, { wrap: "truncate", color: color, children: [' ', activityLine(run, cols)] }) }), _jsxs(Text, { wrap: "truncate", color: theme.muted, children: [' ', run.startedAt ? formatDuration(Math.max(0, (run.endedAt ?? at) - run.startedAt)) : ''] })] }, run.label));
|
|
124
124
|
}), hiddenTotal > 0 && (_jsxs(Text, { wrap: "truncate", color: theme.muted, children: [' ', "+", hiddenTotal, " more", hiddenRunning > 0 ? ` (${hiddenRunning} running)` : ''] })), snapshot.lastMessage && (_jsxs(Text, { wrap: "truncate", color: theme.muted, children: [' ', glyphs.teamMail, " ", snapshot.lastMessage.from, " ", glyphs.arrowRight, " ", snapshot.lastMessage.to, ": ", snapshot.lastMessage.subject] }))] }));
|
|
125
125
|
}
|
|
126
126
|
function marker(run, glyphs) {
|
package/dist/ui/TodoPanel.d.ts
CHANGED
|
@@ -8,10 +8,11 @@
|
|
|
8
8
|
* this component is not rendered at all, so a session that never plans has zero
|
|
9
9
|
* columns and zero layout shift (R-g's "no furniture when idle" / AC-24).
|
|
10
10
|
*
|
|
11
|
-
* IT MUST BE MOUNTED IN `AppShell`'s MIDDLE BAND, NEVER
|
|
12
|
-
* (C-6 / I-4).
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* IT MUST BE MOUNTED IN `AppShell`'s MIDDLE BAND, NEVER IN THE BOTTOM CHROME
|
|
12
|
+
* (C-6 / I-4). This is a COLUMN BESIDE the viewport, and the middle band is the
|
|
13
|
+
* only row-wrapped region there is; moved down into the bottom chrome it would
|
|
14
|
+
* stop being a rail and start eating viewport height, growing and shrinking the
|
|
15
|
+
* transcript every time the list changed length.
|
|
15
16
|
*
|
|
16
17
|
* WIDTH IS MEASURED IN COLUMNS, NEVER IN CODE UNITS (P2-3). This rail is 18-36
|
|
17
18
|
* columns wide and the system prompt's last line is "Respond in the language the
|
package/dist/ui/Transcript.d.ts
CHANGED
|
@@ -15,12 +15,23 @@
|
|
|
15
15
|
* parallel product. What inline still guarantees is its GEOMETRY contract — no
|
|
16
16
|
* fixed frame, `<Static>` keeps the settled history, no private ANSI — not its
|
|
17
17
|
* pixel-for-pixel appearance.
|
|
18
|
+
*
|
|
19
|
+
* Two things changed with tui-render-performance:
|
|
20
|
+
* - `EntryView` is `React.memo`'d with an explicit comparator (L2 / R3), which
|
|
21
|
+
* is only worth anything because `mapEntry` already preserves object
|
|
22
|
+
* identity for untouched entries;
|
|
23
|
+
* - `TranscriptList` (the FULL-SCREEN body) mounts only the entries inside the
|
|
24
|
+
* viewport and replaces the rest with two spacer boxes (L3 / R1), and the
|
|
25
|
+
* inline `Transcript` clamps its live region so `ink.js:121` is unreachable
|
|
26
|
+
* (L5 / R6).
|
|
18
27
|
*/
|
|
19
28
|
import React from 'react';
|
|
20
29
|
import { type Theme } from './theme.js';
|
|
21
30
|
import type { TermCapabilities } from './capabilities.js';
|
|
22
31
|
import { type DensityMode } from './density.js';
|
|
23
32
|
import type { Entry } from '../agent/reducer.js';
|
|
33
|
+
import type { RenderMode } from './layout/frame.js';
|
|
34
|
+
import type { HeightStore } from './use-height-store.js';
|
|
24
35
|
/**
|
|
25
36
|
* Largest prefix length P such that `entries[0..P)` are all terminal, none is
|
|
26
37
|
* within the last `LIVE_TAIL` entries, and none is currently expanded. Pure and
|
|
@@ -34,9 +45,60 @@ interface TranscriptProps {
|
|
|
34
45
|
thinkingVisible: boolean;
|
|
35
46
|
reducedMotion: boolean;
|
|
36
47
|
density: DensityMode;
|
|
48
|
+
/**
|
|
49
|
+
* The render mode, threaded from `App` as a plain scalar prop.
|
|
50
|
+
*
|
|
51
|
+
* It decides whether the collapsed thinking marker may offer `ctrl+t` (D-16):
|
|
52
|
+
* inline prints settled entries into `<Static>`, which cannot re-print them.
|
|
53
|
+
* NOT read from a module-level singleton — `render-memo.test.tsx` asserts prop
|
|
54
|
+
* stability across frames, and a hidden read would be invisible to it.
|
|
55
|
+
*/
|
|
56
|
+
mode: RenderMode;
|
|
57
|
+
/**
|
|
58
|
+
* Wall-clock seconds, threaded from `App`'s existing 200 ms ticker, for the
|
|
59
|
+
* live tool card's stall row (agent-activity-presentation-live §3.3.4 / D-36).
|
|
60
|
+
*
|
|
61
|
+
* BOTH MAP CALLBACKS BELOW DECIDE PER ENTRY WHETHER TO PASS IT ON, and neither
|
|
62
|
+
* may pass it unconditionally: `ToolCard` is `React.memo` with the default
|
|
63
|
+
* comparator, so a prop that changes every second on every card would defeat
|
|
64
|
+
* that boundary for the whole transcript.
|
|
65
|
+
*/
|
|
66
|
+
nowSec?: number;
|
|
37
67
|
theme: Theme;
|
|
38
68
|
caps: TermCapabilities;
|
|
39
69
|
}
|
|
70
|
+
export interface EntryViewProps {
|
|
71
|
+
entry: Entry;
|
|
72
|
+
/** Previous entry in the list; `undefined` for the first item. */
|
|
73
|
+
prev: Entry | undefined;
|
|
74
|
+
expanded: boolean;
|
|
75
|
+
thinkingVisible: boolean;
|
|
76
|
+
reducedMotion: boolean;
|
|
77
|
+
density: DensityMode;
|
|
78
|
+
mode: RenderMode;
|
|
79
|
+
theme: Theme;
|
|
80
|
+
caps: TermCapabilities;
|
|
81
|
+
/** Inline mode only (L5); `undefined` in full-screen, which means no clamp. */
|
|
82
|
+
liveClampRows?: number;
|
|
83
|
+
/** Wall-clock seconds; set ONLY on a running tool entry (§3.3.4 / P1-3). */
|
|
84
|
+
nowSec?: number;
|
|
85
|
+
}
|
|
86
|
+
declare function EntryViewImpl({ entry, prev, expanded, thinkingVisible, reducedMotion, density, mode, theme, caps, liveClampRows, nowSec, }: EntryViewProps): React.ReactElement | null;
|
|
87
|
+
/**
|
|
88
|
+
* THE memo boundary that makes a long transcript cheap (L2 / R3).
|
|
89
|
+
*
|
|
90
|
+
* The comparator is written out rather than defaulted because `prev` is the one
|
|
91
|
+
* prop whose identity matters for a reason the type does not show: it feeds
|
|
92
|
+
* `separationRows`, so an entry whose PREDECESSOR changed kind must re-render
|
|
93
|
+
* even though the entry itself did not.
|
|
94
|
+
*
|
|
95
|
+
* I-L2-1 — `theme` and `caps` are `useMemo`d in `App.tsx` and are therefore
|
|
96
|
+
* referentially stable across frames. If a future change makes either a fresh
|
|
97
|
+
* object per render, EVERY boundary below becomes a no-op AND NOTHING FAILS;
|
|
98
|
+
* `render-memo.test.tsx` asserts that stability directly so the trap is a red
|
|
99
|
+
* test rather than a silent regression.
|
|
100
|
+
*/
|
|
101
|
+
export declare const EntryView: React.MemoExoticComponent<typeof EntryViewImpl>;
|
|
40
102
|
/**
|
|
41
103
|
* Full-screen transcript body — the same entry renderers with NO `<Static>`.
|
|
42
104
|
*
|
|
@@ -51,12 +113,25 @@ interface TranscriptProps {
|
|
|
51
113
|
* mark feeds nothing else — `/save` serializes `entries` in full — so leaving it
|
|
52
114
|
* un-advanced has no side effect.
|
|
53
115
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
116
|
+
* VIRTUALISED (L3 / R1). `windowSize` is now the SCROLL HORIZON — how far back
|
|
117
|
+
* the user can scroll — and no longer the rendering budget, because entries
|
|
118
|
+
* outside the viewport are not mounted at all. What bounds the frame is
|
|
119
|
+
* `selectWindow`, and the two spacers are what keep the scroll maths honest
|
|
120
|
+
* while they are absent.
|
|
57
121
|
*/
|
|
58
|
-
export declare function TranscriptList({ entries, expandedToolIds, thinkingVisible, reducedMotion, density, theme, caps, windowSize, }: TranscriptProps & {
|
|
122
|
+
export declare function TranscriptList({ entries, expandedToolIds, thinkingVisible, reducedMotion, density, mode, nowSec, theme, caps, windowSize, cols, heights, mountedSink, }: TranscriptProps & {
|
|
59
123
|
windowSize: number;
|
|
124
|
+
/** The viewport's own width — narrower than the terminal when the rail is up. */
|
|
125
|
+
cols: number;
|
|
126
|
+
heights: HeightStore;
|
|
127
|
+
/**
|
|
128
|
+
* Written during render with the number of entries actually mounted, for
|
|
129
|
+
* `/perf` (AC-9). A ref rather than a callback: a `setState` here would make
|
|
130
|
+
* observing the render budget cost a render.
|
|
131
|
+
*/
|
|
132
|
+
mountedSink?: {
|
|
133
|
+
current: number;
|
|
134
|
+
};
|
|
60
135
|
}): React.ReactElement;
|
|
61
|
-
export declare function Transcript({ entries, expandedToolIds, thinkingVisible, reducedMotion, density, theme, caps, }: TranscriptProps): React.ReactElement;
|
|
136
|
+
export declare function Transcript({ entries, expandedToolIds, thinkingVisible, reducedMotion, density, mode, nowSec, theme, caps, }: TranscriptProps): React.ReactElement;
|
|
62
137
|
export {};
|