@thegitai/cli 1.0.0-preview.1 → 1.0.0-preview.10
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 +16 -4
- package/dist/bin/ai.js +57 -287
- package/dist/src/api/auth.js +2 -2
- package/dist/src/api/browser-login.js +72 -3
- package/dist/src/api/chat.js +125 -24
- package/dist/src/api/http.js +16 -3
- package/dist/src/api/models.js +9 -4
- package/dist/src/help-text.js +19 -7
- package/dist/src/patcher.js +96 -9
- package/dist/src/project-index.js +13 -1
- package/dist/src/project-orientation.js +99 -0
- package/dist/src/scratch-dir.js +51 -33
- package/dist/src/session-store.js +52 -20
- package/dist/src/session.js +8 -0
- package/dist/src/tool-executor.js +38 -6
- package/dist/src/tools/delete-file.js +22 -4
- package/dist/src/tools/patch-file.js +30 -5
- package/dist/src/tools/read-file.js +3 -1
- package/dist/src/tools/replace-document-text.js +7 -1
- package/dist/src/tools/run-command.js +37 -19
- package/dist/src/tools/run-node-script.js +24 -4
- package/dist/src/tools/str-replace.js +30 -5
- package/dist/src/tools/write-file.js +25 -5
- package/dist/src/turn-failure-marker.js +11 -0
- package/dist/src/ui/prompt-history-store.js +1 -1
- package/dist/src/ui/repl.js +188 -49
- package/dist/src/ui/tui/bridge.js +3 -0
- package/dist/src/ui/tui/build-frame.js +179 -82
- package/dist/src/ui/tui/markdown-render.js +72 -73
- package/dist/src/ui/tui/shell-input.js +42 -13
- package/dist/src/ui/tui/terminal-title.js +3 -0
- package/dist/src/ui/tui/terminal-writes.js +48 -0
- package/dist/src/ui/tui/text.js +158 -4
- package/dist/src/utils.js +9 -0
- package/package.json +18 -6
- package/dist/src/markdown-renderer.js +0 -112
package/dist/src/ui/repl.js
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { createRatatuiBridge } from './tui/bridge.js';
|
|
2
2
|
import { buildTuiFrame, formatJobElapsed, formatTodoProgress, renderTranscriptEntryLines, } from './tui/build-frame.js';
|
|
3
3
|
import { createTerminalTitleController } from './tui/terminal-title.js';
|
|
4
|
+
import { captureTerminalWrites, releaseTerminalWrites, } from './tui/terminal-writes.js';
|
|
4
5
|
export { getSlashCommandSuggestions } from './tui/build-frame.js';
|
|
5
6
|
import { agentModeLabel, nextAgentMode, } from '../agent-mode.js';
|
|
6
7
|
import { chat, models } from '../api/index.js';
|
|
7
8
|
import { isTurnCancelledError } from '../api/chat.js';
|
|
8
9
|
import { getJobBufferedOutput, getJobOutputPreview, hasRunningBackgroundJobs, killAllBackgroundJobs, killBackgroundJob, listBackgroundJobs, setBackgroundJobSession, setBackgroundJobUpdateHook, } from '../background-jobs.js';
|
|
9
10
|
import { clearTodos, listTodos, setTodoSession } from '../todo-list.js';
|
|
11
|
+
import { setScratchSession } from '../scratch-dir.js';
|
|
10
12
|
import { cancelActiveCommand } from '../executor.js';
|
|
13
|
+
import { isTurnFailureMarker } from '../turn-failure-marker.js';
|
|
14
|
+
import { clearCliAuthConfig } from '../api/auth.js';
|
|
15
|
+
import { authenticationErrorMessage, isAuthenticationError, } from '../api/http.js';
|
|
11
16
|
import { setCommandOutputHook, withTuiMode } from '../runtime-mode.js';
|
|
12
17
|
import { collectBackgroundJobUiKillMutations, collectBackgroundJobUiOutputMutations, } from '../tool-executor.js';
|
|
13
|
-
import {
|
|
14
|
-
import { applySessionSnapshot, listSessionMetadata, loadSessionSnapshot, saveSessionState, } from '../session-store.js';
|
|
18
|
+
import { startNewConversation, } from '../session.js';
|
|
19
|
+
import { applySessionSnapshot, listSessionMetadata, loadSessionSnapshot, saveSessionState, sessionHasUserMessage, } from '../session-store.js';
|
|
15
20
|
import { truncate } from '../utils.js';
|
|
16
21
|
import { writeClipboardText } from '../core/clipboard.js';
|
|
17
22
|
import { openUrl } from '../core/open-url.js';
|
|
@@ -111,8 +116,8 @@ export const SLASH_COMMANDS = [
|
|
|
111
116
|
description: 'Background jobs: pick to view output or kill',
|
|
112
117
|
},
|
|
113
118
|
{
|
|
114
|
-
command: '/
|
|
115
|
-
description: '
|
|
119
|
+
command: '/new',
|
|
120
|
+
description: 'start a new conversation; this session remains saved',
|
|
116
121
|
},
|
|
117
122
|
{
|
|
118
123
|
command: '/exit',
|
|
@@ -558,6 +563,31 @@ function buildFileChangeEntry(event) {
|
|
|
558
563
|
title: skipped ? `${verb} skipped: ${filePath}` : `${verb} failed: ${filePath}`,
|
|
559
564
|
};
|
|
560
565
|
}
|
|
566
|
+
if (result?.scratch === true) {
|
|
567
|
+
const scratchName = truncate(filePath.split(/[\\/]/).filter(Boolean).at(-1) ?? filePath, 72);
|
|
568
|
+
if (call.name === 'delete_file') {
|
|
569
|
+
return {
|
|
570
|
+
body: '',
|
|
571
|
+
filePath,
|
|
572
|
+
kind: 'tool',
|
|
573
|
+
title: result?.deleted === true
|
|
574
|
+
? `Removed scratch file: ${scratchName}`
|
|
575
|
+
: `Scratch delete skipped: ${scratchName}`,
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
const content = typeof call.args?.content === 'string' ? call.args.content : '';
|
|
579
|
+
const lineSummary = call.name === 'write_file' && content
|
|
580
|
+
? ` (${splitDiffLines(content).length} lines)`
|
|
581
|
+
: '';
|
|
582
|
+
return {
|
|
583
|
+
body: '',
|
|
584
|
+
filePath,
|
|
585
|
+
kind: 'tool',
|
|
586
|
+
title: call.name === 'write_file'
|
|
587
|
+
? `Wrote scratch file: ${scratchName}${lineSummary}`
|
|
588
|
+
: `Edited scratch file: ${scratchName}`,
|
|
589
|
+
};
|
|
590
|
+
}
|
|
561
591
|
if (call.name === 'undo_edit') {
|
|
562
592
|
const dryRun = result?.dryRun === true ||
|
|
563
593
|
result?.dry_run === true ||
|
|
@@ -754,7 +784,7 @@ function displayUserTextFromHistoryEntry(entry) {
|
|
|
754
784
|
.slice(contentStart, contentEnd === -1 ? text.length : contentEnd)
|
|
755
785
|
.trim();
|
|
756
786
|
}
|
|
757
|
-
function buildTranscriptFromSessionHistory(history) {
|
|
787
|
+
export function buildTranscriptFromSessionHistory(history) {
|
|
758
788
|
const entries = [];
|
|
759
789
|
const pendingCalls = new Map();
|
|
760
790
|
for (const entry of history) {
|
|
@@ -800,6 +830,14 @@ function buildTranscriptFromSessionHistory(history) {
|
|
|
800
830
|
}
|
|
801
831
|
const text = textFromHistoryEntry(entry);
|
|
802
832
|
if ((entry.role === 'model' || entry.role === 'assistant') && text) {
|
|
833
|
+
if (isTurnFailureMarker(text)) {
|
|
834
|
+
entries.push({
|
|
835
|
+
body: 'This request did not complete.',
|
|
836
|
+
kind: 'system',
|
|
837
|
+
title: 'Previous turn',
|
|
838
|
+
});
|
|
839
|
+
continue;
|
|
840
|
+
}
|
|
803
841
|
entries.push({ body: text, kind: 'assistant', title: 'Response' });
|
|
804
842
|
}
|
|
805
843
|
}
|
|
@@ -925,6 +963,7 @@ function createInitialShellState(session, serverModels, debugUi) {
|
|
|
925
963
|
activeTurnInput: '',
|
|
926
964
|
activeTurnInputPreformatted: false,
|
|
927
965
|
agentMode: session.agentMode,
|
|
966
|
+
analyzingImages: 0,
|
|
928
967
|
approvalCursor: getDefaultApprovalCursor(),
|
|
929
968
|
approvalPrompt: null,
|
|
930
969
|
autoYes: session.autoYes,
|
|
@@ -1212,7 +1251,11 @@ export function buildModelPickerOptions(currentModelId, serverModels) {
|
|
|
1212
1251
|
return serverModels.map((model) => ({
|
|
1213
1252
|
id: model.id,
|
|
1214
1253
|
label: model.label,
|
|
1215
|
-
|
|
1254
|
+
publicId: model.id,
|
|
1255
|
+
costRating: model.costRating,
|
|
1256
|
+
current: model.id === currentModelId,
|
|
1257
|
+
disabled: false,
|
|
1258
|
+
note: model.description,
|
|
1216
1259
|
}));
|
|
1217
1260
|
}
|
|
1218
1261
|
function getDefaultModelPickerIndex(currentModelId, serverModels) {
|
|
@@ -1240,23 +1283,22 @@ function appendCommandLog(state, text) {
|
|
|
1240
1283
|
};
|
|
1241
1284
|
}
|
|
1242
1285
|
async function saveSessionBoth({ serverSessionClient, session, }) {
|
|
1286
|
+
if (!sessionHasUserMessage(session))
|
|
1287
|
+
return;
|
|
1243
1288
|
saveSessionState(session);
|
|
1244
1289
|
await serverSessionClient.save(session);
|
|
1245
1290
|
}
|
|
1246
|
-
function shouldUseRatatuiShell() {
|
|
1247
|
-
if (process.env.THEGITAI_PLAIN === '1')
|
|
1248
|
-
return false;
|
|
1249
|
-
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
1250
|
-
}
|
|
1251
|
-
export function shouldUseClientRatatuiShell() {
|
|
1252
|
-
return shouldUseRatatuiShell();
|
|
1253
|
-
}
|
|
1254
1291
|
export async function runClientInteractive({ appendPromptHistory, authConfig, debugUi, projectIndex, serverModels, serverSessionClient, session, usageText, initialPrompt, }) {
|
|
1255
|
-
if (
|
|
1256
|
-
throw new Error('
|
|
1292
|
+
if (process.stdin.isTTY !== true) {
|
|
1293
|
+
throw new Error('stdin is not a terminal');
|
|
1257
1294
|
}
|
|
1295
|
+
if (process.stdout.isTTY !== true) {
|
|
1296
|
+
throw new Error('stdout is not a terminal');
|
|
1297
|
+
}
|
|
1298
|
+
let fatalError = null;
|
|
1258
1299
|
await withTuiMode(async () => {
|
|
1259
1300
|
setBackgroundJobSession(session.sessionId);
|
|
1301
|
+
setScratchSession(session.sessionId);
|
|
1260
1302
|
setTodoSession(session.sessionId);
|
|
1261
1303
|
const store = createShellStore(createInitialShellState(session, serverModels, debugUi));
|
|
1262
1304
|
store.replaceTranscript(createSessionTranscript(session));
|
|
@@ -1268,6 +1310,7 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
1268
1310
|
let cleanupSudoPasswordPrompt = null;
|
|
1269
1311
|
let sudoPasswordBuffer = '';
|
|
1270
1312
|
const bridge = createRatatuiBridge();
|
|
1313
|
+
captureTerminalWrites();
|
|
1271
1314
|
const { handleShellKeyEvent } = await import('./tui/shell-input.js');
|
|
1272
1315
|
let terminalCols = 80;
|
|
1273
1316
|
let terminalRows = 24;
|
|
@@ -1280,6 +1323,7 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
1280
1323
|
let latestUsageSummary = null;
|
|
1281
1324
|
let pendingTurnEntries = [];
|
|
1282
1325
|
let activeTurnAbort = null;
|
|
1326
|
+
let newConversationInFlight = false;
|
|
1283
1327
|
let todosTouchedThisTurn = false;
|
|
1284
1328
|
const syncTodosState = () => {
|
|
1285
1329
|
store.update((current) => ({ ...current, todos: listTodos() }));
|
|
@@ -1312,7 +1356,9 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
1312
1356
|
store.update((current) => current.status === status ? { ...current, status: 'Ready' } : current);
|
|
1313
1357
|
}, 2500);
|
|
1314
1358
|
};
|
|
1315
|
-
const terminalTitle = createTerminalTitleController(
|
|
1359
|
+
const terminalTitle = createTerminalTitleController({
|
|
1360
|
+
write: (title) => bridge.setTitle(title),
|
|
1361
|
+
});
|
|
1316
1362
|
const syncTerminalTitle = () => {
|
|
1317
1363
|
const state = store.getState();
|
|
1318
1364
|
terminalTitle.sync({
|
|
@@ -1479,7 +1525,7 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
1479
1525
|
}));
|
|
1480
1526
|
};
|
|
1481
1527
|
const cancelActiveTurn = () => {
|
|
1482
|
-
if (!store.getState().busy)
|
|
1528
|
+
if (!store.getState().busy || newConversationInFlight)
|
|
1483
1529
|
return;
|
|
1484
1530
|
disarmExitConfirm();
|
|
1485
1531
|
dismissPendingApproval();
|
|
@@ -1523,14 +1569,6 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
1523
1569
|
scheduleLiveFrameRemount();
|
|
1524
1570
|
void remountTui();
|
|
1525
1571
|
};
|
|
1526
|
-
const saveActiveSession = async () => {
|
|
1527
|
-
try {
|
|
1528
|
-
await saveSessionBoth({ serverSessionClient, session });
|
|
1529
|
-
}
|
|
1530
|
-
catch (error) {
|
|
1531
|
-
appendError(`Session save failed: ${error.message}`);
|
|
1532
|
-
}
|
|
1533
|
-
};
|
|
1534
1572
|
const syncShellStateFromSession = () => {
|
|
1535
1573
|
store.update((current) => ({
|
|
1536
1574
|
...current,
|
|
@@ -1618,9 +1656,45 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
1618
1656
|
status: 'Exiting...',
|
|
1619
1657
|
}));
|
|
1620
1658
|
void bridge.close().then(() => {
|
|
1659
|
+
releaseTerminalWrites();
|
|
1621
1660
|
resolveDone?.();
|
|
1622
1661
|
});
|
|
1623
1662
|
};
|
|
1663
|
+
const exitForAuthenticationError = (error) => {
|
|
1664
|
+
if (!isAuthenticationError(error))
|
|
1665
|
+
return false;
|
|
1666
|
+
clearCliAuthConfig(session.env);
|
|
1667
|
+
if (sessionHasUserMessage(session)) {
|
|
1668
|
+
saveSessionState(session);
|
|
1669
|
+
}
|
|
1670
|
+
fatalError = new Error(authenticationErrorMessage(error));
|
|
1671
|
+
requestExit();
|
|
1672
|
+
return true;
|
|
1673
|
+
};
|
|
1674
|
+
const saveActiveSession = async () => {
|
|
1675
|
+
try {
|
|
1676
|
+
await saveSessionBoth({ serverSessionClient, session });
|
|
1677
|
+
return true;
|
|
1678
|
+
}
|
|
1679
|
+
catch (error) {
|
|
1680
|
+
if (exitForAuthenticationError(error))
|
|
1681
|
+
return false;
|
|
1682
|
+
appendError(`Session save failed: ${error.message}`);
|
|
1683
|
+
return true;
|
|
1684
|
+
}
|
|
1685
|
+
};
|
|
1686
|
+
const saveActiveSessionOrAbort = async () => {
|
|
1687
|
+
try {
|
|
1688
|
+
await saveSessionBoth({ serverSessionClient, session });
|
|
1689
|
+
return true;
|
|
1690
|
+
}
|
|
1691
|
+
catch (error) {
|
|
1692
|
+
if (exitForAuthenticationError(error))
|
|
1693
|
+
return false;
|
|
1694
|
+
appendError(`Session save failed: ${error.message}`);
|
|
1695
|
+
return false;
|
|
1696
|
+
}
|
|
1697
|
+
};
|
|
1624
1698
|
const openSudoPasswordPrompt = (command, prompt, signal) => new Promise((resolve) => {
|
|
1625
1699
|
if (exiting || signal?.aborted) {
|
|
1626
1700
|
resolve(null);
|
|
@@ -1757,7 +1831,8 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
1757
1831
|
selectedModelId: selected,
|
|
1758
1832
|
serverModels: fresh,
|
|
1759
1833
|
});
|
|
1760
|
-
await saveActiveSession()
|
|
1834
|
+
if (!(await saveActiveSession()))
|
|
1835
|
+
return;
|
|
1761
1836
|
syncShellStateFromSession();
|
|
1762
1837
|
appendStaticEntry({
|
|
1763
1838
|
body: `Switched to ${formatModelLabel(selected, fresh.models)}. Conversation history preserved.`,
|
|
@@ -1876,6 +1951,8 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
1876
1951
|
await switchToModel(selected.id);
|
|
1877
1952
|
}
|
|
1878
1953
|
catch (error) {
|
|
1954
|
+
if (exitForAuthenticationError(error))
|
|
1955
|
+
return;
|
|
1879
1956
|
appendError(error.message);
|
|
1880
1957
|
}
|
|
1881
1958
|
};
|
|
@@ -1933,10 +2010,10 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
1933
2010
|
const snapshot = await loadInteractiveSession(selected.id);
|
|
1934
2011
|
applySessionSnapshot(session, snapshot);
|
|
1935
2012
|
setBackgroundJobSession(session.sessionId);
|
|
2013
|
+
setScratchSession(session.sessionId);
|
|
1936
2014
|
syncBackgroundJobsState();
|
|
1937
2015
|
setTodoSession(session.sessionId);
|
|
1938
2016
|
syncTodosState();
|
|
1939
|
-
await saveActiveSession();
|
|
1940
2017
|
syncShellStateFromSession();
|
|
1941
2018
|
store.update((next) => ({
|
|
1942
2019
|
...next,
|
|
@@ -1959,6 +2036,8 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
1959
2036
|
await remountTui();
|
|
1960
2037
|
}
|
|
1961
2038
|
catch (error) {
|
|
2039
|
+
if (exitForAuthenticationError(error))
|
|
2040
|
+
return;
|
|
1962
2041
|
store.update((next) => ({
|
|
1963
2042
|
...next,
|
|
1964
2043
|
busy: false,
|
|
@@ -2111,14 +2190,18 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
2111
2190
|
});
|
|
2112
2191
|
}
|
|
2113
2192
|
catch (error) {
|
|
2193
|
+
if (exitForAuthenticationError(error))
|
|
2194
|
+
return;
|
|
2114
2195
|
appendError(error.message);
|
|
2115
2196
|
}
|
|
2116
2197
|
finally {
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2198
|
+
if (!exiting) {
|
|
2199
|
+
store.update((current) => ({
|
|
2200
|
+
...current,
|
|
2201
|
+
busy: false,
|
|
2202
|
+
status: 'Ready',
|
|
2203
|
+
}));
|
|
2204
|
+
}
|
|
2122
2205
|
}
|
|
2123
2206
|
return;
|
|
2124
2207
|
}
|
|
@@ -2132,14 +2215,18 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
2132
2215
|
await openResumePicker();
|
|
2133
2216
|
}
|
|
2134
2217
|
catch (error) {
|
|
2218
|
+
if (exitForAuthenticationError(error))
|
|
2219
|
+
return;
|
|
2135
2220
|
appendError(error.message);
|
|
2136
2221
|
}
|
|
2137
2222
|
finally {
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2223
|
+
if (!exiting) {
|
|
2224
|
+
store.update((current) => ({
|
|
2225
|
+
...current,
|
|
2226
|
+
busy: false,
|
|
2227
|
+
status: current.resumePickerOpen ? 'Select a session to resume' : 'Ready',
|
|
2228
|
+
}));
|
|
2229
|
+
}
|
|
2143
2230
|
}
|
|
2144
2231
|
return;
|
|
2145
2232
|
}
|
|
@@ -2159,33 +2246,68 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
2159
2246
|
}
|
|
2160
2247
|
}
|
|
2161
2248
|
catch (error) {
|
|
2249
|
+
if (exitForAuthenticationError(error))
|
|
2250
|
+
return;
|
|
2162
2251
|
appendError(error.message);
|
|
2163
2252
|
}
|
|
2164
2253
|
finally {
|
|
2254
|
+
if (!exiting) {
|
|
2255
|
+
store.update((current) => ({
|
|
2256
|
+
...current,
|
|
2257
|
+
busy: false,
|
|
2258
|
+
status: current.modelPickerOpen ? 'Select a model' : 'Ready',
|
|
2259
|
+
}));
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
return;
|
|
2263
|
+
}
|
|
2264
|
+
if (input === '/new') {
|
|
2265
|
+
newConversationInFlight = true;
|
|
2266
|
+
store.update((current) => ({
|
|
2267
|
+
...current,
|
|
2268
|
+
busy: true,
|
|
2269
|
+
busySince: Date.now(),
|
|
2270
|
+
imageAttachments: [],
|
|
2271
|
+
queuedMessage: null,
|
|
2272
|
+
status: 'Starting a new conversation...',
|
|
2273
|
+
}));
|
|
2274
|
+
if (!(await saveActiveSessionOrAbort())) {
|
|
2275
|
+
newConversationInFlight = false;
|
|
2165
2276
|
store.update((current) => ({
|
|
2166
2277
|
...current,
|
|
2167
2278
|
busy: false,
|
|
2168
|
-
|
|
2279
|
+
busySince: null,
|
|
2280
|
+
status: 'Ready',
|
|
2169
2281
|
}));
|
|
2282
|
+
await flushQueuedMessage();
|
|
2283
|
+
return;
|
|
2170
2284
|
}
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2285
|
+
startNewConversation(session);
|
|
2286
|
+
setBackgroundJobSession(session.sessionId);
|
|
2287
|
+
setScratchSession(session.sessionId);
|
|
2288
|
+
setTodoSession(session.sessionId);
|
|
2175
2289
|
clearTodos();
|
|
2290
|
+
syncBackgroundJobsState();
|
|
2176
2291
|
syncTodosState();
|
|
2177
2292
|
latestUsageSummary = null;
|
|
2178
|
-
await saveActiveSession();
|
|
2179
2293
|
store.replaceTranscript([
|
|
2180
2294
|
{
|
|
2181
|
-
body: '
|
|
2295
|
+
body: 'Started a new conversation. The previous session remains saved.',
|
|
2182
2296
|
kind: 'system',
|
|
2183
|
-
title: '
|
|
2297
|
+
title: 'Session',
|
|
2184
2298
|
},
|
|
2185
2299
|
]);
|
|
2300
|
+
await saveActiveSession();
|
|
2186
2301
|
syncShellStateFromSession();
|
|
2187
|
-
|
|
2302
|
+
newConversationInFlight = false;
|
|
2303
|
+
store.update((current) => ({
|
|
2304
|
+
...current,
|
|
2305
|
+
busy: false,
|
|
2306
|
+
busySince: null,
|
|
2307
|
+
status: 'Ready',
|
|
2308
|
+
}));
|
|
2188
2309
|
await remountTui();
|
|
2310
|
+
await flushQueuedMessage();
|
|
2189
2311
|
return;
|
|
2190
2312
|
}
|
|
2191
2313
|
latestUsageSummary = null;
|
|
@@ -2196,6 +2318,8 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
2196
2318
|
activeTurnAbort = turnAbort;
|
|
2197
2319
|
lastTurnStartedAt = turnStartedAt;
|
|
2198
2320
|
todosTouchedThisTurn = false;
|
|
2321
|
+
clearTodos();
|
|
2322
|
+
syncTodosState();
|
|
2199
2323
|
const userEntry = {
|
|
2200
2324
|
body: input,
|
|
2201
2325
|
kind: 'user',
|
|
@@ -2208,6 +2332,7 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
2208
2332
|
...current,
|
|
2209
2333
|
activeTurnInput: input,
|
|
2210
2334
|
activeTurnInputPreformatted: preformatted,
|
|
2335
|
+
analyzingImages: 0,
|
|
2211
2336
|
busy: true,
|
|
2212
2337
|
busySince: turnStartedAt,
|
|
2213
2338
|
clockNow: turnStartedAt,
|
|
@@ -2232,7 +2357,8 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
2232
2357
|
return;
|
|
2233
2358
|
latestUsageSummary = result.usageSummary ?? null;
|
|
2234
2359
|
const turnEntries = takePendingTurnEntries();
|
|
2235
|
-
await saveActiveSession()
|
|
2360
|
+
if (!(await saveActiveSession()))
|
|
2361
|
+
return;
|
|
2236
2362
|
syncShellStateFromSession();
|
|
2237
2363
|
store.update((current) => ({
|
|
2238
2364
|
...current,
|
|
@@ -2283,6 +2409,8 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
2283
2409
|
return;
|
|
2284
2410
|
}
|
|
2285
2411
|
const cancelled = isTurnCancelledError(error);
|
|
2412
|
+
if (exitForAuthenticationError(error))
|
|
2413
|
+
return;
|
|
2286
2414
|
store.update((current) => ({
|
|
2287
2415
|
...current,
|
|
2288
2416
|
activeTurnInput: '',
|
|
@@ -2307,7 +2435,8 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
2307
2435
|
title: 'System',
|
|
2308
2436
|
},
|
|
2309
2437
|
]);
|
|
2310
|
-
await saveActiveSession()
|
|
2438
|
+
if (!(await saveActiveSession()))
|
|
2439
|
+
return;
|
|
2311
2440
|
}
|
|
2312
2441
|
else {
|
|
2313
2442
|
appendStaticEntries(turnEntries);
|
|
@@ -2327,6 +2456,12 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
2327
2456
|
}
|
|
2328
2457
|
}
|
|
2329
2458
|
};
|
|
2459
|
+
session.onImageAnalysis = (activeImageCount) => {
|
|
2460
|
+
store.update((current) => ({
|
|
2461
|
+
...current,
|
|
2462
|
+
analyzingImages: Math.max(0, activeImageCount),
|
|
2463
|
+
}));
|
|
2464
|
+
};
|
|
2330
2465
|
session.onStatus = (message) => {
|
|
2331
2466
|
const panel = thinkingPanelFromStatus(message);
|
|
2332
2467
|
store.update((current) => ({
|
|
@@ -2531,10 +2666,14 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
2531
2666
|
terminalTitle.dispose();
|
|
2532
2667
|
killAllBackgroundJobs();
|
|
2533
2668
|
setBackgroundJobSession(null);
|
|
2669
|
+
setScratchSession(null);
|
|
2534
2670
|
setTodoSession(null);
|
|
2535
2671
|
setBackgroundJobUpdateHook(null);
|
|
2536
2672
|
await bridge.close();
|
|
2673
|
+
releaseTerminalWrites();
|
|
2537
2674
|
setCommandOutputHook(null);
|
|
2538
2675
|
}
|
|
2539
2676
|
});
|
|
2677
|
+
if (fatalError)
|
|
2678
|
+
throw fatalError;
|
|
2540
2679
|
}
|