cvc-tui 0.4.4 → 0.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICES.md +13 -0
- package/dist/app/completion.js +102 -0
- package/dist/app/createGatewayEventHandler.js +508 -0
- package/dist/app/createSlashHandler.js +101 -0
- package/dist/app/delegationStore.js +51 -0
- package/dist/app/gatewayContext.js +17 -0
- package/dist/app/historyStore.js +123 -0
- package/dist/app/inputBuffer.js +120 -0
- package/dist/app/inputSelectionStore.js +8 -0
- package/dist/app/inputStore.js +28 -0
- package/dist/app/interfaces.js +6 -0
- package/dist/app/overlayStore.js +40 -0
- package/dist/app/promptStore.js +44 -0
- package/dist/app/queueStore.js +25 -0
- package/dist/app/scroll.js +44 -0
- package/dist/app/setupHandoff.js +28 -0
- package/dist/app/slash/commands/core.js +479 -0
- package/dist/app/slash/commands/debug.js +44 -0
- package/dist/app/slash/commands/ops.js +512 -0
- package/dist/app/slash/commands/session.js +431 -0
- package/dist/app/slash/commands/setup.js +20 -0
- package/dist/app/slash/commands/toggles.js +40 -0
- package/dist/app/slash/registry.js +18 -0
- package/dist/app/slash/types.js +1 -0
- package/dist/app/spawnHistoryStore.js +105 -0
- package/dist/app/turnController.js +650 -0
- package/dist/app/turnStore.js +48 -0
- package/dist/app/uiStore.js +36 -0
- package/dist/app/useComposerState.js +265 -0
- package/dist/app/useConfigSync.js +144 -0
- package/dist/app/useInputHandlers.js +403 -0
- package/dist/app/useLongRunToolCharms.js +50 -0
- package/dist/app/useMainApp.js +638 -0
- package/dist/app/useSessionLifecycle.js +175 -0
- package/dist/app/useSubmission.js +287 -0
- package/dist/app.js +15 -0
- package/dist/banner.js +63 -0
- package/dist/components/agentsOverlay.js +474 -0
- package/dist/components/appChrome.js +252 -0
- package/dist/components/appLayout.js +122 -0
- package/dist/components/appOverlays.js +65 -0
- package/dist/components/branding.js +97 -0
- package/dist/components/fpsOverlay.js +22 -0
- package/dist/components/helpHint.js +21 -0
- package/dist/components/markdown.js +501 -0
- package/dist/components/maskedPrompt.js +12 -0
- package/dist/components/messageLine.js +82 -0
- package/dist/components/modelPicker.js +254 -0
- package/dist/components/overlayControls.js +30 -0
- package/dist/components/overlays/confirmPrompt.js +25 -0
- package/dist/components/overlays/helpOverlay.js +76 -0
- package/dist/components/overlays/historySearch.js +49 -0
- package/dist/components/overlays/modelPicker.js +60 -0
- package/dist/components/overlays/overlayUtils.js +19 -0
- package/dist/components/overlays/secretPrompt.js +36 -0
- package/dist/components/overlays/sessionPicker.js +93 -0
- package/dist/components/overlays/skillsHub.js +71 -0
- package/dist/components/prompts.js +95 -0
- package/dist/components/queuedMessages.js +24 -0
- package/dist/components/sessionPicker.js +130 -0
- package/dist/components/skillsHub.js +165 -0
- package/dist/components/streamingAssistant.js +35 -0
- package/dist/components/streamingMarkdown.js +144 -0
- package/dist/components/textInput.js +794 -0
- package/dist/components/themed.js +12 -0
- package/dist/components/thinking.js +496 -0
- package/dist/components/todoPanel.js +40 -0
- package/dist/components/transcript.js +22 -0
- package/dist/config/env.js +18 -0
- package/dist/config/limits.js +22 -0
- package/dist/config/timing.js +25 -0
- package/dist/content/charms.js +5 -0
- package/dist/content/faces.js +21 -0
- package/dist/content/fortunes.js +29 -0
- package/dist/content/hotkeys.js +38 -0
- package/dist/content/placeholders.js +15 -0
- package/dist/content/setup.js +14 -0
- package/dist/content/verbs.js +41 -0
- package/dist/domain/details.js +53 -0
- package/dist/domain/messages.js +63 -0
- package/dist/domain/paths.js +16 -0
- package/dist/domain/providers.js +11 -0
- package/dist/domain/roles.js +6 -0
- package/dist/domain/slash.js +11 -0
- package/dist/domain/usage.js +1 -0
- package/dist/domain/viewport.js +33 -0
- package/dist/entry.js +64 -70236
- package/dist/gateway/client.js +312 -0
- package/dist/gatewayClient.js +574 -0
- package/dist/gatewayTypes.js +1 -0
- package/dist/hooks/useCompletion.js +86 -0
- package/dist/hooks/useGitBranch.js +58 -0
- package/dist/hooks/useInputHistory.js +12 -0
- package/dist/hooks/useQueue.js +57 -0
- package/dist/hooks/useVirtualHistory.js +401 -0
- package/dist/lib/circularBuffer.js +43 -0
- package/dist/lib/clipboard.js +126 -0
- package/dist/lib/editor.js +41 -0
- package/dist/lib/editor.test.js +58 -0
- package/dist/lib/emoji.js +49 -0
- package/dist/lib/externalCli.js +11 -0
- package/dist/lib/forceTruecolor.js +26 -0
- package/dist/lib/fpsStore.js +36 -0
- package/dist/lib/gracefulExit.js +29 -0
- package/dist/lib/history.js +69 -0
- package/dist/lib/inputMetrics.js +143 -0
- package/dist/lib/liveProgress.js +51 -0
- package/dist/lib/liveProgress.test.js +89 -0
- package/dist/lib/localSessionInfo.js +116 -0
- package/dist/lib/mathUnicode.js +685 -0
- package/dist/lib/memory.js +123 -0
- package/dist/lib/memoryMonitor.js +76 -0
- package/dist/lib/messages.js +3 -0
- package/dist/lib/messages.test.js +25 -0
- package/dist/lib/osc52.js +53 -0
- package/dist/lib/perfPane.js +94 -0
- package/dist/lib/platform.js +312 -0
- package/dist/lib/precisionWheel.js +25 -0
- package/dist/lib/react-devtools-stub.js +12 -0
- package/dist/lib/reasoning.js +39 -0
- package/dist/lib/rpc.js +26 -0
- package/dist/lib/subagentTree.js +287 -0
- package/dist/lib/syntax.js +89 -0
- package/dist/lib/terminalModes.js +46 -0
- package/dist/lib/terminalParity.js +48 -0
- package/dist/lib/terminalSetup.js +321 -0
- package/dist/lib/text.js +203 -0
- package/dist/lib/text.test.js +18 -0
- package/dist/lib/todo.js +2 -0
- package/dist/lib/todo.test.js +22 -0
- package/dist/lib/viewportStore.js +82 -0
- package/dist/lib/virtualHeights.js +61 -0
- package/dist/lib/wheelAccel.js +143 -0
- package/dist/protocol/interpolation.js +4 -0
- package/dist/protocol/paste.js +3 -0
- package/dist/theme.js +398 -0
- package/dist/types.js +1 -0
- package/dist/vendor/cvc-ink/dist/entry-exports.js +52737 -0
- package/dist/vendor/cvc-ink/index.js +1 -0
- package/dist/vendor/cvc-ink/package.json +9 -0
- package/dist/vendor/cvc-ink/text-input.js +1 -0
- package/package.json +9 -9
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Ported from CVC Agent (https://github.com/NousResearch/cvc)
|
|
4
|
+
// Original Copyright (c) 2025 Nous Research. CVC adaptations (c) 2026 Jai Kumar Meena.
|
|
5
|
+
/** Platform-aware keybinding helpers.
|
|
6
|
+
*
|
|
7
|
+
* On macOS the "action" modifier is Cmd. Modern terminals that support kitty
|
|
8
|
+
* keyboard protocol report Cmd as `key.super`; legacy terminals often surface it
|
|
9
|
+
* as `key.meta`. Some macOS terminals also translate Cmd+Left/Right/Backspace
|
|
10
|
+
* into readline-style Ctrl+A/Ctrl+E/Ctrl+U before the app sees them.
|
|
11
|
+
* On other platforms the action modifier is Ctrl.
|
|
12
|
+
* Ctrl+C stays the interrupt key on macOS. On non-mac terminals it can also
|
|
13
|
+
* copy an active TUI selection, matching common terminal selection behavior.
|
|
14
|
+
*/
|
|
15
|
+
export const isMac = process.platform === 'darwin';
|
|
16
|
+
/** True when the platform action-modifier is pressed (Cmd on macOS, Ctrl elsewhere). */
|
|
17
|
+
export const isActionMod = (key) => isMac ? key.meta || key.super === true : key.ctrl;
|
|
18
|
+
/**
|
|
19
|
+
* Accept raw Ctrl+<letter> as an action shortcut on macOS, where `isActionMod`
|
|
20
|
+
* otherwise means Cmd. Two motivations:
|
|
21
|
+
* - Some macOS terminals rewrite Cmd navigation/deletion into readline control
|
|
22
|
+
* keys (Cmd+Left → Ctrl+A, Cmd+Right → Ctrl+E, Cmd+Backspace → Ctrl+U).
|
|
23
|
+
* - Ctrl+K (kill-to-end) and Ctrl+W (delete-word-back) are standard readline
|
|
24
|
+
* bindings that users expect to work regardless of platform, even though
|
|
25
|
+
* no terminal rewrites Cmd into them.
|
|
26
|
+
*/
|
|
27
|
+
export const isMacActionFallback = (key, ch, target) => isMac && key.ctrl && !key.meta && key.super !== true && ch.toLowerCase() === target;
|
|
28
|
+
/** Match action-modifier + a single character (case-insensitive). */
|
|
29
|
+
export const isAction = (key, ch, target) => isActionMod(key) && ch.toLowerCase() === target;
|
|
30
|
+
export const isRemoteShell = (env = process.env) => Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.SSH_TTY);
|
|
31
|
+
export const isCopyShortcut = (key, ch, env = process.env) => ch.toLowerCase() === 'c' &&
|
|
32
|
+
(isAction(key, ch, 'c') ||
|
|
33
|
+
(isRemoteShell(env) && (key.meta || key.super === true)) ||
|
|
34
|
+
// VS Code/Cursor/Windsurf terminal setup forwards Cmd+C as a CSI-u
|
|
35
|
+
// sequence with the super bit plus a benign ctrl bit. Accept that shape
|
|
36
|
+
// even though raw Ctrl+C should remain interrupt on local macOS.
|
|
37
|
+
(isMac && key.ctrl && (key.meta || key.super === true)));
|
|
38
|
+
export const DEFAULT_VOICE_RECORD_KEY = {
|
|
39
|
+
ch: 'b',
|
|
40
|
+
mod: 'ctrl',
|
|
41
|
+
raw: 'ctrl+b'
|
|
42
|
+
};
|
|
43
|
+
/** Modifier aliases.
|
|
44
|
+
*
|
|
45
|
+
* ``meta`` / ``cmd`` / ``command`` are intentionally absent.
|
|
46
|
+
* hermes-ink sets ``key.meta`` for plain Alt/Option on every platform
|
|
47
|
+
* AND for Cmd on some legacy macOS terminals (Terminal.app without
|
|
48
|
+
* kitty-protocol passthrough). Accepting any of those as a literal
|
|
49
|
+
* modifier would produce a display/binding mismatch — a config like
|
|
50
|
+
* ``cmd+b`` would render as ``Cmd+B`` but silently fire on Alt+B, or
|
|
51
|
+
* never fire at all on legacy terminals even though the UI advertises
|
|
52
|
+
* it (Copilot round-6 review on #19835). Users on modern kitty-style
|
|
53
|
+
* terminals (iTerm2 CSI-u, Ghostty, Kitty, WezTerm, Alacritty) spell
|
|
54
|
+
* the platform action modifier ``super`` / ``win``, which match the
|
|
55
|
+
* unambiguous ``key.super`` bit. macOS users on Terminal.app stick
|
|
56
|
+
* with the documented ``ctrl+b``.
|
|
57
|
+
*
|
|
58
|
+
* Cross-runtime parity: the ``ctrl`` / ``control`` / ``alt`` / ``option`` /
|
|
59
|
+
* ``opt`` spellings are normalized identically in the classic CLI
|
|
60
|
+
* (``hermes_cli/voice.py::normalize_voice_record_key_for_prompt_toolkit``)
|
|
61
|
+
* so one ``voice.record_key`` value binds the same shortcut in both
|
|
62
|
+
* runtimes (Copilot round-9 review on #19835). The ``super`` /
|
|
63
|
+
* ``win`` / ``windows`` spellings are TUI-only — prompt_toolkit has no
|
|
64
|
+
* super modifier, so the CLI falls back to the documented default and
|
|
65
|
+
* logs a warning at startup (Copilot round-11 review on #19835). */
|
|
66
|
+
const _MOD_ALIASES = {
|
|
67
|
+
alt: 'alt',
|
|
68
|
+
control: 'ctrl',
|
|
69
|
+
ctrl: 'ctrl',
|
|
70
|
+
option: 'alt',
|
|
71
|
+
opt: 'alt',
|
|
72
|
+
super: 'super',
|
|
73
|
+
win: 'super',
|
|
74
|
+
windows: 'super'
|
|
75
|
+
};
|
|
76
|
+
/** Map config-string named tokens to the canonical name used at match time.
|
|
77
|
+
*
|
|
78
|
+
* Aliases mirror what prompt_toolkit accepts (``return`` ↔ ``enter``,
|
|
79
|
+
* ``esc`` ↔ ``escape``) so a config that round-trips through the CLI also
|
|
80
|
+
* binds in the TUI. */
|
|
81
|
+
const _NAMED_KEY_ALIASES = {
|
|
82
|
+
backspace: 'backspace',
|
|
83
|
+
bs: 'backspace',
|
|
84
|
+
del: 'delete',
|
|
85
|
+
delete: 'delete',
|
|
86
|
+
enter: 'enter',
|
|
87
|
+
esc: 'escape',
|
|
88
|
+
escape: 'escape',
|
|
89
|
+
ret: 'enter',
|
|
90
|
+
return: 'enter',
|
|
91
|
+
space: 'space',
|
|
92
|
+
spc: 'space',
|
|
93
|
+
tab: 'tab'
|
|
94
|
+
};
|
|
95
|
+
/** ``useInputHandlers()`` intercepts these unconditionally before the
|
|
96
|
+
* voice check runs, so a binding like ``ctrl+c`` (interrupt),
|
|
97
|
+
* ``ctrl+d`` (quit), or ``ctrl+l`` (clear screen) would be advertised
|
|
98
|
+
* in /voice status but never fire push-to-talk. Reject at parse time
|
|
99
|
+
* so the user gets the documented Ctrl+B instead of a dead shortcut
|
|
100
|
+
* (Copilot round-4 review on #19835).
|
|
101
|
+
*
|
|
102
|
+
* ``ctrl+x`` is intentionally NOT here — it's only claimed during
|
|
103
|
+
* queue-edit (``queueEditIdx !== null``), so the voice binding works
|
|
104
|
+
* for most of the session and matches CLI parity for ``ctrl+<letter>``
|
|
105
|
+
* bindings (Copilot round-8 review on #19835). */
|
|
106
|
+
const _RESERVED_CTRL_CHARS = new Set(['c', 'd', 'l']);
|
|
107
|
+
/** On macOS the action-modifier intercepts these editor chords via
|
|
108
|
+
* ``isCopyShortcut`` / ``isAction`` in ``useInputHandlers()``:
|
|
109
|
+
* - super+c → copy
|
|
110
|
+
* - super+d → exit
|
|
111
|
+
* - super+l → clear screen
|
|
112
|
+
* - super+v → paste (also claimed at the TextInput layer)
|
|
113
|
+
* On Linux/Windows those globals key off Ctrl instead of Super, so
|
|
114
|
+
* super+<letter> bindings don't collide. Gate the rejection to darwin
|
|
115
|
+
* at parse time so kitty/CSI-u ``super+<key>`` configs still work for
|
|
116
|
+
* non-mac users (Copilot round-8 review on #19835). */
|
|
117
|
+
const _RESERVED_SUPER_CHARS = new Set(['c', 'd', 'l', 'v']);
|
|
118
|
+
/** On macOS ``isActionMod`` accepts ``key.meta`` as the action
|
|
119
|
+
* modifier — but hermes-ink reports Alt as ``key.meta`` on many
|
|
120
|
+
* terminals. So on darwin a configured ``alt+c`` / ``alt+d`` / ``alt+l``
|
|
121
|
+
* gets swallowed by ``isCopyShortcut`` / ``isAction`` before the voice
|
|
122
|
+
* check runs. Block at parse time so /voice status doesn't advertise
|
|
123
|
+
* a shortcut that actually copies / quits / clears (Copilot round-12
|
|
124
|
+
* review on #19835). */
|
|
125
|
+
const _RESERVED_ALT_CHARS_MAC = new Set(['c', 'd', 'l']);
|
|
126
|
+
/** Match an ink ``key`` event against a parsed named key. The ink runtime
|
|
127
|
+
* sets one boolean per named key; ``space`` is a printable char so it
|
|
128
|
+
* arrives as ``ch === ' '`` rather than a dedicated ``key.space`` flag. */
|
|
129
|
+
const _matchesNamedKey = (named, key, ch) => {
|
|
130
|
+
switch (named) {
|
|
131
|
+
case 'backspace':
|
|
132
|
+
return key.backspace === true;
|
|
133
|
+
case 'delete':
|
|
134
|
+
return key.delete === true;
|
|
135
|
+
case 'enter':
|
|
136
|
+
return key.return === true;
|
|
137
|
+
case 'escape':
|
|
138
|
+
return key.escape === true;
|
|
139
|
+
case 'space':
|
|
140
|
+
return ch === ' ';
|
|
141
|
+
case 'tab':
|
|
142
|
+
return key.tab === true;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Parse a config-string voice record key like ``ctrl+b`` / ``alt+r`` /
|
|
147
|
+
* ``ctrl+space`` into ``{mod, ch, named?}``. Accepts single characters
|
|
148
|
+
* AND the named tokens declared in ``_NAMED_KEY_ALIASES`` (``space``,
|
|
149
|
+
* ``enter``/``return``, ``tab``, ``escape``/``esc``, ``backspace``,
|
|
150
|
+
* ``delete``) — matching the keys prompt_toolkit accepts on the CLI
|
|
151
|
+
* side via the ``c-<name>`` rewrite in ``cli.py``.
|
|
152
|
+
*
|
|
153
|
+
* Accepts ``unknown`` because the source is raw YAML via
|
|
154
|
+
* ``config.get full`` — a hand-edited ``voice.record_key: 1`` or
|
|
155
|
+
* ``voice.record_key: true`` would otherwise crash ``.trim()`` on a
|
|
156
|
+
* non-string scalar (Copilot round-3 review on #19835). Non-string /
|
|
157
|
+
* empty / unrecognised values fall back to the documented Ctrl+B
|
|
158
|
+
* default so a typo never silently disables the shortcut.
|
|
159
|
+
*/
|
|
160
|
+
export const parseVoiceRecordKey = (raw) => {
|
|
161
|
+
if (typeof raw !== 'string') {
|
|
162
|
+
return DEFAULT_VOICE_RECORD_KEY;
|
|
163
|
+
}
|
|
164
|
+
const lower = raw.trim().toLowerCase();
|
|
165
|
+
if (!lower) {
|
|
166
|
+
return DEFAULT_VOICE_RECORD_KEY;
|
|
167
|
+
}
|
|
168
|
+
const parts = lower.split('+').map(p => p.trim()).filter(Boolean);
|
|
169
|
+
if (!parts.length) {
|
|
170
|
+
return DEFAULT_VOICE_RECORD_KEY;
|
|
171
|
+
}
|
|
172
|
+
const last = parts[parts.length - 1];
|
|
173
|
+
const modCandidates = parts.slice(0, -1);
|
|
174
|
+
// Reject multi-modifier chords (``ctrl+alt+r``, ``cmd+ctrl+b``) rather
|
|
175
|
+
// than silently dropping the extra modifier — the previous
|
|
176
|
+
// single-token validator made a typo bind a different shortcut than
|
|
177
|
+
// the user configured (Copilot round-3 review on #19835). The classic
|
|
178
|
+
// CLI only supports single-modifier bindings via prompt_toolkit's
|
|
179
|
+
// ``c-x`` / ``a-x`` rewrite in ``cli.py``, so this matches CLI parity.
|
|
180
|
+
if (modCandidates.length > 1) {
|
|
181
|
+
return DEFAULT_VOICE_RECORD_KEY;
|
|
182
|
+
}
|
|
183
|
+
// Require an explicit modifier. A bare ``o`` / ``space`` / ``escape``
|
|
184
|
+
// has no sensible mapping: the CLI's prompt_toolkit binds the raw
|
|
185
|
+
// key (no rewrite) so bare-char configs would silently diverge
|
|
186
|
+
// between the two runtimes (Copilot round-4 review on #19835).
|
|
187
|
+
// Fall back to the documented default.
|
|
188
|
+
if (modCandidates.length === 0) {
|
|
189
|
+
return DEFAULT_VOICE_RECORD_KEY;
|
|
190
|
+
}
|
|
191
|
+
const norm = _MOD_ALIASES[modCandidates[0]];
|
|
192
|
+
// Unknown modifier token (e.g. bare ``meta+b`` which is ambiguous on
|
|
193
|
+
// the wire) falls back to the documented default rather than
|
|
194
|
+
// silently coercing to Ctrl and producing a misleading bind.
|
|
195
|
+
if (!norm) {
|
|
196
|
+
return DEFAULT_VOICE_RECORD_KEY;
|
|
197
|
+
}
|
|
198
|
+
const mod = norm;
|
|
199
|
+
// Block bindings the TUI input handler intercepts before the voice
|
|
200
|
+
// check — ``ctrl+c`` / ``ctrl+d`` / ``ctrl+l`` would never actually
|
|
201
|
+
// fire push-to-talk, so advertising them in /voice status is a lie.
|
|
202
|
+
if (mod === 'ctrl' && last.length === 1 && _RESERVED_CTRL_CHARS.has(last)) {
|
|
203
|
+
return DEFAULT_VOICE_RECORD_KEY;
|
|
204
|
+
}
|
|
205
|
+
// Same for ``super+c`` / ``super+d`` / ``super+l`` / ``super+v`` on
|
|
206
|
+
// macOS only — those are copy / exit / clear / paste and get claimed
|
|
207
|
+
// by ``isCopyShortcut`` / ``isAction`` / the TextInput paste layer
|
|
208
|
+
// before voice has a chance to toggle. On Linux/Windows the TUI
|
|
209
|
+
// globals key off Ctrl (not Super), so kitty/CSI-u ``super+<letter>``
|
|
210
|
+
// bindings stay usable for non-mac users.
|
|
211
|
+
if (isMac && mod === 'super' && last.length === 1 && _RESERVED_SUPER_CHARS.has(last)) {
|
|
212
|
+
return DEFAULT_VOICE_RECORD_KEY;
|
|
213
|
+
}
|
|
214
|
+
// On macOS hermes-ink reports Alt as ``key.meta``, which ``isActionMod``
|
|
215
|
+
// accepts as the mac action modifier. So ``alt+c`` / ``alt+d`` / ``alt+l``
|
|
216
|
+
// collide with copy / exit / clear in ``useInputHandlers()`` before the
|
|
217
|
+
// voice check. Reject at parse time on darwin only — non-mac ``alt+<letter>``
|
|
218
|
+
// bindings are still usable (Copilot round-12 review on #19835).
|
|
219
|
+
if (isMac && mod === 'alt' && last.length === 1 && _RESERVED_ALT_CHARS_MAC.has(last)) {
|
|
220
|
+
return DEFAULT_VOICE_RECORD_KEY;
|
|
221
|
+
}
|
|
222
|
+
if (last.length === 1) {
|
|
223
|
+
return { ch: last, mod, raw: lower };
|
|
224
|
+
}
|
|
225
|
+
const named = _NAMED_KEY_ALIASES[last];
|
|
226
|
+
if (named) {
|
|
227
|
+
return { ch: named, mod, named, raw: lower };
|
|
228
|
+
}
|
|
229
|
+
// Unknown multi-character token (e.g. typo'd ``ctrl+spcae``) — fall back
|
|
230
|
+
// to the doc default rather than silently disabling the binding.
|
|
231
|
+
return DEFAULT_VOICE_RECORD_KEY;
|
|
232
|
+
};
|
|
233
|
+
/** Render a parsed key back as ``Ctrl+B`` / ``Ctrl+Space`` for status text.
|
|
234
|
+
*
|
|
235
|
+
* Platform-aware for the ``super`` modifier: renders ``Cmd`` on macOS and
|
|
236
|
+
* ``Super`` elsewhere. Previously rendered ``Cmd`` universally, which told
|
|
237
|
+
* Linux/Windows users the wrong modifier to press (Copilot review, round
|
|
238
|
+
* 2 on #19835). */
|
|
239
|
+
export const formatVoiceRecordKey = (parsed) => {
|
|
240
|
+
const modLabel = parsed.mod === 'super' ? (isMac ? 'Cmd' : 'Super') : parsed.mod[0].toUpperCase() + parsed.mod.slice(1);
|
|
241
|
+
// Named tokens render in title case (Ctrl+Space, Ctrl+Enter); single
|
|
242
|
+
// chars render upper-case to match the existing Ctrl+B convention.
|
|
243
|
+
const keyLabel = parsed.named
|
|
244
|
+
? parsed.named[0].toUpperCase() + parsed.named.slice(1)
|
|
245
|
+
: parsed.ch.toUpperCase();
|
|
246
|
+
return `${modLabel}+${keyLabel}`;
|
|
247
|
+
};
|
|
248
|
+
/** Whether the parsed binding is the documented default (ctrl+b).
|
|
249
|
+
*
|
|
250
|
+
* Compare on the parsed spec rather than ``raw`` so semantically-equal
|
|
251
|
+
* aliases (``control+b``, ``ctrl + b``) still get the macOS Cmd+B
|
|
252
|
+
* muscle-memory fallback (Copilot review, round 2 on #19835). */
|
|
253
|
+
const _isDefaultVoiceKey = (parsed) => parsed.mod === DEFAULT_VOICE_RECORD_KEY.mod &&
|
|
254
|
+
parsed.ch === DEFAULT_VOICE_RECORD_KEY.ch &&
|
|
255
|
+
parsed.named === DEFAULT_VOICE_RECORD_KEY.named;
|
|
256
|
+
export const isVoiceToggleKey = (key, ch, configured = DEFAULT_VOICE_RECORD_KEY) => {
|
|
257
|
+
// Match the configured key first (single-char compare or named-key
|
|
258
|
+
// event-property check). Bail out before evaluating modifier shape
|
|
259
|
+
// so the wrong key never reaches the modifier guard.
|
|
260
|
+
if (configured.named) {
|
|
261
|
+
if (!_matchesNamedKey(configured.named, key, ch)) {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
else if (ch.toLowerCase() !== configured.ch) {
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
// The parser rejects multi-modifier configs (``ctrl+shift+b`` etc.),
|
|
269
|
+
// so at match time Shift must always be clear — otherwise
|
|
270
|
+
// ``ctrl+tab`` would also fire on Ctrl+Shift+Tab and ``alt+enter``
|
|
271
|
+
// on Alt+Shift+Enter, triggering a different chord than configured
|
|
272
|
+
// (Copilot round-5 review on #19835).
|
|
273
|
+
if (key.shift === true) {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
switch (configured.mod) {
|
|
277
|
+
case 'alt':
|
|
278
|
+
// Most terminals surface Alt as either ``alt`` or ``meta``; accept
|
|
279
|
+
// both so the binding works across xterm-style and kitty-style
|
|
280
|
+
// protocols. Guard against ctrl/super bits so a chord like
|
|
281
|
+
// Ctrl+Alt+<key> or Cmd+Alt+<key> doesn't spuriously fire the
|
|
282
|
+
// alt binding.
|
|
283
|
+
//
|
|
284
|
+
// Bare Escape on hermes-ink can arrive as ``key.meta=true`` on some
|
|
285
|
+
// terminals, so a configured ``alt+escape`` must not match that shape;
|
|
286
|
+
// require an explicit alt bit for escape chords (Copilot round-7
|
|
287
|
+
// follow-up on #19835).
|
|
288
|
+
return (key.alt === true || (key.meta && key.escape !== true)) && !key.ctrl && key.super !== true;
|
|
289
|
+
case 'ctrl':
|
|
290
|
+
// Require the Ctrl bit AND a clear Alt/Super so a chord like
|
|
291
|
+
// Ctrl+Alt+<key> / Ctrl+Cmd+<key> doesn't spuriously match
|
|
292
|
+
// ``ctrl+<key>`` (Copilot round-6 review on #19835).
|
|
293
|
+
//
|
|
294
|
+
// The documented default (``ctrl+b``) additionally accepts the
|
|
295
|
+
// explicit ``key.super`` bit on macOS for Cmd+B muscle memory —
|
|
296
|
+
// but ONLY ``key.super`` (kitty-style), never ``key.meta``, since
|
|
297
|
+
// ``key.meta`` is hermes-ink's Alt signal and accepting it would
|
|
298
|
+
// fire the binding on Alt+B.
|
|
299
|
+
if (key.ctrl) {
|
|
300
|
+
return !key.alt && !key.meta && key.super !== true;
|
|
301
|
+
}
|
|
302
|
+
return _isDefaultVoiceKey(configured) && isMac && key.super === true && !key.alt && !key.meta;
|
|
303
|
+
case 'super':
|
|
304
|
+
// Require the explicit ``key.super`` bit (kitty-style protocol)
|
|
305
|
+
// AND clear Ctrl/Alt/Meta so Ctrl+Cmd+X or Alt+Cmd+X don't
|
|
306
|
+
// spuriously fire the super binding (Copilot round-6 review on
|
|
307
|
+
// #19835). Legacy-terminal users whose Cmd arrives as
|
|
308
|
+
// ``key.meta`` need a kitty-protocol terminal — see the
|
|
309
|
+
// _MOD_ALIASES doc-comment for the rationale.
|
|
310
|
+
return key.super === true && !key.ctrl && !key.alt && !key.meta;
|
|
311
|
+
}
|
|
312
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Ported from CVC Agent (https://github.com/NousResearch/cvc)
|
|
4
|
+
// Original Copyright (c) 2025 Nous Research. CVC adaptations (c) 2026 Jai Kumar Meena.
|
|
5
|
+
const PRECISION_WHEEL_FRAME_MS = 16;
|
|
6
|
+
const PRECISION_WHEEL_STICKY_MS = 80;
|
|
7
|
+
export function initPrecisionWheel() {
|
|
8
|
+
return { active: false, dir: 0, lastEventAtMs: 0, lastScrollAtMs: 0 };
|
|
9
|
+
}
|
|
10
|
+
export function computePrecisionWheelStep(state, dir, hasModifier, now) {
|
|
11
|
+
const active = hasModifier || now - state.lastEventAtMs < PRECISION_WHEEL_STICKY_MS;
|
|
12
|
+
if (!active) {
|
|
13
|
+
state.active = false;
|
|
14
|
+
return { active: false, entered: false, rows: 0 };
|
|
15
|
+
}
|
|
16
|
+
const entered = !state.active;
|
|
17
|
+
state.active = true;
|
|
18
|
+
state.lastEventAtMs = now;
|
|
19
|
+
if (dir === state.dir && now - state.lastScrollAtMs < PRECISION_WHEEL_FRAME_MS) {
|
|
20
|
+
return { active: true, entered, rows: 0 };
|
|
21
|
+
}
|
|
22
|
+
state.dir = dir;
|
|
23
|
+
state.lastScrollAtMs = now;
|
|
24
|
+
return { active: true, entered, rows: 1 };
|
|
25
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Noop stub for react-devtools-core — used only when DEV=true is set in env.
|
|
3
|
+
// Inlined into the bundle so that the published cvc-tui doesn't require an
|
|
4
|
+
// external dev-only dependency at runtime.
|
|
5
|
+
const noop = () => undefined;
|
|
6
|
+
const stub = {
|
|
7
|
+
initialize: noop,
|
|
8
|
+
connectToDevTools: noop,
|
|
9
|
+
};
|
|
10
|
+
export default stub;
|
|
11
|
+
export const initialize = noop;
|
|
12
|
+
export const connectToDevTools = noop;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Ported from CVC Agent (https://github.com/NousResearch/cvc)
|
|
4
|
+
// Original Copyright (c) 2025 Nous Research. CVC adaptations (c) 2026 Jai Kumar Meena.
|
|
5
|
+
const TAGS = ['think', 'reasoning', 'thinking', 'thought', 'REASONING_SCRATCHPAD'];
|
|
6
|
+
export function splitReasoning(input) {
|
|
7
|
+
let text = input;
|
|
8
|
+
const reasoning = [];
|
|
9
|
+
for (const tag of TAGS) {
|
|
10
|
+
const paired = new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>\\s*`, 'gi');
|
|
11
|
+
text = text.replace(paired, (_m, inner) => {
|
|
12
|
+
const trimmed = inner.trim();
|
|
13
|
+
if (trimmed) {
|
|
14
|
+
reasoning.push(trimmed);
|
|
15
|
+
}
|
|
16
|
+
return '';
|
|
17
|
+
});
|
|
18
|
+
const unclosed = new RegExp(`<${tag}>([\\s\\S]*)$`, 'i');
|
|
19
|
+
text = text.replace(unclosed, (_m, inner) => {
|
|
20
|
+
const trimmed = inner.trim();
|
|
21
|
+
if (trimmed) {
|
|
22
|
+
reasoning.push(trimmed);
|
|
23
|
+
}
|
|
24
|
+
return '';
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
reasoning: reasoning.join('\n\n').trim(),
|
|
29
|
+
text: text.trim()
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export const hasReasoningTag = (input) => {
|
|
33
|
+
for (const tag of TAGS) {
|
|
34
|
+
if (input.includes(`<${tag}>`)) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
};
|
package/dist/lib/rpc.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const asRpcResult = (value) => !value || typeof value !== 'object' || Array.isArray(value) ? null : value;
|
|
2
|
+
export const asCommandDispatch = (value) => {
|
|
3
|
+
const o = asRpcResult(value);
|
|
4
|
+
if (!o || typeof o.type !== 'string') {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
const t = o.type;
|
|
8
|
+
if (t === 'exec' || t === 'plugin') {
|
|
9
|
+
return { type: t, output: typeof o.output === 'string' ? o.output : undefined };
|
|
10
|
+
}
|
|
11
|
+
if (t === 'alias' && typeof o.target === 'string') {
|
|
12
|
+
return { type: 'alias', target: o.target };
|
|
13
|
+
}
|
|
14
|
+
if (t === 'skill' && typeof o.name === 'string') {
|
|
15
|
+
return { type: 'skill', name: o.name, message: typeof o.message === 'string' ? o.message : undefined };
|
|
16
|
+
}
|
|
17
|
+
if (t === 'send' && typeof o.message === 'string') {
|
|
18
|
+
return {
|
|
19
|
+
type: 'send',
|
|
20
|
+
message: o.message,
|
|
21
|
+
notice: typeof o.notice === 'string' ? o.notice : undefined,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
};
|
|
26
|
+
export const rpcErrorMessage = (err) => err instanceof Error && err.message ? err.message : typeof err === 'string' && err.trim() ? err : 'request failed';
|