@thegitai/cli 1.0.0-preview.7 → 1.0.0-preview.8
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/src/help-text.js +1 -1
- package/dist/src/session.js +8 -0
- package/dist/src/ui/repl.js +54 -11
- package/dist/src/ui/tui/build-frame.js +5 -2
- package/package.json +5 -5
package/dist/src/help-text.js
CHANGED
|
@@ -79,7 +79,7 @@ const HELP_MARKDOWN = [
|
|
|
79
79
|
' browse them, press Enter to expand one and read its output, k to stop it',
|
|
80
80
|
'- `/jobs output <id>` — print one job\'s full captured output',
|
|
81
81
|
'- `/jobs kill <id>` — stop one background job',
|
|
82
|
-
'- `/
|
|
82
|
+
'- `/new` — start a new conversation; this session remains saved',
|
|
83
83
|
'- `/exit` — quit the session',
|
|
84
84
|
'',
|
|
85
85
|
'## Safety & approvals',
|
package/dist/src/session.js
CHANGED
|
@@ -69,6 +69,14 @@ export function createSession({ rootDir, autoYes = false, agentMode, modelId, ma
|
|
|
69
69
|
serverState: cloneOpaqueState(serverState),
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
|
+
export function startNewConversation(session) {
|
|
73
|
+
clearConversation(session);
|
|
74
|
+
const createdAt = new Date().toISOString();
|
|
75
|
+
session.sessionId = createSessionId();
|
|
76
|
+
session.sessionName = null;
|
|
77
|
+
session.sessionCreatedAt = createdAt;
|
|
78
|
+
session.sessionUpdatedAt = createdAt;
|
|
79
|
+
}
|
|
72
80
|
export function clearConversation(session) {
|
|
73
81
|
session.history = [];
|
|
74
82
|
session.serverState = preserveProviderSelection(session.serverState);
|
package/dist/src/ui/repl.js
CHANGED
|
@@ -15,7 +15,7 @@ import { clearCliAuthConfig } from '../api/auth.js';
|
|
|
15
15
|
import { authenticationErrorMessage, isAuthenticationError, } from '../api/http.js';
|
|
16
16
|
import { setCommandOutputHook, withTuiMode } from '../runtime-mode.js';
|
|
17
17
|
import { collectBackgroundJobUiKillMutations, collectBackgroundJobUiOutputMutations, } from '../tool-executor.js';
|
|
18
|
-
import {
|
|
18
|
+
import { startNewConversation, } from '../session.js';
|
|
19
19
|
import { applySessionSnapshot, listSessionMetadata, loadSessionSnapshot, saveSessionState, } from '../session-store.js';
|
|
20
20
|
import { truncate } from '../utils.js';
|
|
21
21
|
import { writeClipboardText } from '../core/clipboard.js';
|
|
@@ -116,8 +116,8 @@ export const SLASH_COMMANDS = [
|
|
|
116
116
|
description: 'Background jobs: pick to view output or kill',
|
|
117
117
|
},
|
|
118
118
|
{
|
|
119
|
-
command: '/
|
|
120
|
-
description: '
|
|
119
|
+
command: '/new',
|
|
120
|
+
description: 'start a new conversation; this session remains saved',
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
command: '/exit',
|
|
@@ -1320,6 +1320,7 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
1320
1320
|
let latestUsageSummary = null;
|
|
1321
1321
|
let pendingTurnEntries = [];
|
|
1322
1322
|
let activeTurnAbort = null;
|
|
1323
|
+
let newConversationInFlight = false;
|
|
1323
1324
|
let todosTouchedThisTurn = false;
|
|
1324
1325
|
const syncTodosState = () => {
|
|
1325
1326
|
store.update((current) => ({ ...current, todos: listTodos() }));
|
|
@@ -1521,7 +1522,7 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
1521
1522
|
}));
|
|
1522
1523
|
};
|
|
1523
1524
|
const cancelActiveTurn = () => {
|
|
1524
|
-
if (!store.getState().busy)
|
|
1525
|
+
if (!store.getState().busy || newConversationInFlight)
|
|
1525
1526
|
return;
|
|
1526
1527
|
disarmExitConfirm();
|
|
1527
1528
|
dismissPendingApproval();
|
|
@@ -1677,6 +1678,18 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
1677
1678
|
return true;
|
|
1678
1679
|
}
|
|
1679
1680
|
};
|
|
1681
|
+
const saveActiveSessionOrAbort = async () => {
|
|
1682
|
+
try {
|
|
1683
|
+
await saveSessionBoth({ serverSessionClient, session });
|
|
1684
|
+
return true;
|
|
1685
|
+
}
|
|
1686
|
+
catch (error) {
|
|
1687
|
+
if (exitForAuthenticationError(error))
|
|
1688
|
+
return false;
|
|
1689
|
+
appendError(`Session save failed: ${error.message}`);
|
|
1690
|
+
return false;
|
|
1691
|
+
}
|
|
1692
|
+
};
|
|
1680
1693
|
const openSudoPasswordPrompt = (command, prompt, signal) => new Promise((resolve) => {
|
|
1681
1694
|
if (exiting || signal?.aborted) {
|
|
1682
1695
|
resolve(null);
|
|
@@ -2243,23 +2256,53 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
2243
2256
|
}
|
|
2244
2257
|
return;
|
|
2245
2258
|
}
|
|
2246
|
-
if (input === '/
|
|
2247
|
-
|
|
2259
|
+
if (input === '/new') {
|
|
2260
|
+
newConversationInFlight = true;
|
|
2261
|
+
store.update((current) => ({
|
|
2262
|
+
...current,
|
|
2263
|
+
busy: true,
|
|
2264
|
+
busySince: Date.now(),
|
|
2265
|
+
imageAttachments: [],
|
|
2266
|
+
queuedMessage: null,
|
|
2267
|
+
status: 'Starting a new conversation...',
|
|
2268
|
+
}));
|
|
2269
|
+
if (!(await saveActiveSessionOrAbort())) {
|
|
2270
|
+
newConversationInFlight = false;
|
|
2271
|
+
store.update((current) => ({
|
|
2272
|
+
...current,
|
|
2273
|
+
busy: false,
|
|
2274
|
+
busySince: null,
|
|
2275
|
+
status: 'Ready',
|
|
2276
|
+
}));
|
|
2277
|
+
await flushQueuedMessage();
|
|
2278
|
+
return;
|
|
2279
|
+
}
|
|
2280
|
+
startNewConversation(session);
|
|
2281
|
+
setBackgroundJobSession(session.sessionId);
|
|
2282
|
+
setScratchSession(session.sessionId);
|
|
2283
|
+
setTodoSession(session.sessionId);
|
|
2248
2284
|
clearTodos();
|
|
2285
|
+
syncBackgroundJobsState();
|
|
2249
2286
|
syncTodosState();
|
|
2250
2287
|
latestUsageSummary = null;
|
|
2251
|
-
if (!(await saveActiveSession()))
|
|
2252
|
-
return;
|
|
2253
2288
|
store.replaceTranscript([
|
|
2254
2289
|
{
|
|
2255
|
-
body: '
|
|
2290
|
+
body: 'Started a new conversation. The previous session remains saved.',
|
|
2256
2291
|
kind: 'system',
|
|
2257
|
-
title: '
|
|
2292
|
+
title: 'Session',
|
|
2258
2293
|
},
|
|
2259
2294
|
]);
|
|
2295
|
+
await saveActiveSession();
|
|
2260
2296
|
syncShellStateFromSession();
|
|
2261
|
-
|
|
2297
|
+
newConversationInFlight = false;
|
|
2298
|
+
store.update((current) => ({
|
|
2299
|
+
...current,
|
|
2300
|
+
busy: false,
|
|
2301
|
+
busySince: null,
|
|
2302
|
+
status: 'Ready',
|
|
2303
|
+
}));
|
|
2262
2304
|
await remountTui();
|
|
2305
|
+
await flushQueuedMessage();
|
|
2263
2306
|
return;
|
|
2264
2307
|
}
|
|
2265
2308
|
latestUsageSummary = null;
|
|
@@ -163,7 +163,7 @@ const CLIENT_SLASH_COMMANDS = [
|
|
|
163
163
|
{ command: '/model', description: 'Switch the active model' },
|
|
164
164
|
{ command: '/resume', description: 'Open the session picker to resume a previous session' },
|
|
165
165
|
{ command: '/jobs', description: 'Background jobs: pick to view output or kill' },
|
|
166
|
-
{ command: '/
|
|
166
|
+
{ command: '/new', description: 'start a new conversation; this session remains saved' },
|
|
167
167
|
{ command: '/exit', description: 'Quit the current session' },
|
|
168
168
|
];
|
|
169
169
|
function buildModelPickerOptions(currentModelId, serverModels) {
|
|
@@ -923,7 +923,10 @@ export function buildTuiFrame(state, cols, rows, spinnerFrame, elapsedSeconds, n
|
|
|
923
923
|
const overlayActive = Boolean(state.approvalPrompt || state.sudoPrompt);
|
|
924
924
|
if (!state.resumePickerOpen && !state.modelPickerOpen && !state.jobsPickerOpen && !overlayActive) {
|
|
925
925
|
const composerLines = [];
|
|
926
|
-
if (state.
|
|
926
|
+
if (state.busy && state.status === 'Starting a new conversation...') {
|
|
927
|
+
composerLines.push(line(span('Starting a new conversation…', { color: 'gray', dim: true })));
|
|
928
|
+
}
|
|
929
|
+
else if (state.queuedMessage) {
|
|
927
930
|
const preview = truncate(state.queuedMessage.body.trim().replace(/\s+/g, ' '), 60);
|
|
928
931
|
const imageCount = state.queuedMessage.imageAttachments.length;
|
|
929
932
|
composerLines.push(line(span(`↳ Queued · "${preview}"`, { color: 'gray', dim: true }), ...(imageCount > 0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thegitai/cli",
|
|
3
|
-
"version": "1.0.0-preview.
|
|
3
|
+
"version": "1.0.0-preview.8",
|
|
4
4
|
"description": "TheGitAI is an AI coding agent for your terminal. It indexes your repository, writes and edits files, runs commands, and builds features with you.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"@lydell/node-pty-linux-x64": "1.1.0",
|
|
38
38
|
"@lydell/node-pty-win32-arm64": "1.1.0",
|
|
39
39
|
"@lydell/node-pty-win32-x64": "1.1.0",
|
|
40
|
-
"@thegitai/tui-darwin-arm64": "1.0.0-preview.
|
|
41
|
-
"@thegitai/tui-darwin-x64": "1.0.0-preview.
|
|
42
|
-
"@thegitai/tui-linux-x64": "1.0.0-preview.
|
|
43
|
-
"@thegitai/tui-win32-x64": "1.0.0-preview.
|
|
40
|
+
"@thegitai/tui-darwin-arm64": "1.0.0-preview.8",
|
|
41
|
+
"@thegitai/tui-darwin-x64": "1.0.0-preview.8",
|
|
42
|
+
"@thegitai/tui-linux-x64": "1.0.0-preview.8",
|
|
43
|
+
"@thegitai/tui-win32-x64": "1.0.0-preview.8",
|
|
44
44
|
"@vscode/ripgrep": "1.18.0"
|
|
45
45
|
},
|
|
46
46
|
"publishConfig": {
|