cvc-tui 0.4.0 → 0.4.1

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 (133) hide show
  1. package/dist/entry.js +71147 -61
  2. package/package.json +2 -2
  3. package/dist/app/completion.js +0 -102
  4. package/dist/app/createGatewayEventHandler.js +0 -508
  5. package/dist/app/createSlashHandler.js +0 -101
  6. package/dist/app/delegationStore.js +0 -51
  7. package/dist/app/gatewayContext.js +0 -17
  8. package/dist/app/historyStore.js +0 -123
  9. package/dist/app/inputBuffer.js +0 -120
  10. package/dist/app/inputSelectionStore.js +0 -8
  11. package/dist/app/inputStore.js +0 -28
  12. package/dist/app/interfaces.js +0 -6
  13. package/dist/app/overlayStore.js +0 -40
  14. package/dist/app/promptStore.js +0 -44
  15. package/dist/app/queueStore.js +0 -25
  16. package/dist/app/scroll.js +0 -44
  17. package/dist/app/setupHandoff.js +0 -28
  18. package/dist/app/slash/commands/core.js +0 -479
  19. package/dist/app/slash/commands/debug.js +0 -44
  20. package/dist/app/slash/commands/ops.js +0 -498
  21. package/dist/app/slash/commands/session.js +0 -431
  22. package/dist/app/slash/commands/setup.js +0 -20
  23. package/dist/app/slash/commands/toggles.js +0 -40
  24. package/dist/app/slash/registry.js +0 -18
  25. package/dist/app/slash/types.js +0 -1
  26. package/dist/app/spawnHistoryStore.js +0 -105
  27. package/dist/app/turnController.js +0 -650
  28. package/dist/app/turnStore.js +0 -48
  29. package/dist/app/uiStore.js +0 -36
  30. package/dist/app/useComposerState.js +0 -265
  31. package/dist/app/useConfigSync.js +0 -144
  32. package/dist/app/useInputHandlers.js +0 -403
  33. package/dist/app/useLongRunToolCharms.js +0 -50
  34. package/dist/app/useMainApp.js +0 -629
  35. package/dist/app/useSessionLifecycle.js +0 -175
  36. package/dist/app/useSubmission.js +0 -287
  37. package/dist/app.js +0 -15
  38. package/dist/banner.js +0 -57
  39. package/dist/components/agentsOverlay.js +0 -474
  40. package/dist/components/appChrome.js +0 -252
  41. package/dist/components/appLayout.js +0 -121
  42. package/dist/components/appOverlays.js +0 -65
  43. package/dist/components/branding.js +0 -97
  44. package/dist/components/fpsOverlay.js +0 -22
  45. package/dist/components/helpHint.js +0 -21
  46. package/dist/components/markdown.js +0 -501
  47. package/dist/components/maskedPrompt.js +0 -12
  48. package/dist/components/messageLine.js +0 -82
  49. package/dist/components/modelPicker.js +0 -254
  50. package/dist/components/overlayControls.js +0 -30
  51. package/dist/components/overlays/confirmPrompt.js +0 -25
  52. package/dist/components/overlays/helpOverlay.js +0 -76
  53. package/dist/components/overlays/historySearch.js +0 -49
  54. package/dist/components/overlays/modelPicker.js +0 -60
  55. package/dist/components/overlays/overlayUtils.js +0 -19
  56. package/dist/components/overlays/secretPrompt.js +0 -36
  57. package/dist/components/overlays/sessionPicker.js +0 -93
  58. package/dist/components/overlays/skillsHub.js +0 -71
  59. package/dist/components/prompts.js +0 -95
  60. package/dist/components/queuedMessages.js +0 -24
  61. package/dist/components/sessionPicker.js +0 -130
  62. package/dist/components/skillsHub.js +0 -165
  63. package/dist/components/streamingAssistant.js +0 -35
  64. package/dist/components/streamingMarkdown.js +0 -144
  65. package/dist/components/textInput.js +0 -794
  66. package/dist/components/themed.js +0 -12
  67. package/dist/components/thinking.js +0 -496
  68. package/dist/components/todoPanel.js +0 -40
  69. package/dist/components/transcript.js +0 -22
  70. package/dist/config/env.js +0 -18
  71. package/dist/config/limits.js +0 -22
  72. package/dist/config/timing.js +0 -18
  73. package/dist/content/charms.js +0 -5
  74. package/dist/content/faces.js +0 -21
  75. package/dist/content/fortunes.js +0 -29
  76. package/dist/content/hotkeys.js +0 -38
  77. package/dist/content/placeholders.js +0 -15
  78. package/dist/content/setup.js +0 -14
  79. package/dist/content/verbs.js +0 -41
  80. package/dist/domain/details.js +0 -53
  81. package/dist/domain/messages.js +0 -63
  82. package/dist/domain/paths.js +0 -16
  83. package/dist/domain/providers.js +0 -11
  84. package/dist/domain/roles.js +0 -6
  85. package/dist/domain/slash.js +0 -11
  86. package/dist/domain/usage.js +0 -1
  87. package/dist/domain/viewport.js +0 -33
  88. package/dist/gateway/client.js +0 -312
  89. package/dist/gatewayClient.js +0 -574
  90. package/dist/gatewayTypes.js +0 -1
  91. package/dist/hooks/useCompletion.js +0 -86
  92. package/dist/hooks/useGitBranch.js +0 -58
  93. package/dist/hooks/useInputHistory.js +0 -12
  94. package/dist/hooks/useQueue.js +0 -57
  95. package/dist/hooks/useVirtualHistory.js +0 -401
  96. package/dist/lib/circularBuffer.js +0 -43
  97. package/dist/lib/clipboard.js +0 -126
  98. package/dist/lib/editor.js +0 -41
  99. package/dist/lib/editor.test.js +0 -58
  100. package/dist/lib/emoji.js +0 -49
  101. package/dist/lib/externalCli.js +0 -11
  102. package/dist/lib/forceTruecolor.js +0 -26
  103. package/dist/lib/fpsStore.js +0 -36
  104. package/dist/lib/gracefulExit.js +0 -29
  105. package/dist/lib/history.js +0 -69
  106. package/dist/lib/inputMetrics.js +0 -143
  107. package/dist/lib/liveProgress.js +0 -51
  108. package/dist/lib/liveProgress.test.js +0 -89
  109. package/dist/lib/mathUnicode.js +0 -685
  110. package/dist/lib/memory.js +0 -123
  111. package/dist/lib/memoryMonitor.js +0 -76
  112. package/dist/lib/messages.js +0 -3
  113. package/dist/lib/messages.test.js +0 -25
  114. package/dist/lib/osc52.js +0 -53
  115. package/dist/lib/perfPane.js +0 -94
  116. package/dist/lib/platform.js +0 -312
  117. package/dist/lib/precisionWheel.js +0 -25
  118. package/dist/lib/reasoning.js +0 -39
  119. package/dist/lib/rpc.js +0 -26
  120. package/dist/lib/subagentTree.js +0 -287
  121. package/dist/lib/syntax.js +0 -89
  122. package/dist/lib/terminalModes.js +0 -46
  123. package/dist/lib/terminalParity.js +0 -48
  124. package/dist/lib/terminalSetup.js +0 -321
  125. package/dist/lib/text.js +0 -203
  126. package/dist/lib/text.test.js +0 -18
  127. package/dist/lib/todo.js +0 -2
  128. package/dist/lib/todo.test.js +0 -22
  129. package/dist/lib/viewportStore.js +0 -82
  130. package/dist/lib/virtualHeights.js +0 -61
  131. package/dist/lib/wheelAccel.js +0 -143
  132. package/dist/theme.js +0 -398
  133. package/dist/types.js +0 -1
@@ -1,479 +0,0 @@
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
- import { forceRedraw } from '@cvc/ink';
6
- import { NO_CONFIRM_DESTRUCTIVE } from '../../../config/env.js';
7
- import { dailyFortune, randomFortune } from '../../../content/fortunes.js';
8
- import { HOTKEYS } from '../../../content/hotkeys.js';
9
- import { SECTION_NAMES, isSectionName, nextDetailsMode, parseDetailsMode } from '../../../domain/details.js';
10
- import { writeClipboardText } from '../../../lib/clipboard.js';
11
- import { writeOsc52Clipboard } from '../../../lib/osc52.js';
12
- import { configureDetectedTerminalKeybindings, configureTerminalKeybindings } from '../../../lib/terminalSetup.js';
13
- import { patchOverlayState } from '../../overlayStore.js';
14
- import { patchUiState } from '../../uiStore.js';
15
- const flagFromArg = (arg, current) => {
16
- if (!arg) {
17
- return !current;
18
- }
19
- const mode = arg.trim().toLowerCase();
20
- if (mode === 'on') {
21
- return true;
22
- }
23
- if (mode === 'off') {
24
- return false;
25
- }
26
- if (mode === 'toggle') {
27
- return !current;
28
- }
29
- return null;
30
- };
31
- const RESET_WORDS = new Set(['reset', 'clear', 'default']);
32
- const CYCLE_WORDS = new Set(['cycle', 'toggle']);
33
- const DETAILS_USAGE = 'usage: /details [hidden|collapsed|expanded|cycle] or /details <section> [hidden|collapsed|expanded|reset]';
34
- const DETAILS_SECTION_USAGE = 'usage: /details <section> [hidden|collapsed|expanded|reset]';
35
- export const coreCommands = [
36
- {
37
- help: 'list commands + hotkeys',
38
- name: 'help',
39
- run: (_arg, ctx) => {
40
- const sections = (ctx.local.catalog?.categories ?? []).map(cat => ({
41
- rows: cat.pairs,
42
- title: cat.name
43
- }));
44
- if (ctx.local.catalog?.skillCount) {
45
- sections.push({ text: `${ctx.local.catalog.skillCount} skill commands available — /skills to browse` });
46
- }
47
- sections.push({
48
- rows: [
49
- ['/details [hidden|collapsed|expanded|cycle]', 'set global agent detail visibility mode'],
50
- [
51
- '/details <section> [hidden|collapsed|expanded|reset]',
52
- 'override one section (thinking/tools/subagents/activity)'
53
- ],
54
- ['/fortune [random|daily]', 'show a random or daily local fortune']
55
- ],
56
- title: 'TUI'
57
- }, { rows: HOTKEYS, title: 'Hotkeys' });
58
- ctx.transcript.panel(ctx.ui.theme.brand.helpHeader, sections);
59
- }
60
- },
61
- {
62
- aliases: ['exit', 'q'],
63
- help: 'exit hermes',
64
- name: 'quit',
65
- run: (_arg, ctx) => ctx.session.die()
66
- },
67
- {
68
- aliases: ['scroll'],
69
- help: 'toggle mouse/wheel tracking [on|off|toggle]',
70
- name: 'mouse',
71
- run: (arg, ctx) => {
72
- const current = ctx.ui.mouseTracking;
73
- const next = flagFromArg(arg, current);
74
- if (next === null) {
75
- return ctx.transcript.sys('usage: /mouse [on|off|toggle]');
76
- }
77
- patchUiState({ mouseTracking: next });
78
- ctx.gateway.rpc('config.set', { key: 'mouse', value: next ? 'on' : 'off' }).catch(() => { });
79
- queueMicrotask(() => ctx.transcript.sys(`mouse tracking ${next ? 'on' : 'off'}`));
80
- }
81
- },
82
- {
83
- aliases: ['new'],
84
- help: 'start a new session',
85
- name: 'clear',
86
- run: (arg, ctx, cmd) => {
87
- if (ctx.session.guardBusySessionSwitch('switch sessions')) {
88
- return;
89
- }
90
- const isNew = cmd.startsWith('/new');
91
- const requestedTitle = isNew ? arg.trim() : '';
92
- const commit = () => {
93
- patchUiState({ status: 'forging session…' });
94
- ctx.session.newSession(isNew ? 'new session started' : undefined, requestedTitle || undefined);
95
- };
96
- if (NO_CONFIRM_DESTRUCTIVE) {
97
- return commit();
98
- }
99
- patchOverlayState({
100
- confirm: {
101
- cancelLabel: 'No, keep going',
102
- confirmLabel: isNew ? 'Yes, start a new session' : 'Yes, clear the session',
103
- danger: true,
104
- detail: 'This ends the current conversation and clears the transcript.',
105
- onConfirm: commit,
106
- title: isNew ? 'Start a new session?' : 'Clear the current session?'
107
- }
108
- });
109
- }
110
- },
111
- {
112
- help: 'force a full UI repaint',
113
- name: 'redraw',
114
- run: (_arg, ctx) => {
115
- forceRedraw(process.stdout);
116
- ctx.transcript.sys('ui redrawn');
117
- }
118
- },
119
- {
120
- help: 'show live session info',
121
- name: 'status',
122
- run: (_arg, ctx) => {
123
- if (!ctx.sid) {
124
- return ctx.transcript.sys('no active session');
125
- }
126
- ctx.gateway
127
- .rpc('session.status', { session_id: ctx.sid })
128
- .then(ctx.guarded(r => ctx.transcript.page(r.output || '(no status)', 'Status')))
129
- .catch(ctx.guardedErr);
130
- }
131
- },
132
- {
133
- help: 'resume a prior session',
134
- name: 'resume',
135
- run: (arg, ctx) => {
136
- if (ctx.session.guardBusySessionSwitch('switch sessions')) {
137
- return;
138
- }
139
- arg ? ctx.session.resumeById(arg) : patchOverlayState({ picker: true });
140
- }
141
- },
142
- {
143
- help: 'set or show current session title',
144
- name: 'title',
145
- run: (arg, ctx) => {
146
- if (!ctx.sid) {
147
- return ctx.transcript.sys('no active session');
148
- }
149
- const title = arg.trim();
150
- if (!arg) {
151
- ctx.gateway
152
- .rpc('session.title', { session_id: ctx.sid })
153
- .then(ctx.guarded(r => {
154
- const current = (r?.title ?? '').trim();
155
- ctx.transcript.sys(current ? `title: ${current}` : 'no title set');
156
- }))
157
- .catch(ctx.guardedErr);
158
- return;
159
- }
160
- if (!title) {
161
- return ctx.transcript.sys('usage: /title <your session title>');
162
- }
163
- ctx.gateway
164
- .rpc('session.title', { session_id: ctx.sid, title })
165
- .then(ctx.guarded(r => {
166
- const next = (r?.title ?? title).trim();
167
- const suffix = r?.pending ? ' (queued while session initializes)' : '';
168
- ctx.transcript.sys(`session title set: ${next}${suffix}`);
169
- }))
170
- .catch(ctx.guardedErr);
171
- }
172
- },
173
- {
174
- help: 'toggle compact transcript',
175
- name: 'compact',
176
- run: (arg, ctx) => {
177
- const next = flagFromArg(arg, ctx.ui.compact);
178
- if (next === null) {
179
- return ctx.transcript.sys('usage: /compact [on|off|toggle]');
180
- }
181
- patchUiState({ compact: next });
182
- ctx.gateway.rpc('config.set', { key: 'compact', value: next ? 'on' : 'off' }).catch(() => { });
183
- queueMicrotask(() => ctx.transcript.sys(`compact ${next ? 'on' : 'off'}`));
184
- }
185
- },
186
- {
187
- aliases: ['detail'],
188
- help: 'control agent detail visibility (global or per-section)',
189
- name: 'details',
190
- run: (arg, ctx) => {
191
- const { gateway, transcript, ui } = ctx;
192
- if (!arg) {
193
- gateway
194
- .rpc('config.get', { key: 'details_mode' })
195
- .then(r => {
196
- if (ctx.stale()) {
197
- return;
198
- }
199
- const mode = parseDetailsMode(r?.value) ?? ui.detailsMode;
200
- patchUiState({ detailsMode: mode, detailsModeCommandOverride: false });
201
- const overrides = SECTION_NAMES.filter(s => ui.sections[s])
202
- .map(s => `${s}=${ui.sections[s]}`)
203
- .join(' ');
204
- transcript.sys(`details: ${mode}${overrides ? ` (${overrides})` : ''}`);
205
- })
206
- .catch(() => !ctx.stale() && transcript.sys(`details: ${ui.detailsMode}`));
207
- return;
208
- }
209
- const [first, second] = arg.trim().toLowerCase().split(/\s+/);
210
- if (second && isSectionName(first)) {
211
- const reset = RESET_WORDS.has(second);
212
- const mode = reset ? null : parseDetailsMode(second);
213
- if (!reset && !mode) {
214
- return transcript.sys(DETAILS_SECTION_USAGE);
215
- }
216
- const { [first]: _drop, ...rest } = ui.sections;
217
- patchUiState({ sections: mode ? { ...rest, [first]: mode } : rest });
218
- gateway
219
- .rpc('config.set', { key: `details_mode.${first}`, value: mode ?? '' })
220
- .catch(() => { });
221
- transcript.sys(`details ${first}: ${mode ?? 'reset'}`);
222
- return;
223
- }
224
- const next = CYCLE_WORDS.has(first ?? '') ? nextDetailsMode(ui.detailsMode) : parseDetailsMode(first);
225
- if (!next) {
226
- return transcript.sys(DETAILS_USAGE);
227
- }
228
- const sections = Object.fromEntries(SECTION_NAMES.map(section => [section, next]));
229
- patchUiState({ detailsMode: next, detailsModeCommandOverride: true, sections });
230
- gateway.rpc('config.set', { key: 'details_mode', value: next }).catch(() => { });
231
- transcript.sys(`details: ${next}`);
232
- }
233
- },
234
- {
235
- help: 'local fortune',
236
- name: 'fortune',
237
- run: (arg, ctx) => {
238
- const key = arg.trim().toLowerCase();
239
- if (!arg || key === 'random') {
240
- return ctx.transcript.sys(randomFortune());
241
- }
242
- if (['daily', 'stable', 'today'].includes(key)) {
243
- return ctx.transcript.sys(dailyFortune(ctx.sid));
244
- }
245
- ctx.transcript.sys('usage: /fortune [random|daily]');
246
- }
247
- },
248
- {
249
- help: 'copy selection or assistant message',
250
- name: 'copy',
251
- run: async (arg, ctx) => {
252
- const { sys } = ctx.transcript;
253
- if (!arg && ctx.composer.hasSelection) {
254
- const text = await ctx.composer.selection.copySelection();
255
- if (text) {
256
- return sys(`copied ${text.length} characters`);
257
- }
258
- else {
259
- return sys('clipboard copy failed — try CVC_TUI_FORCE_OSC52=1 to force the escape sequence; CVC_TUI_DEBUG_CLIPBOARD=1 for details');
260
- }
261
- }
262
- if (arg && Number.isNaN(parseInt(arg, 10))) {
263
- return sys('usage: /copy [number]');
264
- }
265
- const all = ctx.local.getHistoryItems().filter(m => m.role === 'assistant');
266
- const target = all[arg ? Math.min(parseInt(arg, 10), all.length) - 1 : all.length - 1];
267
- if (!target) {
268
- return sys('nothing to copy — start a conversation first');
269
- }
270
- void writeClipboardText(target.text)
271
- .then(nativeOk => {
272
- if (ctx.stale()) {
273
- return;
274
- }
275
- if (nativeOk) {
276
- sys('copied to clipboard');
277
- }
278
- else {
279
- writeOsc52Clipboard(target.text);
280
- sys('sent OSC52 copy sequence (terminal support required)');
281
- }
282
- })
283
- .catch(error => {
284
- if (!ctx.stale()) {
285
- sys(`copy failed: ${String(error)}`);
286
- }
287
- });
288
- }
289
- },
290
- {
291
- help: 'attach clipboard image',
292
- name: 'paste',
293
- run: (arg, ctx) => (arg ? ctx.transcript.sys('usage: /paste') : ctx.composer.paste())
294
- },
295
- {
296
- help: 'configure IDE terminal keybindings for multiline + undo/redo',
297
- name: 'terminal-setup',
298
- run: (arg, ctx) => {
299
- const target = arg.trim().toLowerCase();
300
- if (target && !['auto', 'cursor', 'vscode', 'windsurf'].includes(target)) {
301
- return ctx.transcript.sys('usage: /terminal-setup [auto|vscode|cursor|windsurf]');
302
- }
303
- const runner = !target || target === 'auto'
304
- ? configureDetectedTerminalKeybindings()
305
- : configureTerminalKeybindings(target);
306
- void runner
307
- .then(result => {
308
- if (ctx.stale()) {
309
- return;
310
- }
311
- ctx.transcript.sys(result.message);
312
- if (result.success && result.requiresRestart) {
313
- ctx.transcript.sys('restart the IDE terminal for the new keybindings to take effect');
314
- }
315
- })
316
- .catch(error => {
317
- if (!ctx.stale()) {
318
- ctx.transcript.sys(`terminal setup failed: ${String(error)}`);
319
- }
320
- });
321
- }
322
- },
323
- {
324
- help: 'view gateway logs',
325
- name: 'logs',
326
- run: (arg, ctx) => {
327
- const text = ctx.gateway.gw.getLogTail(Math.min(80, Math.max(1, parseInt(arg, 10) || 20)));
328
- text ? ctx.transcript.page(text, 'Logs') : ctx.transcript.sys('no gateway logs');
329
- }
330
- },
331
- {
332
- help: 'view current transcript (user + assistant messages)',
333
- name: 'history',
334
- run: (arg, ctx) => {
335
- // The CLI-side `/history` runs in a detached slash-worker subprocess
336
- // that never sees the TUI's turns — it only surfaces whatever was
337
- // persisted before this process started. Render the TUI's own
338
- // transcript so `/history` actually reflects what the user just did.
339
- const items = ctx.local.getHistoryItems().filter(m => m.role === 'user' || m.role === 'assistant');
340
- if (!items.length) {
341
- return ctx.transcript.sys('no conversation yet');
342
- }
343
- const preview = Math.max(80, parseInt(arg, 10) || 400);
344
- const lines = items.map((m, i) => {
345
- const tag = m.role === 'user' ? `You #${i + 1}` : `Hermes #${i + 1}`;
346
- const body = m.text.trim() || (m.tools?.length ? `(${m.tools.length} tool calls)` : '(empty)');
347
- const clipped = body.length > preview ? `${body.slice(0, preview).trimEnd()}…` : body;
348
- return `[${tag}]\n${clipped}`;
349
- });
350
- ctx.transcript.page(lines.join('\n\n'), 'History');
351
- }
352
- },
353
- {
354
- help: 'save the current transcript to JSON',
355
- name: 'save',
356
- run: (_arg, ctx) => {
357
- const hasConversation = ctx.local
358
- .getHistoryItems()
359
- .some(m => m.role === 'user' || m.role === 'assistant' || m.role === 'tool');
360
- if (!hasConversation) {
361
- return ctx.transcript.sys('no conversation yet');
362
- }
363
- if (!ctx.sid) {
364
- return ctx.transcript.sys('no active session — nothing to save');
365
- }
366
- ctx.gateway
367
- .rpc('session.save', { session_id: ctx.sid })
368
- .then(ctx.guarded(r => {
369
- const file = r?.file;
370
- if (file) {
371
- ctx.transcript.sys(`conversation saved to: ${file}`);
372
- }
373
- else {
374
- ctx.transcript.sys('failed to save');
375
- }
376
- }))
377
- .catch(ctx.guardedErr);
378
- }
379
- },
380
- {
381
- aliases: ['sb'],
382
- help: 'status bar position (on|off|top|bottom)',
383
- name: 'statusbar',
384
- run: (arg, ctx) => {
385
- const mode = arg.trim().toLowerCase();
386
- const toggle = ctx.ui.statusBar === 'off' ? 'top' : 'off';
387
- const next = !mode || mode === 'toggle'
388
- ? toggle
389
- : mode === 'on' || mode === 'top'
390
- ? 'top'
391
- : mode === 'off' || mode === 'bottom'
392
- ? mode
393
- : null;
394
- if (!next) {
395
- return ctx.transcript.sys('usage: /statusbar [on|off|top|bottom|toggle]');
396
- }
397
- patchUiState({ statusBar: next });
398
- ctx.gateway.rpc('config.set', { key: 'statusbar', value: next }).catch(() => { });
399
- queueMicrotask(() => ctx.transcript.sys(`status bar ${next}`));
400
- }
401
- },
402
- {
403
- help: 'inspect or enqueue a message',
404
- name: 'queue',
405
- run: (arg, ctx) => {
406
- if (!arg) {
407
- return ctx.transcript.sys(`${ctx.composer.queueRef.current.length} queued message(s)`);
408
- }
409
- ctx.composer.enqueue(arg);
410
- ctx.transcript.sys(`queued: "${arg.slice(0, 50)}${arg.length > 50 ? '…' : ''}"`);
411
- }
412
- },
413
- {
414
- help: 'inject a message after the next tool call (no interrupt)',
415
- name: 'steer',
416
- run: (arg, ctx) => {
417
- const payload = arg?.trim() ?? '';
418
- if (!payload) {
419
- return ctx.transcript.sys('usage: /steer <prompt>');
420
- }
421
- // If the agent isn't running, fall back to the queue so the user's
422
- // message isn't lost — identical semantics to the gateway handler.
423
- if (!ctx.ui.busy || !ctx.sid) {
424
- ctx.composer.enqueue(payload);
425
- ctx.transcript.sys(`no active turn — queued for next: "${payload.slice(0, 50)}${payload.length > 50 ? '…' : ''}"`);
426
- return;
427
- }
428
- ctx.gateway
429
- .rpc('session.steer', { session_id: ctx.sid, text: payload })
430
- .then(ctx.guarded(r => {
431
- if (r?.status === 'queued') {
432
- ctx.transcript.sys(`steer queued — arrives after next tool call: "${payload.slice(0, 50)}${payload.length > 50 ? '…' : ''}"`);
433
- }
434
- else {
435
- ctx.transcript.sys('steer rejected');
436
- }
437
- }))
438
- .catch(ctx.guardedErr);
439
- }
440
- },
441
- {
442
- help: 'undo last exchange',
443
- name: 'undo',
444
- run: (_arg, ctx) => {
445
- if (!ctx.sid) {
446
- return ctx.transcript.sys('nothing to undo');
447
- }
448
- ctx.gateway.rpc('session.undo', { session_id: ctx.sid }).then(ctx.guarded(r => {
449
- if ((r.removed ?? 0) > 0) {
450
- ctx.transcript.setHistoryItems((prev) => ctx.transcript.trimLastExchange(prev));
451
- ctx.transcript.sys(`undid ${r.removed} messages`);
452
- }
453
- else {
454
- ctx.transcript.sys('nothing to undo');
455
- }
456
- }));
457
- }
458
- },
459
- {
460
- help: 'retry last user message',
461
- name: 'retry',
462
- run: (_arg, ctx) => {
463
- const last = ctx.local.getLastUserMsg();
464
- if (!last) {
465
- return ctx.transcript.sys('nothing to retry');
466
- }
467
- if (!ctx.sid) {
468
- return ctx.transcript.send(last);
469
- }
470
- ctx.gateway.rpc('session.undo', { session_id: ctx.sid }).then(ctx.guarded(r => {
471
- if ((r.removed ?? 0) <= 0) {
472
- return ctx.transcript.sys('nothing to retry');
473
- }
474
- ctx.transcript.setHistoryItems((prev) => ctx.transcript.trimLastExchange(prev));
475
- ctx.transcript.send(last);
476
- }));
477
- }
478
- }
479
- ];
@@ -1,44 +0,0 @@
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
- import { formatBytes, performHeapDump } from '../../../lib/memory.js';
6
- export const debugCommands = [
7
- {
8
- help: 'write a V8 heap snapshot + memory diagnostics (see HERMES_HEAPDUMP_DIR)',
9
- name: 'heapdump',
10
- run: (_arg, ctx) => {
11
- const { heapUsed, rss } = process.memoryUsage();
12
- ctx.transcript.sys(`writing heap dump (heap ${formatBytes(heapUsed)} · rss ${formatBytes(rss)})…`);
13
- void performHeapDump('manual').then(r => {
14
- if (ctx.stale()) {
15
- return;
16
- }
17
- if (!r.success) {
18
- return ctx.transcript.sys(`heapdump failed: ${r.error ?? 'unknown error'}`);
19
- }
20
- ctx.transcript.sys(`heapdump: ${r.heapPath}`);
21
- ctx.transcript.sys(`diagnostics: ${r.diagPath}`);
22
- });
23
- }
24
- },
25
- {
26
- help: 'print live V8 heap + rss numbers',
27
- name: 'mem',
28
- run: (_arg, ctx) => {
29
- const { arrayBuffers, external, heapTotal, heapUsed, rss } = process.memoryUsage();
30
- ctx.transcript.panel('Memory', [
31
- {
32
- rows: [
33
- ['heap used', formatBytes(heapUsed)],
34
- ['heap total', formatBytes(heapTotal)],
35
- ['external', formatBytes(external)],
36
- ['array buffers', formatBytes(arrayBuffers)],
37
- ['rss', formatBytes(rss)],
38
- ['uptime', `${process.uptime().toFixed(0)}s`]
39
- ]
40
- }
41
- ]);
42
- }
43
- }
44
- ];