praxis-agent 0.34.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/dist/application/background-agent-manager.d.ts +16 -6
- package/dist/application/background-agent-manager.js +139 -97
- package/dist/application/context-engine.d.ts +56 -0
- package/dist/application/context-engine.js +129 -0
- package/dist/application/session-service.d.ts +8 -5
- package/dist/application/session-service.js +1824 -1728
- package/dist/application/subagent-service.js +385 -193
- package/dist/application/top-level-agent-manager.d.ts +1 -0
- package/dist/application/top-level-agent-manager.js +1025 -403
- package/dist/application/transcript-projection.d.ts +33 -0
- package/dist/application/transcript-projection.js +110 -0
- package/dist/application/turn-lifecycle.d.ts +40 -0
- package/dist/application/turn-lifecycle.js +36 -0
- package/dist/application/turn-memory-coordinator.d.ts +43 -0
- package/dist/application/turn-memory-coordinator.js +98 -0
- package/dist/cli/agents-dashboard.js +10 -5
- package/dist/cli/interactive.js +279 -209
- package/dist/cli/protocol.js +5 -2
- package/dist/cli/tui/claude-style.d.ts +5 -48
- package/dist/cli/tui/claude-style.js +167 -197
- package/dist/cli/tui/task-panel.js +10 -1
- package/dist/cli/tui/theme.d.ts +46 -3
- package/dist/cli/tui/theme.js +414 -56
- package/dist/cli/tui/tool-permission.js +9 -5
- package/dist/cli/tui/transcript-presentation.d.ts +89 -0
- package/dist/cli/tui/transcript-presentation.js +169 -0
- package/dist/cli/tui/transcript-viewport.d.ts +5 -34
- package/dist/cli/tui/transcript-viewport.js +639 -158
- package/dist/cli/tui/tui-interaction-router.d.ts +78 -0
- package/dist/cli/tui/tui-interaction-router.js +127 -0
- package/dist/cli/tui/tui-view-model.d.ts +6 -2
- package/dist/cli/tui/tui-view-model.js +23 -6
- package/dist/cli-runtime.d.ts +2 -2
- package/dist/compatibility/claude/context.d.ts +2 -2
- package/dist/compatibility/claude/context.js +2 -14
- package/dist/compatibility/claude/data-plane-adapter.d.ts +9 -0
- package/dist/compatibility/claude/data-plane-adapter.js +44 -0
- package/dist/compatibility/claude/paths.js +2 -2
- package/dist/compatibility/claude/shared-resources.d.ts +7 -38
- package/dist/compatibility/claude/transcript-codec.d.ts +21 -0
- package/dist/compatibility/claude/transcript-codec.js +512 -0
- package/dist/core/agent-orchestration.d.ts +31 -0
- package/dist/core/agent-orchestration.js +235 -0
- package/dist/core/context.d.ts +25 -7
- package/dist/core/context.js +46 -0
- package/dist/core/prompt-composer.d.ts +8 -16
- package/dist/core/prompt-composer.js +65 -25
- package/dist/core/resources.d.ts +39 -0
- package/dist/core/resources.js +2 -0
- package/dist/core/runtime.d.ts +6 -1
- package/dist/core/runtime.js +15 -1
- package/dist/core/session.d.ts +2 -0
- package/dist/core/session.js +5 -0
- package/dist/core/transcript-codec.d.ts +70 -0
- package/dist/core/transcript-codec.js +60 -0
- package/dist/core/transcript-event.d.ts +33 -0
- package/dist/core/transcript-event.js +198 -0
- package/dist/persistence/claude-job-store.d.ts +58 -0
- package/dist/persistence/claude-job-store.js +483 -1
- package/dist/persistence/data-plane-adapter.d.ts +32 -0
- package/dist/persistence/data-plane-adapter.js +2 -0
- package/dist/persistence/data-plane.d.ts +4 -20
- package/dist/persistence/data-plane.js +10 -47
- package/dist/persistence/native-data-plane-adapter.d.ts +9 -0
- package/dist/persistence/native-data-plane-adapter.js +39 -0
- package/dist/persistence/native-resources.d.ts +4 -4
- package/dist/persistence/native-transcript-codec.d.ts +13 -0
- package/dist/persistence/native-transcript-codec.js +102 -0
- package/dist/persistence/native-transcript-reader.d.ts +53 -0
- package/dist/persistence/native-transcript-reader.js +283 -0
- package/dist/persistence/subagent-lifecycle-store.d.ts +41 -8
- package/dist/persistence/subagent-lifecycle-store.js +373 -146
- package/dist/platform/exclusive-file-lease.d.ts +3 -0
- package/dist/platform/exclusive-file-lease.js +3 -0
- package/dist/tools/claude-user-message.d.ts +0 -1
- package/dist/tools/claude-user-message.js +0 -1
- package/package.json +6 -2
package/dist/cli/interactive.js
CHANGED
|
@@ -18,7 +18,6 @@ import { loadClaudeReleaseNotes } from './tui/release-notes.js';
|
|
|
18
18
|
import { fullscreenInkRenderOptions } from './tui/fullscreen-renderer.js';
|
|
19
19
|
import { StreamingFrameBuffer } from './tui/streaming-frame-buffer.js';
|
|
20
20
|
import { createClaudeStatusLineInput, StatusLine } from './tui/status-line.js';
|
|
21
|
-
import { FULLSCREEN_TRANSCRIPT_RESERVED_ROWS, transcriptLineCount, } from './tui/transcript-viewport.js';
|
|
22
21
|
import { projectTuiView, resolveTuiRenderer } from './tui/tui-view-model.js';
|
|
23
22
|
import { loadGitDiff, visiblePatchLines, } from './tui/git-diff.js';
|
|
24
23
|
import { addTuiPermissionRule, loadTuiPermissionRules, removeTuiPermissionRule, } from './tui/permission-settings.js';
|
|
@@ -27,18 +26,19 @@ import { agentColorMessage, parseAgentColorInput, } from '../compatibility/claud
|
|
|
27
26
|
import { filterTuiSlashCommands, mergeTuiSlashCommands, slashCommandQuery, } from './tui/slash-commands.js';
|
|
28
27
|
import { runDoctor, } from '../maintenance/doctor.js';
|
|
29
28
|
import { canonicalClaudeCostModelName, formatCostSummary, } from './tui/cost-summary.js';
|
|
30
|
-
import { createComposerEditor, deleteComposerBackward, deleteComposerForward,
|
|
29
|
+
import { createComposerEditor, deleteComposerBackward, deleteComposerForward, insertComposerText, moveComposerCursor, } from './tui/composer-editor.js';
|
|
31
30
|
import { routeComposerKey, } from './tui/composer-key-router.js';
|
|
31
|
+
import { routeTuiInteraction, } from './tui/tui-interaction-router.js';
|
|
32
32
|
import { applyMentionReference, fileReferenceAtCursor, filterTuiMentionEntries, loadTuiFileEntries, } from './tui/file-picker.js';
|
|
33
33
|
import { editTuiPrompt, openTuiEditorFile, } from './tui/external-editor.js';
|
|
34
34
|
import { suspendTuiProcess } from './tui/terminal-suspend.js';
|
|
35
35
|
import { readTuiClipboard, writeTuiClipboard, writeTuiOsc52Clipboard, } from './tui/clipboard.js';
|
|
36
|
-
import { composerImageIds,
|
|
36
|
+
import { composerImageIds, insertComposerImageMarker, } from './tui/composer-images.js';
|
|
37
37
|
import { defaultTuiKeybindings, ensureTuiKeybindingsFile, hasTuiKeybindingPrefix, loadTuiKeybindings, resolveTuiKeybinding, tuiKeyChord, } from './tui/keybindings.js';
|
|
38
38
|
import { completeTuiWorkspaceDirectory, resolveTuiWorkspaceDirectory, } from './tui/workspace-directories.js';
|
|
39
39
|
import { conversationExportPath, conversationExportText, defaultConversationExportFilename, writeConversationExport, } from './tui/conversation-export.js';
|
|
40
40
|
import { loadTuiThemeSettings, saveTuiThemeSettings, themeSettingsWithCustomTheme, } from './tui/theme-settings.js';
|
|
41
|
-
import { DEFAULT_TUI_THEME_SETTINGS, TUI_THEMES, TuiThemeProvider,
|
|
41
|
+
import { DEFAULT_TUI_THEME_SETTINGS, TUI_THEMES, TuiThemeProvider, useTuiTheme, } from './tui/theme.js';
|
|
42
42
|
import { CUSTOM_THEME_TOKENS, createTuiCustomTheme, deleteTuiCustomTheme, loadTuiCustomThemes, updateTuiCustomTheme, } from './tui/custom-themes.js';
|
|
43
43
|
import { setupTuiTerminal, terminalSetupTuiSlashCommand, } from './tui/terminal-setup.js';
|
|
44
44
|
import { commitElicitationText, createTuiElicitationForm, elicitationFormIsValid, elicitationTextValue, expandElicitationOptions, focusedElicitationField, McpElicitationForm, McpElicitationUrl, moveElicitationFocus, moveElicitationOption, selectElicitationOption, toggleElicitationBoolean, typeaheadElicitationOption, unsetElicitationField, validateTuiElicitationForm, } from './tui/mcp-elicitation.js';
|
|
@@ -112,11 +112,6 @@ const ZERO_COST_SUMMARY = {
|
|
|
112
112
|
hasUnknownModelCost: false,
|
|
113
113
|
modelUsage: [],
|
|
114
114
|
};
|
|
115
|
-
function selectionPrefix(selected, screenReader) {
|
|
116
|
-
if (selected)
|
|
117
|
-
return screenReader ? 'Selected: ' : '❯ ';
|
|
118
|
-
return screenReader ? '' : ' ';
|
|
119
|
-
}
|
|
120
115
|
function rewindActions(point) {
|
|
121
116
|
const shared = [
|
|
122
117
|
{ action: 'summarize-from', label: 'Summarize from here' },
|
|
@@ -267,6 +262,25 @@ const HIDDEN_TUI_SLASH_COMMANDS = new Set([
|
|
|
267
262
|
'update',
|
|
268
263
|
'usage',
|
|
269
264
|
]);
|
|
265
|
+
function RewindWarning() {
|
|
266
|
+
const theme = useTuiTheme();
|
|
267
|
+
return (_jsx(Text, { ...theme.text.warning, children: "\u26A0 Rewinding does not affect files edited manually or via bash." }));
|
|
268
|
+
}
|
|
269
|
+
function ExitWarning() {
|
|
270
|
+
const theme = useTuiTheme();
|
|
271
|
+
return _jsx(Text, { ...theme.text.warning, children: "Press Ctrl-C again to exit" });
|
|
272
|
+
}
|
|
273
|
+
function DecisionOption({ selected, screenReader, children, selectedPrefix = '❯ ', unselectedPrefix = ' ', }) {
|
|
274
|
+
const theme = useTuiTheme();
|
|
275
|
+
const accessible = screenReader || theme.noColor;
|
|
276
|
+
return (_jsxs(Text, { ...(selected ? theme.text.selectedRow : {}), children: [selected
|
|
277
|
+
? accessible
|
|
278
|
+
? 'Selected: '
|
|
279
|
+
: selectedPrefix
|
|
280
|
+
: accessible
|
|
281
|
+
? ''
|
|
282
|
+
: unselectedPrefix, children] }));
|
|
283
|
+
}
|
|
270
284
|
export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: suppliedConfigRoot, statePath: suppliedStatePath, factory, initialSessions, initialPrompt, initialHistory = [], initialSessionColor, signal, onCancel, onTurnChange, onCleanup, onRendererChange, onBackground, axScreenReader = false, allowNewSession = true, resume, display = { version: 'dev', cwd: process.cwd() }, terminalWidth, slashCommands = EMPTY_SLASH_COMMANDS, agents = EMPTY_AGENTS, allowDangerouslySkipPermissions = false, additionalDirectories = [], diffLoader, doctorLoader, fileLoader, externalEditor = editTuiPrompt, keybindingsConfigRoot, keybindingsFile = ensureTuiKeybindingsFile, keybindingsLoader = loadTuiKeybindings, keybindingsEditor = openTuiEditorFile, memoryFilesLoader, memoryEditor = openTuiEditorFile, memoryFolderOpener = openTuiMemoryFolder, suspendProcess = suspendTuiProcess, clipboardReader = readTuiClipboard, clipboardWriter = writeTuiClipboard, sideQuestionClipboardWriter = writeTuiOsc52Clipboard, exportWriter = writeConversationExport, permissionRuleStore, sandboxStore: suppliedSandboxStore, recentlyDeniedStore: suppliedRecentlyDeniedStore, terminalSetup: terminalSetupOverride, themeStore, initialThemeSettings, initialThemeLoadError, workspaceDirectoryResolver = resolveTuiWorkspaceDirectory, workspaceDirectoryCompleter = completeTuiWorkspaceDirectory, runtimeSettings: suppliedRuntimeSettings, runtimeSettingsTarget, notificationWriter, notificationDelayMs = 6_000, elicitationUrlOpener = openTuiUrl, releaseNotesLoader = (configRoot) => loadClaudeReleaseNotes({ configRoot }), settingSources, }) {
|
|
271
285
|
const { exit, suspendTerminal, waitUntilRenderFlush } = useApp();
|
|
272
286
|
const width = useTerminalWidth(terminalWidth);
|
|
@@ -346,9 +360,6 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
346
360
|
runtimeSettingsRef.current = runtimeSettings;
|
|
347
361
|
runtimeGitignoreRef.current = runtimeSettings.gitignore;
|
|
348
362
|
const [vimInsertMode, setVimInsertMode] = useState(true);
|
|
349
|
-
const activePalette = tuiPalette(TUI_THEMES.includes(themeSettings.theme)
|
|
350
|
-
? themeSettings.theme
|
|
351
|
-
: 'dark', themeSettings.syntaxHighlightingDisabled, process.env, themeSettings.customTheme);
|
|
352
363
|
const choices = useMemo(() => allowNewSession ? [null, ...initialSessions] : initialSessions, [allowNewSession, initialSessions]);
|
|
353
364
|
const [pickerIncludesNewSession, setPickerIncludesNewSession] = useState(allowNewSession);
|
|
354
365
|
const pickerIncludesNewSessionRef = useRef(allowNewSession);
|
|
@@ -450,7 +461,12 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
450
461
|
const [contextWindowTokens, setContextWindowTokens] = useState(display.contextWindowTokens);
|
|
451
462
|
const [history, setHistory] = useState([...initialHistory]);
|
|
452
463
|
const activeAttemptThinkingItemsRef = useRef([]);
|
|
453
|
-
const [transcriptScrollOffset,
|
|
464
|
+
const [transcriptScrollOffset, setTranscriptScrollOffsetState] = useState(0);
|
|
465
|
+
const transcriptScrollOffsetRef = useRef(0);
|
|
466
|
+
const setTranscriptScrollOffset = (offset) => {
|
|
467
|
+
transcriptScrollOffsetRef.current = offset;
|
|
468
|
+
setTranscriptScrollOffsetState(offset);
|
|
469
|
+
};
|
|
454
470
|
// The pure TUI view model classifies the session identity (fresh/resumed/
|
|
455
471
|
// started) and projects the rendered transcript. Startup diagnostics are
|
|
456
472
|
// useful before the first prompt, but they are not conversation history and
|
|
@@ -466,7 +482,7 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
466
482
|
// composer/status chrome intact and keeping the active stream visible.
|
|
467
483
|
// Classic and screen-reader modes always render the full history exactly as
|
|
468
484
|
// before.
|
|
469
|
-
const {
|
|
485
|
+
const { transcriptEntries, transcriptPageRows, maxTranscriptScrollOffset, resumed, freshSession, hasConversationHistory, } = useMemo(() => projectTuiView({
|
|
470
486
|
initialHistory,
|
|
471
487
|
history,
|
|
472
488
|
resume: resume !== undefined,
|
|
@@ -475,7 +491,19 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
475
491
|
rows,
|
|
476
492
|
width,
|
|
477
493
|
scrollOffset: transcriptScrollOffset,
|
|
478
|
-
|
|
494
|
+
detailedTranscript: thinkingExpanded || runtimeSettings.verbose,
|
|
495
|
+
}), [
|
|
496
|
+
initialHistory,
|
|
497
|
+
history,
|
|
498
|
+
resume,
|
|
499
|
+
fixedViewport,
|
|
500
|
+
axScreenReader,
|
|
501
|
+
rows,
|
|
502
|
+
width,
|
|
503
|
+
transcriptScrollOffset,
|
|
504
|
+
thinkingExpanded,
|
|
505
|
+
runtimeSettings.verbose,
|
|
506
|
+
]);
|
|
479
507
|
const sessionLoadRef = useRef(0);
|
|
480
508
|
const [turnDiffs, setTurnDiffs] = useState([]);
|
|
481
509
|
const turnNumberRef = useRef(0);
|
|
@@ -1141,25 +1169,6 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
1141
1169
|
exitConfirmationTimerRef.current = null;
|
|
1142
1170
|
setExitConfirmation(false);
|
|
1143
1171
|
};
|
|
1144
|
-
const armExitConfirmation = () => {
|
|
1145
|
-
if (exitConfirmation) {
|
|
1146
|
-
permissionRef.current?.resolve(false);
|
|
1147
|
-
elicitationRef.current?.resolve({ action: 'cancel' });
|
|
1148
|
-
questionRef.current?.resolve(null);
|
|
1149
|
-
planApprovalRef.current?.resolve({ behavior: 'deny' });
|
|
1150
|
-
onCancel?.();
|
|
1151
|
-
exit();
|
|
1152
|
-
return;
|
|
1153
|
-
}
|
|
1154
|
-
clearComposerInput();
|
|
1155
|
-
setExitConfirmation(true);
|
|
1156
|
-
if (exitConfirmationTimerRef.current)
|
|
1157
|
-
clearTimeout(exitConfirmationTimerRef.current);
|
|
1158
|
-
exitConfirmationTimerRef.current = setTimeout(() => {
|
|
1159
|
-
exitConfirmationTimerRef.current = null;
|
|
1160
|
-
setExitConfirmation(false);
|
|
1161
|
-
}, 1_500);
|
|
1162
|
-
};
|
|
1163
1172
|
useEffect(() => {
|
|
1164
1173
|
setCommandSelection((current) => Math.min(current, Math.max(0, matchingSlashCommands.length - 1)));
|
|
1165
1174
|
}, [matchingSlashCommands.length]);
|
|
@@ -2861,74 +2870,150 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
2861
2870
|
const codePoint = character.codePointAt(0) ?? 0;
|
|
2862
2871
|
return codePoint >= 32 && codePoint !== 127;
|
|
2863
2872
|
});
|
|
2873
|
+
const composerKey = {
|
|
2874
|
+
value,
|
|
2875
|
+
left: key.leftArrow,
|
|
2876
|
+
right: key.rightArrow,
|
|
2877
|
+
backspace: key.backspace,
|
|
2878
|
+
delete: key.delete,
|
|
2879
|
+
ctrl: key.ctrl,
|
|
2880
|
+
meta: key.meta,
|
|
2881
|
+
escape: key.escape || value === '\u001B',
|
|
2882
|
+
};
|
|
2864
2883
|
const editor = () => createComposerEditor(inputRef.current, inputCursorRef.current);
|
|
2865
2884
|
const editComposer = () => {
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
: moveComposerCursorAcrossImages(editor(), -1));
|
|
2870
|
-
return true;
|
|
2871
|
-
}
|
|
2872
|
-
if (key.rightArrow) {
|
|
2873
|
-
updateComposerEditor(key.meta
|
|
2874
|
-
? moveComposerCursorByWord(editor(), 'forward')
|
|
2875
|
-
: moveComposerCursorAcrossImages(editor(), 1));
|
|
2876
|
-
return true;
|
|
2877
|
-
}
|
|
2878
|
-
if (controlKey('a')) {
|
|
2879
|
-
updateComposerEditor(createComposerEditor(inputRef.current, 0));
|
|
2885
|
+
const transition = routeComposerKey(editor(), composerKey);
|
|
2886
|
+
if (transition.kind === 'edit') {
|
|
2887
|
+
updateComposerEditor(transition.editor);
|
|
2880
2888
|
return true;
|
|
2881
2889
|
}
|
|
2882
|
-
if (
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
}
|
|
2886
|
-
if (controlKey('b')) {
|
|
2887
|
-
updateComposerEditor(moveComposerCursorAcrossImages(editor(), -1));
|
|
2888
|
-
return true;
|
|
2889
|
-
}
|
|
2890
|
-
if (controlKey('f')) {
|
|
2891
|
-
updateComposerEditor(moveComposerCursorAcrossImages(editor(), 1));
|
|
2892
|
-
return true;
|
|
2893
|
-
}
|
|
2894
|
-
if (controlKey('w')) {
|
|
2895
|
-
updateComposerEditor(deleteComposerWordBackward(editor()));
|
|
2896
|
-
return true;
|
|
2897
|
-
}
|
|
2898
|
-
if (controlKey('u')) {
|
|
2899
|
-
updateComposerEditor(deleteComposerToStart(editor()));
|
|
2900
|
-
return true;
|
|
2901
|
-
}
|
|
2902
|
-
if (controlKey('k')) {
|
|
2903
|
-
updateComposerEditor(deleteComposerToEnd(editor()));
|
|
2904
|
-
return true;
|
|
2905
|
-
}
|
|
2906
|
-
if (key.backspace) {
|
|
2907
|
-
updateComposerEditor(deleteComposerImageBackward(editor()));
|
|
2908
|
-
return true;
|
|
2909
|
-
}
|
|
2910
|
-
if (key.delete) {
|
|
2911
|
-
updateComposerEditor(deleteComposerImageForward(editor()));
|
|
2912
|
-
return true;
|
|
2913
|
-
}
|
|
2914
|
-
if (!key.ctrl && !key.meta && value && printable) {
|
|
2915
|
-
updateComposerEditor(insertComposerText(editor(), value));
|
|
2916
|
-
return true;
|
|
2917
|
-
}
|
|
2918
|
-
return false;
|
|
2890
|
+
if (transition.kind === 'cancel')
|
|
2891
|
+
clearComposerInput();
|
|
2892
|
+
return transition.kind === 'cancel';
|
|
2919
2893
|
};
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2894
|
+
const interactionComposer = () => ({
|
|
2895
|
+
mode: runtimeSettingsRef.current.editor === 'vim'
|
|
2896
|
+
? vimInsertMode
|
|
2897
|
+
? 'vim-insert'
|
|
2898
|
+
: 'vim-normal'
|
|
2899
|
+
: 'readline',
|
|
2900
|
+
editor: editor(),
|
|
2901
|
+
lastCancelAtMs: lastEscapeAtRef.current,
|
|
2902
|
+
});
|
|
2903
|
+
const applyInteractionEffects = (effects) => {
|
|
2904
|
+
for (const effect of effects) {
|
|
2905
|
+
if (effect.kind === 'request-process-suspension') {
|
|
2906
|
+
processSuspendRequestedRef.current = true;
|
|
2907
|
+
setProcessSuspendRequested(true);
|
|
2908
|
+
}
|
|
2909
|
+
else if (effect.kind === 'set-transcript-scroll-offset') {
|
|
2910
|
+
setTranscriptScrollOffset(effect.offset);
|
|
2911
|
+
}
|
|
2912
|
+
else if (effect.kind === 'interrupt-turn') {
|
|
2913
|
+
turnControllerRef.current?.abort();
|
|
2914
|
+
}
|
|
2915
|
+
else if (effect.kind === 'arm-exit-confirmation') {
|
|
2916
|
+
setExitConfirmation(true);
|
|
2917
|
+
if (exitConfirmationTimerRef.current)
|
|
2918
|
+
clearTimeout(exitConfirmationTimerRef.current);
|
|
2919
|
+
exitConfirmationTimerRef.current = setTimeout(() => {
|
|
2920
|
+
exitConfirmationTimerRef.current = null;
|
|
2921
|
+
setExitConfirmation(false);
|
|
2922
|
+
}, 1_500);
|
|
2923
|
+
}
|
|
2924
|
+
else if (effect.kind === 'dismiss-exit-confirmation') {
|
|
2925
|
+
dismissExitConfirmation();
|
|
2926
|
+
}
|
|
2927
|
+
else if (effect.kind === 'exit-application') {
|
|
2928
|
+
permissionRef.current?.resolve(false);
|
|
2929
|
+
elicitationRef.current?.resolve({ action: 'cancel' });
|
|
2930
|
+
questionRef.current?.resolve(null);
|
|
2931
|
+
planApprovalRef.current?.resolve({ behavior: 'deny' });
|
|
2932
|
+
onCancel?.();
|
|
2933
|
+
exit();
|
|
2934
|
+
}
|
|
2935
|
+
else if (effect.kind === 'set-vim-insert-mode') {
|
|
2936
|
+
setVimInsertMode(effect.insert);
|
|
2937
|
+
}
|
|
2938
|
+
else if (effect.kind === 'set-composer-editor') {
|
|
2939
|
+
updateComposerEditor(effect.editor);
|
|
2940
|
+
}
|
|
2941
|
+
else if (effect.kind === 'clear-composer') {
|
|
2942
|
+
clearComposerInput();
|
|
2943
|
+
}
|
|
2944
|
+
else if (effect.kind === 'record-composer-cancel') {
|
|
2945
|
+
lastEscapeAtRef.current = effect.timestamp;
|
|
2946
|
+
}
|
|
2947
|
+
else if (effect.kind === 'cancel-tui-layer') {
|
|
2948
|
+
switch (effect.target) {
|
|
2949
|
+
case 'permission':
|
|
2950
|
+
permissionRef.current?.resolve(false);
|
|
2951
|
+
break;
|
|
2952
|
+
case 'plan-approval':
|
|
2953
|
+
planApprovalRef.current?.resolve({ behavior: 'deny' });
|
|
2954
|
+
break;
|
|
2955
|
+
case 'question':
|
|
2956
|
+
questionRef.current?.resolve(null);
|
|
2957
|
+
break;
|
|
2958
|
+
case 'elicitation-url-waiting':
|
|
2959
|
+
if (elicitationUrlWaitingRef.current) {
|
|
2960
|
+
elicitationUrlWaitingRef.current = null;
|
|
2961
|
+
setElicitationUrlWaiting(false);
|
|
2962
|
+
setElicitation(null);
|
|
2963
|
+
setElicitationForm(null);
|
|
2964
|
+
clearComposerInput();
|
|
2965
|
+
}
|
|
2966
|
+
break;
|
|
2967
|
+
case 'elicitation-options':
|
|
2968
|
+
setElicitationForm((current) => current?.expandedField
|
|
2969
|
+
? { ...current, expandedField: undefined }
|
|
2970
|
+
: current);
|
|
2971
|
+
break;
|
|
2972
|
+
case 'elicitation':
|
|
2973
|
+
elicitationRef.current?.resolve({ action: 'cancel' });
|
|
2974
|
+
break;
|
|
2975
|
+
case 'file-picker':
|
|
2976
|
+
setFilePickerOpen(false);
|
|
2977
|
+
break;
|
|
2978
|
+
case 'command-palette':
|
|
2979
|
+
setCommandPaletteOpen(false);
|
|
2980
|
+
break;
|
|
2981
|
+
default: {
|
|
2982
|
+
const unhandledTarget = effect.target;
|
|
2983
|
+
return unhandledTarget;
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
}
|
|
2987
|
+
else {
|
|
2988
|
+
const unhandledEffect = effect;
|
|
2989
|
+
return unhandledEffect;
|
|
2990
|
+
}
|
|
2928
2991
|
}
|
|
2992
|
+
};
|
|
2993
|
+
if (controlKey('c') || controlKey('z')) {
|
|
2994
|
+
const globalInteraction = routeTuiInteraction({
|
|
2995
|
+
suspensionPending: processSuspendRequestedRef.current,
|
|
2996
|
+
exitConfirmationArmed: exitConfirmation,
|
|
2997
|
+
layer: { kind: 'none' },
|
|
2998
|
+
busy,
|
|
2999
|
+
viewport: {
|
|
3000
|
+
enabled: false,
|
|
3001
|
+
offset: 0,
|
|
3002
|
+
maxOffset: 0,
|
|
3003
|
+
pageRows: 0,
|
|
3004
|
+
},
|
|
3005
|
+
composer: interactionComposer(),
|
|
3006
|
+
}, {
|
|
3007
|
+
globalIntent: controlKey('c') ? 'exit' : 'suspend',
|
|
3008
|
+
scrollIntent: 'none',
|
|
3009
|
+
action: undefined,
|
|
3010
|
+
composerKey,
|
|
3011
|
+
timestamp: Date.now(),
|
|
3012
|
+
callerIntent: 'none',
|
|
3013
|
+
});
|
|
3014
|
+
applyInteractionEffects(globalInteraction.effects);
|
|
2929
3015
|
return;
|
|
2930
3016
|
}
|
|
2931
|
-
dismissExitConfirmation();
|
|
2932
3017
|
const keybindingContexts = menuRef.current
|
|
2933
3018
|
? menuRef.current.kind === 'diff'
|
|
2934
3019
|
? ['DiffDialog']
|
|
@@ -2965,58 +3050,90 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
2965
3050
|
if (!keybindingAction) {
|
|
2966
3051
|
keybindingAction = resolveTuiKeybinding(keybindings, keybindingContexts, inputChord);
|
|
2967
3052
|
}
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
3053
|
+
const scrollIntent = key.pageUp
|
|
3054
|
+
? 'page-older'
|
|
3055
|
+
: key.pageDown
|
|
3056
|
+
? 'page-newer'
|
|
3057
|
+
: controlKey('u') || controlKey('b')
|
|
3058
|
+
? 'half-page-older'
|
|
3059
|
+
: controlKey('f') || controlKey('n')
|
|
3060
|
+
? 'half-page-newer'
|
|
3061
|
+
: inputRef.current.length === 0 && key.upArrow
|
|
3062
|
+
? 'line-older'
|
|
3063
|
+
: inputRef.current.length === 0 && key.downArrow
|
|
3064
|
+
? 'line-newer'
|
|
3065
|
+
: 'none';
|
|
3066
|
+
const hasPendingPrefix = !keybindingAction &&
|
|
3067
|
+
inputChord !== null &&
|
|
3068
|
+
hasTuiKeybindingPrefix(keybindings, keybindingContexts, inputChord);
|
|
3069
|
+
if (hasPendingPrefix) {
|
|
2971
3070
|
keySequenceRef.current = { chord: inputChord, at: Date.now() };
|
|
3071
|
+
}
|
|
3072
|
+
const layer = hasPendingPrefix
|
|
3073
|
+
? { kind: 'pending-prefix' }
|
|
3074
|
+
: permission
|
|
3075
|
+
? { kind: 'cancelable', target: 'permission' }
|
|
3076
|
+
: planApproval
|
|
3077
|
+
? { kind: 'cancelable', target: 'plan-approval' }
|
|
3078
|
+
: question
|
|
3079
|
+
? { kind: 'cancelable', target: 'question' }
|
|
3080
|
+
: elicitation
|
|
3081
|
+
? {
|
|
3082
|
+
kind: 'cancelable',
|
|
3083
|
+
target: elicitationUrlWaiting
|
|
3084
|
+
? 'elicitation-url-waiting'
|
|
3085
|
+
: elicitationForm?.expandedField
|
|
3086
|
+
? 'elicitation-options'
|
|
3087
|
+
: 'elicitation',
|
|
3088
|
+
}
|
|
3089
|
+
: selectingSession
|
|
3090
|
+
? { kind: 'delegated', target: 'session-picker' }
|
|
3091
|
+
: menuRef.current
|
|
3092
|
+
? { kind: 'delegated', target: 'menu' }
|
|
3093
|
+
: filePickerVisible
|
|
3094
|
+
? { kind: 'cancelable', target: 'file-picker' }
|
|
3095
|
+
: commandPaletteVisible
|
|
3096
|
+
? { kind: 'cancelable', target: 'command-palette' }
|
|
3097
|
+
: { kind: 'none' };
|
|
3098
|
+
const callerIntent = !busy && value === '?' && inputRef.current.length === 0
|
|
3099
|
+
? 'toggle-shortcuts'
|
|
3100
|
+
: runtimeSettingsRef.current.leftArrowOpensAgents &&
|
|
3101
|
+
key.leftArrow &&
|
|
3102
|
+
inputRef.current.length === 0 &&
|
|
3103
|
+
availableAgents.length > 0
|
|
3104
|
+
? 'open-agents'
|
|
3105
|
+
: key.return &&
|
|
3106
|
+
(key.shift || key.meta) &&
|
|
3107
|
+
keybindingAction === undefined
|
|
3108
|
+
? 'implicit-newline'
|
|
3109
|
+
: 'none';
|
|
3110
|
+
const interaction = routeTuiInteraction({
|
|
3111
|
+
suspensionPending: processSuspendRequestedRef.current,
|
|
3112
|
+
exitConfirmationArmed: exitConfirmation,
|
|
3113
|
+
layer,
|
|
3114
|
+
busy,
|
|
3115
|
+
viewport: {
|
|
3116
|
+
enabled: fixedViewport,
|
|
3117
|
+
offset: transcriptScrollOffsetRef.current,
|
|
3118
|
+
maxOffset: maxTranscriptScrollOffset,
|
|
3119
|
+
pageRows: transcriptPageRows,
|
|
3120
|
+
},
|
|
3121
|
+
composer: interactionComposer(),
|
|
3122
|
+
}, {
|
|
3123
|
+
globalIntent: 'none',
|
|
3124
|
+
scrollIntent,
|
|
3125
|
+
action: keybindingAction,
|
|
3126
|
+
composerKey,
|
|
3127
|
+
timestamp: Date.now(),
|
|
3128
|
+
callerIntent,
|
|
3129
|
+
});
|
|
3130
|
+
applyInteractionEffects(interaction.effects);
|
|
3131
|
+
if (interaction.disposition === 'handled') {
|
|
2972
3132
|
return;
|
|
2973
3133
|
}
|
|
2974
3134
|
const isKeybinding = (action) => keybindingAction === action;
|
|
2975
|
-
if (
|
|
2976
|
-
|
|
2977
|
-
!permission &&
|
|
2978
|
-
!planApproval &&
|
|
2979
|
-
!question &&
|
|
2980
|
-
!elicitation &&
|
|
2981
|
-
!selectingSession) {
|
|
2982
|
-
const page = Math.max(1, (rows ?? 0) - FULLSCREEN_TRANSCRIPT_RESERVED_ROWS);
|
|
2983
|
-
const scrollDelta = key.pageUp
|
|
2984
|
-
? page
|
|
2985
|
-
: key.pageDown
|
|
2986
|
-
? -page
|
|
2987
|
-
: controlKey('u') || controlKey('b')
|
|
2988
|
-
? page / 2
|
|
2989
|
-
: controlKey('f') || controlKey('n')
|
|
2990
|
-
? -page / 2
|
|
2991
|
-
: inputRef.current.length === 0 && key.upArrow
|
|
2992
|
-
? 1
|
|
2993
|
-
: inputRef.current.length === 0 && key.downArrow
|
|
2994
|
-
? -1
|
|
2995
|
-
: 0;
|
|
2996
|
-
if (scrollDelta !== 0) {
|
|
2997
|
-
setTranscriptScrollOffset((current) => Math.min(Math.max(0, transcriptLineCount(history, width) -
|
|
2998
|
-
Math.max(1, (rows ?? 0) - FULLSCREEN_TRANSCRIPT_RESERVED_ROWS)), Math.max(0, current + Math.trunc(scrollDelta))));
|
|
2999
|
-
return;
|
|
3000
|
-
}
|
|
3001
|
-
}
|
|
3002
|
-
if (runtimeSettingsRef.current.editor === 'vim' &&
|
|
3003
|
-
!permission &&
|
|
3004
|
-
!planApproval &&
|
|
3005
|
-
!question &&
|
|
3006
|
-
!elicitation &&
|
|
3007
|
-
menuRef.current === null) {
|
|
3008
|
-
if (!vimInsertMode) {
|
|
3009
|
-
if (value === 'i' || value === 'a')
|
|
3010
|
-
setVimInsertMode(true);
|
|
3011
|
-
else if (key.leftArrow || key.rightArrow)
|
|
3012
|
-
editComposer();
|
|
3013
|
-
return;
|
|
3014
|
-
}
|
|
3015
|
-
if (key.escape || value === '\u001B') {
|
|
3016
|
-
setVimInsertMode(false);
|
|
3017
|
-
return;
|
|
3018
|
-
}
|
|
3019
|
-
}
|
|
3135
|
+
if (hasPendingPrefix)
|
|
3136
|
+
return;
|
|
3020
3137
|
if (permission) {
|
|
3021
3138
|
const options = permission.kind === 'tool' && toolPermissionModel
|
|
3022
3139
|
? toolPermissionModel.options
|
|
@@ -3162,10 +3279,7 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
3162
3279
|
}
|
|
3163
3280
|
permission.resolve(feedback ? { behavior: 'deny', message: feedback } : false);
|
|
3164
3281
|
};
|
|
3165
|
-
if (
|
|
3166
|
-
permission.resolve(false);
|
|
3167
|
-
}
|
|
3168
|
-
else if (permissionFeedbackMode) {
|
|
3282
|
+
if (permissionFeedbackMode) {
|
|
3169
3283
|
if (key.tab) {
|
|
3170
3284
|
clearComposerInput();
|
|
3171
3285
|
setPermissionFeedbackMode(false);
|
|
@@ -3246,10 +3360,7 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
3246
3360
|
...(feedback ? { feedback } : {}),
|
|
3247
3361
|
});
|
|
3248
3362
|
};
|
|
3249
|
-
if (
|
|
3250
|
-
planApproval.resolve({ behavior: 'deny' });
|
|
3251
|
-
}
|
|
3252
|
-
else if (planApprovalFeedbackMode) {
|
|
3363
|
+
if (planApprovalFeedbackMode) {
|
|
3253
3364
|
if (key.tab) {
|
|
3254
3365
|
clearComposerInput();
|
|
3255
3366
|
setPlanApprovalFeedbackMode(false);
|
|
@@ -3286,10 +3397,7 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
3286
3397
|
return;
|
|
3287
3398
|
}
|
|
3288
3399
|
if (question) {
|
|
3289
|
-
if (key.
|
|
3290
|
-
question.resolve(null);
|
|
3291
|
-
}
|
|
3292
|
-
else if (key.return) {
|
|
3400
|
+
if (key.return) {
|
|
3293
3401
|
try {
|
|
3294
3402
|
const current = question.questions[question.index];
|
|
3295
3403
|
if (!current)
|
|
@@ -3343,13 +3451,7 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
3343
3451
|
setElicitationForm(null);
|
|
3344
3452
|
clearComposerInput();
|
|
3345
3453
|
};
|
|
3346
|
-
if (key.
|
|
3347
|
-
if (elicitationUrlWaiting)
|
|
3348
|
-
dismissUrlDialog();
|
|
3349
|
-
else
|
|
3350
|
-
elicitation.resolve({ action: 'cancel' });
|
|
3351
|
-
}
|
|
3352
|
-
else if (key.leftArrow || key.rightArrow) {
|
|
3454
|
+
if (key.leftArrow || key.rightArrow) {
|
|
3353
3455
|
setElicitationForm({
|
|
3354
3456
|
...form,
|
|
3355
3457
|
focusIndex: form.focusIndex === 0 ? 1 : 0,
|
|
@@ -3375,7 +3477,7 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
3375
3477
|
return;
|
|
3376
3478
|
}
|
|
3377
3479
|
if (form.expandedField && currentField) {
|
|
3378
|
-
if (key.
|
|
3480
|
+
if (key.leftArrow) {
|
|
3379
3481
|
setElicitationForm({ ...form, expandedField: undefined });
|
|
3380
3482
|
}
|
|
3381
3483
|
else if (key.upArrow) {
|
|
@@ -3394,9 +3496,6 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
3394
3496
|
setElicitationForm(typeaheadElicitationOption(form, value));
|
|
3395
3497
|
}
|
|
3396
3498
|
}
|
|
3397
|
-
else if (key.escape) {
|
|
3398
|
-
elicitation.resolve({ action: 'cancel' });
|
|
3399
|
-
}
|
|
3400
3499
|
else if (key.upArrow) {
|
|
3401
3500
|
move(-1);
|
|
3402
3501
|
}
|
|
@@ -5165,8 +5264,6 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
5165
5264
|
void backgrounding;
|
|
5166
5265
|
return;
|
|
5167
5266
|
}
|
|
5168
|
-
if (isKeybinding('chat:cancel'))
|
|
5169
|
-
turnControllerRef.current?.abort();
|
|
5170
5267
|
return;
|
|
5171
5268
|
}
|
|
5172
5269
|
if (isKeybinding('chat:imagePaste')) {
|
|
@@ -5182,10 +5279,6 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
5182
5279
|
return;
|
|
5183
5280
|
}
|
|
5184
5281
|
if (filePickerVisible) {
|
|
5185
|
-
if (key.escape || value === '\u001B') {
|
|
5186
|
-
setFilePickerOpen(false);
|
|
5187
|
-
return;
|
|
5188
|
-
}
|
|
5189
5282
|
if (key.upArrow) {
|
|
5190
5283
|
setFileSelection((current) => Math.max(0, current - 1));
|
|
5191
5284
|
return;
|
|
@@ -5210,13 +5303,6 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
5210
5303
|
updateMenu({ kind: 'agents', agents: availableAgents, selectedIndex: 0 });
|
|
5211
5304
|
return;
|
|
5212
5305
|
}
|
|
5213
|
-
if (isKeybinding('chat:cancel')) {
|
|
5214
|
-
const now = Date.now();
|
|
5215
|
-
if (now - lastEscapeAtRef.current <= 500)
|
|
5216
|
-
clearComposerInput();
|
|
5217
|
-
lastEscapeAtRef.current = now;
|
|
5218
|
-
return;
|
|
5219
|
-
}
|
|
5220
5306
|
if (isKeybinding('chat:cycleMode')) {
|
|
5221
5307
|
const currentIndex = permissionOptions.findIndex((option) => option.mode === runtimePreferences.permissionMode);
|
|
5222
5308
|
const next = permissionOptions[(currentIndex + 1) % permissionOptions.length];
|
|
@@ -5225,10 +5311,6 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
5225
5311
|
return;
|
|
5226
5312
|
}
|
|
5227
5313
|
if (commandPaletteVisible) {
|
|
5228
|
-
if (key.escape) {
|
|
5229
|
-
setCommandPaletteOpen(false);
|
|
5230
|
-
return;
|
|
5231
|
-
}
|
|
5232
5314
|
if (key.upArrow) {
|
|
5233
5315
|
if (matchingSlashCommands.length > 0) {
|
|
5234
5316
|
setCommandSelection((current) => Math.max(0, current - 1));
|
|
@@ -5832,24 +5914,12 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
5832
5914
|
clearComposerInput();
|
|
5833
5915
|
return;
|
|
5834
5916
|
}
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
right: key.rightArrow,
|
|
5839
|
-
backspace: key.backspace,
|
|
5840
|
-
delete: key.delete,
|
|
5841
|
-
ctrl: key.ctrl,
|
|
5842
|
-
meta: key.meta,
|
|
5843
|
-
escape: key.escape || value === '\u001B',
|
|
5844
|
-
});
|
|
5845
|
-
if (transition.kind === 'cancel') {
|
|
5846
|
-
clearComposerInput();
|
|
5847
|
-
}
|
|
5848
|
-
else if (transition.kind === 'edit') {
|
|
5849
|
-
updateComposerEditor(transition.editor);
|
|
5917
|
+
if (filePickerVisible || commandPaletteVisible) {
|
|
5918
|
+
editComposer();
|
|
5919
|
+
return;
|
|
5850
5920
|
}
|
|
5851
5921
|
});
|
|
5852
|
-
return (_jsx(TuiThemeProvider, { settings: themeSettings, children: _jsx(Box, { flexDirection: "column", ...(!fixedViewport
|
|
5922
|
+
return (_jsx(TuiThemeProvider, { settings: themeSettings, screenReader: axScreenReader, children: _jsx(Box, { flexDirection: "column", ...(!fixedViewport
|
|
5853
5923
|
? {}
|
|
5854
5924
|
: { height: rows, overflowY: 'hidden' }), children: selectingSession ? (_jsx(SessionPicker, { sessions: filteredPickerChoices, selectedIndex: selectedIndex, screenReader: axScreenReader, query: sessionSearch })) : (_jsxs(_Fragment, { children: [!axScreenReader && freshSession ? (_jsx(WelcomePanel, { display: runtimeDisplay, width: width, showTips: runtimeSettings.tips, dataPlane: dataPlane })) : null, sessionId ? (_jsxs(Text, { dimColor: true, children: ["Session ", sessionId.slice(0, 8)] })) : null, !axScreenReader && !resumed && hasConversationHistory ? (_jsx(SessionIdentity, { display: runtimeDisplay, width: width })) : null, _jsx(Box, { ...(fixedViewport
|
|
5855
5925
|
? {
|
|
@@ -5857,18 +5927,18 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
5857
5927
|
minHeight: 0,
|
|
5858
5928
|
overflowY: 'hidden',
|
|
5859
5929
|
}
|
|
5860
|
-
: {}), children: _jsx(Transcript, {
|
|
5930
|
+
: {}), children: _jsx(Transcript, { entries: transcriptEntries, activeText: activeText, activeThinking: activeThinking, activeStreamVisible: transcriptScrollOffset === 0, thinkingExpanded: thinkingExpanded, detailedTranscript: thinkingExpanded || runtimeSettings.verbose, screenReader: axScreenReader }) }), externalEditorRequest !== null ||
|
|
5861
5931
|
keybindingsEditing ||
|
|
5862
|
-
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?" }),
|
|
5932
|
+
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?" }), _jsx(DecisionOption, { selected: permissionSelection === 0, screenReader: axScreenReader, children: "1. Yes" }), _jsx(DecisionOption, { selected: permissionSelection === 1, screenReader: axScreenReader, children: "2. No" }), permissionFeedbackMode ? (_jsxs(Text, { children: ["\u203A", ' ', input ||
|
|
5863
5933
|
(permissionSelection === 0
|
|
5864
5934
|
? 'tell Praxis what to do next'
|
|
5865
5935
|
: 'tell Praxis what to do differently')] })) : null, _jsx(Text, { dimColor: true, children: permissionFeedbackMode
|
|
5866
5936
|
? 'Enter to submit · Tab to collapse · Esc to cancel'
|
|
5867
|
-
: 'Enter to confirm · Tab to add feedback · Esc to cancel' })] }))) : planApproval ? (_jsxs(DialogFrame, { title: "Ready to code?", screenReader: axScreenReader, children: [_jsx(Text, { children: "Here is Praxis's plan:" }), planApproval.request.plan ? (_jsx(Box, { borderStyle: axScreenReader ? undefined : 'classic', borderLeft: false, borderRight: false, paddingX: axScreenReader ? 0 : 1, marginY: 1, children: _jsx(Text, { children: planApproval.request.plan }) })) : null, _jsx(Text, { dimColor: true, children: "Praxis has written up a plan and is ready to execute. Would you like to proceed?" }), _jsxs(
|
|
5937
|
+
: 'Enter to confirm · Tab to add feedback · Esc to cancel' })] }))) : planApproval ? (_jsxs(DialogFrame, { title: "Ready to code?", screenReader: axScreenReader, children: [_jsx(Text, { children: "Here is Praxis's plan:" }), planApproval.request.plan ? (_jsx(Box, { borderStyle: axScreenReader ? undefined : 'classic', borderLeft: false, borderRight: false, paddingX: axScreenReader ? 0 : 1, marginY: 1, children: _jsx(Text, { children: planApproval.request.plan }) })) : null, _jsx(Text, { dimColor: true, children: "Praxis has written up a plan and is ready to execute. Would you like to proceed?" }), _jsxs(DecisionOption, { selected: planApprovalSelection === 0, screenReader: axScreenReader, children: ["1.", ' ', runtimeSettings.useAutoModeDuringPlan
|
|
5868
5938
|
? 'Yes, and use auto mode'
|
|
5869
5939
|
: allowDangerouslySkipPermissions
|
|
5870
5940
|
? 'Yes, and bypass permissions'
|
|
5871
|
-
: 'Yes, auto-accept edits'] }),
|
|
5941
|
+
: 'Yes, auto-accept edits'] }), _jsx(DecisionOption, { selected: planApprovalSelection === 1, screenReader: axScreenReader, children: "2. Yes, manually approve edits" }), _jsx(DecisionOption, { selected: planApprovalSelection === 2, screenReader: axScreenReader, children: "3. No, keep planning" }), planApprovalFeedbackMode ? (_jsxs(Text, { children: ["\u203A", ' ', input ||
|
|
5872
5942
|
(planApprovalSelection === 2
|
|
5873
5943
|
? 'Tell Praxis what to change'
|
|
5874
5944
|
: 'Add feedback for implementation')] })) : null, _jsx(Text, { dimColor: true, children: planApproval.request.planPath }), _jsx(Text, { dimColor: true, children: planApprovalFeedbackMode
|
|
@@ -5884,9 +5954,9 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
5884
5954
|
.slice(window.start, window.end)
|
|
5885
5955
|
.map((point, offset) => {
|
|
5886
5956
|
const index = window.start + offset;
|
|
5887
|
-
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
5888
|
-
|
|
5889
|
-
|
|
5957
|
+
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(DecisionOption, { selected: menu.selectedIndex === index, screenReader: axScreenReader, selectedPrefix: " \u276F ", unselectedPrefix: " ", children: point.prompt
|
|
5958
|
+
.replace(/\s+/gu, ' ')
|
|
5959
|
+
.slice(0, 72) }), _jsxs(Text, { dimColor: true, children: [' ', point.fileChanges.length > 0
|
|
5890
5960
|
? point.fileChanges
|
|
5891
5961
|
.map((path) => path.startsWith(`${runtimeCwd}/`)
|
|
5892
5962
|
? path.slice(runtimeCwd.length + 1)
|
|
@@ -5896,11 +5966,11 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
5896
5966
|
? 'No code changes'
|
|
5897
5967
|
: '⚠ No code restore'] })] }, point.messageId));
|
|
5898
5968
|
}), window.end < menu.points.length ? (_jsxs(Text, { dimColor: true, children: [' ', "\u2193 ", menu.points.length - window.end, " more below"] })) : null] }));
|
|
5899
|
-
})(),
|
|
5969
|
+
})(), _jsx(DecisionOption, { selected: menu.selectedIndex === menu.points.length, screenReader: axScreenReader, selectedPrefix: " \u276F ", unselectedPrefix: " ", children: "(current)" }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: " Enter to continue \u00B7 Esc to cancel" })] })) : menu?.kind === 'rewind-confirm' ? (_jsxs(DialogFrame, { title: "Confirm restore point", screenReader: axScreenReader, children: [_jsxs(Text, { children: ["\u2502 ", menu.point.prompt] }), _jsx(Text, { children: " " }), _jsx(Text, { children: "The conversation will be forked." }), _jsxs(Text, { children: ["The code will", ' ', menu.point.fileChanges.length > 0
|
|
5900
5970
|
? `restore ${menu.point.fileChanges.join(', ')}.`
|
|
5901
|
-
: 'be unchanged.'] }), _jsx(Text, { children: " " }), rewindActions(menu.point).map((option, index) => (_jsxs(
|
|
5971
|
+
: 'be unchanged.'] }), _jsx(Text, { children: " " }), rewindActions(menu.point).map((option, index) => (_jsxs(DecisionOption, { selected: menu.selectedIndex === index, screenReader: axScreenReader, children: [index + 1, ". ", option.label] }, option.action))), _jsx(Text, { children: " " }), _jsx(RewindWarning, {})] })) : menu?.kind === 'rewind-context' ? (_jsxs(DialogFrame, { title: `Summarize ${menu.direction === 'from' ? 'from' : 'up to'} here`, screenReader: axScreenReader, children: [_jsx(Text, { children: menu.direction === 'from'
|
|
5902
5972
|
? 'Messages after this point will be summarized.'
|
|
5903
|
-
: 'Messages up to this point will be summarized.' }), _jsx(Text, { children: " " }), _jsxs(Text, { children: ["add context (optional): ", input] }), _jsx(Text, { dimColor: true, children: "Enter to summarize \u00B7 Esc to go back" })] })) : menu?.kind === 'permission-rule-input' ? (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { bold: true, children: ["Add ", menu.behavior, " permission rule"] }), _jsx(Text, { children: "Permission rules are a tool name, optionally followed by a specifier in parentheses." }), _jsx(Text, { children: "e.g., WebFetch or Bash(ls *)" }), _jsx(Text, { children: " " }), _jsx(Box, { borderStyle: axScreenReader ? undefined : 'round', paddingX: axScreenReader ? 0 : 1, children: _jsx(Text, { ...(input ? {} : { dimColor: true }), children: input || 'Enter permission rule…' }) }), _jsx(Text, { dimColor: true, children: "Enter to submit \u00B7 Esc to cancel" })] })) : menu?.kind === 'workspace-directory-input' ? (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Add directory to workspace" }), _jsx(Text, { children: "Praxis Code will be able to read files in this directory and make edits when auto-accept edits is on." }), _jsx(Text, { children: " " }), _jsx(Text, { children: "Enter the path to the directory:" }), _jsx(Box, { borderStyle: axScreenReader ? undefined : 'round', paddingX: axScreenReader ? 0 : 1, children: _jsx(Text, { ...(input ? {} : { dimColor: true }), children: input || 'Directory path…' }) }), _jsx(Text, { dimColor: true, children: "Tab to complete \u00B7 Enter to add \u00B7 Esc to cancel" })] })) : menu?.kind === 'permission-delete' ? (_jsxs(DialogFrame, { title: permissionDeleteTitle(menu.rule.behavior), screenReader: axScreenReader, children: [_jsx(Text, { children: menu.rule.rule }), permissionRuleDescription(menu.rule.rule) ? (_jsx(Text, { dimColor: true, children: permissionRuleDescription(menu.rule.rule) })) : null, _jsx(Text, { dimColor: true, children: permissionScopeLabel(menu.rule.scope) }), _jsx(Text, { children: " " }), _jsx(Text, { children: "Are you sure you want to delete this permission rule?" }), _jsx(Text, { children: " " }),
|
|
5973
|
+
: 'Messages up to this point will be summarized.' }), _jsx(Text, { children: " " }), _jsxs(Text, { children: ["add context (optional): ", input] }), _jsx(Text, { dimColor: true, children: "Enter to summarize \u00B7 Esc to go back" })] })) : menu?.kind === 'permission-rule-input' ? (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { bold: true, children: ["Add ", menu.behavior, " permission rule"] }), _jsx(Text, { children: "Permission rules are a tool name, optionally followed by a specifier in parentheses." }), _jsx(Text, { children: "e.g., WebFetch or Bash(ls *)" }), _jsx(Text, { children: " " }), _jsx(Box, { borderStyle: axScreenReader ? undefined : 'round', paddingX: axScreenReader ? 0 : 1, children: _jsx(Text, { ...(input ? {} : { dimColor: true }), children: input || 'Enter permission rule…' }) }), _jsx(Text, { dimColor: true, children: "Enter to submit \u00B7 Esc to cancel" })] })) : menu?.kind === 'workspace-directory-input' ? (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Add directory to workspace" }), _jsx(Text, { children: "Praxis Code will be able to read files in this directory and make edits when auto-accept edits is on." }), _jsx(Text, { children: " " }), _jsx(Text, { children: "Enter the path to the directory:" }), _jsx(Box, { borderStyle: axScreenReader ? undefined : 'round', paddingX: axScreenReader ? 0 : 1, children: _jsx(Text, { ...(input ? {} : { dimColor: true }), children: input || 'Directory path…' }) }), _jsx(Text, { dimColor: true, children: "Tab to complete \u00B7 Enter to add \u00B7 Esc to cancel" })] })) : menu?.kind === 'permission-delete' ? (_jsxs(DialogFrame, { title: permissionDeleteTitle(menu.rule.behavior), screenReader: axScreenReader, children: [_jsx(Text, { children: menu.rule.rule }), permissionRuleDescription(menu.rule.rule) ? (_jsx(Text, { dimColor: true, children: permissionRuleDescription(menu.rule.rule) })) : null, _jsx(Text, { dimColor: true, children: permissionScopeLabel(menu.rule.scope) }), _jsx(Text, { children: " " }), _jsx(Text, { children: "Are you sure you want to delete this permission rule?" }), _jsx(Text, { children: " " }), _jsx(DecisionOption, { selected: menu.selectedIndex === 0, screenReader: axScreenReader, children: "1. Yes" }), _jsx(DecisionOption, { selected: menu.selectedIndex === 1, screenReader: axScreenReader, children: "2. No" }), _jsx(Text, { dimColor: true, children: "Esc to cancel" })] })) : menu?.kind === 'workspace-directory-delete' ? (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Remove directory from workspace?" }), _jsxs(Text, { children: [" ", menu.path] }), _jsx(Text, { children: " " }), _jsx(Text, { children: "Praxis Code will no longer have access to files in this directory." }), _jsx(Text, { children: " " }), _jsx(DecisionOption, { selected: menu.selectedIndex === 0, screenReader: axScreenReader, children: "1. Yes" }), _jsx(DecisionOption, { selected: menu.selectedIndex === 1, screenReader: axScreenReader, children: "2. No" }), _jsx(Text, { dimColor: true, children: "Enter to confirm \u00B7 Esc to cancel" })] })) : menu ? (menu.kind === 'help' ? (_jsx(HelpMenu, { tabIndex: menu.tabIndex, selectedIndex: menu.selectedIndex, builtinCommands: builtinSlashCommands, customCommands: customSlashCommands, width: width, screenReader: axScreenReader })) : menu.kind === 'diff' ? (_jsx(DiffDashboard, { snapshots: menu.snapshots, sourceIndex: menu.sourceIndex, selectedIndex: menu.selectedIndex, viewingFile: menu.viewingFile, scrollOffset: menu.scrollOffset, width: width, screenReader: axScreenReader })) : menu.kind === 'permission-dashboard' ? (_jsx(PermissionDashboard, { tabIndex: menu.tabIndex, selectedIndex: menu.selectedIndex, query: menu.query, rules: menu.rules, recentDenied: recentDenied, retryingDeniedId: retryingDeniedId, workspaceDirectories: workspaceDirectories, width: width, screenReader: axScreenReader })) : menu.kind === 'sandbox' ? (_jsx(SandboxDashboard, { snapshot: menu.snapshot, tab: menu.tab, selectedIndex: menu.selectedIndex, width: width, screenReader: axScreenReader })) : menu.kind === 'permission-scope' ? (_jsx(SelectionMenu, { title: "Where should this rule be saved?", description: `${menu.rule}${permissionRuleDescription(menu.rule)
|
|
5904
5974
|
? ` · ${permissionRuleDescription(menu.rule)}`
|
|
5905
5975
|
: ''}`, options: [
|
|
5906
5976
|
{
|
|
@@ -5947,7 +6017,7 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
5947
6017
|
label: 'Save to file',
|
|
5948
6018
|
description: 'Save the conversation to a file in the current directory',
|
|
5949
6019
|
},
|
|
5950
|
-
], selectedIndex: menu.selectedIndex, footer: "Esc to cancel", width: width, screenReader: axScreenReader })) : menu.kind === 'copy' ? (_jsx(SelectionMenu, { title: "Copy", description: "Select content to copy:", options: menu.candidates, selectedIndex: menu.selectedIndex, footer: "Enter to copy \u00B7 w to write to /tmp/claude \u00B7 Esc to cancel", width: width, screenReader: axScreenReader })) : null) : (_jsxs(_Fragment, { children: [commandPaletteVisible ? (_jsx(CommandPalette, { commands: matchingSlashCommands, selectedIndex: selectedSlashCommandIndex, width: width, screenReader: axScreenReader })) : null, filePickerVisible ? (_jsx(MentionPicker, { entries: matchingMentionEntries, selectedIndex: selectedFileIndex, width: width, screenReader: axScreenReader })) : null, exitConfirmation ?
|
|
6020
|
+
], selectedIndex: menu.selectedIndex, footer: "Esc to cancel", width: width, screenReader: axScreenReader })) : menu.kind === 'copy' ? (_jsx(SelectionMenu, { title: "Copy", description: "Select content to copy:", options: menu.candidates, selectedIndex: menu.selectedIndex, footer: "Enter to copy \u00B7 w to write to /tmp/claude \u00B7 Esc to cancel", width: width, screenReader: axScreenReader })) : null) : (_jsxs(_Fragment, { children: [commandPaletteVisible ? (_jsx(CommandPalette, { commands: matchingSlashCommands, selectedIndex: selectedSlashCommandIndex, width: width, screenReader: axScreenReader })) : null, filePickerVisible ? (_jsx(MentionPicker, { entries: matchingMentionEntries, selectedIndex: selectedFileIndex, width: width, screenReader: axScreenReader })) : null, exitConfirmation ? _jsx(ExitWarning, {}) : null, fixedViewport ? _jsx(Box, { flexGrow: 1 }) : null, _jsx(Composer, { input: shellMode ? input.slice(1) : input, cursor: shellMode ? Math.max(0, inputCursor - 1) : inputCursor, shellMode: shellMode, ...(sessionColor === undefined ? {} : { sessionColor }), ...(commandArgumentHint === undefined
|
|
5951
6021
|
? {}
|
|
5952
6022
|
: { commandArgumentHint }), busy: busy, clipboardBusy: clipboardBusy, status: status, display: runtimeDisplay, ...(usage === undefined ? {} : { usage }), ...(costUsd === undefined ? {} : { costUsd }), width: width, screenReader: axScreenReader, hasThinking: hasDetailedTranscript, thinkingExpanded: thinkingExpanded, reduceMotion: runtimeSettings.reduceMotion, progressBar: runtimeSettings.progressBar, ...(runtimeSettings.turnDuration
|
|
5953
6023
|
? (() => {
|