praxis-agent 0.21.4 → 0.21.6
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/dist/cli/interactive.js
CHANGED
|
@@ -16,7 +16,7 @@ import { loadTuiMemoryFiles, openTuiMemoryFolder, } from './tui/memory-files.js'
|
|
|
16
16
|
import { loadClaudeReleaseNotes } from './tui/release-notes.js';
|
|
17
17
|
import { StreamingFrameBuffer } from './tui/streaming-frame-buffer.js';
|
|
18
18
|
import { createClaudeStatusLineInput, StatusLine } from './tui/status-line.js';
|
|
19
|
-
import { FULLSCREEN_TRANSCRIPT_RESERVED_ROWS, projectTranscriptTail, } from './tui/transcript-viewport.js';
|
|
19
|
+
import { FULLSCREEN_TRANSCRIPT_RESERVED_ROWS, projectTranscriptTail, projectTranscriptWindow, transcriptLineCount, } from './tui/transcript-viewport.js';
|
|
20
20
|
import { loadGitDiff, visiblePatchLines, } from './tui/git-diff.js';
|
|
21
21
|
import { addTuiPermissionRule, loadTuiPermissionRules, removeTuiPermissionRule, } from './tui/permission-settings.js';
|
|
22
22
|
import { createRecentlyDeniedStore, } from './tui/recently-denied.js';
|
|
@@ -431,6 +431,7 @@ export function InteractiveApp({ factory, initialSessions, initialPrompt, initia
|
|
|
431
431
|
const [costUsd, setCostUsd] = useState();
|
|
432
432
|
const [contextWindowTokens, setContextWindowTokens] = useState(display.contextWindowTokens);
|
|
433
433
|
const [history, setHistory] = useState([...initialHistory]);
|
|
434
|
+
const [transcriptScrollOffset, setTranscriptScrollOffset] = useState(0);
|
|
434
435
|
// Startup diagnostics are useful before the first prompt, but they are not
|
|
435
436
|
// conversation history and must not suppress the new-session welcome panel.
|
|
436
437
|
// Only real user/assistant transcript entries start a conversation; every
|
|
@@ -453,7 +454,9 @@ export function InteractiveApp({ factory, initialSessions, initialPrompt, initia
|
|
|
453
454
|
// stream visible. Classic and screen-reader modes always render the full
|
|
454
455
|
// history exactly as before.
|
|
455
456
|
const projectedHistory = fixedViewport && !axScreenReader
|
|
456
|
-
?
|
|
457
|
+
? transcriptScrollOffset > 0
|
|
458
|
+
? projectTranscriptWindow(history, Math.max(1, (rows ?? 0) - FULLSCREEN_TRANSCRIPT_RESERVED_ROWS), width, transcriptScrollOffset)
|
|
459
|
+
: projectTranscriptTail(history, Math.max(1, (rows ?? 0) - FULLSCREEN_TRANSCRIPT_RESERVED_ROWS), width)
|
|
457
460
|
: history;
|
|
458
461
|
const sessionLoadRef = useRef(0);
|
|
459
462
|
const [turnDiffs, setTurnDiffs] = useState([]);
|
|
@@ -721,6 +724,7 @@ export function InteractiveApp({ factory, initialSessions, initialPrompt, initia
|
|
|
721
724
|
// transcript state so the active stream never renders below a tool,
|
|
722
725
|
// thinking, or completion entry that it textually precedes.
|
|
723
726
|
streamingFrameRef.current?.flush();
|
|
727
|
+
setTranscriptScrollOffset(0);
|
|
724
728
|
setHistory((current) => [...current, line]);
|
|
725
729
|
};
|
|
726
730
|
useEffect(() => {
|
|
@@ -2590,6 +2594,7 @@ export function InteractiveApp({ factory, initialSessions, initialPrompt, initia
|
|
|
2590
2594
|
void restoring.finally(() => onTurnChange?.(null));
|
|
2591
2595
|
};
|
|
2592
2596
|
const submit = async (prompt, shellCommand, images = []) => {
|
|
2597
|
+
setTranscriptScrollOffset(0);
|
|
2593
2598
|
const turnNumber = turnNumberRef.current + 1;
|
|
2594
2599
|
const turnStartedAt = Date.now();
|
|
2595
2600
|
turnNumberRef.current = turnNumber;
|
|
@@ -2898,6 +2903,33 @@ export function InteractiveApp({ factory, initialSessions, initialPrompt, initia
|
|
|
2898
2903
|
return;
|
|
2899
2904
|
}
|
|
2900
2905
|
const isKeybinding = (action) => keybindingAction === action;
|
|
2906
|
+
if (fixedViewport &&
|
|
2907
|
+
menuRef.current === null &&
|
|
2908
|
+
!permission &&
|
|
2909
|
+
!planApproval &&
|
|
2910
|
+
!question &&
|
|
2911
|
+
!elicitation &&
|
|
2912
|
+
!selectingSession) {
|
|
2913
|
+
const page = Math.max(1, (rows ?? 0) - FULLSCREEN_TRANSCRIPT_RESERVED_ROWS);
|
|
2914
|
+
const scrollDelta = key.pageUp
|
|
2915
|
+
? page
|
|
2916
|
+
: key.pageDown
|
|
2917
|
+
? -page
|
|
2918
|
+
: controlKey('u') || controlKey('b')
|
|
2919
|
+
? page / 2
|
|
2920
|
+
: controlKey('f') || controlKey('n')
|
|
2921
|
+
? -page / 2
|
|
2922
|
+
: inputRef.current.length === 0 && key.upArrow
|
|
2923
|
+
? 1
|
|
2924
|
+
: inputRef.current.length === 0 && key.downArrow
|
|
2925
|
+
? -1
|
|
2926
|
+
: 0;
|
|
2927
|
+
if (scrollDelta !== 0) {
|
|
2928
|
+
setTranscriptScrollOffset((current) => Math.min(Math.max(0, transcriptLineCount(history, width) -
|
|
2929
|
+
Math.max(1, (rows ?? 0) - FULLSCREEN_TRANSCRIPT_RESERVED_ROWS)), Math.max(0, current + Math.trunc(scrollDelta))));
|
|
2930
|
+
return;
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2901
2933
|
if (runtimeSettingsRef.current.editor === 'vim' &&
|
|
2902
2934
|
!permission &&
|
|
2903
2935
|
!planApproval &&
|
|
@@ -5691,7 +5723,7 @@ export function InteractiveApp({ factory, initialSessions, initialPrompt, initia
|
|
|
5691
5723
|
minHeight: 0,
|
|
5692
5724
|
overflowY: 'hidden',
|
|
5693
5725
|
}
|
|
5694
|
-
: {}), children: _jsx(Transcript, { items: projectedHistory, activeText: activeText, activeThinking: activeThinking, thinkingExpanded: thinkingExpanded, detailedTranscript: thinkingExpanded || runtimeSettings.verbose, screenReader: axScreenReader }) }), externalEditorRequest !== null ||
|
|
5726
|
+
: {}), children: _jsx(Transcript, { items: projectedHistory, activeText: activeText, activeThinking: activeThinking, activeStreamVisible: transcriptScrollOffset === 0, thinkingExpanded: thinkingExpanded, detailedTranscript: thinkingExpanded || runtimeSettings.verbose, screenReader: axScreenReader }) }), externalEditorRequest !== null ||
|
|
5695
5727
|
keybindingsEditing ||
|
|
5696
5728
|
memoryEditorRequest !== null ? (_jsx(ExternalEditorWait, { screenReader: axScreenReader })) : permission ? (permission.kind === 'tool' && toolPermissionModel ? (_jsx(ToolPermissionDialog, { model: toolPermissionModel, selection: permissionSelection, feedbackMode: permissionFeedbackMode, feedback: input, ruleEditor: permissionRuleEditor, screenReader: axScreenReader })) : (_jsxs(DialogFrame, { title: `Retry interrupted ${permission.call.name}?`, screenReader: axScreenReader, children: [_jsx(Box, { flexDirection: "column", paddingX: 1, paddingY: 1, children: _jsx(Text, { bold: true, children: describeTool(permission.call, sensitiveValues) }) }), _jsx(Text, { children: "Do you want to proceed?" }), _jsxs(Text, { inverse: !axScreenReader && permissionSelection === 0, children: [selectionPrefix(permissionSelection === 0, axScreenReader), "1. Yes"] }), _jsxs(Text, { inverse: !axScreenReader && permissionSelection === 1, children: [selectionPrefix(permissionSelection === 1, axScreenReader), "2. No"] }), permissionFeedbackMode ? (_jsxs(Text, { children: ["\u203A", ' ', input ||
|
|
5697
5729
|
(permissionSelection === 0
|
|
@@ -90,10 +90,11 @@ export declare function activeStreamWindow(text: string): {
|
|
|
90
90
|
pendingText: string;
|
|
91
91
|
truncated: boolean;
|
|
92
92
|
};
|
|
93
|
-
export declare function Transcript({ items, activeText, activeThinking, thinkingExpanded, detailedTranscript, screenReader, }: {
|
|
93
|
+
export declare function Transcript({ items, activeText, activeThinking, activeStreamVisible, thinkingExpanded, detailedTranscript, screenReader, }: {
|
|
94
94
|
items: readonly TranscriptItem[];
|
|
95
95
|
activeText: string;
|
|
96
96
|
activeThinking?: string;
|
|
97
|
+
activeStreamVisible?: boolean;
|
|
97
98
|
thinkingExpanded?: boolean;
|
|
98
99
|
detailedTranscript?: boolean;
|
|
99
100
|
screenReader: boolean;
|
|
@@ -511,7 +511,7 @@ function ActiveStreamText({ text }) {
|
|
|
511
511
|
const { stableText, pendingText, truncated } = activeStreamWindow(text);
|
|
512
512
|
return (_jsxs(Box, { flexDirection: "column", children: [truncated ? _jsx(Text, { dimColor: true, children: "\u2026 earlier streaming content \u2026" }) : null, stableText ? _jsx(MarkdownText, { text: stableText }) : null, pendingText ? _jsx(Text, { children: pendingText }) : null] }));
|
|
513
513
|
}
|
|
514
|
-
export function Transcript({ items, activeText, activeThinking = '', thinkingExpanded = false, detailedTranscript = false, screenReader, }) {
|
|
514
|
+
export function Transcript({ items, activeText, activeThinking = '', activeStreamVisible = true, thinkingExpanded = false, detailedTranscript = false, screenReader, }) {
|
|
515
515
|
const palette = useTuiPalette();
|
|
516
516
|
const detailed = thinkingExpanded || detailedTranscript;
|
|
517
517
|
const results = new Map(items
|
|
@@ -623,7 +623,7 @@ export function Transcript({ items, activeText, activeThinking = '', thinkingExp
|
|
|
623
623
|
return (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { dimColor: true, children: ["\u23BF ", item.text] }) }, index));
|
|
624
624
|
}
|
|
625
625
|
return (_jsxs(Text, { ...(item.kind === 'warning' ? { color: palette.error } : {}), dimColor: item.kind === 'notice', children: [item.kind === 'warning' ? '⚠ ' : '· ', item.text] }, index));
|
|
626
|
-
}), activeThinking ? (_jsx(ThinkingBlock, { text: activeThinking, active: true, expanded: detailed, screenReader: screenReader })) : activeText ? (_jsxs(Box, { marginTop: 1, children: [screenReader ? (_jsx(Text, { children: "Praxis: " })) : (_jsx(Text, { color: palette.accent, children: "\u2733 " })), screenReader ? (_jsx(MarkdownText, { text: activeText })) : (_jsx(ActiveStreamText, { text: activeText }))] })) : null] }));
|
|
626
|
+
}), activeStreamVisible && activeThinking ? (_jsx(ThinkingBlock, { text: activeThinking, active: true, expanded: detailed, screenReader: screenReader })) : activeStreamVisible && activeText ? (_jsxs(Box, { marginTop: 1, children: [screenReader ? (_jsx(Text, { children: "Praxis: " })) : (_jsx(Text, { color: palette.accent, children: "\u2733 " })), screenReader ? (_jsx(MarkdownText, { text: activeText })) : (_jsx(ActiveStreamText, { text: activeText }))] })) : null] }));
|
|
627
627
|
}
|
|
628
628
|
export function DiffDashboard({ snapshots, sourceIndex, selectedIndex, viewingFile, scrollOffset, width, screenReader, }) {
|
|
629
629
|
const palette = useTuiPalette();
|
|
@@ -19,6 +19,7 @@ export declare const TRANSCRIPT_TRUNCATION_MARKER = "\u2026";
|
|
|
19
19
|
* rather than dropping items that would actually render.
|
|
20
20
|
*/
|
|
21
21
|
export declare function estimateTranscriptLines(item: TranscriptItem, width: number): number;
|
|
22
|
+
export declare function transcriptLineCount(items: readonly TranscriptItem[], width: number): number;
|
|
22
23
|
/**
|
|
23
24
|
* Pure, deterministic suffix projector for the fullscreen transcript region.
|
|
24
25
|
*
|
|
@@ -31,4 +32,6 @@ export declare function estimateTranscriptLines(item: TranscriptItem, width: num
|
|
|
31
32
|
* that fit and the input is never mutated.
|
|
32
33
|
*/
|
|
33
34
|
export declare function projectTranscriptTail(items: readonly TranscriptItem[], budget: number, width: number): readonly TranscriptItem[];
|
|
35
|
+
/** Projects a fixed-size transcript window, measured upward from the newest row. */
|
|
36
|
+
export declare function projectTranscriptWindow(items: readonly TranscriptItem[], budget: number, width: number, scrollOffset: number): readonly TranscriptItem[];
|
|
34
37
|
//# sourceMappingURL=transcript-viewport.d.ts.map
|
|
@@ -117,6 +117,9 @@ export function estimateTranscriptLines(item, width) {
|
|
|
117
117
|
return wrappedLineCount(bounded(`${item.stdout}\n${item.stderr}`, 500), width);
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
|
+
export function transcriptLineCount(items, width) {
|
|
121
|
+
return items.reduce((total, item) => total + estimateTranscriptLines(item, width), 0);
|
|
122
|
+
}
|
|
120
123
|
/**
|
|
121
124
|
* Pure, deterministic suffix projector for the fullscreen transcript region.
|
|
122
125
|
*
|
|
@@ -153,4 +156,29 @@ export function projectTranscriptTail(items, budget, width) {
|
|
|
153
156
|
}
|
|
154
157
|
return items.slice(start);
|
|
155
158
|
}
|
|
159
|
+
/** Projects a fixed-size transcript window, measured upward from the newest row. */
|
|
160
|
+
export function projectTranscriptWindow(items, budget, width, scrollOffset) {
|
|
161
|
+
if (scrollOffset <= 0)
|
|
162
|
+
return projectTranscriptTail(items, budget, width);
|
|
163
|
+
const endRows = Math.max(0, transcriptLineCount(items, width) - scrollOffset);
|
|
164
|
+
const startRows = Math.max(0, endRows - budget);
|
|
165
|
+
let rows = 0;
|
|
166
|
+
let start = 0;
|
|
167
|
+
let end = 0;
|
|
168
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
169
|
+
const item = items[index];
|
|
170
|
+
if (!item)
|
|
171
|
+
break;
|
|
172
|
+
const nextRows = rows + estimateTranscriptLines(item, width);
|
|
173
|
+
if (nextRows <= startRows) {
|
|
174
|
+
start = index + 1;
|
|
175
|
+
}
|
|
176
|
+
if (rows < endRows)
|
|
177
|
+
end = index + 1;
|
|
178
|
+
rows = nextRows;
|
|
179
|
+
if (rows >= endRows)
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
return items.slice(start, end);
|
|
183
|
+
}
|
|
156
184
|
//# sourceMappingURL=transcript-viewport.js.map
|