@agi-fans/dsh-tui 0.15.0 → 0.16.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 +30 -1
- package/lib/chrome/diff-render.js +12 -0
- package/lib/chrome/diff-render.js.map +1 -1
- package/lib/chrome/main-screen-renderer.js +21 -5
- package/lib/chrome/main-screen-renderer.js.map +1 -1
- package/lib/chrome/markdown.js +5 -2
- package/lib/chrome/markdown.js.map +1 -1
- package/lib/chrome/renderer.d.ts +8 -0
- package/lib/chrome/renderer.js.map +1 -1
- package/lib/chrome/status-line.d.ts +1 -1
- package/lib/chrome/status-line.js +38 -9
- package/lib/chrome/status-line.js.map +1 -1
- package/lib/chrome/theme.d.ts +9 -2
- package/lib/chrome/theme.js +60 -12
- package/lib/chrome/theme.js.map +1 -1
- package/lib/chrome/tool-renderers.d.ts +2 -0
- package/lib/chrome/tool-renderers.js +102 -1
- package/lib/chrome/tool-renderers.js.map +1 -1
- package/lib/chrome/welcome-tips.js +1 -0
- package/lib/chrome/welcome-tips.js.map +1 -1
- package/lib/chrome/width.d.ts +19 -1
- package/lib/chrome/width.js +135 -41
- package/lib/chrome/width.js.map +1 -1
- package/lib/commands/session.js +3 -0
- package/lib/commands/session.js.map +1 -1
- package/lib/definition.d.ts +13 -1
- package/lib/runtime/provider-local.d.ts +6 -4
- package/lib/runtime/provider-local.js +75 -9
- package/lib/runtime/provider-local.js.map +1 -1
- package/lib/session/interaction-adapter.d.ts +10 -0
- package/lib/session/interaction-adapter.js +12 -1
- package/lib/session/interaction-adapter.js.map +1 -1
- package/lib/session/session-controller.js +7 -4
- package/lib/session/session-controller.js.map +1 -1
- package/lib/session/subagent-roster.d.ts +2 -9
- package/lib/session/subagent-roster.js +26 -31
- package/lib/session/subagent-roster.js.map +1 -1
- package/lib/views/agent-hub.d.ts +3 -0
- package/lib/views/agent-hub.js +40 -4
- package/lib/views/agent-hub.js.map +1 -1
- package/lib/views/copy-selector.d.ts +3 -0
- package/lib/views/copy-selector.js +26 -6
- package/lib/views/copy-selector.js.map +1 -1
- package/lib/views/event-views.d.ts +16 -0
- package/lib/views/event-views.js +57 -12
- package/lib/views/event-views.js.map +1 -1
- package/lib/views/history-search.d.ts +3 -0
- package/lib/views/history-search.js +40 -4
- package/lib/views/history-search.js.map +1 -1
- package/lib/views/hotkey-format.d.ts +39 -0
- package/lib/views/hotkey-format.js +42 -0
- package/lib/views/hotkey-format.js.map +1 -0
- package/lib/views/hotkeys.d.ts +3 -0
- package/lib/views/hotkeys.js +33 -3
- package/lib/views/hotkeys.js.map +1 -1
- package/lib/views/prompt-selector.d.ts +3 -0
- package/lib/views/prompt-selector.js +46 -7
- package/lib/views/prompt-selector.js.map +1 -1
- package/lib/views/settings-list.d.ts +3 -0
- package/lib/views/settings-list.js +35 -5
- package/lib/views/settings-list.js.map +1 -1
- package/lib/views/streaming-reveal.js +56 -17
- package/lib/views/streaming-reveal.js.map +1 -1
- package/lib/views/trajectory.d.ts +15 -5
- package/lib/views/trajectory.js +64 -7
- package/lib/views/trajectory.js.map +1 -1
- package/lib/views/transcript-search.d.ts +3 -0
- package/lib/views/transcript-search.js +24 -3
- package/lib/views/transcript-search.js.map +1 -1
- package/package.json +33 -33
|
@@ -33,7 +33,8 @@ import { applyTranscriptSearchEvent, createTranscriptSearch, searchBlockIndexes,
|
|
|
33
33
|
import { nextRevealStep, revealStreamingAssistant, streamingAssistantKey, streamingAssistantUnits, } from "../views/streaming-reveal.js";
|
|
34
34
|
import { flushPending, parseKeys } from "../input/keys.js";
|
|
35
35
|
import { MainScreenRenderer } from "../chrome/main-screen-renderer.js";
|
|
36
|
-
import { createTheme, detectTrueColor, parseThemeName } from "../chrome/theme.js";
|
|
36
|
+
import { colorDisabledByEnv, createTheme, detectTrueColor, parseThemeName } from "../chrome/theme.js";
|
|
37
|
+
import { renderTool } from "../chrome/tool-renderers.js";
|
|
37
38
|
import { TUI_SETTINGS_NAMESPACE, TuiSettingsSchema } from "../session/tui-settings.js";
|
|
38
39
|
import { defaultStatusBarConfig, resolveStatusBarConfig } from "../chrome/status-config.js";
|
|
39
40
|
import { HistoryStore } from "../views/history-store.js";
|
|
@@ -81,6 +82,18 @@ function detectTerminalProfile() {
|
|
|
81
82
|
}
|
|
82
83
|
return process.platform === 'win32' ? 'conpty' : 'direct';
|
|
83
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Decide whether SGR is emitted. An explicit preference — plugin config or a
|
|
87
|
+
* value the user picked in `/settings` — always wins, so a non-empty `NO_COLOR`
|
|
88
|
+
* can never block someone who asked for color. Without a preference, a
|
|
89
|
+
* non-empty `NO_COLOR` or `FORCE_COLOR=0` suppresses color and the output
|
|
90
|
+
* stream's tty-ness decides.
|
|
91
|
+
*/
|
|
92
|
+
function resolveColors(preference, isTty) {
|
|
93
|
+
if (preference !== undefined)
|
|
94
|
+
return preference;
|
|
95
|
+
return isTty && !colorDisabledByEnv();
|
|
96
|
+
}
|
|
84
97
|
export class LocalTui {
|
|
85
98
|
#deferInitialRender = false;
|
|
86
99
|
#terminalProfile;
|
|
@@ -187,7 +200,12 @@ export class LocalTui {
|
|
|
187
200
|
#subagentLauncherFocused = false;
|
|
188
201
|
#inspected;
|
|
189
202
|
#promptDocument;
|
|
190
|
-
|
|
203
|
+
/**
|
|
204
|
+
* 24-bit switch for the current color preference, re-derived whenever that
|
|
205
|
+
* preference changes so a session that starts colorless can still enable
|
|
206
|
+
* hexadecimal palettes without a restart.
|
|
207
|
+
*/
|
|
208
|
+
#trueColor = false;
|
|
191
209
|
#copy;
|
|
192
210
|
#readClipboard;
|
|
193
211
|
#readClipboardImage;
|
|
@@ -212,7 +230,8 @@ export class LocalTui {
|
|
|
212
230
|
/**
|
|
213
231
|
* @param term - terminal surface (injectable for tests).
|
|
214
232
|
* @param model - model label for the status line.
|
|
215
|
-
* @param colors - SGR styling switch
|
|
233
|
+
* @param colors - SGR styling switch; `undefined` derives one from the
|
|
234
|
+
* output stream's tty-ness and the environment.
|
|
216
235
|
* @param themeName - shipped palette.
|
|
217
236
|
* @param copy - clipboard writer (defaults to the platform tool).
|
|
218
237
|
* @param paths - cwd/home/listing used by `@` and path autocomplete.
|
|
@@ -220,7 +239,7 @@ export class LocalTui {
|
|
|
220
239
|
constructor(term, model, colors, themeName = 'dark', copy = copyToClipboard, paths = {}) {
|
|
221
240
|
this.#term = term;
|
|
222
241
|
this.#model = model;
|
|
223
|
-
this.#colors = colors;
|
|
242
|
+
this.#colors = resolveColors(colors, term.output.isTTY === true);
|
|
224
243
|
this.#themeName = themeName;
|
|
225
244
|
this.#copy = copy;
|
|
226
245
|
this.#readClipboard = paths.readClipboard ?? readFromClipboard;
|
|
@@ -245,7 +264,7 @@ export class LocalTui {
|
|
|
245
264
|
this.#terminalProfile = paths.terminalProfile ?? detectTerminalProfile();
|
|
246
265
|
this.#resizeDebounceMs = Math.max(0, paths.resizeDebounceMs ?? 120);
|
|
247
266
|
this.#streamRenderMs = Math.max(0, paths.streamRenderMs ?? 8);
|
|
248
|
-
this.#
|
|
267
|
+
this.#syncTrueColor();
|
|
249
268
|
this.#tty = term.input.isTTY === true;
|
|
250
269
|
this.#pwd = shortenPath(project.root);
|
|
251
270
|
this.#branch = project.gitLabel;
|
|
@@ -354,6 +373,13 @@ export class LocalTui {
|
|
|
354
373
|
this.#render();
|
|
355
374
|
}
|
|
356
375
|
setSubagents(roster) {
|
|
376
|
+
const previous = this.#subagents?.agents ?? [];
|
|
377
|
+
const incoming = roster?.agents ?? [];
|
|
378
|
+
const statusChanged = previous.length !== incoming.length || incoming.some((agent, index) => {
|
|
379
|
+
const before = previous[index];
|
|
380
|
+
return before === undefined || before.id !== agent.id || before.label !== agent.label
|
|
381
|
+
|| before.phase !== agent.phase || before.depth !== agent.depth || before.mode !== agent.mode;
|
|
382
|
+
});
|
|
357
383
|
this.#subagents = roster === undefined
|
|
358
384
|
? undefined
|
|
359
385
|
: { agents: roster.agents.map(agent => ({ ...agent, activity: [...agent.activity] })) };
|
|
@@ -378,11 +404,17 @@ export class LocalTui {
|
|
|
378
404
|
};
|
|
379
405
|
}
|
|
380
406
|
}
|
|
407
|
+
if (!statusChanged && this.#agentHub === null)
|
|
408
|
+
return;
|
|
381
409
|
this.#syncTick();
|
|
382
410
|
if (this.#tty)
|
|
383
|
-
this.#
|
|
411
|
+
this.#scheduleStreamRender();
|
|
384
412
|
}
|
|
385
413
|
setInspectedSubagent(inspected) {
|
|
414
|
+
if (this.#inspected?.id === inspected?.id && this.#inspected?.label === inspected?.label
|
|
415
|
+
&& this.#inspected?.phase === inspected?.phase && this.#inspected?.mode === inspected?.mode
|
|
416
|
+
&& this.#inspected?.writable === inspected?.writable)
|
|
417
|
+
return;
|
|
386
418
|
this.#inspected = inspected === undefined ? undefined : { ...inspected };
|
|
387
419
|
if (inspected !== undefined) {
|
|
388
420
|
this.#inspectEscapeFenceUntil = 0;
|
|
@@ -433,6 +465,31 @@ export class LocalTui {
|
|
|
433
465
|
setImageValidator(validate) {
|
|
434
466
|
this.#validateImageDraft = validate;
|
|
435
467
|
}
|
|
468
|
+
toolCallContext(callId) {
|
|
469
|
+
const block = this.#state.blocks.findLast(candidate => candidate.kind === 'tool' && String(candidate.callId) === callId);
|
|
470
|
+
if (block?.kind !== 'tool')
|
|
471
|
+
return undefined;
|
|
472
|
+
// Reuse the card renderer so a decision explains the call the same way the
|
|
473
|
+
// transcript already does. The approval prompt renders its detail on one
|
|
474
|
+
// line, so the parts are joined here rather than handed over as rows.
|
|
475
|
+
const view = renderTool({
|
|
476
|
+
name: block.name,
|
|
477
|
+
arguments: block.args,
|
|
478
|
+
output: block.output,
|
|
479
|
+
status: block.status,
|
|
480
|
+
expanded: false,
|
|
481
|
+
...(block.presentation === undefined ? {} : { presentation: block.presentation }),
|
|
482
|
+
});
|
|
483
|
+
const detail = view.summary === undefined || view.summary === ''
|
|
484
|
+
? view.input.join(' ').replace(/\s+/gu, ' ').trim()
|
|
485
|
+
: '';
|
|
486
|
+
// A card with a summary already says what the call is. Without one the raw
|
|
487
|
+
// argument text is all there is, and its pretty-printed form would reduce to
|
|
488
|
+
// a lone brace on a single row, so the whole body is folded into one line.
|
|
489
|
+
return [view.title, view.summary, detail === '' ? undefined : detail]
|
|
490
|
+
.filter((part) => part !== undefined && part !== '')
|
|
491
|
+
.join(' · ');
|
|
492
|
+
}
|
|
436
493
|
notice(text, options = {}) {
|
|
437
494
|
const block = {
|
|
438
495
|
kind: 'notice',
|
|
@@ -538,11 +595,19 @@ export class LocalTui {
|
|
|
538
595
|
this.#writtenWindowTitle = title;
|
|
539
596
|
this.#term.output.write(`\x1b]2;${title}\x07`);
|
|
540
597
|
}
|
|
598
|
+
/**
|
|
599
|
+
* Re-derive the 24-bit switch from the active color preference. Every path
|
|
600
|
+
* that changes `#colors` calls this so `/settings` takes effect immediately.
|
|
601
|
+
*/
|
|
602
|
+
#syncTrueColor() {
|
|
603
|
+
this.#trueColor = this.#colors && detectTrueColor();
|
|
604
|
+
}
|
|
541
605
|
/** Apply prefs loaded from the settings document (does not persist). */
|
|
542
606
|
applyStoredPrefs(prefs) {
|
|
543
607
|
const previousMotion = this.#motion;
|
|
544
608
|
this.#themeName = prefs.theme;
|
|
545
609
|
this.#colors = prefs.colors;
|
|
610
|
+
this.#syncTrueColor();
|
|
546
611
|
this.#motion = prefs.motion ?? 'full';
|
|
547
612
|
this.#terminalProgress = prefs.terminalProgress ?? false;
|
|
548
613
|
this.#expandTools = prefs.expandTools;
|
|
@@ -1745,6 +1810,7 @@ export class LocalTui {
|
|
|
1745
1810
|
const expandChanged = prefs.expandTools !== this.#expandTools;
|
|
1746
1811
|
this.#themeName = prefs.theme;
|
|
1747
1812
|
this.#colors = prefs.colors;
|
|
1813
|
+
this.#syncTrueColor();
|
|
1748
1814
|
const previousMotion = this.#motion;
|
|
1749
1815
|
this.#motion = prefs.motion ?? 'full';
|
|
1750
1816
|
this.#terminalProgress = prefs.terminalProgress ?? false;
|
|
@@ -2315,7 +2381,7 @@ export class LocalTui {
|
|
|
2315
2381
|
formatHelpText(this.#commands()),
|
|
2316
2382
|
'',
|
|
2317
2383
|
full
|
|
2318
|
-
? `**Keyboard Shortcuts · ${hotkeyCount(this.#keybindings)}
|
|
2384
|
+
? `**Keyboard Shortcuts · ${hotkeyCount(this.#keybindings)} shortcuts**`
|
|
2319
2385
|
: '**Essential Shortcuts**',
|
|
2320
2386
|
'',
|
|
2321
2387
|
full
|
|
@@ -2617,7 +2683,7 @@ export function apply(ctx, config) {
|
|
|
2617
2683
|
return () => { process.stdout.removeListener('resize', listener); };
|
|
2618
2684
|
},
|
|
2619
2685
|
};
|
|
2620
|
-
const tui = new LocalTui(term, config.model, config.colors
|
|
2686
|
+
const tui = new LocalTui(term, config.model, config.colors, parseThemeName(config.theme), copyToClipboard, {
|
|
2621
2687
|
deferInitialRender: true,
|
|
2622
2688
|
terminalProfile,
|
|
2623
2689
|
alternateScreenOverlays: terminalProfile === 'direct',
|
|
@@ -2627,7 +2693,7 @@ export function apply(ctx, config) {
|
|
|
2627
2693
|
ctx.provide(TUI_SERVICE, tui);
|
|
2628
2694
|
ctx.effect(() => () => { tui.dispose(); });
|
|
2629
2695
|
ctx.inject(['settings'], (settingsCtx) => {
|
|
2630
|
-
const scope = settingsCtx.settings.register(TUI_SETTINGS_NAMESPACE, TuiSettingsSchema, { base: { theme: parseThemeName(config.theme), colors: config.colors
|
|
2696
|
+
const scope = settingsCtx.settings.register(TUI_SETTINGS_NAMESPACE, TuiSettingsSchema, { base: { theme: parseThemeName(config.theme), colors: resolveColors(config.colors, term.output.isTTY === true), expandTools: false } });
|
|
2631
2697
|
tui.applyStoredPrefs(scope.get());
|
|
2632
2698
|
tui.setPrefsPersist((prefs) => { void scope.update(prefs); });
|
|
2633
2699
|
scope.watch((next) => { tui.applyStoredPrefs(next); });
|