@jun133/kitty 0.0.8 → 0.0.9

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/dist/tui.mjs ADDED
@@ -0,0 +1,728 @@
1
+ import {
2
+ InteractiveSessionDriver,
3
+ createHostSession,
4
+ createTerminalLogWriter,
5
+ formatRelativeSessionTime,
6
+ formatSessionPickerTitle,
7
+ mirrorInteractionShellToTerminalLog,
8
+ parseSessionPickerChoice,
9
+ renderKittyBanner
10
+ } from "./chunk-6NJJLOY3.mjs";
11
+ import "./chunk-4BN45TQG.mjs";
12
+ import {
13
+ loadProjectContext
14
+ } from "./chunk-ELBEXOR7.mjs";
15
+ import "./chunk-3KMC6H5K.mjs";
16
+ import {
17
+ TUI_COLORS,
18
+ appendTranscriptEntry,
19
+ appendTranscriptText,
20
+ applyViewportResize,
21
+ createInitialTuiState,
22
+ formatContextBudget,
23
+ parseSubmittedInputEcho,
24
+ scrollTuiTranscript,
25
+ scrollTuiTranscriptToBottom,
26
+ scrollTuiTranscriptToTop,
27
+ updateComposerState,
28
+ updateRuntimeDock
29
+ } from "./chunk-DFDOKON5.mjs";
30
+
31
+ // src/shell/tui/input/scroll.ts
32
+ var ENABLE_MOUSE_TRACKING = "\x1B[?1000h\x1B[?1002h\x1B[?1006h";
33
+ var DISABLE_MOUSE_TRACKING = "\x1B[?1006l\x1B[?1002l\x1B[?1000l";
34
+ function enableMouseWheelTracking(output = process.stdout) {
35
+ output.write(ENABLE_MOUSE_TRACKING);
36
+ let active = true;
37
+ return () => {
38
+ if (!active) {
39
+ return;
40
+ }
41
+ active = false;
42
+ output.write(DISABLE_MOUSE_TRACKING);
43
+ };
44
+ }
45
+ function parseMouseWheelDelta(input) {
46
+ let delta = 0;
47
+ for (const match of input.matchAll(SGR_MOUSE_PATTERN)) {
48
+ const code = Number(match[1]);
49
+ if (Number.isNaN(code)) {
50
+ continue;
51
+ }
52
+ if ((code & 64) !== 64) {
53
+ continue;
54
+ }
55
+ delta += (code & 1) === 1 ? 3 : -3;
56
+ }
57
+ for (let index = 0; index < input.length - 5; index += 1) {
58
+ if (input.charCodeAt(index) !== 27 || input[index + 1] !== "[" || input[index + 2] !== "M") {
59
+ continue;
60
+ }
61
+ const code = input.charCodeAt(index + 3) - 32;
62
+ if ((code & 64) !== 64) {
63
+ continue;
64
+ }
65
+ delta += (code & 1) === 1 ? 3 : -3;
66
+ }
67
+ return delta;
68
+ }
69
+ function stripMouseInputSequences(input) {
70
+ return input.replace(SGR_MOUSE_PATTERN, "").replace(X10_MOUSE_PATTERN, "");
71
+ }
72
+ var SGR_MOUSE_PATTERN = /\x1b\[<(\d+);(\d+);(\d+)([mM])/g;
73
+ var X10_MOUSE_PATTERN = /\x1b\[M[\s-\x7f]{3}/g;
74
+
75
+ // src/shell/tui/input/gateway.ts
76
+ import { PassThrough } from "stream";
77
+ function createTuiInputGateway(options) {
78
+ const source = options.source ?? process.stdin;
79
+ const filtered = new PassThrough();
80
+ mirrorTtyFacts(source, filtered);
81
+ const onData = (chunk) => {
82
+ const text = chunk.toString();
83
+ const delta = parseMouseWheelDelta(text);
84
+ if (delta !== 0) {
85
+ options.onMouseWheel(delta);
86
+ }
87
+ const keyboardInput = stripMouseInputSequences(text);
88
+ if (keyboardInput.length > 0) {
89
+ filtered.write(keyboardInput);
90
+ }
91
+ };
92
+ source.on("data", onData);
93
+ return {
94
+ stdin: filtered,
95
+ dispose() {
96
+ source.off("data", onData);
97
+ filtered.end();
98
+ }
99
+ };
100
+ }
101
+ function mirrorTtyFacts(source, target) {
102
+ const tty = source;
103
+ const output = target;
104
+ output.isTTY = Boolean(tty.isTTY);
105
+ output.setRawMode = (mode) => {
106
+ tty.setRawMode?.(mode);
107
+ return output;
108
+ };
109
+ output.ref = () => {
110
+ tty.ref?.();
111
+ return output;
112
+ };
113
+ output.unref = () => {
114
+ tty.unref?.();
115
+ return output;
116
+ };
117
+ }
118
+
119
+ // src/shell/tui/controller.ts
120
+ var DEFAULT_VIEWPORT = {
121
+ width: 80,
122
+ height: 18
123
+ };
124
+ var TuiController = class {
125
+ state;
126
+ viewport = DEFAULT_VIEWPORT;
127
+ listeners = /* @__PURE__ */ new Set();
128
+ pendingInput = null;
129
+ interruptHandler;
130
+ disposed = false;
131
+ constructor(session) {
132
+ this.state = createInitialTuiState(session);
133
+ this.state = applyViewportResize(this.state, this.viewport);
134
+ }
135
+ getState() {
136
+ return this.state;
137
+ }
138
+ subscribe(listener) {
139
+ this.listeners.add(listener);
140
+ listener(this.state);
141
+ return () => {
142
+ this.listeners.delete(listener);
143
+ };
144
+ }
145
+ setViewport(viewport) {
146
+ const nextViewport = {
147
+ width: Math.max(20, Math.floor(viewport.width)),
148
+ height: Math.max(1, Math.floor(viewport.height))
149
+ };
150
+ this.viewport = nextViewport;
151
+ this.setState(applyViewportResize(this.state, nextViewport));
152
+ }
153
+ readInput(promptLabel = "> ") {
154
+ return this.openInput(promptLabel);
155
+ }
156
+ submitInput(value) {
157
+ const pending = this.pendingInput;
158
+ if (!pending || this.disposed) {
159
+ return;
160
+ }
161
+ this.pendingInput = null;
162
+ this.setState(updateComposerState(this.state, {
163
+ promptLabel: "> "
164
+ }));
165
+ pending.resolve({ kind: "submit", value });
166
+ }
167
+ closeInput() {
168
+ const pending = this.pendingInput;
169
+ this.pendingInput = null;
170
+ if (pending) {
171
+ pending.resolve({ kind: "closed" });
172
+ }
173
+ }
174
+ bindInterrupt(handler) {
175
+ this.interruptHandler = handler;
176
+ return () => {
177
+ if (this.interruptHandler === handler) {
178
+ this.interruptHandler = void 0;
179
+ }
180
+ };
181
+ }
182
+ interrupt() {
183
+ this.interruptHandler?.();
184
+ }
185
+ append(role, text) {
186
+ if (!text) {
187
+ return;
188
+ }
189
+ this.setState(appendTranscriptEntry(this.state, { role, text }, this.viewport));
190
+ }
191
+ appendStreaming(role, text) {
192
+ if (!text) {
193
+ return;
194
+ }
195
+ this.setState(appendTranscriptText(this.state, role, text, this.viewport));
196
+ }
197
+ appendOutput(text, role = "system") {
198
+ const submitted = parseSubmittedInputEcho(text);
199
+ if (submitted !== void 0) {
200
+ this.append("user", submitted);
201
+ return;
202
+ }
203
+ this.append(role, text);
204
+ }
205
+ updateDock(dock) {
206
+ this.setState(updateRuntimeDock(this.state, dock));
207
+ }
208
+ updateSessionFacts(session) {
209
+ this.updateDock({
210
+ context: formatContextBudget(session)
211
+ });
212
+ }
213
+ updateComposerVisibleRows(visibleRows) {
214
+ const normalized = Math.max(1, Math.floor(visibleRows));
215
+ if (this.state.composer.visibleRows === normalized) {
216
+ return;
217
+ }
218
+ this.setState(updateComposerState(this.state, {
219
+ visibleRows: normalized
220
+ }));
221
+ }
222
+ scrollBy(delta) {
223
+ this.setState(scrollTuiTranscript(this.state, this.viewport, delta));
224
+ }
225
+ pageUp() {
226
+ this.scrollBy(-Math.max(1, this.viewport.height - 2));
227
+ }
228
+ pageDown() {
229
+ this.scrollBy(Math.max(1, this.viewport.height - 2));
230
+ }
231
+ scrollTop() {
232
+ this.setState(scrollTuiTranscriptToTop(this.state));
233
+ }
234
+ scrollBottom() {
235
+ this.setState(scrollTuiTranscriptToBottom(this.state, this.viewport));
236
+ }
237
+ dispose() {
238
+ this.disposed = true;
239
+ this.closeInput();
240
+ this.listeners.clear();
241
+ }
242
+ openInput(promptLabel) {
243
+ if (this.disposed) {
244
+ return Promise.resolve({ kind: "closed" });
245
+ }
246
+ this.closeInput();
247
+ this.setState(updateComposerState(this.state, {
248
+ promptLabel
249
+ }));
250
+ return new Promise((resolve) => {
251
+ this.pendingInput = {
252
+ resolve
253
+ };
254
+ });
255
+ }
256
+ setState(state) {
257
+ this.state = state;
258
+ for (const listener of this.listeners) {
259
+ listener(this.state);
260
+ }
261
+ }
262
+ };
263
+
264
+ // src/shell/tui/turnDisplay.ts
265
+ function createTuiTurnDisplay(options) {
266
+ let aborted = false;
267
+ const isAborted = () => aborted || options.abortSignal.aborted;
268
+ const updateWork = (active, label, detail) => {
269
+ if (!isAborted()) {
270
+ options.controller.updateDock({
271
+ work: {
272
+ active,
273
+ label,
274
+ detail
275
+ }
276
+ });
277
+ }
278
+ };
279
+ options.abortSignal.addEventListener("abort", () => {
280
+ aborted = true;
281
+ updateWork(false, "\u5DF2\u4E2D\u65AD", "\u5F53\u524D\u8F6E\u5DF2\u4E2D\u65AD");
282
+ });
283
+ const callbacks = {
284
+ onModelWaitStart() {
285
+ updateWork(true, "\u601D\u8003\u4E2D", "\u7B49\u5F85\u6A21\u578B\u56DE\u590D");
286
+ },
287
+ onModelWaitStop() {
288
+ updateWork(false, "\u7A7A\u95F2", "\u6A21\u578B\u7B49\u5F85\u7ED3\u675F");
289
+ },
290
+ onReasoningDelta(delta) {
291
+ if (options.config.showReasoning && !isAborted()) {
292
+ options.controller.appendStreaming("reasoning", delta);
293
+ }
294
+ },
295
+ onReasoning(text) {
296
+ if (options.config.showReasoning && !isAborted()) {
297
+ options.controller.appendStreaming("reasoning", text);
298
+ }
299
+ },
300
+ onAssistantDelta(delta) {
301
+ if (!isAborted()) {
302
+ options.controller.appendStreaming("assistant", delta);
303
+ }
304
+ },
305
+ onAssistantText(text) {
306
+ if (!isAborted()) {
307
+ options.controller.append("assistant", text);
308
+ }
309
+ },
310
+ onAssistantStage(text) {
311
+ if (!isAborted()) {
312
+ options.controller.append("assistant", text);
313
+ }
314
+ },
315
+ onAssistantDone() {
316
+ updateWork(false, "\u7A7A\u95F2", "\u56DE\u590D\u5B8C\u6210");
317
+ },
318
+ onToolCall(name) {
319
+ if (isAborted()) {
320
+ return;
321
+ }
322
+ const lane = classifyToolLane(name);
323
+ options.controller.updateDock({
324
+ work: {
325
+ active: true,
326
+ label: "\u6267\u884C\u5DE5\u5177",
327
+ detail: name
328
+ },
329
+ ...lane
330
+ });
331
+ },
332
+ onToolResult(name) {
333
+ if (isAborted()) {
334
+ return;
335
+ }
336
+ const lane = classifyToolLane(name, "\u5B8C\u6210");
337
+ options.controller.updateDock({
338
+ work: {
339
+ active: false,
340
+ label: "\u5DE5\u5177\u5B8C\u6210",
341
+ detail: name
342
+ },
343
+ ...lane
344
+ });
345
+ },
346
+ onToolError(name, error) {
347
+ if (isAborted()) {
348
+ return;
349
+ }
350
+ const lane = classifyToolLane(name, "\u5931\u8D25");
351
+ options.controller.updateDock({
352
+ work: {
353
+ active: false,
354
+ label: "\u5DE5\u5177\u5931\u8D25",
355
+ detail: `${name}: ${shorten(error)}`
356
+ },
357
+ ...lane
358
+ });
359
+ options.controller.append("system", `\u5DE5\u5177\u5931\u8D25\uFF1A${name}`);
360
+ },
361
+ onStatus(text) {
362
+ if (isAborted()) {
363
+ return;
364
+ }
365
+ options.controller.updateDock({
366
+ work: {
367
+ active: text.trim().length > 0,
368
+ label: text.trim() ? "\u72B6\u6001" : "\u7A7A\u95F2",
369
+ detail: text.trim() || "\u7A7A\u95F2"
370
+ }
371
+ });
372
+ }
373
+ };
374
+ return {
375
+ callbacks,
376
+ flush() {
377
+ options.controller.updateDock({
378
+ work: {
379
+ active: false,
380
+ label: "\u7A7A\u95F2",
381
+ detail: "\u5F53\u524D\u8F6E\u5DF2\u6536\u53E3"
382
+ }
383
+ });
384
+ },
385
+ dispose() {
386
+ options.controller.updateDock({
387
+ work: {
388
+ active: false,
389
+ label: "\u7A7A\u95F2",
390
+ detail: "\u6CA1\u6709\u4EFB\u52A1\u6B63\u5728\u6267\u884C"
391
+ }
392
+ });
393
+ }
394
+ };
395
+ }
396
+ function classifyToolLane(name, suffix = "\u8FD0\u884C\u4E2D") {
397
+ const normalized = name.toLowerCase();
398
+ if (normalized.includes("background")) {
399
+ return { background: `${name} ${suffix}` };
400
+ }
401
+ if (normalized.includes("subagent")) {
402
+ return { subagent: `${name} ${suffix}` };
403
+ }
404
+ return {};
405
+ }
406
+ function shorten(value) {
407
+ const normalized = value.replace(/\s+/g, " ").trim();
408
+ if (normalized.length <= 80) {
409
+ return normalized;
410
+ }
411
+ return `${normalized.slice(0, 77)}...`;
412
+ }
413
+
414
+ // src/shell/tui/shell.ts
415
+ function createTuiInteractionShell(controller) {
416
+ return {
417
+ input: createTuiInputPort(controller),
418
+ output: createTuiOutputPort(controller),
419
+ createTurnDisplay(options) {
420
+ return createTuiTurnDisplay({
421
+ controller,
422
+ config: options.config,
423
+ abortSignal: options.abortSignal
424
+ });
425
+ },
426
+ dispose() {
427
+ controller.dispose();
428
+ }
429
+ };
430
+ }
431
+ function createTuiInputPort(controller) {
432
+ return {
433
+ readInput(promptLabel) {
434
+ return controller.readInput(promptLabel);
435
+ },
436
+ bindInterrupt(handler) {
437
+ return controller.bindInterrupt(handler);
438
+ }
439
+ };
440
+ }
441
+ function createTuiOutputPort(controller) {
442
+ return {
443
+ plain(text) {
444
+ controller.appendOutput(text, "system");
445
+ },
446
+ info(text) {
447
+ controller.appendOutput(text, "system");
448
+ },
449
+ warn(text) {
450
+ controller.appendOutput(text, "system");
451
+ controller.updateDock({
452
+ work: {
453
+ active: false,
454
+ label: "\u63D0\u9192",
455
+ detail: text
456
+ }
457
+ });
458
+ },
459
+ error(text) {
460
+ controller.appendOutput(text, "system");
461
+ controller.updateDock({
462
+ work: {
463
+ active: false,
464
+ label: "\u9519\u8BEF",
465
+ detail: text
466
+ }
467
+ });
468
+ },
469
+ dim(text) {
470
+ controller.appendOutput(text, "system");
471
+ },
472
+ heading(text) {
473
+ controller.appendOutput(text, "system");
474
+ },
475
+ interrupt(text) {
476
+ controller.appendOutput(text, "system");
477
+ controller.updateDock({
478
+ work: {
479
+ active: false,
480
+ label: "\u4E2D\u65AD",
481
+ detail: text
482
+ }
483
+ });
484
+ }
485
+ };
486
+ }
487
+
488
+ // src/shell/tui/lifecycle.ts
489
+ function createCleanupStack() {
490
+ const cleanups = [];
491
+ let disposed = false;
492
+ return {
493
+ add(cleanup) {
494
+ if (!cleanup) {
495
+ return;
496
+ }
497
+ if (disposed) {
498
+ cleanup();
499
+ return;
500
+ }
501
+ cleanups.push(cleanup);
502
+ },
503
+ run() {
504
+ if (disposed) {
505
+ return;
506
+ }
507
+ disposed = true;
508
+ for (const cleanup of cleanups.splice(0).reverse()) {
509
+ cleanup();
510
+ }
511
+ }
512
+ };
513
+ }
514
+
515
+ // src/shell/tui/sessionPicker.ts
516
+ async function selectTuiSession(options) {
517
+ const sessions = await options.sessionStore.list(options.limit ?? 10);
518
+ if (sessions.length === 0) {
519
+ return {
520
+ session: await createHostSession(options.sessionStore, options.cwd),
521
+ cwd: options.cwd
522
+ };
523
+ }
524
+ return new Promise((resolve) => {
525
+ let app;
526
+ const finish = async (choice) => {
527
+ app?.unmount();
528
+ await app?.waitUntilExit().catch(() => void 0);
529
+ if (choice === null) {
530
+ resolve(null);
531
+ return;
532
+ }
533
+ if (choice === 0) {
534
+ resolve({
535
+ session: await createHostSession(options.sessionStore, options.cwd),
536
+ cwd: options.cwd
537
+ });
538
+ return;
539
+ }
540
+ const session = sessions[choice - 1];
541
+ if (!session) {
542
+ resolve(null);
543
+ return;
544
+ }
545
+ resolve({
546
+ session,
547
+ cwd: options.cwdOverridden ? options.cwd : session.cwd
548
+ });
549
+ };
550
+ const Picker = createTuiSessionPickerComponent({
551
+ React: options.React,
552
+ Box: options.ink.Box,
553
+ Text: options.ink.Text,
554
+ useInput: options.ink.useInput,
555
+ useStdout: options.ink.useStdout
556
+ });
557
+ app = options.ink.render(
558
+ options.React.createElement(Picker, {
559
+ sessions,
560
+ now: /* @__PURE__ */ new Date(),
561
+ onSelect: (choice) => {
562
+ void finish(choice);
563
+ },
564
+ onCancel: () => {
565
+ void finish(null);
566
+ }
567
+ }),
568
+ {
569
+ exitOnCtrlC: false,
570
+ alternateScreen: true
571
+ }
572
+ );
573
+ });
574
+ }
575
+ function createTuiSessionPickerComponent(kit) {
576
+ const { React, Box, Text, useInput, useStdout } = kit;
577
+ return function TuiSessionPicker(props) {
578
+ const [cursor, setCursor] = React.useState(1);
579
+ const { stdout } = useStdout();
580
+ const width = Math.max(40, stdout.columns ?? 80);
581
+ const choices = props.sessions.length + 1;
582
+ useInput((input, key) => {
583
+ if (key.ctrl && input === "c") {
584
+ props.onCancel();
585
+ return;
586
+ }
587
+ if (key.escape) {
588
+ props.onCancel();
589
+ return;
590
+ }
591
+ if (key.upArrow) {
592
+ setCursor((value) => wrapChoice(value - 1, choices));
593
+ return;
594
+ }
595
+ if (key.downArrow) {
596
+ setCursor((value) => wrapChoice(value + 1, choices));
597
+ return;
598
+ }
599
+ if (key.return) {
600
+ props.onSelect(cursor);
601
+ return;
602
+ }
603
+ const parsed = parseSessionPickerChoice(input, props.sessions.length);
604
+ if (parsed.kind === "new") {
605
+ props.onSelect(0);
606
+ } else if (parsed.kind === "existing") {
607
+ props.onSelect(parsed.index + 1);
608
+ }
609
+ });
610
+ return React.createElement(
611
+ Box,
612
+ {
613
+ flexDirection: "column",
614
+ width,
615
+ minHeight: 16,
616
+ paddingX: 3,
617
+ paddingY: 1,
618
+ backgroundColor: TUI_COLORS.background
619
+ },
620
+ React.createElement(Text, { color: TUI_COLORS.user, bold: true }, "Kitty Agent"),
621
+ React.createElement(Text, { color: TUI_COLORS.user, bold: true }, renderKittyBanner()),
622
+ React.createElement(Text, { color: TUI_COLORS.muted }, "\u9009\u62E9\u4F1A\u8BDD\u3002Enter \u8FDB\u5165\uFF0C\u2191/\u2193 \u5207\u6362\uFF0C0 \u65B0\u5EFA\uFF0CEsc \u9000\u51FA\u3002"),
623
+ React.createElement(
624
+ Box,
625
+ { marginTop: 1, flexDirection: "column" },
626
+ renderChoiceLine(React, Text, cursor === 0, "0", "\u65B0\u5EFA\u4F1A\u8BDD", ""),
627
+ ...props.sessions.map((session, index) => renderChoiceLine(
628
+ React,
629
+ Text,
630
+ cursor === index + 1,
631
+ String(index + 1),
632
+ formatSessionPickerTitle(session),
633
+ formatRelativeSessionTime(session.updatedAt, props.now)
634
+ ))
635
+ )
636
+ );
637
+ };
638
+ }
639
+ function renderChoiceLine(React, Text, selected, index, title, meta) {
640
+ return React.createElement(
641
+ Text,
642
+ { color: selected ? TUI_COLORS.user : TUI_COLORS.text, bold: selected },
643
+ `${selected ? "\u2503" : " "} ${index}. ${title}${meta ? ` ${meta}` : ""}`
644
+ );
645
+ }
646
+ function wrapChoice(value, count) {
647
+ if (value < 0) {
648
+ return count - 1;
649
+ }
650
+ if (value >= count) {
651
+ return 0;
652
+ }
653
+ return value;
654
+ }
655
+
656
+ // src/shell/tui/start.ts
657
+ async function startTuiChat(options) {
658
+ const cleanup = createCleanupStack();
659
+ const [{ default: React }, ink, { createTuiAppComponent }] = await Promise.all([
660
+ import("react"),
661
+ import("ink"),
662
+ import("./App-6FETP3LH.mjs")
663
+ ]);
664
+ const selected = await selectTuiSession({
665
+ cwd: options.cwd,
666
+ cwdOverridden: Boolean(options.cwdOverridden),
667
+ sessionStore: options.sessionStore,
668
+ React,
669
+ ink
670
+ });
671
+ if (!selected) {
672
+ return;
673
+ }
674
+ const projectContext = await loadProjectContext(selected.cwd, {
675
+ projectDocMaxBytes: options.config.projectDocMaxBytes
676
+ });
677
+ const controller = new TuiController(selected.session);
678
+ const shell = createTuiInteractionShell(controller);
679
+ const terminalLogWriter = createTerminalLogWriter(projectContext.stateRootDir, selected.session.id);
680
+ const terminalShell = mirrorInteractionShellToTerminalLog(shell, terminalLogWriter);
681
+ const inputGateway = createTuiInputGateway({
682
+ onMouseWheel: (delta) => {
683
+ controller.scrollBy(delta);
684
+ }
685
+ });
686
+ const TuiApp = createTuiAppComponent({
687
+ React,
688
+ Box: ink.Box,
689
+ Text: ink.Text,
690
+ useInput: ink.useInput,
691
+ useBoxMetrics: ink.useBoxMetrics,
692
+ useCursor: ink.useCursor,
693
+ useStdout: ink.useStdout
694
+ });
695
+ const app = ink.render(
696
+ React.createElement(TuiApp, {
697
+ controller,
698
+ enableMouseTracking: () => enableMouseWheelTracking(process.stdout)
699
+ }),
700
+ {
701
+ stdin: inputGateway.stdin,
702
+ exitOnCtrlC: false,
703
+ alternateScreen: true
704
+ }
705
+ );
706
+ cleanup.add(() => inputGateway.dispose());
707
+ cleanup.add(() => terminalShell.dispose?.());
708
+ cleanup.add(() => app.unmount());
709
+ const driver = new InteractiveSessionDriver({
710
+ cwd: selected.cwd,
711
+ config: options.config,
712
+ session: selected.session,
713
+ sessionStore: options.sessionStore,
714
+ shell: terminalShell,
715
+ onSessionUpdated(session) {
716
+ controller.updateSessionFacts(session);
717
+ }
718
+ });
719
+ try {
720
+ await driver.run();
721
+ } finally {
722
+ cleanup.run();
723
+ await app.waitUntilExit().catch(() => void 0);
724
+ }
725
+ }
726
+ export {
727
+ startTuiChat
728
+ };