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.
Files changed (142) hide show
  1. package/NOTICES.md +13 -0
  2. package/dist/app/completion.js +102 -0
  3. package/dist/app/createGatewayEventHandler.js +508 -0
  4. package/dist/app/createSlashHandler.js +101 -0
  5. package/dist/app/delegationStore.js +51 -0
  6. package/dist/app/gatewayContext.js +17 -0
  7. package/dist/app/historyStore.js +123 -0
  8. package/dist/app/inputBuffer.js +120 -0
  9. package/dist/app/inputSelectionStore.js +8 -0
  10. package/dist/app/inputStore.js +28 -0
  11. package/dist/app/interfaces.js +6 -0
  12. package/dist/app/overlayStore.js +40 -0
  13. package/dist/app/promptStore.js +44 -0
  14. package/dist/app/queueStore.js +25 -0
  15. package/dist/app/scroll.js +44 -0
  16. package/dist/app/setupHandoff.js +28 -0
  17. package/dist/app/slash/commands/core.js +479 -0
  18. package/dist/app/slash/commands/debug.js +44 -0
  19. package/dist/app/slash/commands/ops.js +512 -0
  20. package/dist/app/slash/commands/session.js +431 -0
  21. package/dist/app/slash/commands/setup.js +20 -0
  22. package/dist/app/slash/commands/toggles.js +40 -0
  23. package/dist/app/slash/registry.js +18 -0
  24. package/dist/app/slash/types.js +1 -0
  25. package/dist/app/spawnHistoryStore.js +105 -0
  26. package/dist/app/turnController.js +650 -0
  27. package/dist/app/turnStore.js +48 -0
  28. package/dist/app/uiStore.js +36 -0
  29. package/dist/app/useComposerState.js +265 -0
  30. package/dist/app/useConfigSync.js +144 -0
  31. package/dist/app/useInputHandlers.js +403 -0
  32. package/dist/app/useLongRunToolCharms.js +50 -0
  33. package/dist/app/useMainApp.js +638 -0
  34. package/dist/app/useSessionLifecycle.js +175 -0
  35. package/dist/app/useSubmission.js +287 -0
  36. package/dist/app.js +15 -0
  37. package/dist/banner.js +63 -0
  38. package/dist/components/agentsOverlay.js +474 -0
  39. package/dist/components/appChrome.js +252 -0
  40. package/dist/components/appLayout.js +122 -0
  41. package/dist/components/appOverlays.js +65 -0
  42. package/dist/components/branding.js +97 -0
  43. package/dist/components/fpsOverlay.js +22 -0
  44. package/dist/components/helpHint.js +21 -0
  45. package/dist/components/markdown.js +501 -0
  46. package/dist/components/maskedPrompt.js +12 -0
  47. package/dist/components/messageLine.js +82 -0
  48. package/dist/components/modelPicker.js +254 -0
  49. package/dist/components/overlayControls.js +30 -0
  50. package/dist/components/overlays/confirmPrompt.js +25 -0
  51. package/dist/components/overlays/helpOverlay.js +76 -0
  52. package/dist/components/overlays/historySearch.js +49 -0
  53. package/dist/components/overlays/modelPicker.js +60 -0
  54. package/dist/components/overlays/overlayUtils.js +19 -0
  55. package/dist/components/overlays/secretPrompt.js +36 -0
  56. package/dist/components/overlays/sessionPicker.js +93 -0
  57. package/dist/components/overlays/skillsHub.js +71 -0
  58. package/dist/components/prompts.js +95 -0
  59. package/dist/components/queuedMessages.js +24 -0
  60. package/dist/components/sessionPicker.js +130 -0
  61. package/dist/components/skillsHub.js +165 -0
  62. package/dist/components/streamingAssistant.js +35 -0
  63. package/dist/components/streamingMarkdown.js +144 -0
  64. package/dist/components/textInput.js +794 -0
  65. package/dist/components/themed.js +12 -0
  66. package/dist/components/thinking.js +496 -0
  67. package/dist/components/todoPanel.js +40 -0
  68. package/dist/components/transcript.js +22 -0
  69. package/dist/config/env.js +18 -0
  70. package/dist/config/limits.js +22 -0
  71. package/dist/config/timing.js +25 -0
  72. package/dist/content/charms.js +5 -0
  73. package/dist/content/faces.js +21 -0
  74. package/dist/content/fortunes.js +29 -0
  75. package/dist/content/hotkeys.js +38 -0
  76. package/dist/content/placeholders.js +15 -0
  77. package/dist/content/setup.js +14 -0
  78. package/dist/content/verbs.js +41 -0
  79. package/dist/domain/details.js +53 -0
  80. package/dist/domain/messages.js +63 -0
  81. package/dist/domain/paths.js +16 -0
  82. package/dist/domain/providers.js +11 -0
  83. package/dist/domain/roles.js +6 -0
  84. package/dist/domain/slash.js +11 -0
  85. package/dist/domain/usage.js +1 -0
  86. package/dist/domain/viewport.js +33 -0
  87. package/dist/entry.js +64 -70236
  88. package/dist/gateway/client.js +312 -0
  89. package/dist/gatewayClient.js +574 -0
  90. package/dist/gatewayTypes.js +1 -0
  91. package/dist/hooks/useCompletion.js +86 -0
  92. package/dist/hooks/useGitBranch.js +58 -0
  93. package/dist/hooks/useInputHistory.js +12 -0
  94. package/dist/hooks/useQueue.js +57 -0
  95. package/dist/hooks/useVirtualHistory.js +401 -0
  96. package/dist/lib/circularBuffer.js +43 -0
  97. package/dist/lib/clipboard.js +126 -0
  98. package/dist/lib/editor.js +41 -0
  99. package/dist/lib/editor.test.js +58 -0
  100. package/dist/lib/emoji.js +49 -0
  101. package/dist/lib/externalCli.js +11 -0
  102. package/dist/lib/forceTruecolor.js +26 -0
  103. package/dist/lib/fpsStore.js +36 -0
  104. package/dist/lib/gracefulExit.js +29 -0
  105. package/dist/lib/history.js +69 -0
  106. package/dist/lib/inputMetrics.js +143 -0
  107. package/dist/lib/liveProgress.js +51 -0
  108. package/dist/lib/liveProgress.test.js +89 -0
  109. package/dist/lib/localSessionInfo.js +116 -0
  110. package/dist/lib/mathUnicode.js +685 -0
  111. package/dist/lib/memory.js +123 -0
  112. package/dist/lib/memoryMonitor.js +76 -0
  113. package/dist/lib/messages.js +3 -0
  114. package/dist/lib/messages.test.js +25 -0
  115. package/dist/lib/osc52.js +53 -0
  116. package/dist/lib/perfPane.js +94 -0
  117. package/dist/lib/platform.js +312 -0
  118. package/dist/lib/precisionWheel.js +25 -0
  119. package/dist/lib/react-devtools-stub.js +12 -0
  120. package/dist/lib/reasoning.js +39 -0
  121. package/dist/lib/rpc.js +26 -0
  122. package/dist/lib/subagentTree.js +287 -0
  123. package/dist/lib/syntax.js +89 -0
  124. package/dist/lib/terminalModes.js +46 -0
  125. package/dist/lib/terminalParity.js +48 -0
  126. package/dist/lib/terminalSetup.js +321 -0
  127. package/dist/lib/text.js +203 -0
  128. package/dist/lib/text.test.js +18 -0
  129. package/dist/lib/todo.js +2 -0
  130. package/dist/lib/todo.test.js +22 -0
  131. package/dist/lib/viewportStore.js +82 -0
  132. package/dist/lib/virtualHeights.js +61 -0
  133. package/dist/lib/wheelAccel.js +143 -0
  134. package/dist/protocol/interpolation.js +4 -0
  135. package/dist/protocol/paste.js +3 -0
  136. package/dist/theme.js +398 -0
  137. package/dist/types.js +1 -0
  138. package/dist/vendor/cvc-ink/dist/entry-exports.js +52737 -0
  139. package/dist/vendor/cvc-ink/index.js +1 -0
  140. package/dist/vendor/cvc-ink/package.json +9 -0
  141. package/dist/vendor/cvc-ink/text-input.js +1 -0
  142. 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
+ };
@@ -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';