@agi-fans/dsh-tui 0.9.0 → 0.10.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 +21 -1
- package/lib/chrome/welcome-tips.js +1 -0
- package/lib/chrome/welcome-tips.js.map +1 -1
- package/lib/chrome/width.js +36 -0
- package/lib/chrome/width.js.map +1 -1
- package/lib/commands/export.js +11 -6
- package/lib/commands/export.js.map +1 -1
- package/lib/commands/model.js +111 -4
- package/lib/commands/model.js.map +1 -1
- package/lib/commands/session.js +79 -36
- package/lib/commands/session.js.map +1 -1
- package/lib/commands/trajectory.d.ts +5 -0
- package/lib/commands/trajectory.js +20 -0
- package/lib/commands/trajectory.js.map +1 -0
- package/lib/definition.d.ts +12 -0
- package/lib/input/keybindings-config.d.ts +1 -1
- package/lib/input/keybindings-config.js +7 -1
- package/lib/input/keybindings-config.js.map +1 -1
- package/lib/runtime/provider-local.d.ts +1 -0
- package/lib/runtime/provider-local.js +110 -19
- package/lib/runtime/provider-local.js.map +1 -1
- package/lib/runtime/terminal-notifications.d.ts +24 -0
- package/lib/runtime/terminal-notifications.js +61 -0
- package/lib/runtime/terminal-notifications.js.map +1 -0
- package/lib/session/context-diagnostics.d.ts +8 -0
- package/lib/session/context-diagnostics.js +50 -0
- package/lib/session/context-diagnostics.js.map +1 -0
- package/lib/session/model-favorites.d.ts +11 -0
- package/lib/session/model-favorites.js +74 -0
- package/lib/session/model-favorites.js.map +1 -0
- package/lib/session/session-controller.d.ts +7 -1
- package/lib/session/session-controller.js +39 -6
- package/lib/session/session-controller.js.map +1 -1
- package/lib/session/session-library.d.ts +8 -0
- package/lib/session/session-library.js +43 -0
- package/lib/session/session-library.js.map +1 -0
- package/lib/session/subagent-roster.js +11 -1
- package/lib/session/subagent-roster.js.map +1 -1
- package/lib/session/tui-settings.d.ts +2 -0
- package/lib/session/tui-settings.js +2 -0
- package/lib/session/tui-settings.js.map +1 -1
- package/lib/views/agent-hub.d.ts +29 -0
- package/lib/views/agent-hub.js +165 -0
- package/lib/views/agent-hub.js.map +1 -0
- package/lib/views/event-views.d.ts +6 -0
- package/lib/views/event-views.js +18 -0
- package/lib/views/event-views.js.map +1 -1
- package/lib/views/hotkeys.js +3 -0
- package/lib/views/hotkeys.js.map +1 -1
- package/lib/views/prompt-selector.js +2 -1
- package/lib/views/prompt-selector.js.map +1 -1
- package/lib/views/settings-list.d.ts +2 -0
- package/lib/views/settings-list.js +21 -1
- package/lib/views/settings-list.js.map +1 -1
- package/lib/views/trajectory.d.ts +64 -0
- package/lib/views/trajectory.js +550 -0
- package/lib/views/trajectory.js.map +1 -0
- package/lib/views/transcript-export.d.ts +2 -0
- package/lib/views/transcript-export.js +34 -0
- package/lib/views/transcript-export.js.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Full-screen session Trajectory command registered through dsh-commands. */
|
|
2
|
+
import { registerCommands } from "./registration.js";
|
|
3
|
+
export const name = 'omdsh-command-trajectory';
|
|
4
|
+
export const inject = ['commands', 'tui'];
|
|
5
|
+
function openTrajectory(ctx, invocation) {
|
|
6
|
+
if (invocation.rawInput.trim() !== '')
|
|
7
|
+
return { kind: 'error', text: 'Usage: /trajectory' };
|
|
8
|
+
if (!ctx.tui.openTrajectory(invocation.agent.session.events)) {
|
|
9
|
+
return { kind: 'error', text: 'Trajectory requires an interactive terminal.' };
|
|
10
|
+
}
|
|
11
|
+
return { kind: 'success' };
|
|
12
|
+
}
|
|
13
|
+
export function apply(ctx) {
|
|
14
|
+
registerCommands(ctx, [{
|
|
15
|
+
name: 'trajectory',
|
|
16
|
+
description: 'Inspect the session event trajectory',
|
|
17
|
+
handler: invocation => openTrajectory(ctx, invocation),
|
|
18
|
+
}], 'omdsh trajectory command');
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=trajectory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trajectory.js","sourceRoot":"","sources":["../../src/commands/trajectory.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAI9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEpD,MAAM,CAAC,MAAM,IAAI,GAAG,0BAA0B,CAAA;AAC9C,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAA;AAEzC,SAAS,cAAc,CAAC,GAAY,EAAE,UAA6B;IACjE,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAA;IAC3F,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,8CAA8C,EAAE,CAAA;IAChF,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAA;AAC5B,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,GAAY;IAChC,gBAAgB,CAAC,GAAG,EAAE,CAAC;YACrB,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,sCAAsC;YACnD,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,UAAU,CAAC;SACvD,CAAC,EAAE,0BAA0B,CAAC,CAAA;AACjC,CAAC"}
|
package/lib/definition.d.ts
CHANGED
|
@@ -48,6 +48,13 @@ export interface TuiPrompt {
|
|
|
48
48
|
tone: 'success' | 'warning' | 'error' | 'muted';
|
|
49
49
|
};
|
|
50
50
|
}[];
|
|
51
|
+
/** Optional single-key actions applied to the active option while the filter is empty. */
|
|
52
|
+
actions?: readonly {
|
|
53
|
+
key: string;
|
|
54
|
+
label: string;
|
|
55
|
+
/** Prefix returned before the selected option value. */
|
|
56
|
+
valuePrefix: string;
|
|
57
|
+
}[];
|
|
51
58
|
multiSelect?: boolean;
|
|
52
59
|
allowCustom?: boolean;
|
|
53
60
|
/** Mask custom input while retaining the real value only in the prompt editor. */
|
|
@@ -110,6 +117,9 @@ export interface TuiSubagentView {
|
|
|
110
117
|
readonly mode?: 'one-shot' | 'continuable';
|
|
111
118
|
readonly phase: TuiSubagentPhase;
|
|
112
119
|
readonly activity: readonly TuiSubagentActivity[];
|
|
120
|
+
/** First and latest durable event timestamps for elapsed-time presentation. */
|
|
121
|
+
readonly startedAt?: number;
|
|
122
|
+
readonly updatedAt?: number;
|
|
113
123
|
}
|
|
114
124
|
/** Live descendant roster for the active root session. */
|
|
115
125
|
export interface TuiSubagentRoster {
|
|
@@ -196,6 +206,8 @@ export interface TuiService {
|
|
|
196
206
|
}[]): void;
|
|
197
207
|
/** Replace commands contributed by the active agent's Harness scope. */
|
|
198
208
|
setCommands(commands: readonly TuiCommand[]): void;
|
|
209
|
+
/** Open a keyboard-driven event ledger for the active session. */
|
|
210
|
+
openTrajectory(events: readonly SessionEvent[]): boolean;
|
|
199
211
|
/** Append a direct UI/command result without fabricating a session event. */
|
|
200
212
|
notice(text: string, options?: TuiNoticeOptions): void;
|
|
201
213
|
/** Append one successful plugin command result using the command-output surface. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** User-overridable application keybindings loaded from one JSON document. */
|
|
2
|
-
export type TuiAction = 'external-editor' | 'retry' | 'paste-clipboard' | 'copy-prompt' | 'copy-line' | 'inspect-subagent';
|
|
2
|
+
export type TuiAction = 'external-editor' | 'retry' | 'paste-clipboard' | 'copy-prompt' | 'copy-line' | 'inspect-subagent' | 'cycle-model-forward' | 'cycle-model-backward' | 'cycle-reasoning';
|
|
3
3
|
export declare const DEFAULT_KEYBINDINGS: Readonly<Record<string, TuiAction>>;
|
|
4
4
|
/** Load `{ "key-id": "action" }`; invalid rows are ignored independently. */
|
|
5
5
|
export declare function loadKeybindings(path: string | undefined): Record<string, TuiAction>;
|
|
@@ -7,8 +7,14 @@ export const DEFAULT_KEYBINDINGS = Object.freeze({
|
|
|
7
7
|
'alt+c': 'copy-prompt',
|
|
8
8
|
'ctrl+alt+c': 'copy-line',
|
|
9
9
|
'alt+a': 'inspect-subagent',
|
|
10
|
+
'ctrl+p': 'cycle-model-forward',
|
|
11
|
+
'alt+p': 'cycle-model-backward',
|
|
12
|
+
'ctrl+t': 'cycle-reasoning',
|
|
10
13
|
});
|
|
11
|
-
const ACTIONS = [
|
|
14
|
+
const ACTIONS = [
|
|
15
|
+
'external-editor', 'retry', 'paste-clipboard', 'copy-prompt', 'copy-line', 'inspect-subagent',
|
|
16
|
+
'cycle-model-forward', 'cycle-model-backward', 'cycle-reasoning',
|
|
17
|
+
];
|
|
12
18
|
/** Load `{ "key-id": "action" }`; invalid rows are ignored independently. */
|
|
13
19
|
export function loadKeybindings(path) {
|
|
14
20
|
const result = { ...DEFAULT_KEYBINDINGS };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keybindings-config.js","sourceRoot":"","sources":["../../src/input/keybindings-config.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAE9E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"keybindings-config.js","sourceRoot":"","sources":["../../src/input/keybindings-config.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAE9E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAKtC,MAAM,CAAC,MAAM,mBAAmB,GAAwC,MAAM,CAAC,MAAM,CAAC;IACpF,QAAQ,EAAE,iBAAiB;IAC3B,OAAO,EAAE,OAAO;IAChB,QAAQ,EAAE,iBAAiB;IAC3B,OAAO,EAAE,aAAa;IACtB,YAAY,EAAE,WAAW;IACzB,OAAO,EAAE,kBAAkB;IAC3B,QAAQ,EAAE,qBAAqB;IAC/B,OAAO,EAAE,sBAAsB;IAC/B,QAAQ,EAAE,iBAAiB;CAC5B,CAAC,CAAA;AAEF,MAAM,OAAO,GAAyB;IACpC,iBAAiB,EAAE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,WAAW,EAAE,kBAAkB;IAC7F,qBAAqB,EAAE,sBAAsB,EAAE,iBAAiB;CACjE,CAAA;AAED,6EAA6E;AAC7E,MAAM,UAAU,eAAe,CAAC,IAAwB;IACtD,MAAM,MAAM,GAA8B,EAAE,GAAG,mBAAmB,EAAE,CAAA;IACpE,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,MAAM,CAAA;IACrC,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;QAC9D,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,MAAM,CAAA;QAChE,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACnD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAmB,CAAC;gBAAE,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,GAAG,MAAmB,CAAA;QAC1H,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,kEAAkE,CAAC,CAAC;IAC9E,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -92,6 +92,7 @@ export declare class LocalTui implements TuiService {
|
|
|
92
92
|
setInspectedSubagent(inspected: TuiInspectedSubagent | undefined): void;
|
|
93
93
|
setTools(tools: readonly ToolInfo[]): void;
|
|
94
94
|
setCommands(commands: readonly TuiCommand[]): void;
|
|
95
|
+
openTrajectory(events: readonly SessionEvent[]): boolean;
|
|
95
96
|
setSessionSearch(search?: SessionSearcher): void;
|
|
96
97
|
setFileSearch(search?: FileSearcher): void;
|
|
97
98
|
setImageValidator(validate?: (image: TuiInputImage) => Promise<void>): void;
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* printing of settled blocks.
|
|
11
11
|
* @module @agi-fans/dsh-tui
|
|
12
12
|
*/
|
|
13
|
+
import { TerminalNotificationController, terminalNotificationSequence } from "./terminal-notifications.js";
|
|
13
14
|
import { homedir } from 'node:os';
|
|
14
15
|
import { join } from 'node:path';
|
|
15
16
|
import { createInterface } from 'node:readline';
|
|
@@ -24,6 +25,8 @@ import { buildCopyTargets, extractCopyTarget, parseCopyKind } from "../views/cop
|
|
|
24
25
|
import { applyHistorySearchEvent, createHistorySearch, } from "../views/history-search.js";
|
|
25
26
|
import { InputEditor, lineEnd, lineStart } from "../input/editor.js";
|
|
26
27
|
import { applySettingsEvent, createSettings, } from "../views/settings-list.js";
|
|
28
|
+
import { appendTrajectoryEvent, applyTrajectoryEvent, createTrajectory, } from "../views/trajectory.js";
|
|
29
|
+
import { applyAgentHubEvent, createAgentHub, updateAgentHub, } from "../views/agent-hub.js";
|
|
27
30
|
import { applyEvent, blockLines, initialTranscript, replayEvents, renderView, TRANSCRIPT_FAST_SCROLL, } from "../views/event-views.js";
|
|
28
31
|
import { flushPending, parseKeys } from "../input/keys.js";
|
|
29
32
|
import { MainScreenRenderer } from "../chrome/main-screen-renderer.js";
|
|
@@ -83,6 +86,8 @@ export class LocalTui {
|
|
|
83
86
|
#search = null;
|
|
84
87
|
#settings = null;
|
|
85
88
|
#copySelector = null;
|
|
89
|
+
#trajectory = null;
|
|
90
|
+
#agentHub = null;
|
|
86
91
|
#pending = null;
|
|
87
92
|
#queuedSubmissions = [];
|
|
88
93
|
/** Newer queue entries temporarily detached while Up browses backward. */
|
|
@@ -128,6 +133,9 @@ export class LocalTui {
|
|
|
128
133
|
#expandTools = false;
|
|
129
134
|
#checkUpdates = true;
|
|
130
135
|
#startupChangelog = 'summary';
|
|
136
|
+
#notifications = new TerminalNotificationController();
|
|
137
|
+
#notificationPolicy = 'off';
|
|
138
|
+
#notificationThreshold = '30s';
|
|
131
139
|
#statusBar = defaultStatusBarConfig();
|
|
132
140
|
#toolsExpanded = false;
|
|
133
141
|
#expandedToolCalls = new Set();
|
|
@@ -238,6 +246,9 @@ export class LocalTui {
|
|
|
238
246
|
}
|
|
239
247
|
event(event, presentation) {
|
|
240
248
|
this.#state = applyEvent(this.#state, event, presentation);
|
|
249
|
+
this.#emitNotification(this.#notifications.event({ type: event.type, ...('reason' in event && typeof event.reason === 'string' ? { reason: event.reason } : {}) }));
|
|
250
|
+
if (this.#trajectory !== null)
|
|
251
|
+
this.#trajectory = appendTrajectoryEvent(this.#trajectory, event);
|
|
241
252
|
this.#syncTick();
|
|
242
253
|
if (this.#tty) {
|
|
243
254
|
if (event.type === 'assistant/chunk' && this.#streamRenderMs > 0) {
|
|
@@ -277,6 +288,12 @@ export class LocalTui {
|
|
|
277
288
|
: { agents: roster.agents.map(agent => ({ ...agent, activity: [...agent.activity] })) };
|
|
278
289
|
if ((this.#subagents?.agents.length ?? 0) === 0)
|
|
279
290
|
this.#subagentLauncherFocused = false;
|
|
291
|
+
if (this.#agentHub !== null) {
|
|
292
|
+
if (this.#subagents === undefined)
|
|
293
|
+
this.#agentHub = null;
|
|
294
|
+
else
|
|
295
|
+
this.#agentHub = updateAgentHub(this.#agentHub, this.#subagents);
|
|
296
|
+
}
|
|
280
297
|
const inspected = this.#inspected;
|
|
281
298
|
if (inspected !== undefined) {
|
|
282
299
|
const current = this.#subagents?.agents.find(agent => agent.id === inspected.id);
|
|
@@ -315,6 +332,19 @@ export class LocalTui {
|
|
|
315
332
|
if (this.#tty)
|
|
316
333
|
this.#render();
|
|
317
334
|
}
|
|
335
|
+
openTrajectory(events) {
|
|
336
|
+
if (!this.#tty)
|
|
337
|
+
return false;
|
|
338
|
+
this.#trajectory = createTrajectory(events);
|
|
339
|
+
this.#agentHub = null;
|
|
340
|
+
this.#prompt = null;
|
|
341
|
+
this.#settings = null;
|
|
342
|
+
this.#copySelector = null;
|
|
343
|
+
this.#search = null;
|
|
344
|
+
this.#ac = null;
|
|
345
|
+
this.#render();
|
|
346
|
+
return true;
|
|
347
|
+
}
|
|
318
348
|
setSessionSearch(search) {
|
|
319
349
|
this.#searchSessions = search;
|
|
320
350
|
this.#refreshAutocomplete();
|
|
@@ -355,6 +385,7 @@ export class LocalTui {
|
|
|
355
385
|
return Promise.reject(new Error('omdsh-tui: prompt already in flight'));
|
|
356
386
|
if (this.#disposed || request.signal?.aborted === true)
|
|
357
387
|
return Promise.resolve(null);
|
|
388
|
+
this.#emitNotification(this.#notifications.humanPrompt());
|
|
358
389
|
this.#editor.setText('');
|
|
359
390
|
this.#ac = null;
|
|
360
391
|
return new Promise((resolve) => {
|
|
@@ -386,6 +417,7 @@ export class LocalTui {
|
|
|
386
417
|
});
|
|
387
418
|
}
|
|
388
419
|
replaceSession(events, presentations, status = 'idle') {
|
|
420
|
+
this.#trajectory = null;
|
|
389
421
|
const state = replayEvents(events, presentations);
|
|
390
422
|
this.#state = { ...state, status, compactCommandId: undefined };
|
|
391
423
|
this.#plainPrinted = 0;
|
|
@@ -417,6 +449,9 @@ export class LocalTui {
|
|
|
417
449
|
this.#expandTools = prefs.expandTools;
|
|
418
450
|
this.#checkUpdates = prefs.checkUpdates ?? true;
|
|
419
451
|
this.#startupChangelog = prefs.startupChangelog ?? 'summary';
|
|
452
|
+
this.#notificationPolicy = prefs.notifications ?? 'off';
|
|
453
|
+
this.#notificationThreshold = prefs.notificationThreshold ?? '30s';
|
|
454
|
+
this.#configureNotifications();
|
|
420
455
|
this.#statusBar = resolveStatusBarConfig(prefs.statusBar, prefs.statusPreset);
|
|
421
456
|
this.#toolsExpanded = prefs.expandTools;
|
|
422
457
|
if (this.#settings !== null)
|
|
@@ -714,6 +749,8 @@ export class LocalTui {
|
|
|
714
749
|
...(this.#subagents === undefined ? {} : { subagents: this.#subagents }),
|
|
715
750
|
subagentLauncherFocused: this.#subagentLauncherFocused,
|
|
716
751
|
...(this.#inspected === undefined ? {} : { inspected: this.#inspected }),
|
|
752
|
+
...(this.#trajectory === null ? {} : { trajectory: this.#trajectory }),
|
|
753
|
+
...(this.#agentHub === null ? {} : { agentHub: this.#agentHub }),
|
|
717
754
|
statusBar: this.#statusBar,
|
|
718
755
|
...(this.#prompt === null ? {} : { promptSelector: this.#prompt }),
|
|
719
756
|
...(this.#settings !== null
|
|
@@ -1026,6 +1063,28 @@ export class LocalTui {
|
|
|
1026
1063
|
this.#lastEscapeTime = 0;
|
|
1027
1064
|
if (this.#handlePrompt(event))
|
|
1028
1065
|
return;
|
|
1066
|
+
if (this.#trajectory !== null) {
|
|
1067
|
+
const command = applyTrajectoryEvent(this.#trajectory, event);
|
|
1068
|
+
if ('close' in command)
|
|
1069
|
+
this.#trajectory = null;
|
|
1070
|
+
else
|
|
1071
|
+
this.#trajectory = command.state;
|
|
1072
|
+
this.#render();
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1075
|
+
if (this.#agentHub !== null) {
|
|
1076
|
+
const command = applyAgentHubEvent(this.#agentHub, event);
|
|
1077
|
+
if ('close' in command)
|
|
1078
|
+
this.#agentHub = null;
|
|
1079
|
+
else if ('open' in command) {
|
|
1080
|
+
this.#agentHub = null;
|
|
1081
|
+
this.#openInspect(command.open);
|
|
1082
|
+
}
|
|
1083
|
+
else
|
|
1084
|
+
this.#agentHub = command.state;
|
|
1085
|
+
this.#render();
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1029
1088
|
if (event.type === 'key') {
|
|
1030
1089
|
const action = this.#keybindings[event.id];
|
|
1031
1090
|
if (action !== undefined) {
|
|
@@ -1184,6 +1243,15 @@ export class LocalTui {
|
|
|
1184
1243
|
return false;
|
|
1185
1244
|
if (prompt.request.presentation === 'plan-review')
|
|
1186
1245
|
return this.#handlePlanReview(event, prompt);
|
|
1246
|
+
if (event.type === 'text' && this.#editor.text === '') {
|
|
1247
|
+
const action = prompt.request.actions?.find(item => item.key === event.value);
|
|
1248
|
+
const selected = filteredPromptOptions(prompt.request, '')[prompt.selected];
|
|
1249
|
+
if (action !== undefined && selected !== undefined) {
|
|
1250
|
+
this.#finishPrompt(action.valuePrefix + (selected.value ?? selected.label));
|
|
1251
|
+
this.#render();
|
|
1252
|
+
return true;
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1187
1255
|
if (event.type === 'text' && event.value === ' ' && prompt.request.multiSelect === true && this.#editor.text === '') {
|
|
1188
1256
|
this.#prompt = togglePromptSelection(prompt);
|
|
1189
1257
|
this.#render();
|
|
@@ -1391,31 +1459,21 @@ export class LocalTui {
|
|
|
1391
1459
|
for (const listener of this.#inspectCloses)
|
|
1392
1460
|
listener();
|
|
1393
1461
|
}
|
|
1394
|
-
|
|
1462
|
+
#pickSubagent() {
|
|
1395
1463
|
this.#subagentLauncherFocused = false;
|
|
1396
1464
|
const agents = this.#subagents?.agents ?? [];
|
|
1397
1465
|
if (agents.length === 0) {
|
|
1398
1466
|
this.notice('No subagents are available in this session.');
|
|
1399
1467
|
return;
|
|
1400
1468
|
}
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
})),
|
|
1410
|
-
...(initialValue === undefined ? {} : { initialValue }),
|
|
1411
|
-
allowCustom: false,
|
|
1412
|
-
presentation: 'fullscreen-list',
|
|
1413
|
-
filterable: true,
|
|
1414
|
-
submitLabel: 'open',
|
|
1415
|
-
});
|
|
1416
|
-
if (answer === null || answer === '')
|
|
1417
|
-
return;
|
|
1418
|
-
this.#openInspect(answer);
|
|
1469
|
+
this.#prompt = null;
|
|
1470
|
+
this.#settings = null;
|
|
1471
|
+
this.#copySelector = null;
|
|
1472
|
+
this.#search = null;
|
|
1473
|
+
this.#trajectory = null;
|
|
1474
|
+
this.#ac = null;
|
|
1475
|
+
this.#agentHub = createAgentHub({ agents });
|
|
1476
|
+
this.#render();
|
|
1419
1477
|
}
|
|
1420
1478
|
#prefs() {
|
|
1421
1479
|
return {
|
|
@@ -1424,6 +1482,8 @@ export class LocalTui {
|
|
|
1424
1482
|
expandTools: this.#expandTools,
|
|
1425
1483
|
checkUpdates: this.#checkUpdates,
|
|
1426
1484
|
startupChangelog: this.#startupChangelog,
|
|
1485
|
+
notifications: this.#notificationPolicy,
|
|
1486
|
+
notificationThreshold: this.#notificationThreshold,
|
|
1427
1487
|
statusBar: {
|
|
1428
1488
|
...this.#statusBar,
|
|
1429
1489
|
groups: [...this.#statusBar.groups],
|
|
@@ -1442,6 +1502,9 @@ export class LocalTui {
|
|
|
1442
1502
|
this.#expandTools = prefs.expandTools;
|
|
1443
1503
|
this.#checkUpdates = prefs.checkUpdates ?? true;
|
|
1444
1504
|
this.#startupChangelog = prefs.startupChangelog ?? 'summary';
|
|
1505
|
+
this.#notificationPolicy = prefs.notifications ?? 'off';
|
|
1506
|
+
this.#notificationThreshold = prefs.notificationThreshold ?? '30s';
|
|
1507
|
+
this.#configureNotifications();
|
|
1445
1508
|
this.#statusBar = resolveStatusBarConfig(prefs.statusBar, prefs.statusPreset);
|
|
1446
1509
|
if (expandChanged)
|
|
1447
1510
|
this.#toolsExpanded = prefs.expandTools;
|
|
@@ -1827,6 +1890,8 @@ export class LocalTui {
|
|
|
1827
1890
|
this.#search = null;
|
|
1828
1891
|
this.#settings = null;
|
|
1829
1892
|
this.#copySelector = null;
|
|
1893
|
+
this.#trajectory = null;
|
|
1894
|
+
this.#agentHub = null;
|
|
1830
1895
|
this.#followTail();
|
|
1831
1896
|
// Image placeholders are TUI-owned. Mixed image+slash drafts stay a
|
|
1832
1897
|
// submission so restore can keep the original markers; the runner strips
|
|
@@ -2031,6 +2096,20 @@ export class LocalTui {
|
|
|
2031
2096
|
blocks: [...this.#state.blocks, { kind: 'notice', level: 'info', text }],
|
|
2032
2097
|
};
|
|
2033
2098
|
}
|
|
2099
|
+
#configureNotifications() {
|
|
2100
|
+
const thresholds = { '15s': 15_000, '30s': 30_000, '1m': 60_000, '2m': 120_000 };
|
|
2101
|
+
this.#notifications.configure({
|
|
2102
|
+
policy: this.#notificationPolicy,
|
|
2103
|
+
thresholdMs: thresholds[this.#notificationThreshold],
|
|
2104
|
+
});
|
|
2105
|
+
}
|
|
2106
|
+
#emitNotification(notification) {
|
|
2107
|
+
if (notification === undefined || !this.#tty)
|
|
2108
|
+
return;
|
|
2109
|
+
const sequence = terminalNotificationSequence(notification);
|
|
2110
|
+
if (sequence !== '')
|
|
2111
|
+
this.#term.output.write(sequence);
|
|
2112
|
+
}
|
|
2034
2113
|
#toolCatalog() {
|
|
2035
2114
|
this.#state = {
|
|
2036
2115
|
...this.#state,
|
|
@@ -2053,6 +2132,18 @@ export class LocalTui {
|
|
|
2053
2132
|
this.#submit('/retry');
|
|
2054
2133
|
return;
|
|
2055
2134
|
}
|
|
2135
|
+
if (action === 'cycle-model-forward') {
|
|
2136
|
+
this.#submit('/model next');
|
|
2137
|
+
return;
|
|
2138
|
+
}
|
|
2139
|
+
if (action === 'cycle-model-backward') {
|
|
2140
|
+
this.#submit('/model previous');
|
|
2141
|
+
return;
|
|
2142
|
+
}
|
|
2143
|
+
if (action === 'cycle-reasoning') {
|
|
2144
|
+
this.#submit('/model reasoning');
|
|
2145
|
+
return;
|
|
2146
|
+
}
|
|
2056
2147
|
if (action === 'copy-prompt') {
|
|
2057
2148
|
void this.#copyPicked(this.#editor.text, 'current prompt');
|
|
2058
2149
|
return;
|