@agi-fans/dsh-tui 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/lib/autocomplete.js +0 -2
- package/lib/autocomplete.js.map +1 -1
- package/lib/command-auth.d.ts +20 -0
- package/lib/command-auth.js +225 -0
- package/lib/command-auth.js.map +1 -0
- package/lib/{command-queue.d.ts → command-export.d.ts} +2 -2
- package/lib/command-export.js +39 -0
- package/lib/command-export.js.map +1 -0
- package/lib/command-model.js +23 -12
- package/lib/command-model.js.map +1 -1
- package/lib/{command-transcript.d.ts → command-steer.d.ts} +2 -2
- package/lib/command-steer.js +18 -0
- package/lib/command-steer.js.map +1 -0
- package/lib/definition.d.ts +25 -1
- package/lib/event-views.d.ts +23 -8
- package/lib/event-views.js +207 -47
- package/lib/event-views.js.map +1 -1
- package/lib/hotkeys.d.ts +2 -5
- package/lib/hotkeys.js +4 -14
- package/lib/hotkeys.js.map +1 -1
- package/lib/prompt-selector.d.ts +2 -0
- package/lib/prompt-selector.js +35 -13
- package/lib/prompt-selector.js.map +1 -1
- package/lib/provider-local.d.ts +6 -3
- package/lib/provider-local.js +180 -44
- package/lib/provider-local.js.map +1 -1
- package/lib/renderer.js +11 -1
- package/lib/renderer.js.map +1 -1
- package/lib/runner.js +32 -4
- package/lib/runner.js.map +1 -1
- package/lib/session-controller.d.ts +27 -3
- package/lib/session-controller.js +200 -7
- package/lib/session-controller.js.map +1 -1
- package/lib/welcome-tips.js +2 -1
- package/lib/welcome-tips.js.map +1 -1
- package/package.json +12 -7
- package/lib/command-queue.js +0 -62
- package/lib/command-queue.js.map +0 -1
- package/lib/command-transcript.js +0 -85
- package/lib/command-transcript.js.map +0 -1
- package/lib/pwd.d.ts +0 -13
- package/lib/pwd.js +0 -14
- package/lib/pwd.js.map +0 -1
package/lib/provider-local.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Owns the tty: raw-mode key input (editing, history, slash/tab
|
|
5
5
|
* autocomplete, /settings overlay, /copy picker, Ctrl-R history search, PgUp/PgDn
|
|
6
6
|
* and mouse-wheel transcript scroll, click-to-caret, Ctrl-O tool
|
|
7
|
-
* expand, bracketed paste, double Ctrl-C exit, Ctrl-D quit),
|
|
7
|
+
* expand, bracketed paste, double-Escape conversation rewind, double Ctrl-C exit, Ctrl-D quit),
|
|
8
8
|
* SIGWINCH reflow, and the differential renderer. In non-tty mode
|
|
9
9
|
* (pipes, CI) it degrades to line-based input with plain append-only
|
|
10
10
|
* printing of settled blocks.
|
|
@@ -22,12 +22,11 @@ import { buildCopyTargets, extractCopyTarget, parseCopyKind } from "./copy-targe
|
|
|
22
22
|
import { applyHistorySearchEvent, createHistorySearch, hitTestHistorySearch, } from "./history-search.js";
|
|
23
23
|
import { InputEditor, lineEnd, lineStart } from "./editor.js";
|
|
24
24
|
import { applySettingsEvent, createSettings, hitTestSettings, selectSetting, tuiSettingItems, } from "./settings-list.js";
|
|
25
|
-
import { applyEvent, blockLines, initialTranscript, renderView, TRANSCRIPT_FAST_SCROLL, TRANSCRIPT_WHEEL_SCROLL, } from "./event-views.js";
|
|
25
|
+
import { applyEvent, blockLines, initialTranscript, replayEvents, renderView, TRANSCRIPT_FAST_SCROLL, TRANSCRIPT_WHEEL_SCROLL, } from "./event-views.js";
|
|
26
26
|
import { flushPending, MOUSE_TRACKING_OFF, MOUSE_TRACKING_ON, parseKeys } from "./keys.js";
|
|
27
27
|
import { LineRenderer } from "./renderer.js";
|
|
28
28
|
import { hitTestEditor } from "./box.js";
|
|
29
29
|
import { createTheme, detectTrueColor, parseThemeName } from "./theme.js";
|
|
30
|
-
import { formatWorkspaceText } from "./pwd.js";
|
|
31
30
|
import { TUI_SETTINGS_NAMESPACE, TuiSettingsSchema } from "./tui-settings.js";
|
|
32
31
|
import { defaultStatusBarConfig, resolveStatusBarConfig } from "./status-config.js";
|
|
33
32
|
import { HistoryStore } from "./history-store.js";
|
|
@@ -37,10 +36,12 @@ import { settingsNamespace } from '@deepseek-ai/dsh-settings';
|
|
|
37
36
|
import { movePromptSelection, filteredPromptOptions, selectedPromptAnswer, selectedFilteredPromptAnswer, togglePromptSelection, } from "./prompt-selector.js";
|
|
38
37
|
import { resolveProjectContext } from "./project-context.js";
|
|
39
38
|
import { pickWelcomeTips } from "./welcome-tips.js";
|
|
39
|
+
import { formatHotkeysText, hotkeyCount } from "./hotkeys.js";
|
|
40
40
|
import { imageMarker, imagePathCandidates, probeImageDimensions, readImageFile, readImageFromClipboard, readMacClipboardFiles, } from "./image-paste.js";
|
|
41
41
|
const APP_NAME = 'omdsh';
|
|
42
42
|
const APP_VERSION = '0.1.0';
|
|
43
43
|
const DOUBLE_CTRL_C_MS = 500;
|
|
44
|
+
const DOUBLE_ESCAPE_MS = 500;
|
|
44
45
|
function shortenPath(cwd) {
|
|
45
46
|
const home = homedir();
|
|
46
47
|
if (cwd === home)
|
|
@@ -73,11 +74,17 @@ export class LocalTui {
|
|
|
73
74
|
#settings = null;
|
|
74
75
|
#copySelector = null;
|
|
75
76
|
#pending = null;
|
|
76
|
-
#
|
|
77
|
+
#queuedSubmissions = [];
|
|
78
|
+
/** Newer queue entries temporarily detached while Up browses backward. */
|
|
79
|
+
#queueEditNewer = null;
|
|
80
|
+
#queueEditPending = false;
|
|
77
81
|
#quitRequested = false;
|
|
78
82
|
#resumeHintRequested = false;
|
|
79
83
|
#lastSigintTime = 0;
|
|
84
|
+
#lastEscapeTime = 0;
|
|
80
85
|
#interrupts = new Set();
|
|
86
|
+
#queueEdits = new Set();
|
|
87
|
+
#rewinds = new Set();
|
|
81
88
|
#disposed = false;
|
|
82
89
|
#pendingKeys = '';
|
|
83
90
|
#escapeTimer = null;
|
|
@@ -202,6 +209,8 @@ export class LocalTui {
|
|
|
202
209
|
}
|
|
203
210
|
}
|
|
204
211
|
setStatus(status) {
|
|
212
|
+
if (this.#state.status === 'compacting')
|
|
213
|
+
return;
|
|
205
214
|
this.#state = { ...this.#state, status };
|
|
206
215
|
this.#syncTick();
|
|
207
216
|
if (this.#tty)
|
|
@@ -226,8 +235,14 @@ export class LocalTui {
|
|
|
226
235
|
if (this.#tty)
|
|
227
236
|
this.#render();
|
|
228
237
|
}
|
|
229
|
-
notice(text,
|
|
230
|
-
|
|
238
|
+
notice(text, options = {}) {
|
|
239
|
+
const block = {
|
|
240
|
+
kind: 'notice',
|
|
241
|
+
level: options.level ?? 'info',
|
|
242
|
+
text,
|
|
243
|
+
...(options.framed === true ? { framed: true } : {}),
|
|
244
|
+
};
|
|
245
|
+
this.#state = { ...this.#state, blocks: [...this.#state.blocks, block] };
|
|
231
246
|
if (this.#tty)
|
|
232
247
|
this.#render();
|
|
233
248
|
else
|
|
@@ -276,10 +291,8 @@ export class LocalTui {
|
|
|
276
291
|
});
|
|
277
292
|
}
|
|
278
293
|
replaceSession(events, presentations) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
state = applyEvent(state, event, presentations?.get(event.seq));
|
|
282
|
-
this.#state = { ...state, status: 'idle' };
|
|
294
|
+
const state = replayEvents(events, presentations);
|
|
295
|
+
this.#state = { ...state, status: 'idle', compactCommandId: undefined };
|
|
283
296
|
this.#plainPrinted = 0;
|
|
284
297
|
this.#followTail();
|
|
285
298
|
if (this.#tty)
|
|
@@ -331,9 +344,11 @@ export class LocalTui {
|
|
|
331
344
|
return this.#readlinePlain();
|
|
332
345
|
// Lines submitted while a turn was still running were queued instead of
|
|
333
346
|
// dropped; serve the oldest before waiting for fresh input.
|
|
334
|
-
const queued = this.#
|
|
335
|
-
if (queued !== undefined)
|
|
347
|
+
const queued = this.#queuedSubmissions.shift();
|
|
348
|
+
if (queued !== undefined) {
|
|
349
|
+
this.#render();
|
|
336
350
|
return Promise.resolve(queued);
|
|
351
|
+
}
|
|
337
352
|
return new Promise((resolve) => {
|
|
338
353
|
this.#pending = { resolve };
|
|
339
354
|
});
|
|
@@ -357,10 +372,49 @@ export class LocalTui {
|
|
|
357
372
|
if (this.#tty)
|
|
358
373
|
this.#render();
|
|
359
374
|
}
|
|
375
|
+
resolveQueueEdit(submission) {
|
|
376
|
+
if (!this.#queueEditPending)
|
|
377
|
+
return;
|
|
378
|
+
this.#queueEditPending = false;
|
|
379
|
+
if (submission === null) {
|
|
380
|
+
if (this.#editor.text === '' && this.#images.length === 0 && this.#queueEditNewer?.length === 0) {
|
|
381
|
+
this.#queueEditNewer = null;
|
|
382
|
+
}
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
if (this.#queueEditNewer === null)
|
|
386
|
+
this.#queueEditNewer = [];
|
|
387
|
+
if (this.#editor.text !== '' || this.#images.length > 0) {
|
|
388
|
+
this.#queueEditNewer.unshift(this.#currentSubmission());
|
|
389
|
+
}
|
|
390
|
+
this.#replaceInput(submission);
|
|
391
|
+
}
|
|
392
|
+
#currentSubmission() {
|
|
393
|
+
return {
|
|
394
|
+
text: this.#editor.text,
|
|
395
|
+
images: this.#images.map(image => ({ ...image })),
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
#replaceInput(submission) {
|
|
399
|
+
this.#images = submission.images.map(image => ({ ...image }));
|
|
400
|
+
this.#editor.setText(submission.text);
|
|
401
|
+
this.#historyIndex = 0;
|
|
402
|
+
this.#refreshAutocomplete();
|
|
403
|
+
if (this.#tty)
|
|
404
|
+
this.#render();
|
|
405
|
+
}
|
|
360
406
|
onInterrupt(listener) {
|
|
361
407
|
this.#interrupts.add(listener);
|
|
362
408
|
return () => { this.#interrupts.delete(listener); };
|
|
363
409
|
}
|
|
410
|
+
onQueueEdit(listener) {
|
|
411
|
+
this.#queueEdits.add(listener);
|
|
412
|
+
return () => { this.#queueEdits.delete(listener); };
|
|
413
|
+
}
|
|
414
|
+
onRewind(listener) {
|
|
415
|
+
this.#rewinds.add(listener);
|
|
416
|
+
return () => { this.#rewinds.delete(listener); };
|
|
417
|
+
}
|
|
364
418
|
dispose() {
|
|
365
419
|
if (this.#disposed)
|
|
366
420
|
return;
|
|
@@ -465,7 +519,7 @@ export class LocalTui {
|
|
|
465
519
|
this.#term.output.write(out);
|
|
466
520
|
}
|
|
467
521
|
#busy() {
|
|
468
|
-
if (this.#state.status
|
|
522
|
+
if (this.#state.status !== 'idle')
|
|
469
523
|
return true;
|
|
470
524
|
return this.#state.blocks.some((block) => block.kind === 'tool' && block.status === 'running');
|
|
471
525
|
}
|
|
@@ -500,6 +554,9 @@ export class LocalTui {
|
|
|
500
554
|
input: this.#editor.text,
|
|
501
555
|
inputCursor: this.#editor.cursor,
|
|
502
556
|
inputImages: this.#images.length,
|
|
557
|
+
queuedSubmissions: this.#queueEditNewer === null
|
|
558
|
+
? this.#queuedSubmissions
|
|
559
|
+
: [...this.#queuedSubmissions, ...this.#queueEditNewer],
|
|
503
560
|
colors: this.#colors,
|
|
504
561
|
pwd: this.#pwd,
|
|
505
562
|
...(this.#branch !== undefined ? { branch: this.#branch } : {}),
|
|
@@ -600,7 +657,7 @@ export class LocalTui {
|
|
|
600
657
|
#startAsyncPaste(operation) {
|
|
601
658
|
this.#pasteInFlight += 1;
|
|
602
659
|
void operation.catch((error) => {
|
|
603
|
-
this.notice('Paste failed: ' + (error instanceof Error ? error.message : String(error)), 'error');
|
|
660
|
+
this.notice('Paste failed: ' + (error instanceof Error ? error.message : String(error)), { level: 'error' });
|
|
604
661
|
}).finally(() => {
|
|
605
662
|
this.#pasteInFlight = Math.max(0, this.#pasteInFlight - 1);
|
|
606
663
|
if (this.#pasteInFlight !== 0 || this.#deferredPasteEvents.length === 0)
|
|
@@ -755,6 +812,22 @@ export class LocalTui {
|
|
|
755
812
|
this.#editor.setText(text, Math.min(this.#editor.cursor, text.length));
|
|
756
813
|
}
|
|
757
814
|
#dispatch(event) {
|
|
815
|
+
if (this.#state.status === 'compacting') {
|
|
816
|
+
if (event.type === 'mouse' && event.wheel !== null) {
|
|
817
|
+
this.#scrollBy(event.wheel < 0 ? -TRANSCRIPT_WHEEL_SCROLL : TRANSCRIPT_WHEEL_SCROLL, true);
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
if (event.type === 'key' && event.id === 'pageUp') {
|
|
821
|
+
this.#scrollBy(-this.#pageSize());
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
if (event.type === 'key' && event.id === 'pageDown') {
|
|
825
|
+
this.#scrollBy(this.#pageSize());
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
if (event.type !== 'key' || event.id !== 'ctrl+c')
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
758
831
|
// Clipboard image inspection is asynchronous. Preserve the exact key
|
|
759
832
|
// order so a fast Ctrl+V, Enter submits the finished image draft rather
|
|
760
833
|
// than an empty prompt.
|
|
@@ -783,9 +856,12 @@ export class LocalTui {
|
|
|
783
856
|
return;
|
|
784
857
|
}
|
|
785
858
|
if (event.type === 'mouse') {
|
|
859
|
+
this.#lastEscapeTime = 0;
|
|
786
860
|
this.#handleMouse(event);
|
|
787
861
|
return;
|
|
788
862
|
}
|
|
863
|
+
if (event.type !== 'key' || event.id !== 'escape')
|
|
864
|
+
this.#lastEscapeTime = 0;
|
|
789
865
|
if (this.#handlePrompt(event))
|
|
790
866
|
return;
|
|
791
867
|
if (event.type === 'key') {
|
|
@@ -824,7 +900,7 @@ export class LocalTui {
|
|
|
824
900
|
return;
|
|
825
901
|
}
|
|
826
902
|
this.#lastSigintTime = now;
|
|
827
|
-
if (this.#state.status
|
|
903
|
+
if (this.#state.status !== 'idle') {
|
|
828
904
|
for (const listener of this.#interrupts)
|
|
829
905
|
listener();
|
|
830
906
|
}
|
|
@@ -857,8 +933,29 @@ export class LocalTui {
|
|
|
857
933
|
this.#applySearch(event);
|
|
858
934
|
return;
|
|
859
935
|
}
|
|
860
|
-
if (this.#handleAutocomplete(event))
|
|
936
|
+
if (this.#handleAutocomplete(event)) {
|
|
937
|
+
if (event.type === 'key' && event.id === 'escape')
|
|
938
|
+
this.#lastEscapeTime = 0;
|
|
861
939
|
return;
|
|
940
|
+
}
|
|
941
|
+
if (event.type === 'key' && event.id === 'escape') {
|
|
942
|
+
if (this.#state.status !== 'idle' || this.#pending === null
|
|
943
|
+
|| this.#editor.text !== '' || this.#images.length > 0) {
|
|
944
|
+
this.#lastEscapeTime = 0;
|
|
945
|
+
}
|
|
946
|
+
else {
|
|
947
|
+
const now = Date.now();
|
|
948
|
+
if (now - this.#lastEscapeTime < DOUBLE_ESCAPE_MS) {
|
|
949
|
+
this.#lastEscapeTime = 0;
|
|
950
|
+
for (const listener of this.#rewinds)
|
|
951
|
+
listener();
|
|
952
|
+
}
|
|
953
|
+
else {
|
|
954
|
+
this.#lastEscapeTime = now;
|
|
955
|
+
}
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
862
959
|
if (event.type === 'key' && (event.id === 'backspace' || event.id === 'delete')
|
|
863
960
|
&& this.#removeImageAtCursor(event.id))
|
|
864
961
|
return;
|
|
@@ -1422,6 +1519,8 @@ export class LocalTui {
|
|
|
1422
1519
|
return;
|
|
1423
1520
|
}
|
|
1424
1521
|
if (command.kind === 'historyPrev') {
|
|
1522
|
+
if (this.#restoreLatestQueuedSubmission())
|
|
1523
|
+
return;
|
|
1425
1524
|
this.#historyPrev();
|
|
1426
1525
|
return;
|
|
1427
1526
|
}
|
|
@@ -1439,6 +1538,8 @@ export class LocalTui {
|
|
|
1439
1538
|
if (command.kind === 'clear') {
|
|
1440
1539
|
this.#editor.clear();
|
|
1441
1540
|
this.#images = [];
|
|
1541
|
+
this.#queueEditNewer = null;
|
|
1542
|
+
this.#queueEditPending = false;
|
|
1442
1543
|
this.#historyIndex = 0;
|
|
1443
1544
|
this.#ac = null;
|
|
1444
1545
|
this.#search = null;
|
|
@@ -1476,6 +1577,41 @@ export class LocalTui {
|
|
|
1476
1577
|
this.#refreshAutocomplete();
|
|
1477
1578
|
this.#render();
|
|
1478
1579
|
}
|
|
1580
|
+
#restoreLatestQueuedSubmission() {
|
|
1581
|
+
if (this.#queueEditPending)
|
|
1582
|
+
return true;
|
|
1583
|
+
if (this.#queueEditNewer !== null) {
|
|
1584
|
+
const previous = this.#queuedSubmissions.pop();
|
|
1585
|
+
if (previous !== undefined) {
|
|
1586
|
+
this.#queueEditNewer.unshift(this.#currentSubmission());
|
|
1587
|
+
this.#replaceInput(previous);
|
|
1588
|
+
return true;
|
|
1589
|
+
}
|
|
1590
|
+
const hasDurableFollowup = this.#state.nextTurnInbox.some(message => message.source.kind === 'user');
|
|
1591
|
+
if (!hasDurableFollowup || this.#queueEdits.size === 0)
|
|
1592
|
+
return true;
|
|
1593
|
+
this.#queueEditPending = true;
|
|
1594
|
+
for (const listener of this.#queueEdits)
|
|
1595
|
+
listener();
|
|
1596
|
+
return true;
|
|
1597
|
+
}
|
|
1598
|
+
if (this.#editor.text !== '' || this.#images.length > 0 || this.#historyIndex !== 0)
|
|
1599
|
+
return false;
|
|
1600
|
+
const submission = this.#queuedSubmissions.pop();
|
|
1601
|
+
if (submission !== undefined) {
|
|
1602
|
+
this.#queueEditNewer = [];
|
|
1603
|
+
this.#replaceInput(submission);
|
|
1604
|
+
return true;
|
|
1605
|
+
}
|
|
1606
|
+
const hasDurableFollowup = this.#state.nextTurnInbox.some(message => message.source.kind === 'user');
|
|
1607
|
+
if (!hasDurableFollowup || this.#queueEdits.size === 0)
|
|
1608
|
+
return false;
|
|
1609
|
+
this.#queueEditNewer = [];
|
|
1610
|
+
this.#queueEditPending = true;
|
|
1611
|
+
for (const listener of this.#queueEdits)
|
|
1612
|
+
listener();
|
|
1613
|
+
return true;
|
|
1614
|
+
}
|
|
1479
1615
|
#historyNext() {
|
|
1480
1616
|
if (this.#images.length > 0)
|
|
1481
1617
|
return;
|
|
@@ -1506,6 +1642,7 @@ export class LocalTui {
|
|
|
1506
1642
|
}
|
|
1507
1643
|
const images = this.#images.map(image => ({ ...image }));
|
|
1508
1644
|
const submittedText = images.length > 0 ? text.trim() : text;
|
|
1645
|
+
const queueEditNewer = this.#queueEditNewer;
|
|
1509
1646
|
const historyText = images.reduce((value, image, index) => value.replaceAll(imageMarker(index, image), ''), submittedText)
|
|
1510
1647
|
.replace(/[ \t]{2,}/gu, ' ')
|
|
1511
1648
|
.trim();
|
|
@@ -1515,6 +1652,8 @@ export class LocalTui {
|
|
|
1515
1652
|
}
|
|
1516
1653
|
this.#historyIndex = 0;
|
|
1517
1654
|
this.#draft = '';
|
|
1655
|
+
this.#queueEditNewer = null;
|
|
1656
|
+
this.#queueEditPending = false;
|
|
1518
1657
|
this.#editor.setText('');
|
|
1519
1658
|
this.#images = [];
|
|
1520
1659
|
this.#ac = null;
|
|
@@ -1524,18 +1663,26 @@ export class LocalTui {
|
|
|
1524
1663
|
this.#followTail();
|
|
1525
1664
|
const slash = images.length === 0 ? parseSlashInput(submittedText) : null;
|
|
1526
1665
|
if (slash !== null) {
|
|
1666
|
+
if (queueEditNewer !== null)
|
|
1667
|
+
this.#queuedSubmissions.push(...queueEditNewer);
|
|
1527
1668
|
this.#runSlash(slash.name, slash.args);
|
|
1528
1669
|
return;
|
|
1529
1670
|
}
|
|
1530
|
-
this.#render();
|
|
1531
1671
|
const pending = this.#pending;
|
|
1532
1672
|
if (pending !== null) {
|
|
1533
1673
|
this.#pending = null;
|
|
1534
1674
|
pending.resolve({ text: submittedText, images });
|
|
1675
|
+
if (queueEditNewer !== null)
|
|
1676
|
+
this.#queuedSubmissions.push(...queueEditNewer);
|
|
1535
1677
|
}
|
|
1536
|
-
else if (submittedText !== '' || images.length > 0) {
|
|
1537
|
-
|
|
1678
|
+
else if (submittedText !== '' || images.length > 0 || queueEditNewer !== null) {
|
|
1679
|
+
if (submittedText !== '' || images.length > 0) {
|
|
1680
|
+
this.#queuedSubmissions.push({ text: submittedText, images });
|
|
1681
|
+
}
|
|
1682
|
+
if (queueEditNewer !== null)
|
|
1683
|
+
this.#queuedSubmissions.push(...queueEditNewer);
|
|
1538
1684
|
}
|
|
1685
|
+
this.#render();
|
|
1539
1686
|
}
|
|
1540
1687
|
#runSlash(name, args = '') {
|
|
1541
1688
|
if (name === '') {
|
|
@@ -1563,11 +1710,6 @@ export class LocalTui {
|
|
|
1563
1710
|
this.#runSettings(args);
|
|
1564
1711
|
return;
|
|
1565
1712
|
}
|
|
1566
|
-
if (command.name === 'hotkeys') {
|
|
1567
|
-
this.#hotkeyCatalog();
|
|
1568
|
-
this.#render();
|
|
1569
|
-
return;
|
|
1570
|
-
}
|
|
1571
1713
|
if (command.name === 'copy') {
|
|
1572
1714
|
void this.#runCopy(args);
|
|
1573
1715
|
return;
|
|
@@ -1577,17 +1719,7 @@ export class LocalTui {
|
|
|
1577
1719
|
this.#render();
|
|
1578
1720
|
return;
|
|
1579
1721
|
}
|
|
1580
|
-
if (command.name === 'pwd') {
|
|
1581
|
-
this.#notice(formatWorkspaceText({
|
|
1582
|
-
cwd: process.cwd(),
|
|
1583
|
-
model: this.#model,
|
|
1584
|
-
...(this.#branch !== undefined ? { branch: this.#branch } : {}),
|
|
1585
|
-
}));
|
|
1586
|
-
this.#render();
|
|
1587
|
-
return;
|
|
1588
|
-
}
|
|
1589
1722
|
if (!BUILTIN_SLASH_COMMANDS.some((entry) => entry.name === command.name)) {
|
|
1590
|
-
this.#render();
|
|
1591
1723
|
const raw = '/' + name + (args === '' ? '' : ' ' + args);
|
|
1592
1724
|
const pending = this.#pending;
|
|
1593
1725
|
if (pending !== null) {
|
|
@@ -1595,13 +1727,24 @@ export class LocalTui {
|
|
|
1595
1727
|
pending.resolve({ text: raw, images: [] });
|
|
1596
1728
|
}
|
|
1597
1729
|
else {
|
|
1598
|
-
this.#
|
|
1730
|
+
this.#queuedSubmissions.push({ text: raw, images: [] });
|
|
1599
1731
|
}
|
|
1732
|
+
this.#render();
|
|
1600
1733
|
return;
|
|
1601
1734
|
}
|
|
1602
1735
|
this.#state = {
|
|
1603
1736
|
...this.#state,
|
|
1604
|
-
blocks: [...this.#state.blocks, {
|
|
1737
|
+
blocks: [...this.#state.blocks, {
|
|
1738
|
+
kind: 'commandOutput',
|
|
1739
|
+
command: 'help',
|
|
1740
|
+
text: [
|
|
1741
|
+
formatHelpText(this.#commands()),
|
|
1742
|
+
'',
|
|
1743
|
+
`**Keyboard Shortcuts · ${hotkeyCount(this.#keybindings)} bindings**`,
|
|
1744
|
+
'',
|
|
1745
|
+
formatHotkeysText(this.#keybindings),
|
|
1746
|
+
].join('\n'),
|
|
1747
|
+
}],
|
|
1605
1748
|
};
|
|
1606
1749
|
this.#focusLatestBlock();
|
|
1607
1750
|
this.#render();
|
|
@@ -1678,13 +1821,6 @@ export class LocalTui {
|
|
|
1678
1821
|
};
|
|
1679
1822
|
this.#focusLatestBlock();
|
|
1680
1823
|
}
|
|
1681
|
-
#hotkeyCatalog() {
|
|
1682
|
-
this.#state = {
|
|
1683
|
-
...this.#state,
|
|
1684
|
-
blocks: [...this.#state.blocks, { kind: 'hotkeyCatalog', bindings: this.#keybindings }],
|
|
1685
|
-
};
|
|
1686
|
-
this.#focusLatestBlock();
|
|
1687
|
-
}
|
|
1688
1824
|
#focusLatestBlock() {
|
|
1689
1825
|
this.#follow = false;
|
|
1690
1826
|
this.#focusBlock = Math.max(0, this.#state.blocks.length - 1);
|
|
@@ -1716,7 +1852,7 @@ export class LocalTui {
|
|
|
1716
1852
|
this.#reconcileImageDrafts();
|
|
1717
1853
|
}
|
|
1718
1854
|
catch (error) {
|
|
1719
|
-
this.notice(error instanceof Error ? error.message : String(error), 'error');
|
|
1855
|
+
this.notice(error instanceof Error ? error.message : String(error), { level: 'error' });
|
|
1720
1856
|
}
|
|
1721
1857
|
finally {
|
|
1722
1858
|
this.#term.input.setRawMode?.(true);
|