@deepseek-harness-tui/dsh-tui 0.5.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/LICENSE +21 -0
- package/README.md +235 -0
- package/bin/dsh-tui.js +95 -0
- package/cordis.patch.yml +218 -0
- package/cordis.yml +185 -0
- package/lib/invariant.js +28 -0
- package/lib/types/activityPrefs.d.ts +29 -0
- package/lib/types/activityPrefs.d.ts.map +1 -0
- package/lib/types/activityPrefs.js +60 -0
- package/lib/types/bootstrap/state.d.ts +13 -0
- package/lib/types/bootstrap/state.d.ts.map +1 -0
- package/lib/types/bootstrap/state.js +12 -0
- package/lib/types/cc/cliHighlight.d.ts +20 -0
- package/lib/types/cc/cliHighlight.d.ts.map +1 -0
- package/lib/types/cc/cliHighlight.js +53 -0
- package/lib/types/cc/figures.d.ts +59 -0
- package/lib/types/cc/figures.d.ts.map +1 -0
- package/lib/types/cc/figures.js +69 -0
- package/lib/types/cc/format.d.ts +26 -0
- package/lib/types/cc/format.d.ts.map +1 -0
- package/lib/types/cc/format.js +55 -0
- package/lib/types/cc/hash.d.ts +25 -0
- package/lib/types/cc/hash.d.ts.map +1 -0
- package/lib/types/cc/hash.js +41 -0
- package/lib/types/cc/hyperlink.d.ts +21 -0
- package/lib/types/cc/hyperlink.d.ts.map +1 -0
- package/lib/types/cc/hyperlink.js +31 -0
- package/lib/types/cc/markdown.d.ts +43 -0
- package/lib/types/cc/markdown.d.ts.map +1 -0
- package/lib/types/cc/markdown.js +345 -0
- package/lib/types/cc/spinnerVerbs.d.ts +3 -0
- package/lib/types/cc/spinnerVerbs.d.ts.map +1 -0
- package/lib/types/cc/spinnerVerbs.js +190 -0
- package/lib/types/cc/terminal.d.ts +15 -0
- package/lib/types/cc/terminal.d.ts.map +1 -0
- package/lib/types/cc/terminal.js +84 -0
- package/lib/types/channel.d.ts +672 -0
- package/lib/types/channel.d.ts.map +1 -0
- package/lib/types/channel.js +2427 -0
- package/lib/types/childStderr.d.ts +63 -0
- package/lib/types/childStderr.d.ts.map +1 -0
- package/lib/types/childStderr.js +161 -0
- package/lib/types/commands.d.ts +55 -0
- package/lib/types/commands.d.ts.map +1 -0
- package/lib/types/commands.js +101 -0
- package/lib/types/components/ActivityLine.d.ts +29 -0
- package/lib/types/components/ActivityLine.d.ts.map +1 -0
- package/lib/types/components/ActivityLine.js +47 -0
- package/lib/types/components/ActivityPicker.d.ts +13 -0
- package/lib/types/components/ActivityPicker.d.ts.map +1 -0
- package/lib/types/components/ActivityPicker.js +24 -0
- package/lib/types/components/CommandSuggestions.d.ts +14 -0
- package/lib/types/components/CommandSuggestions.d.ts.map +1 -0
- package/lib/types/components/CommandSuggestions.js +33 -0
- package/lib/types/components/FileSuggestions.d.ts +12 -0
- package/lib/types/components/FileSuggestions.d.ts.map +1 -0
- package/lib/types/components/FileSuggestions.js +26 -0
- package/lib/types/components/GoalTodoPanel.d.ts +13 -0
- package/lib/types/components/GoalTodoPanel.d.ts.map +1 -0
- package/lib/types/components/GoalTodoPanel.js +57 -0
- package/lib/types/components/HelpMenu.d.ts +12 -0
- package/lib/types/components/HelpMenu.d.ts.map +1 -0
- package/lib/types/components/HelpMenu.js +12 -0
- package/lib/types/components/HistorySearchDialog.d.ts +16 -0
- package/lib/types/components/HistorySearchDialog.d.ts.map +1 -0
- package/lib/types/components/HistorySearchDialog.js +31 -0
- package/lib/types/components/InterruptedByUser.d.ts +7 -0
- package/lib/types/components/InterruptedByUser.d.ts.map +1 -0
- package/lib/types/components/InterruptedByUser.js +9 -0
- package/lib/types/components/LoadedContextPanel.d.ts +20 -0
- package/lib/types/components/LoadedContextPanel.d.ts.map +1 -0
- package/lib/types/components/LoadedContextPanel.js +30 -0
- package/lib/types/components/LogoV2.d.ts +23 -0
- package/lib/types/components/LogoV2.d.ts.map +1 -0
- package/lib/types/components/LogoV2.js +95 -0
- package/lib/types/components/Markdown.d.ts +24 -0
- package/lib/types/components/Markdown.d.ts.map +1 -0
- package/lib/types/components/Markdown.js +106 -0
- package/lib/types/components/MarkdownTable.d.ts +17 -0
- package/lib/types/components/MarkdownTable.d.ts.map +1 -0
- package/lib/types/components/MarkdownTable.js +272 -0
- package/lib/types/components/MessageList.d.ts +41 -0
- package/lib/types/components/MessageList.d.ts.map +1 -0
- package/lib/types/components/MessageList.js +303 -0
- package/lib/types/components/ModelPicker.d.ts +14 -0
- package/lib/types/components/ModelPicker.d.ts.map +1 -0
- package/lib/types/components/ModelPicker.js +15 -0
- package/lib/types/components/PresetPicker.d.ts +17 -0
- package/lib/types/components/PresetPicker.d.ts.map +1 -0
- package/lib/types/components/PresetPicker.js +25 -0
- package/lib/types/components/PromptInput.d.ts +67 -0
- package/lib/types/components/PromptInput.d.ts.map +1 -0
- package/lib/types/components/PromptInput.js +778 -0
- package/lib/types/components/ResumePicker.d.ts +15 -0
- package/lib/types/components/ResumePicker.d.ts.map +1 -0
- package/lib/types/components/ResumePicker.js +34 -0
- package/lib/types/components/RewindPicker.d.ts +14 -0
- package/lib/types/components/RewindPicker.d.ts.map +1 -0
- package/lib/types/components/RewindPicker.js +23 -0
- package/lib/types/components/SearchBox.d.ts +20 -0
- package/lib/types/components/SearchBox.d.ts.map +1 -0
- package/lib/types/components/SearchBox.js +33 -0
- package/lib/types/components/Select.d.ts +22 -0
- package/lib/types/components/Select.d.ts.map +1 -0
- package/lib/types/components/Select.js +19 -0
- package/lib/types/components/Spinner/GlimmerMessage.d.ts +19 -0
- package/lib/types/components/Spinner/GlimmerMessage.d.ts.map +1 -0
- package/lib/types/components/Spinner/GlimmerMessage.js +78 -0
- package/lib/types/components/Spinner/SpinnerAnimationRow.d.ts +31 -0
- package/lib/types/components/Spinner/SpinnerAnimationRow.d.ts.map +1 -0
- package/lib/types/components/Spinner/SpinnerAnimationRow.js +162 -0
- package/lib/types/components/Spinner/SpinnerGlyph.d.ts +16 -0
- package/lib/types/components/Spinner/SpinnerGlyph.d.ts.map +1 -0
- package/lib/types/components/Spinner/SpinnerGlyph.js +36 -0
- package/lib/types/components/Spinner/spinnerMode.d.ts +6 -0
- package/lib/types/components/Spinner/spinnerMode.d.ts.map +1 -0
- package/lib/types/components/Spinner/spinnerMode.js +1 -0
- package/lib/types/components/Spinner/spinnerUtils.d.ts +41 -0
- package/lib/types/components/Spinner/spinnerUtils.d.ts.map +1 -0
- package/lib/types/components/Spinner/spinnerUtils.js +104 -0
- package/lib/types/components/Spinner/useStalledAnimation.d.ts +16 -0
- package/lib/types/components/Spinner/useStalledAnimation.d.ts.map +1 -0
- package/lib/types/components/Spinner/useStalledAnimation.js +71 -0
- package/lib/types/components/StreamingMarkdown.d.ts +12 -0
- package/lib/types/components/StreamingMarkdown.d.ts.map +1 -0
- package/lib/types/components/StreamingMarkdown.js +39 -0
- package/lib/types/components/ThemePicker.d.ts +22 -0
- package/lib/types/components/ThemePicker.d.ts.map +1 -0
- package/lib/types/components/ThemePicker.js +51 -0
- package/lib/types/components/ThinkingToggle.d.ts +17 -0
- package/lib/types/components/ThinkingToggle.d.ts.map +1 -0
- package/lib/types/components/ThinkingToggle.js +30 -0
- package/lib/types/components/ToolUseLoader.d.ts +13 -0
- package/lib/types/components/ToolUseLoader.d.ts.map +1 -0
- package/lib/types/components/ToolUseLoader.js +17 -0
- package/lib/types/components/Whale.d.ts +22 -0
- package/lib/types/components/Whale.d.ts.map +1 -0
- package/lib/types/components/Whale.js +78 -0
- package/lib/types/components/WorkingSpinner.d.ts +26 -0
- package/lib/types/components/WorkingSpinner.d.ts.map +1 -0
- package/lib/types/components/WorkingSpinner.js +68 -0
- package/lib/types/components/activityFrames.d.ts +31 -0
- package/lib/types/components/activityFrames.d.ts.map +1 -0
- package/lib/types/components/activityFrames.js +83 -0
- package/lib/types/components/bigfont.d.ts +28 -0
- package/lib/types/components/bigfont.d.ts.map +1 -0
- package/lib/types/components/bigfont.js +91 -0
- package/lib/types/components/design-system/Byline.d.ts +14 -0
- package/lib/types/components/design-system/Byline.d.ts.map +1 -0
- package/lib/types/components/design-system/Byline.js +17 -0
- package/lib/types/components/design-system/Divider.d.ts +40 -0
- package/lib/types/components/design-system/Divider.d.ts.map +1 -0
- package/lib/types/components/design-system/Divider.js +24 -0
- package/lib/types/components/design-system/KeyboardShortcutHint.d.ts +19 -0
- package/lib/types/components/design-system/KeyboardShortcutHint.d.ts.map +1 -0
- package/lib/types/components/design-system/KeyboardShortcutHint.js +14 -0
- package/lib/types/components/design-system/ListItem.d.ts +36 -0
- package/lib/types/components/design-system/ListItem.d.ts.map +1 -0
- package/lib/types/components/design-system/ListItem.js +48 -0
- package/lib/types/components/design-system/LoadingState.d.ts +19 -0
- package/lib/types/components/design-system/LoadingState.d.ts.map +1 -0
- package/lib/types/components/design-system/LoadingState.js +22 -0
- package/lib/types/components/design-system/Pane.d.ts +17 -0
- package/lib/types/components/design-system/Pane.d.ts.map +1 -0
- package/lib/types/components/design-system/Pane.js +15 -0
- package/lib/types/components/design-system/ProgressBar.d.ts +22 -0
- package/lib/types/components/design-system/ProgressBar.d.ts.map +1 -0
- package/lib/types/components/design-system/ProgressBar.js +27 -0
- package/lib/types/components/design-system/StatusIcon.d.ts +15 -0
- package/lib/types/components/design-system/StatusIcon.d.ts.map +1 -0
- package/lib/types/components/design-system/StatusIcon.js +20 -0
- package/lib/types/components/design-system/ThemeProvider.d.ts +11 -0
- package/lib/types/components/design-system/ThemeProvider.d.ts.map +1 -0
- package/lib/types/components/design-system/ThemeProvider.js +135 -0
- package/lib/types/components/design-system/ThemedBox.d.ts +37 -0
- package/lib/types/components/design-system/ThemedBox.d.ts.map +1 -0
- package/lib/types/components/design-system/ThemedBox.js +26 -0
- package/lib/types/components/design-system/ThemedText.d.ts +56 -0
- package/lib/types/components/design-system/ThemedText.d.ts.map +1 -0
- package/lib/types/components/design-system/ThemedText.js +45 -0
- package/lib/types/components/messages/AssistantTextMessage.d.ts +18 -0
- package/lib/types/components/messages/AssistantTextMessage.d.ts.map +1 -0
- package/lib/types/components/messages/AssistantTextMessage.js +15 -0
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts +23 -0
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -0
- package/lib/types/components/messages/AssistantThinkingMessage.js +23 -0
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts +23 -0
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -0
- package/lib/types/components/messages/AssistantToolUseMessage.js +220 -0
- package/lib/types/components/messages/MessageMetadata.d.ts +15 -0
- package/lib/types/components/messages/MessageMetadata.d.ts.map +1 -0
- package/lib/types/components/messages/MessageMetadata.js +20 -0
- package/lib/types/components/messages/UserPromptMessage.d.ts +19 -0
- package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -0
- package/lib/types/components/messages/UserPromptMessage.js +15 -0
- package/lib/types/components/questions/AskUserQuestionPanel.d.ts +39 -0
- package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -0
- package/lib/types/components/questions/AskUserQuestionPanel.js +228 -0
- package/lib/types/components/shimmer.d.ts +35 -0
- package/lib/types/components/shimmer.d.ts.map +1 -0
- package/lib/types/components/shimmer.js +43 -0
- package/lib/types/components/whaleFrames.d.ts +25 -0
- package/lib/types/components/whaleFrames.d.ts.map +1 -0
- package/lib/types/components/whaleFrames.js +419 -0
- package/lib/types/customTheme.d.ts +104 -0
- package/lib/types/customTheme.d.ts.map +1 -0
- package/lib/types/customTheme.js +268 -0
- package/lib/types/effortPrefs.d.ts +22 -0
- package/lib/types/effortPrefs.d.ts.map +1 -0
- package/lib/types/effortPrefs.js +45 -0
- package/lib/types/history.d.ts +24 -0
- package/lib/types/history.d.ts.map +1 -0
- package/lib/types/history.js +75 -0
- package/lib/types/hooks/useBlink.d.ts +11 -0
- package/lib/types/hooks/useBlink.d.ts.map +1 -0
- package/lib/types/hooks/useBlink.js +20 -0
- package/lib/types/i18n.d.ts +926 -0
- package/lib/types/i18n.d.ts.map +1 -0
- package/lib/types/i18n.js +356 -0
- package/lib/types/index.d.ts +70 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +31 -0
- package/lib/types/ink/Ansi.d.ts +11 -0
- package/lib/types/ink/Ansi.d.ts.map +1 -0
- package/lib/types/ink/Ansi.js +269 -0
- package/lib/types/ink/bidi.d.ts +18 -0
- package/lib/types/ink/bidi.d.ts.map +1 -0
- package/lib/types/ink/bidi.js +119 -0
- package/lib/types/ink/clearTerminal.d.ts +22 -0
- package/lib/types/ink/clearTerminal.d.ts.map +1 -0
- package/lib/types/ink/clearTerminal.js +72 -0
- package/lib/types/ink/colorize.d.ts +33 -0
- package/lib/types/ink/colorize.d.ts.map +1 -0
- package/lib/types/ink/colorize.js +213 -0
- package/lib/types/ink/components/AlternateScreen.d.ts +22 -0
- package/lib/types/ink/components/AlternateScreen.d.ts.map +1 -0
- package/lib/types/ink/components/AlternateScreen.js +74 -0
- package/lib/types/ink/components/App.d.ts +73 -0
- package/lib/types/ink/components/App.d.ts.map +1 -0
- package/lib/types/ink/components/App.js +597 -0
- package/lib/types/ink/components/AppContext.d.ts +15 -0
- package/lib/types/ink/components/AppContext.d.ts.map +1 -0
- package/lib/types/ink/components/AppContext.js +11 -0
- package/lib/types/ink/components/Box.d.ts +49 -0
- package/lib/types/ink/components/Box.d.ts.map +1 -0
- package/lib/types/ink/components/Box.js +153 -0
- package/lib/types/ink/components/Button.d.ts +37 -0
- package/lib/types/ink/components/Button.d.ts.map +1 -0
- package/lib/types/ink/components/Button.js +166 -0
- package/lib/types/ink/components/ClockContext.d.ts +10 -0
- package/lib/types/ink/components/ClockContext.d.ts.map +1 -0
- package/lib/types/ink/components/ClockContext.js +108 -0
- package/lib/types/ink/components/CursorDeclarationContext.d.ts +30 -0
- package/lib/types/ink/components/CursorDeclarationContext.d.ts.map +1 -0
- package/lib/types/ink/components/CursorDeclarationContext.js +6 -0
- package/lib/types/ink/components/ErrorOverview.d.ts +7 -0
- package/lib/types/ink/components/ErrorOverview.d.ts.map +1 -0
- package/lib/types/ink/components/ErrorOverview.js +49 -0
- package/lib/types/ink/components/Link.d.ts +8 -0
- package/lib/types/ink/components/Link.d.ts.map +1 -0
- package/lib/types/ink/components/Link.js +33 -0
- package/lib/types/ink/components/Newline.d.ts +13 -0
- package/lib/types/ink/components/Newline.d.ts.map +1 -0
- package/lib/types/ink/components/Newline.js +29 -0
- package/lib/types/ink/components/NoSelect.d.ts +20 -0
- package/lib/types/ink/components/NoSelect.d.ts.map +1 -0
- package/lib/types/ink/components/NoSelect.js +56 -0
- package/lib/types/ink/components/RawAnsi.d.ts +17 -0
- package/lib/types/ink/components/RawAnsi.d.ts.map +1 -0
- package/lib/types/ink/components/RawAnsi.js +45 -0
- package/lib/types/ink/components/ScrollBox.d.ts +78 -0
- package/lib/types/ink/components/ScrollBox.d.ts.map +1 -0
- package/lib/types/ink/components/ScrollBox.js +174 -0
- package/lib/types/ink/components/Spacer.d.ts +6 -0
- package/lib/types/ink/components/Spacer.d.ts.map +1 -0
- package/lib/types/ink/components/Spacer.js +19 -0
- package/lib/types/ink/components/StdinContext.d.ts +32 -0
- package/lib/types/ink/components/StdinContext.d.ts.map +1 -0
- package/lib/types/ink/components/StdinContext.js +16 -0
- package/lib/types/ink/components/TerminalFocusContext.d.ts +11 -0
- package/lib/types/ink/components/TerminalFocusContext.d.ts.map +1 -0
- package/lib/types/ink/components/TerminalFocusContext.js +45 -0
- package/lib/types/ink/components/TerminalSizeContext.d.ts +6 -0
- package/lib/types/ink/components/TerminalSizeContext.d.ts.map +1 -0
- package/lib/types/ink/components/TerminalSizeContext.js +3 -0
- package/lib/types/ink/components/Text.d.ts +56 -0
- package/lib/types/ink/components/Text.d.ts.map +1 -0
- package/lib/types/ink/components/Text.js +194 -0
- package/lib/types/ink/constants.d.ts +3 -0
- package/lib/types/ink/constants.d.ts.map +1 -0
- package/lib/types/ink/constants.js +2 -0
- package/lib/types/ink/cursor.d.ts +11 -0
- package/lib/types/ink/cursor.d.ts.map +1 -0
- package/lib/types/ink/cursor.js +1 -0
- package/lib/types/ink/devtools.d.ts +7 -0
- package/lib/types/ink/devtools.d.ts.map +1 -0
- package/lib/types/ink/devtools.js +1 -0
- package/lib/types/ink/dom.d.ts +178 -0
- package/lib/types/ink/dom.d.ts.map +1 -0
- package/lib/types/ink/dom.js +424 -0
- package/lib/types/ink/events/click-event.d.ts +32 -0
- package/lib/types/ink/events/click-event.d.ts.map +1 -0
- package/lib/types/ink/events/click-event.js +36 -0
- package/lib/types/ink/events/dispatcher.d.ts +63 -0
- package/lib/types/ink/events/dispatcher.d.ts.map +1 -0
- package/lib/types/ink/events/dispatcher.js +194 -0
- package/lib/types/ink/events/emitter.d.ts +20 -0
- package/lib/types/ink/events/emitter.d.ts.map +1 -0
- package/lib/types/ink/events/emitter.js +43 -0
- package/lib/types/ink/events/event-handlers.d.ts +47 -0
- package/lib/types/ink/events/event-handlers.d.ts.map +1 -0
- package/lib/types/ink/events/event-handlers.js +30 -0
- package/lib/types/ink/events/event.d.ts +19 -0
- package/lib/types/ink/events/event.d.ts.map +1 -0
- package/lib/types/ink/events/event.js +22 -0
- package/lib/types/ink/events/focus-event.d.ts +19 -0
- package/lib/types/ink/events/focus-event.d.ts.map +1 -0
- package/lib/types/ink/events/focus-event.js +21 -0
- package/lib/types/ink/events/input-event.d.ts +53 -0
- package/lib/types/ink/events/input-event.d.ts.map +1 -0
- package/lib/types/ink/events/input-event.js +180 -0
- package/lib/types/ink/events/keyboard-event.d.ts +40 -0
- package/lib/types/ink/events/keyboard-event.d.ts.map +1 -0
- package/lib/types/ink/events/keyboard-event.js +65 -0
- package/lib/types/ink/events/paste-event.d.ts +11 -0
- package/lib/types/ink/events/paste-event.d.ts.map +1 -0
- package/lib/types/ink/events/paste-event.js +13 -0
- package/lib/types/ink/events/resize-event.d.ts +13 -0
- package/lib/types/ink/events/resize-event.d.ts.map +1 -0
- package/lib/types/ink/events/resize-event.js +16 -0
- package/lib/types/ink/events/terminal-event.d.ts +112 -0
- package/lib/types/ink/events/terminal-event.d.ts.map +1 -0
- package/lib/types/ink/events/terminal-event.js +131 -0
- package/lib/types/ink/events/terminal-focus-event.d.ts +21 -0
- package/lib/types/ink/events/terminal-focus-event.d.ts.map +1 -0
- package/lib/types/ink/events/terminal-focus-event.js +18 -0
- package/lib/types/ink/focus.d.ts +74 -0
- package/lib/types/ink/focus.d.ts.map +1 -0
- package/lib/types/ink/focus.js +188 -0
- package/lib/types/ink/frame.d.ts +119 -0
- package/lib/types/ink/frame.d.ts.map +1 -0
- package/lib/types/ink/frame.js +43 -0
- package/lib/types/ink/get-max-width.d.ts +20 -0
- package/lib/types/ink/get-max-width.d.ts.map +1 -0
- package/lib/types/ink/get-max-width.js +25 -0
- package/lib/types/ink/hit-test.d.ts +47 -0
- package/lib/types/ink/hit-test.d.ts.map +1 -0
- package/lib/types/ink/hit-test.js +126 -0
- package/lib/types/ink/hooks/use-animation-frame.d.ts +27 -0
- package/lib/types/ink/hooks/use-animation-frame.d.ts.map +1 -0
- package/lib/types/ink/hooks/use-animation-frame.js +48 -0
- package/lib/types/ink/hooks/use-app.d.ts +8 -0
- package/lib/types/ink/hooks/use-app.d.ts.map +1 -0
- package/lib/types/ink/hooks/use-app.js +8 -0
- package/lib/types/ink/hooks/use-copy-on-select.d.ts +22 -0
- package/lib/types/ink/hooks/use-copy-on-select.d.ts.map +1 -0
- package/lib/types/ink/hooks/use-copy-on-select.js +40 -0
- package/lib/types/ink/hooks/use-declared-cursor.d.ts +31 -0
- package/lib/types/ink/hooks/use-declared-cursor.d.ts.map +1 -0
- package/lib/types/ink/hooks/use-declared-cursor.js +65 -0
- package/lib/types/ink/hooks/use-input.d.ts +41 -0
- package/lib/types/ink/hooks/use-input.d.ts.map +1 -0
- package/lib/types/ink/hooks/use-input.js +73 -0
- package/lib/types/ink/hooks/use-interval.d.ts +23 -0
- package/lib/types/ink/hooks/use-interval.d.ts.map +1 -0
- package/lib/types/ink/hooks/use-interval.js +58 -0
- package/lib/types/ink/hooks/use-search-highlight.d.ts +34 -0
- package/lib/types/ink/hooks/use-search-highlight.d.ts.map +1 -0
- package/lib/types/ink/hooks/use-search-highlight.js +35 -0
- package/lib/types/ink/hooks/use-selection.d.ts +44 -0
- package/lib/types/ink/hooks/use-selection.d.ts.map +1 -0
- package/lib/types/ink/hooks/use-selection.js +64 -0
- package/lib/types/ink/hooks/use-stdin.d.ts +8 -0
- package/lib/types/ink/hooks/use-stdin.d.ts.map +1 -0
- package/lib/types/ink/hooks/use-stdin.js +8 -0
- package/lib/types/ink/hooks/use-tab-status.d.ts +18 -0
- package/lib/types/ink/hooks/use-tab-status.d.ts.map +1 -0
- package/lib/types/ink/hooks/use-tab-status.js +58 -0
- package/lib/types/ink/hooks/use-terminal-focus.d.ts +11 -0
- package/lib/types/ink/hooks/use-terminal-focus.d.ts.map +1 -0
- package/lib/types/ink/hooks/use-terminal-focus.js +15 -0
- package/lib/types/ink/hooks/use-terminal-size.d.ts +6 -0
- package/lib/types/ink/hooks/use-terminal-size.d.ts.map +1 -0
- package/lib/types/ink/hooks/use-terminal-size.js +12 -0
- package/lib/types/ink/hooks/use-terminal-title.d.ts +14 -0
- package/lib/types/ink/hooks/use-terminal-title.d.ts.map +1 -0
- package/lib/types/ink/hooks/use-terminal-title.js +30 -0
- package/lib/types/ink/hooks/use-terminal-viewport.d.ts +32 -0
- package/lib/types/ink/hooks/use-terminal-viewport.d.ts.map +1 -0
- package/lib/types/ink/hooks/use-terminal-viewport.js +79 -0
- package/lib/types/ink/ink.d.ts +370 -0
- package/lib/types/ink/ink.d.ts.map +1 -0
- package/lib/types/ink/ink.js +1665 -0
- package/lib/types/ink/instances.d.ts +10 -0
- package/lib/types/ink/instances.d.ts.map +1 -0
- package/lib/types/ink/instances.js +13 -0
- package/lib/types/ink/layout/engine.d.ts +7 -0
- package/lib/types/ink/layout/engine.d.ts.map +1 -0
- package/lib/types/ink/layout/engine.js +8 -0
- package/lib/types/ink/layout/geometry.d.ts +86 -0
- package/lib/types/ink/layout/geometry.d.ts.map +1 -0
- package/lib/types/ink/layout/geometry.js +95 -0
- package/lib/types/ink/layout/node.d.ts +151 -0
- package/lib/types/ink/layout/node.d.ts.map +1 -0
- package/lib/types/ink/layout/node.js +72 -0
- package/lib/types/ink/layout/yoga.d.ts +69 -0
- package/lib/types/ink/layout/yoga.d.ts.map +1 -0
- package/lib/types/ink/layout/yoga.js +249 -0
- package/lib/types/ink/line-width-cache.d.ts +9 -0
- package/lib/types/ink/line-width-cache.d.ts.map +1 -0
- package/lib/types/ink/line-width-cache.js +45 -0
- package/lib/types/ink/log-update.d.ts +57 -0
- package/lib/types/ink/log-update.d.ts.map +1 -0
- package/lib/types/ink/log-update.js +710 -0
- package/lib/types/ink/measure-element.d.ts +19 -0
- package/lib/types/ink/measure-element.d.ts.map +1 -0
- package/lib/types/ink/measure-element.js +10 -0
- package/lib/types/ink/measure-text.d.ts +13 -0
- package/lib/types/ink/measure-text.d.ts.map +1 -0
- package/lib/types/ink/measure-text.js +38 -0
- package/lib/types/ink/node-cache.d.ts +33 -0
- package/lib/types/ink/node-cache.d.ts.map +1 -0
- package/lib/types/ink/node-cache.js +42 -0
- package/lib/types/ink/optimizer.d.ts +18 -0
- package/lib/types/ink/optimizer.d.ts.map +1 -0
- package/lib/types/ink/optimizer.js +83 -0
- package/lib/types/ink/output.d.ts +200 -0
- package/lib/types/ink/output.d.ts.map +1 -0
- package/lib/types/ink/output.js +663 -0
- package/lib/types/ink/parse-keypress.d.ts +132 -0
- package/lib/types/ink/parse-keypress.d.ts.map +1 -0
- package/lib/types/ink/parse-keypress.js +707 -0
- package/lib/types/ink/reconciler.d.ts +43 -0
- package/lib/types/ink/reconciler.d.ts.map +1 -0
- package/lib/types/ink/reconciler.js +413 -0
- package/lib/types/ink/render-border.d.ts +36 -0
- package/lib/types/ink/render-border.d.ts.map +1 -0
- package/lib/types/ink/render-border.js +143 -0
- package/lib/types/ink/render-node-to-output.d.ts +93 -0
- package/lib/types/ink/render-node-to-output.d.ts.map +1 -0
- package/lib/types/ink/render-node-to-output.js +1290 -0
- package/lib/types/ink/render-to-screen.d.ts +65 -0
- package/lib/types/ink/render-to-screen.d.ts.map +1 -0
- package/lib/types/ink/render-to-screen.js +189 -0
- package/lib/types/ink/renderer.d.ts +24 -0
- package/lib/types/ink/renderer.d.ts.map +1 -0
- package/lib/types/ink/renderer.js +136 -0
- package/lib/types/ink/root.d.ts +91 -0
- package/lib/types/ink/root.d.ts.map +1 -0
- package/lib/types/ink/root.js +93 -0
- package/lib/types/ink/screen.d.ts +443 -0
- package/lib/types/ink/screen.d.ts.map +1 -0
- package/lib/types/ink/screen.js +1295 -0
- package/lib/types/ink/searchHighlight.d.ts +25 -0
- package/lib/types/ink/searchHighlight.d.ts.map +1 -0
- package/lib/types/ink/searchHighlight.js +82 -0
- package/lib/types/ink/selection.d.ts +323 -0
- package/lib/types/ink/selection.d.ts.map +1 -0
- package/lib/types/ink/selection.js +881 -0
- package/lib/types/ink/squash-text-nodes.d.ts +30 -0
- package/lib/types/ink/squash-text-nodes.d.ts.map +1 -0
- package/lib/types/ink/squash-text-nodes.js +63 -0
- package/lib/types/ink/stringWidth.d.ts +11 -0
- package/lib/types/ink/stringWidth.d.ts.map +1 -0
- package/lib/types/ink/stringWidth.js +209 -0
- package/lib/types/ink/styles.d.ts +324 -0
- package/lib/types/ink/styles.d.ts.map +1 -0
- package/lib/types/ink/styles.js +307 -0
- package/lib/types/ink/supports-hyperlinks.d.ts +20 -0
- package/lib/types/ink/supports-hyperlinks.d.ts.map +1 -0
- package/lib/types/ink/supports-hyperlinks.js +44 -0
- package/lib/types/ink/tabstops.d.ts +9 -0
- package/lib/types/ink/tabstops.d.ts.map +1 -0
- package/lib/types/ink/tabstops.js +46 -0
- package/lib/types/ink/terminal-focus-state.d.ts +35 -0
- package/lib/types/ink/terminal-focus-state.d.ts.map +1 -0
- package/lib/types/ink/terminal-focus-state.js +57 -0
- package/lib/types/ink/terminal-querier.d.ts +161 -0
- package/lib/types/ink/terminal-querier.d.ts.map +1 -0
- package/lib/types/ink/terminal-querier.js +204 -0
- package/lib/types/ink/terminal.d.ts +80 -0
- package/lib/types/ink/terminal.d.ts.map +1 -0
- package/lib/types/ink/terminal.js +268 -0
- package/lib/types/ink/termio/ansi.d.ts +75 -0
- package/lib/types/ink/termio/ansi.d.ts.map +1 -0
- package/lib/types/ink/termio/ansi.js +79 -0
- package/lib/types/ink/termio/csi.d.ts +253 -0
- package/lib/types/ink/termio/csi.d.ts.map +1 -0
- package/lib/types/ink/termio/csi.js +347 -0
- package/lib/types/ink/termio/dec.d.ts +61 -0
- package/lib/types/ink/termio/dec.d.ts.map +1 -0
- package/lib/types/ink/termio/dec.js +76 -0
- package/lib/types/ink/termio/esc.d.ts +15 -0
- package/lib/types/ink/termio/esc.d.ts.map +1 -0
- package/lib/types/ink/termio/esc.js +57 -0
- package/lib/types/ink/termio/osc.d.ts +208 -0
- package/lib/types/ink/termio/osc.d.ts.map +1 -0
- package/lib/types/ink/termio/osc.js +466 -0
- package/lib/types/ink/termio/parser.d.ts +46 -0
- package/lib/types/ink/termio/parser.d.ts.map +1 -0
- package/lib/types/ink/termio/parser.js +366 -0
- package/lib/types/ink/termio/sgr.d.ts +17 -0
- package/lib/types/ink/termio/sgr.d.ts.map +1 -0
- package/lib/types/ink/termio/sgr.js +300 -0
- package/lib/types/ink/termio/tokenize.d.ts +50 -0
- package/lib/types/ink/termio/tokenize.d.ts.map +1 -0
- package/lib/types/ink/termio/tokenize.js +266 -0
- package/lib/types/ink/termio/types.d.ts +211 -0
- package/lib/types/ink/termio/types.d.ts.map +1 -0
- package/lib/types/ink/termio/types.js +68 -0
- package/lib/types/ink/termio.d.ts +25 -0
- package/lib/types/ink/termio.d.ts.map +1 -0
- package/lib/types/ink/termio.js +24 -0
- package/lib/types/ink/truncateToWidth.d.ts +7 -0
- package/lib/types/ink/truncateToWidth.d.ts.map +1 -0
- package/lib/types/ink/truncateToWidth.js +18 -0
- package/lib/types/ink/useTerminalNotification.d.ts +45 -0
- package/lib/types/ink/useTerminalNotification.d.ts.map +1 -0
- package/lib/types/ink/useTerminalNotification.js +70 -0
- package/lib/types/ink/warn.d.ts +7 -0
- package/lib/types/ink/warn.d.ts.map +1 -0
- package/lib/types/ink/warn.js +15 -0
- package/lib/types/ink/widest-line.d.ts +7 -0
- package/lib/types/ink/widest-line.d.ts.map +1 -0
- package/lib/types/ink/widest-line.js +19 -0
- package/lib/types/ink/wrap-text.d.ts +10 -0
- package/lib/types/ink/wrap-text.d.ts.map +1 -0
- package/lib/types/ink/wrap-text.js +61 -0
- package/lib/types/ink/wrapAnsi.d.ts +18 -0
- package/lib/types/ink/wrapAnsi.d.ts.map +1 -0
- package/lib/types/ink/wrapAnsi.js +16 -0
- package/lib/types/invariant.d.ts +20 -0
- package/lib/types/invariant.d.ts.map +1 -0
- package/lib/types/invariant.js +26 -0
- package/lib/types/modelPrefs.d.ts +37 -0
- package/lib/types/modelPrefs.d.ts.map +1 -0
- package/lib/types/modelPrefs.js +66 -0
- package/lib/types/modelRoute.d.ts +79 -0
- package/lib/types/modelRoute.d.ts.map +1 -0
- package/lib/types/modelRoute.js +96 -0
- package/lib/types/native-ts/yoga-layout/enums.d.ts +183 -0
- package/lib/types/native-ts/yoga-layout/enums.d.ts.map +1 -0
- package/lib/types/native-ts/yoga-layout/enums.js +150 -0
- package/lib/types/native-ts/yoga-layout/index.d.ts +788 -0
- package/lib/types/native-ts/yoga-layout/index.d.ts.map +1 -0
- package/lib/types/native-ts/yoga-layout/index.js +2571 -0
- package/lib/types/packaged-skills.d.ts +10 -0
- package/lib/types/packaged-skills.d.ts.map +1 -0
- package/lib/types/packaged-skills.js +63 -0
- package/lib/types/plugin.d.ts +33 -0
- package/lib/types/plugin.d.ts.map +1 -0
- package/lib/types/plugin.js +454 -0
- package/lib/types/presetPrefs.d.ts +29 -0
- package/lib/types/presetPrefs.d.ts.map +1 -0
- package/lib/types/presetPrefs.js +61 -0
- package/lib/types/presets.d.ts +110 -0
- package/lib/types/presets.d.ts.map +1 -0
- package/lib/types/presets.js +114 -0
- package/lib/types/questions.d.ts +97 -0
- package/lib/types/questions.d.ts.map +1 -0
- package/lib/types/questions.js +201 -0
- package/lib/types/screens/Chat.d.ts +23 -0
- package/lib/types/screens/Chat.d.ts.map +1 -0
- package/lib/types/screens/Chat.js +1263 -0
- package/lib/types/screens/StatusLine.d.ts +16 -0
- package/lib/types/screens/StatusLine.d.ts.map +1 -0
- package/lib/types/screens/StatusLine.js +105 -0
- package/lib/types/screens/StatusMetrics.d.ts +87 -0
- package/lib/types/screens/StatusMetrics.d.ts.map +1 -0
- package/lib/types/screens/StatusMetrics.js +252 -0
- package/lib/types/sessionHistory.d.ts +32 -0
- package/lib/types/sessionHistory.d.ts.map +1 -0
- package/lib/types/sessionHistory.js +87 -0
- package/lib/types/theme.d.ts +115 -0
- package/lib/types/theme.d.ts.map +1 -0
- package/lib/types/theme.js +300 -0
- package/lib/types/themePrefs.d.ts +28 -0
- package/lib/types/themePrefs.d.ts.map +1 -0
- package/lib/types/themePrefs.js +59 -0
- package/lib/types/ui.d.ts +28 -0
- package/lib/types/ui.d.ts.map +1 -0
- package/lib/types/ui.js +25 -0
- package/lib/types/update.d.ts +76 -0
- package/lib/types/update.d.ts.map +1 -0
- package/lib/types/update.js +203 -0
- package/lib/types/utils/clipboard.d.ts +43 -0
- package/lib/types/utils/clipboard.d.ts.map +1 -0
- package/lib/types/utils/clipboard.js +82 -0
- package/lib/types/utils/debug.d.ts +8 -0
- package/lib/types/utils/debug.d.ts.map +1 -0
- package/lib/types/utils/debug.js +12 -0
- package/lib/types/utils/earlyInput.d.ts +7 -0
- package/lib/types/utils/earlyInput.d.ts.map +1 -0
- package/lib/types/utils/earlyInput.js +6 -0
- package/lib/types/utils/env.d.ts +10 -0
- package/lib/types/utils/env.d.ts.map +1 -0
- package/lib/types/utils/env.js +9 -0
- package/lib/types/utils/envUtils.d.ts +8 -0
- package/lib/types/utils/envUtils.d.ts.map +1 -0
- package/lib/types/utils/envUtils.js +13 -0
- package/lib/types/utils/execFileNoThrow.d.ts +34 -0
- package/lib/types/utils/execFileNoThrow.d.ts.map +1 -0
- package/lib/types/utils/execFileNoThrow.js +31 -0
- package/lib/types/utils/fullscreen.d.ts +8 -0
- package/lib/types/utils/fullscreen.d.ts.map +1 -0
- package/lib/types/utils/fullscreen.js +10 -0
- package/lib/types/utils/intl.d.ts +7 -0
- package/lib/types/utils/intl.d.ts.map +1 -0
- package/lib/types/utils/intl.js +9 -0
- package/lib/types/utils/loaded-context.d.ts +20 -0
- package/lib/types/utils/loaded-context.d.ts.map +1 -0
- package/lib/types/utils/loaded-context.js +36 -0
- package/lib/types/utils/log.d.ts +7 -0
- package/lib/types/utils/log.d.ts.map +1 -0
- package/lib/types/utils/log.js +9 -0
- package/lib/types/utils/mentions.d.ts +30 -0
- package/lib/types/utils/mentions.d.ts.map +1 -0
- package/lib/types/utils/mentions.js +72 -0
- package/lib/types/utils/narration.d.ts +11 -0
- package/lib/types/utils/narration.d.ts.map +1 -0
- package/lib/types/utils/narration.js +16 -0
- package/lib/types/utils/semver.d.ts +9 -0
- package/lib/types/utils/semver.d.ts.map +1 -0
- package/lib/types/utils/semver.js +24 -0
- package/lib/types/utils/sliceAnsi.d.ts +12 -0
- package/lib/types/utils/sliceAnsi.d.ts.map +1 -0
- package/lib/types/utils/sliceAnsi.js +79 -0
- package/lib/types/working-activity.d.ts +19 -0
- package/lib/types/working-activity.d.ts.map +1 -0
- package/lib/types/working-activity.js +18 -0
- package/package.json +141 -0
- package/skills/audit/SKILL.md +24 -0
- package/skills/bug/SKILL.md +27 -0
- package/skills/pr-comments/SKILL.md +20 -0
- package/skills/practice/SKILL.md +22 -0
- package/skills/release-notes/SKILL.md +25 -0
- package/skills/review/SKILL.md +25 -0
- package/skills/vuln-check/SKILL.md +25 -0
|
@@ -0,0 +1,778 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { t } from '../i18n.js';
|
|
4
|
+
import { Box, Text, useInput, useTerminalSize } from '../ui.js';
|
|
5
|
+
import { useDeclaredCursor } from '../ink/hooks/use-declared-cursor.js';
|
|
6
|
+
import { stringWidth } from '../ink/stringWidth.js';
|
|
7
|
+
import { formatClipboardInsert, readClipboard } from '../utils/clipboard.js';
|
|
8
|
+
import { filterCommands, parseCommandName } from '../commands.js';
|
|
9
|
+
import { appendHistory } from '../history.js';
|
|
10
|
+
import { mentionAtCaret } from '../utils/mentions.js';
|
|
11
|
+
import { CommandSuggestions } from './CommandSuggestions.js';
|
|
12
|
+
import { FileSuggestions } from './FileSuggestions.js';
|
|
13
|
+
import { HelpMenu } from './HelpMenu.js';
|
|
14
|
+
const HISTORY_LIMIT = 50;
|
|
15
|
+
/** Index of the word boundary at or before `cursor` (readline alt+b). */
|
|
16
|
+
function wordBoundaryLeft(text, cursor) {
|
|
17
|
+
let index = cursor;
|
|
18
|
+
while (index > 0 && /\s/.test(text[index - 1]))
|
|
19
|
+
index--;
|
|
20
|
+
while (index > 0 && !/\s/.test(text[index - 1]))
|
|
21
|
+
index--;
|
|
22
|
+
return index;
|
|
23
|
+
}
|
|
24
|
+
/** Index of the word boundary after `cursor` (readline alt+f). */
|
|
25
|
+
function wordBoundaryRight(text, cursor) {
|
|
26
|
+
const length = text.length;
|
|
27
|
+
let index = cursor;
|
|
28
|
+
while (index < length && !/\s/.test(text[index]))
|
|
29
|
+
index++;
|
|
30
|
+
while (index < length && /\s/.test(text[index]))
|
|
31
|
+
index++;
|
|
32
|
+
return index;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The empty input deliberately shows NO placeholder text: terminal emulators
|
|
36
|
+
* paint the IME preedit (pinyin) at the physical cursor, which the app parks
|
|
37
|
+
* on the caret's cell, and the app receives no input events while a
|
|
38
|
+
* composition is active (Windows Terminal suppresses key events during TSF
|
|
39
|
+
* composition) — so it can never hide a placeholder in time. Keeping the row
|
|
40
|
+
* blank while empty is what guarantees the preedit has nothing to overlay.
|
|
41
|
+
*/
|
|
42
|
+
/** Max input rows before the visible viewport starts scrolling (CC's
|
|
43
|
+
* maxVisibleLines behavior — the box keeps a stable height). */
|
|
44
|
+
const MAX_VISIBLE_LINES = 5;
|
|
45
|
+
/**
|
|
46
|
+
* Claude Code style prompt input: rounded border box (top+bottom borders
|
|
47
|
+
* only), `❯ ` prompt char (dimmed while a turn is working), the text with a
|
|
48
|
+
* block cursor at the cursor position, and below it the slash-command
|
|
49
|
+
* suggestion overlay (name column + description, selected row in the
|
|
50
|
+
* `suggestion` color — ported from the leak's PromptInputFooterSuggestions).
|
|
51
|
+
*
|
|
52
|
+
* Empty input: a solid block caret on a blank cell and nothing else — no
|
|
53
|
+
* placeholder text, so the terminal-painted IME preedit (pinyin) at the
|
|
54
|
+
* parked cursor can never be overlaid on anything.
|
|
55
|
+
*
|
|
56
|
+
* Multi-line: Shift+Enter inserts a newline; ↑/↓ move between lines while
|
|
57
|
+
* the input spans multiple lines (history/command selection otherwise); the
|
|
58
|
+
* visible window scrolls to keep the caret row on screen past
|
|
59
|
+
* MAX_VISIBLE_LINES. Enter submits, backspace/delete edit, ←/→ move the
|
|
60
|
+
* cursor, Tab completes the selected command, Escape clears (or closes the
|
|
61
|
+
* help menu), `?` toggles the help menu. Windows ConPTY pipelines deliver
|
|
62
|
+
* whole lines with the Enter key lost: a trailing CR/LF in the input marks
|
|
63
|
+
* a complete line to submit.
|
|
64
|
+
*
|
|
65
|
+
* Enter submits immediately even while the model is streaming — as a STEER
|
|
66
|
+
* (Codex/pi semantics): the message is injected at the next step boundary
|
|
67
|
+
* of the running turn and the agent continues without aborting; Tab instead
|
|
68
|
+
* queues the message for after the turn (followup). Both appear in a
|
|
69
|
+
* pending preview above the input until delivered. Alt+Up pulls the last
|
|
70
|
+
* pending message back for editing; Esc (with pending messages while
|
|
71
|
+
* working) interrupts the turn and delivers them right away; Ctrl+Enter
|
|
72
|
+
* aborts the turn and sends the current input immediately.
|
|
73
|
+
*/
|
|
74
|
+
export function PromptInput({ channel, helpOpen, onToggleHelp, onRunCommand, selectionActive, fillText, onFillConsumed, onRewindRequest, controllerRef, }) {
|
|
75
|
+
const [value, setValue] = React.useState('');
|
|
76
|
+
const [cursor, setCursor] = React.useState(0);
|
|
77
|
+
// Publish the live controller (fresh closure over `value` every render).
|
|
78
|
+
// clear() mirrors the double-tap-Esc clear: text + caret reset.
|
|
79
|
+
React.useEffect(() => {
|
|
80
|
+
if (!controllerRef)
|
|
81
|
+
return;
|
|
82
|
+
controllerRef.current = {
|
|
83
|
+
hasText: () => value.length > 0,
|
|
84
|
+
clear: () => {
|
|
85
|
+
setValue('');
|
|
86
|
+
setCursor(0);
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
return () => {
|
|
90
|
+
controllerRef.current = null;
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
const [selectedCommand, setSelectedCommand] = React.useState(0);
|
|
94
|
+
const history = React.useRef([]);
|
|
95
|
+
const historyIndex = React.useRef(-1);
|
|
96
|
+
// ctrl+r history fill: replace the input when a new fill arrives, then
|
|
97
|
+
// tell the caller to clear it.
|
|
98
|
+
const lastFill = React.useRef(null);
|
|
99
|
+
React.useEffect(() => {
|
|
100
|
+
if (fillText && fillText !== lastFill.current) {
|
|
101
|
+
lastFill.current = fillText;
|
|
102
|
+
setValue(fillText);
|
|
103
|
+
setCursor(fillText.length);
|
|
104
|
+
onFillConsumed?.();
|
|
105
|
+
}
|
|
106
|
+
}, [fillText, onFillConsumed]);
|
|
107
|
+
// Double-tap Esc to clear (CC semantics).
|
|
108
|
+
const escPendingRef = React.useRef(false);
|
|
109
|
+
const escTimerRef = React.useRef(null);
|
|
110
|
+
/** True while a Ctrl+V clipboard read is in flight (ignore repeat keys). */
|
|
111
|
+
const clipboardBusyRef = React.useRef(false);
|
|
112
|
+
/** Enter dedupe window: cmd pipelines can deliver one Enter as `\r`+`\n`. */
|
|
113
|
+
const lastEnterAtRef = React.useRef(0);
|
|
114
|
+
React.useEffect(() => {
|
|
115
|
+
return () => {
|
|
116
|
+
if (escTimerRef.current)
|
|
117
|
+
clearTimeout(escTimerRef.current);
|
|
118
|
+
};
|
|
119
|
+
}, []);
|
|
120
|
+
const { columns } = useTerminalSize();
|
|
121
|
+
const suggestions = value.startsWith('/')
|
|
122
|
+
? filterCommands(value, channel.commandList)
|
|
123
|
+
: [];
|
|
124
|
+
const overlayOpen = suggestions.length > 0 &&
|
|
125
|
+
!helpOpen &&
|
|
126
|
+
!selectionActive &&
|
|
127
|
+
!value.includes('\n');
|
|
128
|
+
// `@` file completion (issue #15): the trigger is the mention token at the
|
|
129
|
+
// CARET, so `@` works mid-message (`看看 @src/a.ts 这个`), not only when it
|
|
130
|
+
// is the input's first character. The cwd listing loads when the trigger
|
|
131
|
+
// appears.
|
|
132
|
+
const [fileList, setFileList] = React.useState([]);
|
|
133
|
+
const [fileSelected, setFileSelected] = React.useState(0);
|
|
134
|
+
const mention = mentionAtCaret(value, cursor);
|
|
135
|
+
const atTrigger = mention !== undefined;
|
|
136
|
+
React.useEffect(() => {
|
|
137
|
+
if (atTrigger) {
|
|
138
|
+
void channel.listFiles().then(setFileList);
|
|
139
|
+
}
|
|
140
|
+
}, [atTrigger, channel]);
|
|
141
|
+
const atRest = (mention?.query ?? '').toLowerCase();
|
|
142
|
+
// Match the relative path prefix OR the basename (CC's IDE suggestions do
|
|
143
|
+
// both): `@src/ink` and `@ink` both find `src/ink/Box.js`.
|
|
144
|
+
const fileMatches = atTrigger
|
|
145
|
+
? fileList.filter(file => {
|
|
146
|
+
const lower = file.toLowerCase();
|
|
147
|
+
if (lower.startsWith(atRest))
|
|
148
|
+
return true;
|
|
149
|
+
if (atRest.includes('/'))
|
|
150
|
+
return false;
|
|
151
|
+
const base = lower.split('/').pop() ?? '';
|
|
152
|
+
return base.startsWith(atRest);
|
|
153
|
+
})
|
|
154
|
+
: [];
|
|
155
|
+
// Esc dismisses the overlay for the token being edited (it reopens once the
|
|
156
|
+
// text changes); it must NOT clear a mid-message input.
|
|
157
|
+
const fileEscRef = React.useRef(-1);
|
|
158
|
+
React.useEffect(() => {
|
|
159
|
+
fileEscRef.current = -1;
|
|
160
|
+
}, [value]);
|
|
161
|
+
const fileOverlayOpen = fileMatches.length > 0 &&
|
|
162
|
+
!helpOpen &&
|
|
163
|
+
!selectionActive &&
|
|
164
|
+
fileEscRef.current !== mention?.start;
|
|
165
|
+
/**
|
|
166
|
+
* Accept the selected file suggestion: replace ONLY the mention token at
|
|
167
|
+
* the caret (prefix/suffix text survives), quoting whitespace paths. A
|
|
168
|
+
* directory inserts `@dir/` without a trailing space so completion
|
|
169
|
+
* continues into it; a file completes the token with a space.
|
|
170
|
+
*/
|
|
171
|
+
const acceptFile = (file) => {
|
|
172
|
+
if (!mention)
|
|
173
|
+
return;
|
|
174
|
+
const body = /\s/.test(file) ? `@"${file}"` : `@${file}`;
|
|
175
|
+
const insert = file.endsWith('/') ? body : `${body} `;
|
|
176
|
+
const next = value.slice(0, mention.start) + insert + value.slice(mention.end);
|
|
177
|
+
setInput(next, mention.start + insert.length);
|
|
178
|
+
setFileSelected(0);
|
|
179
|
+
};
|
|
180
|
+
const submitText = (text, notice) => {
|
|
181
|
+
const trimmed = text.trim();
|
|
182
|
+
if (!trimmed)
|
|
183
|
+
return;
|
|
184
|
+
history.current.push(trimmed);
|
|
185
|
+
if (history.current.length > HISTORY_LIMIT)
|
|
186
|
+
history.current.shift();
|
|
187
|
+
historyIndex.current = -1;
|
|
188
|
+
setValue('');
|
|
189
|
+
setCursor(0);
|
|
190
|
+
setSelectedCommand(0);
|
|
191
|
+
appendHistory(trimmed);
|
|
192
|
+
channel.submit(trimmed);
|
|
193
|
+
if (notice) {
|
|
194
|
+
channel.notify(notice, { timeoutMs: 2500 });
|
|
195
|
+
}
|
|
196
|
+
else if (channel.working) {
|
|
197
|
+
// While the model is streaming, the message joins the DSH inbox and is
|
|
198
|
+
// processed after the current turn — say so, or it looks "lost".
|
|
199
|
+
channel.notify(t('input-sent-after-turn'), { timeoutMs: 2500 });
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* Enter while the model is working = STEER (Codex/pi semantics): the
|
|
204
|
+
* message is injected at the next step boundary of the RUNNING turn and
|
|
205
|
+
* the agent continues without aborting — the "immediate" send.
|
|
206
|
+
*/
|
|
207
|
+
const steerSend = (text) => {
|
|
208
|
+
const trimmed = text.trim();
|
|
209
|
+
if (!trimmed)
|
|
210
|
+
return;
|
|
211
|
+
history.current.push(trimmed);
|
|
212
|
+
if (history.current.length > HISTORY_LIMIT)
|
|
213
|
+
history.current.shift();
|
|
214
|
+
historyIndex.current = -1;
|
|
215
|
+
setValue('');
|
|
216
|
+
setCursor(0);
|
|
217
|
+
setSelectedCommand(0);
|
|
218
|
+
appendHistory(trimmed);
|
|
219
|
+
channel.steer(trimmed);
|
|
220
|
+
channel.notify(t('input-interrupted-next'), { timeoutMs: 2500 });
|
|
221
|
+
};
|
|
222
|
+
/**
|
|
223
|
+
* Tab while the model is working = plain queue (followup): the message
|
|
224
|
+
* waits for the running turn to end, then is processed in order.
|
|
225
|
+
*/
|
|
226
|
+
const queueSend = (text) => {
|
|
227
|
+
const trimmed = text.trim();
|
|
228
|
+
if (!trimmed)
|
|
229
|
+
return;
|
|
230
|
+
history.current.push(trimmed);
|
|
231
|
+
if (history.current.length > HISTORY_LIMIT)
|
|
232
|
+
history.current.shift();
|
|
233
|
+
historyIndex.current = -1;
|
|
234
|
+
setValue('');
|
|
235
|
+
setCursor(0);
|
|
236
|
+
setSelectedCommand(0);
|
|
237
|
+
appendHistory(trimmed);
|
|
238
|
+
channel.submit(trimmed);
|
|
239
|
+
channel.notify(t('input-queued-after-turn'), { timeoutMs: 2500 });
|
|
240
|
+
};
|
|
241
|
+
/**
|
|
242
|
+
* Alt+Up: pull the last pending message back into the input for editing
|
|
243
|
+
* (never interrupts the running turn). Refused when the running dsh-agent
|
|
244
|
+
* cannot withdraw inbox messages (released package without the inbox API).
|
|
245
|
+
*/
|
|
246
|
+
const pullBackLast = () => {
|
|
247
|
+
const item = channel.pending[channel.pending.length - 1];
|
|
248
|
+
if (!item)
|
|
249
|
+
return;
|
|
250
|
+
if (!channel.removePending(item.id)) {
|
|
251
|
+
channel.notify(t('input-cannot-retract'), { color: 'warning', timeoutMs: 2500 });
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
setValue(item.text);
|
|
255
|
+
setCursor(item.text.length);
|
|
256
|
+
setSelectedCommand(0);
|
|
257
|
+
setFileSelected(0);
|
|
258
|
+
channel.notify(t('input-retracted'), { timeoutMs: 2000 });
|
|
259
|
+
};
|
|
260
|
+
/**
|
|
261
|
+
* Ctrl+Enter: abort the running turn and send the input immediately — the
|
|
262
|
+
* model stops what it is doing and starts on this message right away.
|
|
263
|
+
*/
|
|
264
|
+
const interruptSend = () => {
|
|
265
|
+
const trimmed = value.trim();
|
|
266
|
+
if (!trimmed) {
|
|
267
|
+
channel.notify(t('input-empty'), { color: 'warning' });
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
// Abort the running turn and deliver: previously queued pending
|
|
271
|
+
// messages first (FIFO), then the current input — all processed
|
|
272
|
+
// immediately once the abort settles.
|
|
273
|
+
const count = channel.interruptAndDeliver([...channel.pending.map(item => item.text), value]);
|
|
274
|
+
if (count === 0)
|
|
275
|
+
return;
|
|
276
|
+
history.current.push(trimmed);
|
|
277
|
+
if (history.current.length > HISTORY_LIMIT)
|
|
278
|
+
history.current.shift();
|
|
279
|
+
historyIndex.current = -1;
|
|
280
|
+
setValue('');
|
|
281
|
+
setCursor(0);
|
|
282
|
+
setSelectedCommand(0);
|
|
283
|
+
setFileSelected(0);
|
|
284
|
+
appendHistory(trimmed);
|
|
285
|
+
channel.notify(t('input-interrupt-immediate'), { timeoutMs: 2500 });
|
|
286
|
+
};
|
|
287
|
+
/**
|
|
288
|
+
* Execute a slash command (built-in or plugin-registered) when the input
|
|
289
|
+
* resolves to one: the name parses as the first token so `/plan off`
|
|
290
|
+
* dispatches `plan` with its argument text, and the merged command list
|
|
291
|
+
* (locals + registry) decides whether the line is a command at all.
|
|
292
|
+
*/
|
|
293
|
+
const tryRunCommand = (text) => {
|
|
294
|
+
if (!text.startsWith('/'))
|
|
295
|
+
return false;
|
|
296
|
+
const parsed = parseCommandName(text);
|
|
297
|
+
if (parsed === undefined)
|
|
298
|
+
return false;
|
|
299
|
+
const known = channel.commandList.some(command => command.name === parsed.name);
|
|
300
|
+
if (!known)
|
|
301
|
+
return false;
|
|
302
|
+
const handled = onRunCommand(parsed.name, parsed.rawInput);
|
|
303
|
+
if (handled) {
|
|
304
|
+
history.current.push(text.trim());
|
|
305
|
+
if (history.current.length > HISTORY_LIMIT)
|
|
306
|
+
history.current.shift();
|
|
307
|
+
historyIndex.current = -1;
|
|
308
|
+
setValue('');
|
|
309
|
+
setCursor(0);
|
|
310
|
+
setSelectedCommand(0);
|
|
311
|
+
appendHistory(text.trim());
|
|
312
|
+
}
|
|
313
|
+
return handled;
|
|
314
|
+
};
|
|
315
|
+
const setInput = (next, cursorOffset = next.length) => {
|
|
316
|
+
setValue(next);
|
|
317
|
+
setCursor(Math.max(0, Math.min(cursorOffset, next.length)));
|
|
318
|
+
};
|
|
319
|
+
/** Line index of the cursor; -1 when the cursor is at the very end. */
|
|
320
|
+
const cursorLine = () => {
|
|
321
|
+
const before = value.slice(0, cursor);
|
|
322
|
+
return before.split('\n').length - 1;
|
|
323
|
+
};
|
|
324
|
+
/** Column of the cursor within its line. */
|
|
325
|
+
const cursorColumn = () => {
|
|
326
|
+
const before = value.slice(0, cursor);
|
|
327
|
+
const line = before.split('\n').pop() ?? '';
|
|
328
|
+
return line.length;
|
|
329
|
+
};
|
|
330
|
+
useInput((input, key, event) => {
|
|
331
|
+
if (selectionActive)
|
|
332
|
+
return;
|
|
333
|
+
/** Insert text at the caret (typing, paste) and dismiss overlays. */
|
|
334
|
+
const insertAtCaret = (text) => {
|
|
335
|
+
if (helpOpen)
|
|
336
|
+
onToggleHelp();
|
|
337
|
+
const next = value.slice(0, cursor) + text + value.slice(cursor);
|
|
338
|
+
setValue(next);
|
|
339
|
+
setCursor(cursor + text.length);
|
|
340
|
+
setSelectedCommand(0);
|
|
341
|
+
setFileSelected(0);
|
|
342
|
+
};
|
|
343
|
+
// Bracketed paste (terminal paste — Ctrl+Shift+V / right-click): insert
|
|
344
|
+
// verbatim at the caret. Paste content may contain newlines — that is
|
|
345
|
+
// NOT Enter — so this branch runs before the whole-line submit rule.
|
|
346
|
+
if (event?.isPasted && input.length > 0) {
|
|
347
|
+
insertAtCaret(input.replace(/\r\n/g, '\n').replace(/\r/g, '\n'));
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
// Ctrl+V: raw mode hands the key to the app, so the clipboard is read
|
|
351
|
+
// here — text, or file paths when Explorer copied files (pasted files
|
|
352
|
+
// insert their paths).
|
|
353
|
+
if (key.ctrl && input === 'v') {
|
|
354
|
+
if (clipboardBusyRef.current)
|
|
355
|
+
return;
|
|
356
|
+
clipboardBusyRef.current = true;
|
|
357
|
+
void readClipboard().then(content => {
|
|
358
|
+
clipboardBusyRef.current = false;
|
|
359
|
+
if (content === null) {
|
|
360
|
+
channel.notify(t('input-clipboard-empty'), { color: 'warning' });
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
insertAtCaret(formatClipboardInsert(content));
|
|
364
|
+
});
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Unified Enter semantics (both the parsed `return` key and the raw
|
|
369
|
+
* CR/LF line from Windows cmd pipelines):
|
|
370
|
+
* - command menu open → run the SELECTED command (never send `/mo`);
|
|
371
|
+
* - model working → STEER into the running turn (next step boundary,
|
|
372
|
+
* agent continues — the "immediate" send; Codex/pi semantics);
|
|
373
|
+
* - otherwise → submit directly (or run a unique command).
|
|
374
|
+
*/
|
|
375
|
+
const handleEnter = () => {
|
|
376
|
+
// A single Enter can arrive as two events in cmd pipelines (`\r`
|
|
377
|
+
// parsed as return + a raw `\n` line): collapse them so one keypress
|
|
378
|
+
// never sends the message twice.
|
|
379
|
+
const now = Date.now();
|
|
380
|
+
if (now - lastEnterAtRef.current < 80)
|
|
381
|
+
return;
|
|
382
|
+
lastEnterAtRef.current = now;
|
|
383
|
+
if (overlayOpen) {
|
|
384
|
+
const command = suggestions[selectedCommand];
|
|
385
|
+
if (command) {
|
|
386
|
+
tryRunCommand(`/${command.name}`);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
// File-completion overlay open → Enter accepts the selection (same
|
|
391
|
+
// contract as the command menu: the overlay owns Enter while open).
|
|
392
|
+
if (fileOverlayOpen) {
|
|
393
|
+
const file = fileMatches[fileSelected];
|
|
394
|
+
if (file) {
|
|
395
|
+
acceptFile(file);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (channel.working && value.trim() !== '') {
|
|
400
|
+
steerSend(value);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
if (!tryRunCommand(value))
|
|
404
|
+
submitText(value);
|
|
405
|
+
};
|
|
406
|
+
// Whole-line input from Windows ConPTY pipelines (cmd batch -> node):
|
|
407
|
+
// the trailing CR/LF marks a complete line to submit. A bare Enter
|
|
408
|
+
// arrives as `\r`/`\n`/`\r\n` — treat it as Enter, NOT a direct
|
|
409
|
+
// submit. Only real multi-char piped lines keep the legacy
|
|
410
|
+
// direct-submit path.
|
|
411
|
+
if (input.includes('\n') || input.includes('\r')) {
|
|
412
|
+
if (/^[\r\n]+$/.test(input)) {
|
|
413
|
+
handleEnter();
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
const line = (value + input).trim();
|
|
417
|
+
if (line.startsWith('/')) {
|
|
418
|
+
const matches = filterCommands(line, channel.commandList);
|
|
419
|
+
if (matches.length === 1) {
|
|
420
|
+
tryRunCommand(`/${matches[0].name}`);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
if (!tryRunCommand(line))
|
|
425
|
+
submitText(line);
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (key.return && key.ctrl) {
|
|
429
|
+
// Ctrl+Enter: interrupt the running turn and process this message
|
|
430
|
+
// immediately (Windows Terminal sends CSI 13;5u / 13;1;5u).
|
|
431
|
+
interruptSend();
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
if (key.return && key.shift) {
|
|
435
|
+
// Insert a newline at the caret (multi-line input).
|
|
436
|
+
const next = value.slice(0, cursor) + '\n' + value.slice(cursor);
|
|
437
|
+
setValue(next);
|
|
438
|
+
setCursor(cursor + 1);
|
|
439
|
+
setSelectedCommand(0);
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
if (key.return) {
|
|
443
|
+
handleEnter();
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
// Shift+Tab cycles the reasoning effort (dsh parity: the adapter's own
|
|
447
|
+
// level list, e.g. deepseek Off→High→Max). Must precede the plain-Tab
|
|
448
|
+
// arms — the parser reports backtab as key.tab + key.shift.
|
|
449
|
+
if (key.tab && key.shift) {
|
|
450
|
+
void channel.cycleEffort();
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
if (key.tab && fileOverlayOpen) {
|
|
454
|
+
const file = fileMatches[fileSelected];
|
|
455
|
+
if (file)
|
|
456
|
+
acceptFile(file);
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
if (key.tab && overlayOpen) {
|
|
460
|
+
const command = suggestions[selectedCommand];
|
|
461
|
+
if (command)
|
|
462
|
+
setInput(`/${command.name} `);
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
// Tab while the model is working = queue for AFTER the turn (followup),
|
|
466
|
+
// distinct from Enter's steer (Codex's "tab to queue message").
|
|
467
|
+
if (key.tab && channel.working && value.trim() !== '') {
|
|
468
|
+
queueSend(value);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (key.meta && key.upArrow) {
|
|
472
|
+
// Alt+Up: pull the last pending message back for editing (pi/Codex).
|
|
473
|
+
pullBackLast();
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
if (key.upArrow) {
|
|
477
|
+
if (fileOverlayOpen) {
|
|
478
|
+
setFileSelected(index => index <= 0 ? fileMatches.length - 1 : index - 1);
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
const line = cursorLine();
|
|
482
|
+
if (line > 0) {
|
|
483
|
+
// Move to the previous line, clamping to its length.
|
|
484
|
+
const upToLineStart = value.lastIndexOf('\n', cursor - 1);
|
|
485
|
+
const prevLineStart = upToLineStart === -1 ? 0 : value.lastIndexOf('\n', upToLineStart - 1) + 1;
|
|
486
|
+
const prevLine = value.slice(prevLineStart, upToLineStart);
|
|
487
|
+
setCursor(prevLineStart + Math.min(cursorColumn(), prevLine.length));
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
if (overlayOpen) {
|
|
491
|
+
setSelectedCommand(index => index <= 0 ? suggestions.length - 1 : index - 1);
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
if (history.current.length === 0)
|
|
495
|
+
return;
|
|
496
|
+
historyIndex.current = historyIndex.current < 0
|
|
497
|
+
? history.current.length - 1
|
|
498
|
+
: Math.max(0, historyIndex.current - 1);
|
|
499
|
+
const entry = history.current[historyIndex.current] ?? '';
|
|
500
|
+
setValue(entry);
|
|
501
|
+
setCursor(entry.length);
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
if (key.downArrow) {
|
|
505
|
+
if (fileOverlayOpen) {
|
|
506
|
+
setFileSelected(index => index >= fileMatches.length - 1 ? 0 : index + 1);
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
const line = cursorLine();
|
|
510
|
+
const lines = value.split('\n');
|
|
511
|
+
if (line < lines.length - 1) {
|
|
512
|
+
const nextLineStart = value.indexOf('\n', cursor) + 1;
|
|
513
|
+
const nextLineEnd = value.indexOf('\n', nextLineStart);
|
|
514
|
+
const nextLine = value.slice(nextLineStart, nextLineEnd === -1 ? value.length : nextLineEnd);
|
|
515
|
+
setCursor(nextLineStart + Math.min(cursorColumn(), nextLine.length));
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
if (overlayOpen) {
|
|
519
|
+
setSelectedCommand(index => index >= suggestions.length - 1 ? 0 : index + 1);
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
if (historyIndex.current < 0)
|
|
523
|
+
return;
|
|
524
|
+
historyIndex.current += 1;
|
|
525
|
+
const entry = historyIndex.current >= history.current.length
|
|
526
|
+
? ''
|
|
527
|
+
: (history.current[historyIndex.current] ?? '');
|
|
528
|
+
setValue(entry);
|
|
529
|
+
setCursor(entry.length);
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
if (key.leftArrow) {
|
|
533
|
+
setCursor(previous => Math.max(0, previous - 1));
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
if (key.rightArrow) {
|
|
537
|
+
setCursor(previous => Math.min(value.length, previous + 1));
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
if (key.ctrl && key.leftArrow) {
|
|
541
|
+
// Jump to the previous word boundary (readline alt+b).
|
|
542
|
+
setCursor(previous => wordBoundaryLeft(value, previous));
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
if (key.ctrl && key.rightArrow) {
|
|
546
|
+
// Jump to the next word boundary (readline alt+f).
|
|
547
|
+
setCursor(previous => wordBoundaryRight(value, previous));
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
if (key.backspace) {
|
|
551
|
+
if (cursor === 0)
|
|
552
|
+
return;
|
|
553
|
+
setValue(value.slice(0, cursor - 1) + value.slice(cursor));
|
|
554
|
+
setCursor(cursor - 1);
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
if (key.delete) {
|
|
558
|
+
if (cursor >= value.length)
|
|
559
|
+
return;
|
|
560
|
+
setValue(value.slice(0, cursor) + value.slice(cursor + 1));
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
if (key.home) {
|
|
564
|
+
// Start of the current line.
|
|
565
|
+
const lineStart = value.lastIndexOf('\n', cursor - 1) + 1;
|
|
566
|
+
setCursor(lineStart);
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
if (key.end) {
|
|
570
|
+
// End of the current line.
|
|
571
|
+
const nextLine = value.indexOf('\n', cursor);
|
|
572
|
+
setCursor(nextLine === -1 ? value.length : nextLine);
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
if (key.ctrl && input === 'a') {
|
|
576
|
+
const lineStart = value.lastIndexOf('\n', cursor - 1) + 1;
|
|
577
|
+
setCursor(lineStart);
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
if (key.ctrl && input === 'e') {
|
|
581
|
+
const nextLine = value.indexOf('\n', cursor);
|
|
582
|
+
setCursor(nextLine === -1 ? value.length : nextLine);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
if (key.ctrl && input === 'u') {
|
|
586
|
+
// Delete to start of line.
|
|
587
|
+
const lineStart = value.lastIndexOf('\n', cursor - 1) + 1;
|
|
588
|
+
setValue(value.slice(0, lineStart) + value.slice(cursor));
|
|
589
|
+
setCursor(lineStart);
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
if (key.ctrl && input === 'k') {
|
|
593
|
+
// Delete to end of line.
|
|
594
|
+
const nextLine = value.indexOf('\n', cursor);
|
|
595
|
+
const end = nextLine === -1 ? value.length : nextLine;
|
|
596
|
+
setValue(value.slice(0, cursor) + value.slice(end));
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
if (key.ctrl && input === 'w') {
|
|
600
|
+
// Delete the word before the cursor (CC/readline behavior): skip
|
|
601
|
+
// trailing whitespace, then the whitespace-delimited word.
|
|
602
|
+
const before = value.slice(0, cursor);
|
|
603
|
+
let end = before.length;
|
|
604
|
+
while (end > 0 && /\s/.test(before[end - 1]))
|
|
605
|
+
end--;
|
|
606
|
+
let start = end;
|
|
607
|
+
while (start > 0 && !/\s/.test(before[start - 1]))
|
|
608
|
+
start--;
|
|
609
|
+
setValue(value.slice(0, start) + value.slice(cursor));
|
|
610
|
+
setCursor(start);
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
if (key.escape) {
|
|
614
|
+
if (helpOpen) {
|
|
615
|
+
onToggleHelp();
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
// A single Esc closes the open command menu first (CC/pi behavior);
|
|
619
|
+
// the double-tap-clear semantics only apply to ordinary input.
|
|
620
|
+
if (overlayOpen) {
|
|
621
|
+
setValue('');
|
|
622
|
+
setCursor(0);
|
|
623
|
+
setSelectedCommand(0);
|
|
624
|
+
setFileSelected(0);
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
// File overlay: Esc dismisses the menu for THIS token only — clearing
|
|
628
|
+
// the input would nuke a mid-message `@` mention's surrounding text.
|
|
629
|
+
if (fileOverlayOpen) {
|
|
630
|
+
fileEscRef.current = mention?.start ?? -1;
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
// With pending messages while working, Esc = interrupt and deliver
|
|
634
|
+
// them right away (Codex's "interrupt and send immediately"): the
|
|
635
|
+
// turn is aborted and each message is re-queued once it settles.
|
|
636
|
+
if (channel.working && channel.pending.length > 0) {
|
|
637
|
+
const count = channel.interruptAndDeliver(channel.pending.map(item => item.text));
|
|
638
|
+
channel.notify(t('interrupt-delivered', { n: count }), {
|
|
639
|
+
timeoutMs: 2500,
|
|
640
|
+
});
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
// A single Esc clears the current input (if any); the double-tap
|
|
644
|
+
// path below handles rewind/clear on an already-empty input.
|
|
645
|
+
if (value.length > 0) {
|
|
646
|
+
setValue('');
|
|
647
|
+
setCursor(0);
|
|
648
|
+
setSelectedCommand(0);
|
|
649
|
+
setFileSelected(0);
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
// Double-tap Esc: clear the input when it has content; when empty,
|
|
653
|
+
// open the rewind picker (CC's "Double-tap esc to rewind the code
|
|
654
|
+
// and/or conversation to a previous point in time").
|
|
655
|
+
if (escPendingRef.current) {
|
|
656
|
+
escPendingRef.current = false;
|
|
657
|
+
if (escTimerRef.current)
|
|
658
|
+
clearTimeout(escTimerRef.current);
|
|
659
|
+
if (value.length === 0) {
|
|
660
|
+
onRewindRequest?.();
|
|
661
|
+
}
|
|
662
|
+
else {
|
|
663
|
+
setValue('');
|
|
664
|
+
setCursor(0);
|
|
665
|
+
}
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
escPendingRef.current = true;
|
|
669
|
+
channel.notify(value.length === 0
|
|
670
|
+
? 'Press Esc again to rewind'
|
|
671
|
+
: 'Press Esc again to clear');
|
|
672
|
+
escTimerRef.current = setTimeout(() => {
|
|
673
|
+
escPendingRef.current = false;
|
|
674
|
+
}, 3000);
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
if (input === '?' && value.length === 0) {
|
|
678
|
+
onToggleHelp();
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
if (input && !key.ctrl && !key.meta && !key.tab && !key.escape) {
|
|
682
|
+
// Typing anything else dismisses the help menu (CC behavior).
|
|
683
|
+
if (helpOpen)
|
|
684
|
+
onToggleHelp();
|
|
685
|
+
const next = value.slice(0, cursor) + input + value.slice(cursor);
|
|
686
|
+
setValue(next);
|
|
687
|
+
setCursor(cursor + input.length);
|
|
688
|
+
setSelectedCommand(0);
|
|
689
|
+
setFileSelected(0);
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
// === Render: hard-wrap every logical line at the input width, then show
|
|
693
|
+
// the window of visual lines with the caret row always visible (CC's
|
|
694
|
+
// maxVisibleLines behavior with automatic wrapping).
|
|
695
|
+
const inputWidth = Math.max(10, columns - 3);
|
|
696
|
+
const visualLines = wrapToWidth(value, inputWidth);
|
|
697
|
+
const caretVisualLine = wrapToWidth(value.slice(0, cursor), inputWidth).length - 1;
|
|
698
|
+
const windowStart = Math.max(0, Math.min(caretVisualLine - MAX_VISIBLE_LINES + 1, visualLines.length - MAX_VISIBLE_LINES));
|
|
699
|
+
const visibleLines = visualLines.slice(windowStart, windowStart + MAX_VISIBLE_LINES);
|
|
700
|
+
// Caret position in the caret's visual row, in two units:
|
|
701
|
+
// - char index (for slicing the row's characters in the render below)
|
|
702
|
+
// - visual column (for the physical cursor declaration — CJK characters
|
|
703
|
+
// occupy TWO terminal columns, so the raw char count would park the
|
|
704
|
+
// cursor mid-character and Windows Terminal would paint the IME
|
|
705
|
+
// preedit (pinyin) over the surrounding text).
|
|
706
|
+
const caretCharCol = () => {
|
|
707
|
+
const before = value.slice(0, cursor);
|
|
708
|
+
const rows = wrapToWidth(before, inputWidth);
|
|
709
|
+
const last = rows[rows.length - 1] ?? '';
|
|
710
|
+
return last.length;
|
|
711
|
+
};
|
|
712
|
+
const caretVisualCol = () => {
|
|
713
|
+
const before = value.slice(0, cursor);
|
|
714
|
+
const rows = wrapToWidth(before, inputWidth);
|
|
715
|
+
const last = rows[rows.length - 1] ?? '';
|
|
716
|
+
return stringWidth(last);
|
|
717
|
+
};
|
|
718
|
+
const rendered = visibleLines.map((line, index) => {
|
|
719
|
+
const absoluteLine = windowStart + index;
|
|
720
|
+
if (absoluteLine !== caretVisualLine) {
|
|
721
|
+
return (_jsx(Text, { wrap: "truncate-end", children: line }, absoluteLine));
|
|
722
|
+
}
|
|
723
|
+
// Caret row: invert the char at the caret column (solid block).
|
|
724
|
+
const col = caretCharCol();
|
|
725
|
+
const before = line.slice(0, col);
|
|
726
|
+
const at = line[col] ?? ' ';
|
|
727
|
+
const after = line.slice(col + 1);
|
|
728
|
+
return (_jsxs(Text, { wrap: "truncate-end", children: [before, _jsx(Text, { inverse: true, children: at }), after] }, absoluteLine));
|
|
729
|
+
});
|
|
730
|
+
const lastNotification = channel.notifications[channel.notifications.length - 1];
|
|
731
|
+
// Park the native terminal cursor at the input caret (via the renderer's
|
|
732
|
+
// cursor-declaration mechanism). Terminal emulators render IME preedit
|
|
733
|
+
// text and screen-reader focus at the physical cursor, so parking it at
|
|
734
|
+
// the caret makes CJK/IME composition appear inline at the input instead
|
|
735
|
+
// of at the screen's bottom row; in line-mode terminals the console echo
|
|
736
|
+
// of typed characters lands at the same spot. `line`/`column` are
|
|
737
|
+
// relative to the value box the ref attaches to.
|
|
738
|
+
const valueBoxRef = useDeclaredCursor({
|
|
739
|
+
line: caretVisualLine - windowStart,
|
|
740
|
+
column: caretVisualCol(),
|
|
741
|
+
active: !selectionActive,
|
|
742
|
+
});
|
|
743
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [lastNotification && (_jsx(Box, { position: "absolute", marginTop: -1, height: 1, width: "100%", paddingLeft: 2, paddingRight: 1, flexDirection: "column", justifyContent: "flex-end", overflow: "hidden", children: _jsx(Box, { justifyContent: "flex-end", children: _jsx(Text, { color: lastNotification.color, dimColor: !lastNotification.color, wrap: "truncate", children: lastNotification.text }) }) })), helpOpen && (_jsx(Box, { marginBottom: 1, children: _jsx(HelpMenu, { commands: channel.commandList }) })), channel.pending.length > 0 && (_jsxs(Box, { flexDirection: "column", paddingLeft: 2, paddingBottom: 1, children: [channel.pending.some(item => item.placement === 'steer') && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["\u26A1 ", t('input-pending-steer-label')] }), channel.pending
|
|
744
|
+
.filter(item => item.placement === 'steer')
|
|
745
|
+
.map(item => (_jsxs(Text, { dimColor: true, wrap: "truncate", children: [' ', "\u21B3 ", item.text] }, item.id)))] })), channel.pending.some(item => item.placement === 'followup') && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["\u23F3 ", t('input-pending-queue-label')] }), channel.pending
|
|
746
|
+
.filter(item => item.placement === 'followup')
|
|
747
|
+
.map(item => (_jsxs(Text, { dimColor: true, wrap: "truncate", children: [' ', "\u21B3 ", item.text] }, item.id)))] })), _jsxs(Text, { dimColor: true, children: ["Alt+\u2191 ", t('input-pending-actions-hint')] })] })), fileOverlayOpen && (_jsx(Box, { paddingLeft: 2, paddingBottom: 1, children: _jsx(FileSuggestions, { files: fileMatches, selectedIndex: fileSelected, columns: columns }) })), overlayOpen && (_jsx(Box, { paddingLeft: 2, paddingBottom: 1, children: _jsx(CommandSuggestions, { commands: suggestions, selectedIndex: selectedCommand, columns: columns }) })), _jsx(Box, { flexDirection: "column", alignItems: "flex-start", justifyContent: "flex-start", borderColor: "promptBorder", borderStyle: "round", borderLeft: false, borderRight: false, borderBottom: true, width: "100%", children: _jsxs(Box, { flexDirection: "row", alignItems: "flex-start", width: "100%", children: [_jsx(Text, { dimColor: channel.working, children: "\u276F " }), _jsx(Box, { ref: valueBoxRef, flexGrow: 1, flexShrink: 1, children: value.length === 0 ? (_jsx(Text, { inverse: true, children: " " })) : (_jsx(Box, { flexDirection: "column", children: rendered })) })] }) })] }));
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* Hard-wrap text into visual rows of at most `width` columns (CJK-aware via
|
|
751
|
+
* stringWidth). Used by the input renderer so long lines wrap instead of
|
|
752
|
+
* truncating, with exact caret-row mapping.
|
|
753
|
+
*/
|
|
754
|
+
function wrapToWidth(text, width) {
|
|
755
|
+
const rows = [];
|
|
756
|
+
for (const line of text.split('\n')) {
|
|
757
|
+
if (line === '') {
|
|
758
|
+
rows.push('');
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
let current = '';
|
|
762
|
+
let currentWidth = 0;
|
|
763
|
+
for (const ch of line) {
|
|
764
|
+
const w = stringWidth(ch);
|
|
765
|
+
if (currentWidth + w > width && current !== '') {
|
|
766
|
+
rows.push(current);
|
|
767
|
+
current = ch;
|
|
768
|
+
currentWidth = w;
|
|
769
|
+
}
|
|
770
|
+
else {
|
|
771
|
+
current += ch;
|
|
772
|
+
currentWidth += w;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
rows.push(current);
|
|
776
|
+
}
|
|
777
|
+
return rows;
|
|
778
|
+
}
|