@agi-fans/dsh-tui 0.23.0 → 0.24.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/lib/CHANGELOG.md +40 -1
- package/lib/commands/diff.js +58 -33
- package/lib/commands/diff.js.map +1 -1
- package/lib/commands/export.js +3 -1
- package/lib/commands/export.js.map +1 -1
- package/lib/commands/files.js +10 -2
- package/lib/commands/files.js.map +1 -1
- package/lib/commands/model.js +15 -8
- package/lib/commands/model.js.map +1 -1
- package/lib/commands/session.js +6 -1
- package/lib/commands/session.js.map +1 -1
- package/lib/definition.d.ts +10 -0
- package/lib/locale/zh.d.ts +26 -6
- package/lib/locale/zh.js +26 -6
- package/lib/locale/zh.js.map +1 -1
- package/lib/runtime/account-settings.d.ts +1 -0
- package/lib/runtime/account-settings.js +2 -2
- package/lib/runtime/account-settings.js.map +1 -1
- package/lib/runtime/model-settings.d.ts +2 -0
- package/lib/runtime/model-settings.js +2 -2
- package/lib/runtime/model-settings.js.map +1 -1
- package/lib/runtime/plugin-settings.d.ts +1 -0
- package/lib/runtime/plugin-settings.js +6 -6
- package/lib/runtime/plugin-settings.js.map +1 -1
- package/lib/runtime/provider-local.d.ts +3 -0
- package/lib/runtime/provider-local.js +110 -22
- package/lib/runtime/provider-local.js.map +1 -1
- package/lib/runtime/settings-preferences.js +1 -1
- package/lib/runtime/settings-preferences.js.map +1 -1
- package/lib/session/feature-toggles.js +2 -2
- package/lib/session/feature-toggles.js.map +1 -1
- package/lib/session/session-controller.d.ts +2 -8
- package/lib/session/session-controller.js +57 -32
- package/lib/session/session-controller.js.map +1 -1
- package/lib/session/session-library.d.ts +3 -1
- package/lib/session/session-library.js +15 -0
- package/lib/session/session-library.js.map +1 -1
- package/lib/session/tui-settings.d.ts +2 -0
- package/lib/session/tui-settings.js +1 -0
- package/lib/session/tui-settings.js.map +1 -1
- package/lib/views/autocomplete.d.ts +3 -6
- package/lib/views/autocomplete.js +10 -8
- package/lib/views/autocomplete.js.map +1 -1
- package/lib/views/document-reader.js +4 -1
- package/lib/views/document-reader.js.map +1 -1
- package/lib/views/settings-list.d.ts +5 -0
- package/lib/views/settings-list.js +46 -10
- package/lib/views/settings-list.js.map +1 -1
- package/lib/views/transcript-render.d.ts +2 -0
- package/lib/views/transcript-render.js +31 -19
- package/lib/views/transcript-render.js.map +1 -1
- package/package.json +1 -1
|
@@ -414,6 +414,9 @@ export class LocalTui {
|
|
|
414
414
|
#mermaidMode = 'auto';
|
|
415
415
|
/** Transcript collapses every thought to one line; Ctrl+T flips it. */
|
|
416
416
|
#hideThinking = true;
|
|
417
|
+
#showFileChanges = true;
|
|
418
|
+
#workspaceReview;
|
|
419
|
+
#workspacePress;
|
|
417
420
|
#mouseInteraction = 'auto';
|
|
418
421
|
#tmuxMouseEnabled;
|
|
419
422
|
#disclosurePress;
|
|
@@ -439,6 +442,8 @@ export class LocalTui {
|
|
|
439
442
|
*/
|
|
440
443
|
#transientStatus;
|
|
441
444
|
#transientTimer = null;
|
|
445
|
+
/** Idle submissions also pass through the inbox, but are not queue gestures. */
|
|
446
|
+
#directInputIds = new Set();
|
|
442
447
|
/** Aborts the live Shell card, so Ctrl+C interrupts the command it belongs to. */
|
|
443
448
|
#shellAbort;
|
|
444
449
|
/** Turn scopes whose tools stay detailed as new calls arrive during inspection. */
|
|
@@ -596,6 +601,7 @@ export class LocalTui {
|
|
|
596
601
|
// live window so it stays anchored at the bottom.
|
|
597
602
|
this.#selection.clear();
|
|
598
603
|
this.#mouseActionPress = undefined;
|
|
604
|
+
this.#workspacePress = undefined;
|
|
599
605
|
this.#jumpPress = undefined;
|
|
600
606
|
this.#disclosurePress = undefined;
|
|
601
607
|
const repaint = () => {
|
|
@@ -680,9 +686,23 @@ export class LocalTui {
|
|
|
680
686
|
this.#retryDeadline = Date.now() + event.data.delayMs;
|
|
681
687
|
if (event.type === 'llm/retry-started' || event.type === 'turn/end')
|
|
682
688
|
this.#retryDeadline = undefined;
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
689
|
+
let claimedHumanInput = false;
|
|
690
|
+
if (event.type === 'agent/inbox/spliced') {
|
|
691
|
+
const inbox = event.data.target === 'next-step' ? this.#state.nextStepInbox : this.#state.nextTurnInbox;
|
|
692
|
+
const removed = inbox.slice(event.data.start, event.data.start + (event.data.removedCount ?? 0));
|
|
693
|
+
claimedHumanInput = event.data.outcome !== 'canceled' && event.data.inserted.length === 0
|
|
694
|
+
&& removed.some(message => message.source.kind === 'user' && !this.#directInputIds.has(message.id));
|
|
695
|
+
for (const message of removed)
|
|
696
|
+
this.#directInputIds.delete(message.id);
|
|
697
|
+
if (event.data.target === 'next-turn' && this.#state.status === 'idle'
|
|
698
|
+
&& !inbox.some(message => message.source.kind === 'user')) {
|
|
699
|
+
const first = event.data.inserted.find(message => message.source.kind === 'user');
|
|
700
|
+
if (first !== undefined)
|
|
701
|
+
this.#directInputIds.add(first.id);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
else if (event.type === 'session/end-seed')
|
|
705
|
+
this.#directInputIds.clear();
|
|
686
706
|
this.#state = applyEvent(this.#state, event, presentation, workspace);
|
|
687
707
|
if (claimedHumanInput && this.#tty && event.type === 'agent/inbox/spliced') {
|
|
688
708
|
this.#showTransientStatus(event.data.target === 'next-step' ? 'Steer taken for the next step' : 'Queue taken for the next turn');
|
|
@@ -843,6 +863,7 @@ export class LocalTui {
|
|
|
843
863
|
&& this.#inspected?.writable === inspected?.writable)
|
|
844
864
|
return;
|
|
845
865
|
if (this.#inspected?.id !== inspected?.id) {
|
|
866
|
+
this.#workspacePress = undefined;
|
|
846
867
|
this.#fileReviewAbort?.abort();
|
|
847
868
|
this.#closeFileBrowser();
|
|
848
869
|
}
|
|
@@ -870,6 +891,7 @@ export class LocalTui {
|
|
|
870
891
|
async reviewFiles(request) {
|
|
871
892
|
if (!this.#tty || this.#disposed || request.signal.aborted)
|
|
872
893
|
return;
|
|
894
|
+
this.#workspacePress = undefined;
|
|
873
895
|
this.#flushPasteBurst(true);
|
|
874
896
|
this.#pasteBurst.clear();
|
|
875
897
|
this.#finishPrompt(null);
|
|
@@ -1204,7 +1226,8 @@ export class LocalTui {
|
|
|
1204
1226
|
const browserState = promptBrowserState(request);
|
|
1205
1227
|
request = localizePrompt(request, resolveUiLanguage(this.#uiLanguage));
|
|
1206
1228
|
// Background approvals take the terminal from a user-opened file reader.
|
|
1207
|
-
if (this.#fileReviewAbort !== undefined && request.signal !== this.#fileReviewAbort.signal
|
|
1229
|
+
if (this.#fileReviewAbort !== undefined && request.signal !== this.#fileReviewAbort.signal
|
|
1230
|
+
&& request.signal !== this.#fileBrowser?.request.signal)
|
|
1208
1231
|
this.#fileReviewAbort.abort();
|
|
1209
1232
|
if (this.#disposed || request.signal?.aborted === true)
|
|
1210
1233
|
return Promise.resolve(null);
|
|
@@ -1235,6 +1258,7 @@ export class LocalTui {
|
|
|
1235
1258
|
this.#promptChoicePress = undefined;
|
|
1236
1259
|
this.#disclosurePress = undefined;
|
|
1237
1260
|
this.#mouseActionPress = undefined;
|
|
1261
|
+
this.#workspacePress = undefined;
|
|
1238
1262
|
this.#jumpPress = undefined;
|
|
1239
1263
|
this.#wheelGesture = IDLE_WHEEL;
|
|
1240
1264
|
const savedInput = this.#editor.snapshot();
|
|
@@ -1325,6 +1349,7 @@ export class LocalTui {
|
|
|
1325
1349
|
});
|
|
1326
1350
|
}
|
|
1327
1351
|
replaceSession(events, presentations, status = 'idle', reason = 'open') {
|
|
1352
|
+
this.#workspacePress = undefined;
|
|
1328
1353
|
if (reason !== 'refresh') {
|
|
1329
1354
|
this.#fileReviewAbort?.abort();
|
|
1330
1355
|
this.#closeFileBrowser();
|
|
@@ -1332,6 +1357,14 @@ export class LocalTui {
|
|
|
1332
1357
|
}
|
|
1333
1358
|
this.#trajectory = null;
|
|
1334
1359
|
const state = replayEvents(events, presentations);
|
|
1360
|
+
if (reason === 'refresh') {
|
|
1361
|
+
const pendingIds = new Set(state.nextTurnInbox.map(message => message.id));
|
|
1362
|
+
for (const id of this.#directInputIds)
|
|
1363
|
+
if (!pendingIds.has(id))
|
|
1364
|
+
this.#directInputIds.delete(id);
|
|
1365
|
+
}
|
|
1366
|
+
else
|
|
1367
|
+
this.#directInputIds.clear();
|
|
1335
1368
|
// A notice does not turn a blank session into a document that /new needs
|
|
1336
1369
|
// to separate. Refreshes are the same document.
|
|
1337
1370
|
const boundary = reason === 'open' || (reason === 'new' && this.#state.blocks.some(block => block.kind !== 'notice'));
|
|
@@ -1348,6 +1381,7 @@ export class LocalTui {
|
|
|
1348
1381
|
}
|
|
1349
1382
|
setSession(info) {
|
|
1350
1383
|
if (info.id !== this.#sessionId) {
|
|
1384
|
+
this.#workspacePress = undefined;
|
|
1351
1385
|
this.#fileReviewAbort?.abort();
|
|
1352
1386
|
this.#closeFileBrowser();
|
|
1353
1387
|
}
|
|
@@ -1432,6 +1466,7 @@ export class LocalTui {
|
|
|
1432
1466
|
mathMode: this.#mathMode,
|
|
1433
1467
|
mermaidMode: this.#mermaidMode,
|
|
1434
1468
|
hideThinking: this.#hideThinking,
|
|
1469
|
+
showFileChanges: this.#showFileChanges,
|
|
1435
1470
|
editor: this.#externalEditor,
|
|
1436
1471
|
terminalTitle: this.#terminalTitle,
|
|
1437
1472
|
terminalState: this.#terminalState,
|
|
@@ -1719,6 +1754,15 @@ export class LocalTui {
|
|
|
1719
1754
|
return pending.queued.length === 0 && pending.sending.size === 0
|
|
1720
1755
|
&& this.#state.nextTurnInbox.length === 0 && !this.#state.nextStepInbox.some(message => message.source.kind === 'user');
|
|
1721
1756
|
}
|
|
1757
|
+
setWorkspaceReviewHandler(handler) {
|
|
1758
|
+
this.#workspaceReview = handler;
|
|
1759
|
+
return () => {
|
|
1760
|
+
if (this.#workspaceReview === handler) {
|
|
1761
|
+
this.#workspaceReview = undefined;
|
|
1762
|
+
this.#workspacePress = undefined;
|
|
1763
|
+
}
|
|
1764
|
+
};
|
|
1765
|
+
}
|
|
1722
1766
|
setGoalHandler(handler) {
|
|
1723
1767
|
this.#goalHandler = handler;
|
|
1724
1768
|
this.#syncSettingsActions();
|
|
@@ -2137,6 +2181,7 @@ export class LocalTui {
|
|
|
2137
2181
|
mathMode: this.#mathMode,
|
|
2138
2182
|
mermaidMode: this.#mermaidMode,
|
|
2139
2183
|
hideThinking: true,
|
|
2184
|
+
showFileChanges: this.#showFileChanges,
|
|
2140
2185
|
height: this.#term.height(),
|
|
2141
2186
|
model: this.#model,
|
|
2142
2187
|
...(this.#reasoningEffort === undefined ? {} : { reasoningEffort: this.#reasoningEffort }),
|
|
@@ -2262,7 +2307,8 @@ export class LocalTui {
|
|
|
2262
2307
|
return Math.max(1, this.#scrollBudget > 2 ? this.#scrollBudget - 2 : 1);
|
|
2263
2308
|
}
|
|
2264
2309
|
#scrollBy(delta) {
|
|
2265
|
-
|
|
2310
|
+
this.#workspacePress = undefined;
|
|
2311
|
+
if (this.#follow && (delta > 0 || this.#maxStart === 0))
|
|
2266
2312
|
return;
|
|
2267
2313
|
if (delta === 0 && this.#maxStart === 0)
|
|
2268
2314
|
return;
|
|
@@ -2325,6 +2371,7 @@ export class LocalTui {
|
|
|
2325
2371
|
enabled = enabled && this.#mouseInteraction !== 'native'
|
|
2326
2372
|
&& (this.#mouseInteraction === 'tui' || this.#tmuxMouseEnabled !== false);
|
|
2327
2373
|
if (!enabled) {
|
|
2374
|
+
this.#workspacePress = undefined;
|
|
2328
2375
|
this.#mouseActionPress = undefined;
|
|
2329
2376
|
this.#selection.clear();
|
|
2330
2377
|
this.#jumpPress = undefined;
|
|
@@ -2665,6 +2712,18 @@ export class LocalTui {
|
|
|
2665
2712
|
return { row, column: tool.actionColumn, width: tool.key.startsWith('output:') ? 6 : 5, key: tool.key, action: 'tool', block: tool.block };
|
|
2666
2713
|
return undefined;
|
|
2667
2714
|
}
|
|
2715
|
+
#fileRegionAt(row) {
|
|
2716
|
+
const document = this.#renderer.documentRowAt(row);
|
|
2717
|
+
const frame = this.#fileActionFrame;
|
|
2718
|
+
const source = frame?.documentRows;
|
|
2719
|
+
const region = document === undefined ? undefined : frame?.transcript?.fileRegions?.find(region => document >= region.start && document < region.end);
|
|
2720
|
+
const expected = document === undefined || source === undefined || source === null ? undefined
|
|
2721
|
+
: frame?.lines[source.frameStart + document - source.documentStart];
|
|
2722
|
+
const actual = this.#renderer.viewport()[row];
|
|
2723
|
+
// Committed native history can differ from the live document after a reflow.
|
|
2724
|
+
return expected !== undefined && actual !== undefined
|
|
2725
|
+
&& stripAnsi(sanitizeDisplayLine(expected)).trimEnd() === stripAnsi(actual).trimEnd() ? region : undefined;
|
|
2726
|
+
}
|
|
2668
2727
|
#handleMouse(event) {
|
|
2669
2728
|
if (!this.#mouseTracking || this.#paste || this.#pasteInFlight > 0)
|
|
2670
2729
|
return;
|
|
@@ -2741,6 +2800,7 @@ export class LocalTui {
|
|
|
2741
2800
|
const target = this.#mouseActionAt(event.row, event.column);
|
|
2742
2801
|
if (event.action === 'release') {
|
|
2743
2802
|
this.#mouseActionPress = undefined;
|
|
2803
|
+
this.#workspacePress = undefined;
|
|
2744
2804
|
if (event.button === 'left' && !event.shift && target?.key === pressedAction.key && target.row === pressedAction.row && target.column === pressedAction.column) {
|
|
2745
2805
|
if (target.action === 'copy')
|
|
2746
2806
|
void this.#copySelection(true);
|
|
@@ -2771,21 +2831,14 @@ export class LocalTui {
|
|
|
2771
2831
|
}
|
|
2772
2832
|
const inside = (target) => event.row === target.row && event.column >= target.column && event.column < target.column + target.width;
|
|
2773
2833
|
if (event.button === 'right') {
|
|
2834
|
+
this.#workspacePress = undefined;
|
|
2774
2835
|
this.#disclosurePress = undefined;
|
|
2775
2836
|
if (event.action === 'press') {
|
|
2776
2837
|
if (this.#selection.active)
|
|
2777
2838
|
void this.#copySelection(true);
|
|
2778
2839
|
else {
|
|
2779
|
-
const
|
|
2780
|
-
|
|
2781
|
-
const source = frame?.documentRows;
|
|
2782
|
-
const region = document === undefined ? undefined : frame?.transcript?.fileRegions?.find(region => document >= region.start && document < region.end);
|
|
2783
|
-
const expected = document === undefined || source === undefined || source === null ? undefined
|
|
2784
|
-
: frame?.lines[source.frameStart + document - source.documentStart];
|
|
2785
|
-
const actual = this.#renderer.viewport()[event.row];
|
|
2786
|
-
// Native-history snapshots may differ from the current document. Do
|
|
2787
|
-
// not reinterpret their old text as another file after a reflow.
|
|
2788
|
-
if (region !== undefined && expected !== undefined && actual !== undefined && stripAnsi(sanitizeDisplayLine(expected)).trimEnd() === stripAnsi(actual).trimEnd()) {
|
|
2840
|
+
const region = this.#fileRegionAt(event.row);
|
|
2841
|
+
if (region !== undefined) {
|
|
2789
2842
|
const block = this.#state.blocks[region.block];
|
|
2790
2843
|
const action = block === undefined ? undefined : blockFileAction(block);
|
|
2791
2844
|
if (action !== undefined)
|
|
@@ -2796,6 +2849,10 @@ export class LocalTui {
|
|
|
2796
2849
|
return;
|
|
2797
2850
|
}
|
|
2798
2851
|
if (event.action === 'press') {
|
|
2852
|
+
const region = !event.shift && this.#workspaceReview !== undefined ? this.#fileRegionAt(event.row) : undefined;
|
|
2853
|
+
const source = region === undefined ? undefined : this.#state.blocks[region.block];
|
|
2854
|
+
this.#workspacePress = source?.kind === 'workspace' && region !== undefined
|
|
2855
|
+
? { row: event.row, column: event.column, block: region.block, source, ...(region.file === undefined ? {} : { file: region.file }) } : undefined;
|
|
2799
2856
|
const disclosure = event.shift ? undefined : this.#disclosureAt(event.row, event.column);
|
|
2800
2857
|
this.#disclosurePress = disclosure === undefined ? undefined : { target: disclosure, row: event.row, column: event.column };
|
|
2801
2858
|
const target = this.#jumpToLatest;
|
|
@@ -2817,6 +2874,9 @@ export class LocalTui {
|
|
|
2817
2874
|
}
|
|
2818
2875
|
}
|
|
2819
2876
|
else if (event.action === 'drag') {
|
|
2877
|
+
const pressed = this.#workspacePress;
|
|
2878
|
+
if (pressed !== undefined && (event.shift || event.row !== pressed.row || Math.abs(event.column - pressed.column) > 1))
|
|
2879
|
+
this.#workspacePress = undefined;
|
|
2820
2880
|
// Motion confined to the empty gutter is click jitter. Once it leaves,
|
|
2821
2881
|
// selection owns the gesture even if the pointer returns to the arrow.
|
|
2822
2882
|
if (event.shift || this.#pressedDisclosureAt(event.row, event.column) === undefined) {
|
|
@@ -2825,6 +2885,15 @@ export class LocalTui {
|
|
|
2825
2885
|
}
|
|
2826
2886
|
}
|
|
2827
2887
|
else {
|
|
2888
|
+
const pressed = this.#workspacePress;
|
|
2889
|
+
this.#workspacePress = undefined;
|
|
2890
|
+
const region = pressed === undefined ? undefined : this.#fileRegionAt(event.row);
|
|
2891
|
+
if (!event.shift && pressed !== undefined && event.row === pressed.row && Math.abs(event.column - pressed.column) <= 1
|
|
2892
|
+
&& region?.block === pressed.block && region.file === pressed.file && this.#state.blocks[pressed.block] === pressed.source) {
|
|
2893
|
+
this.#selection.clear();
|
|
2894
|
+
this.#openWorkspaceReview(pressed.source, pressed.file);
|
|
2895
|
+
return;
|
|
2896
|
+
}
|
|
2828
2897
|
const target = this.#pressedDisclosureAt(event.row, event.column);
|
|
2829
2898
|
this.#disclosurePress = undefined;
|
|
2830
2899
|
if (!event.shift && target !== undefined) {
|
|
@@ -3017,6 +3086,20 @@ export class LocalTui {
|
|
|
3017
3086
|
this.#fileReviewAbort = undefined;
|
|
3018
3087
|
}
|
|
3019
3088
|
}
|
|
3089
|
+
#openWorkspaceReview(block, file) {
|
|
3090
|
+
const handler = this.#workspaceReview;
|
|
3091
|
+
const sessionId = this.#inspected?.id ?? this.#sessionId;
|
|
3092
|
+
if (handler === undefined || sessionId === undefined || block.kind !== 'workspace' || !this.#tty || this.#disposed
|
|
3093
|
+
|| this.#prompt !== null || this.#fileReviewAbort !== undefined)
|
|
3094
|
+
return;
|
|
3095
|
+
const abort = new AbortController();
|
|
3096
|
+
this.#fileReviewAbort = abort;
|
|
3097
|
+
void handler({ sessionId, turn: block.turn, ...(file === undefined ? {} : { file }), signal: abort.signal })
|
|
3098
|
+
.catch(error => { if (!abort.signal.aborted && !this.#disposed)
|
|
3099
|
+
this.notice(error instanceof Error ? error.message : String(error), { level: 'error' }); })
|
|
3100
|
+
.finally(() => { if (this.#fileReviewAbort === abort)
|
|
3101
|
+
this.#fileReviewAbort = undefined; });
|
|
3102
|
+
}
|
|
3020
3103
|
#openFileAction(action, initial) {
|
|
3021
3104
|
if (!this.#tty || this.#disposed || this.#prompt !== null || this.#fileReviewAbort !== undefined)
|
|
3022
3105
|
return;
|
|
@@ -3068,6 +3151,7 @@ export class LocalTui {
|
|
|
3068
3151
|
this.#jumpPress = undefined;
|
|
3069
3152
|
this.#disclosurePress = undefined;
|
|
3070
3153
|
this.#mouseActionPress = undefined;
|
|
3154
|
+
this.#workspacePress = undefined;
|
|
3071
3155
|
if (this.#keyTest !== undefined && this.#prompt?.request.signal === this.#keyTest.signal
|
|
3072
3156
|
&& (event.type === 'text' || event.type === 'paste-start' || event.type === 'paste-end' || event.type === 'key' && !['escape', 'ctrl+c'].includes(event.id))) {
|
|
3073
3157
|
this.#keyTest.observe(event);
|
|
@@ -3898,6 +3982,7 @@ export class LocalTui {
|
|
|
3898
3982
|
const previous = options.persist ? this.prefs() : undefined;
|
|
3899
3983
|
const version = this.#prefsVersion;
|
|
3900
3984
|
const previousMotion = this.#motion;
|
|
3985
|
+
this.#workspacePress = undefined;
|
|
3901
3986
|
this.#uiLanguage = prefs.uiLanguage ?? 'auto';
|
|
3902
3987
|
if (this.#prompt !== null)
|
|
3903
3988
|
this.#prompt = { ...this.#prompt, request: localizePrompt(this.#prompt.sourceRequest, resolveUiLanguage(this.#uiLanguage)) };
|
|
@@ -3916,6 +4001,7 @@ export class LocalTui {
|
|
|
3916
4001
|
this.#mathMode = prefs.mathMode ?? 'auto';
|
|
3917
4002
|
this.#mermaidMode = prefs.mermaidMode ?? 'auto';
|
|
3918
4003
|
this.#hideThinking = prefs.hideThinking !== false;
|
|
4004
|
+
this.#showFileChanges = prefs.showFileChanges !== false;
|
|
3919
4005
|
this.#mouseInteraction = prefs.mouseInteraction ?? 'auto';
|
|
3920
4006
|
this.#checkUpdates = prefs.checkUpdates ?? true;
|
|
3921
4007
|
this.#startupChangelog = prefs.startupChangelog ?? 'summary';
|
|
@@ -4899,17 +4985,17 @@ export class LocalTui {
|
|
|
4899
4985
|
}
|
|
4900
4986
|
#settingsActions() {
|
|
4901
4987
|
const runtimeActions = [
|
|
4902
|
-
{ id: 'command:model', behavior: 'Session + Profile · Choose scope in Model', group: 'Models', label: 'Model and reasoning', description: '
|
|
4903
|
-
{ id: 'command:permission', behavior: 'Current session · Applies now', group: 'General', label: 'Current session access', description: 'Changes only this session. Default access controls future sessions.', value: this.#sessionControls?.permission ?? 'Choose', values: [], action: 'permission' },
|
|
4904
|
-
{ id: 'command:agent', behavior: 'Current session · Before the first prompt', group: 'Agent presets', label: 'Current session preset', description: 'Choose before the first prompt; does not change the new-session default.', value: this.#sessionControls?.agentPreset === undefined ? 'Choose' : formatAgentPreset(this.#sessionControls.agentPreset), values: [], action: 'agent' },
|
|
4905
|
-
{ id: 'command:login', behavior: '
|
|
4906
|
-
{ id: 'command:logout', behavior: '
|
|
4907
|
-
{ id: 'command:plugins', group: 'Plugins', label: 'Manage plugins', description: 'Inspect installed entries, enable bundles, discover plugins or start Creator.', value: 'Open', values: [], action: 'plugins' },
|
|
4988
|
+
{ id: 'command:model', behavior: 'Session + Profile · Choose scope in Model', group: 'Models', subgroup: 'Model selection', label: 'Model and reasoning', description: 'Choose the current model and reasoning effort. Save as the default or use for this session.', value: [this.#model, this.#reasoningEffort].filter(Boolean).join(' · '), values: [], action: 'model' },
|
|
4989
|
+
{ id: 'command:permission', behavior: 'Current session · Applies now', group: 'General', subgroup: 'Session controls', label: 'Current session access', description: 'Changes only this session. Default access controls future sessions.', value: this.#sessionControls?.permission ?? 'Choose', values: [], action: 'permission' },
|
|
4990
|
+
{ id: 'command:agent', behavior: 'Current session · Before the first prompt', group: 'Agent presets', subgroup: 'Current session', label: 'Current session preset', description: 'Choose before the first prompt; does not change the new-session default.', value: this.#sessionControls?.agentPreset === undefined ? 'Choose' : formatAgentPreset(this.#sessionControls.agentPreset), values: [], action: 'agent' },
|
|
4991
|
+
{ id: 'command:login', behavior: 'Accounts and API keys', group: 'Models', subgroup: 'Accounts and API keys', label: 'Sign in / add API key', description: 'Sign in to a provider account or save an API key.', keywords: ['Provider credentials', 'login', 'API key', 'OAuth'], value: 'Choose provider', values: [], action: 'login' },
|
|
4992
|
+
{ id: 'command:logout', behavior: 'Accounts and API keys', group: 'Models', subgroup: 'Accounts and API keys', label: 'Sign out / remove key', description: 'Choose a provider or account to sign out or remove locally saved credentials.', keywords: ['logout', 'credentials'], value: 'Choose provider', values: [], action: 'logout' },
|
|
4993
|
+
{ id: 'command:plugins', group: 'Plugins', subgroup: 'Plugin management', label: 'Manage plugins', description: 'Inspect installed entries, enable bundles, discover plugins or start Creator.', value: 'Open', values: [], action: 'plugins' },
|
|
4908
4994
|
].filter(item => this.#runtimeCommands.some(command => command.name === item.action));
|
|
4909
4995
|
const customBindings = Object.entries(this.#keybindings).filter(([key, action]) => DEFAULT_KEYBINDINGS[key] !== action).length;
|
|
4910
4996
|
return [
|
|
4911
4997
|
...runtimeActions,
|
|
4912
|
-
...(this.#goalHandler === undefined ? [] : [{ id: 'action:goal', behavior: 'Current session · Applies now', group: 'General', label: 'Current goal', description: 'Edit, pause, resume or clear this session’s goal.', value: 'Open', values: [], action: 'manage-goal' }]),
|
|
4998
|
+
...(this.#goalHandler === undefined ? [] : [{ id: 'action:goal', behavior: 'Current session · Applies now', group: 'General', subgroup: 'Session controls', label: 'Current goal', description: 'Edit, pause, resume or clear this session’s goal.', value: 'Open', values: [], action: 'manage-goal' }]),
|
|
4913
4999
|
...(this.#keybindingsPath === undefined ? [] : [{
|
|
4914
5000
|
id: 'action:keybindings',
|
|
4915
5001
|
label: 'Keybindings',
|
|
@@ -5828,6 +5914,7 @@ export class LocalTui {
|
|
|
5828
5914
|
toolsExpanded: this.#toolsExpanded,
|
|
5829
5915
|
expandedOutputs: this.#expandedOutputs,
|
|
5830
5916
|
hideThinking: true,
|
|
5917
|
+
showFileChanges: this.#showFileChanges,
|
|
5831
5918
|
expandedTools: this.#detailedToolIds(),
|
|
5832
5919
|
expandedReasoning: this.#visibleReasoning(),
|
|
5833
5920
|
...(this.#openedGroups === undefined ? {} : { openedGroups: this.#openedGroups }),
|
|
@@ -5938,6 +6025,7 @@ export function apply(ctx, config) {
|
|
|
5938
6025
|
motion: config.motion.get(),
|
|
5939
6026
|
mathMode: config.mathMode.get(),
|
|
5940
6027
|
mermaidMode: config.mermaidMode.get(),
|
|
6028
|
+
showFileChanges: config.showFileChanges.get(),
|
|
5941
6029
|
editor: config.editor.get(),
|
|
5942
6030
|
terminalTitle: config.terminalTitle.get(),
|
|
5943
6031
|
terminalState: config.terminalState.get(),
|