@thegitai/cli 1.0.0-preview.47 → 1.0.0-preview.49
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 +25 -0
- package/dist/bin/ai.js +21 -11
- package/dist/src/api/chat.js +564 -214
- package/dist/src/api/startup-handshake.js +36 -0
- package/dist/src/api/turn-recovery.js +189 -0
- package/dist/src/browser/session-bridge.js +21 -7
- package/dist/src/help-text.js +7 -0
- package/dist/src/tool-executor.js +1 -0
- package/dist/src/tools/browser.js +19 -36
- package/dist/src/ui/repl.js +69 -38
- package/dist/src/ui/tui/build-frame.js +17 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -52,6 +52,31 @@ CLI login tokens use a rolling 48-hour inactivity timeout. If one expires during
|
|
|
52
52
|
any server request, the CLI removes the expired credential and signs you in
|
|
53
53
|
again on the next run.
|
|
54
54
|
|
|
55
|
+
## When the connection drops
|
|
56
|
+
|
|
57
|
+
A dropped connection does not end your turn. The CLI shows
|
|
58
|
+
`Connection interrupted · retrying in 10s · retry 1/3` under the working timer,
|
|
59
|
+
waits ten seconds, and reconnects to the same turn — it never starts the request
|
|
60
|
+
over, and a command, edit or browser action that already ran is not run again.
|
|
61
|
+
It tries three times. Once it is back, the turn simply continues and a short
|
|
62
|
+
`Connection restored` note stays in the transcript.
|
|
63
|
+
|
|
64
|
+
The same applies when you start `ai` while TheGitAI is briefly unavailable:
|
|
65
|
+
startup shows `Couldn't reach TheGitAI (…) · retrying in 10s · retry 1/3` and
|
|
66
|
+
waits up to three times before giving up.
|
|
67
|
+
|
|
68
|
+
If TheGitAI itself restarted while it was working, the turn cannot resume
|
|
69
|
+
where it was. It continues instead: the CLI sends your request once more with
|
|
70
|
+
the steps that already finished on your machine and everything you told it
|
|
71
|
+
during the turn, and the work picks up from there — a command that already ran
|
|
72
|
+
is not run again, and a correction you made still stands — with a short
|
|
73
|
+
`Server restarted` note in the transcript.
|
|
74
|
+
|
|
75
|
+
Press Esc at any point to stop the turn instead. If all three retries fail, the
|
|
76
|
+
turn ends with an error that names what was interrupted, notes that some actions
|
|
77
|
+
may already have completed, and leaves anything you had queued in the composer
|
|
78
|
+
rather than sending it on top of a turn whose outcome is unknown.
|
|
79
|
+
|
|
55
80
|
## Chrome browser control
|
|
56
81
|
|
|
57
82
|
The TheGitAI Chrome extension is separately installed. After installing it,
|
package/dist/bin/ai.js
CHANGED
|
@@ -4,7 +4,9 @@ import { ServerApi } from '../src/api/index.js';
|
|
|
4
4
|
import { DEFAULT_THEGITAI_HOST } from '../src/api/default-host.js';
|
|
5
5
|
import { isSignInCancelled } from '../src/api/browser-login.js';
|
|
6
6
|
import { runSignIn } from '../src/signin.js';
|
|
7
|
-
import {
|
|
7
|
+
import { ServerApiError, authenticationErrorMessage, isAuthenticationError, isTransientNetworkError, } from '../src/api/http.js';
|
|
8
|
+
import { loadStartupHandshake } from '../src/api/startup-handshake.js';
|
|
9
|
+
import { TURN_RECOVERY_DELAY_MS, TURN_RECOVERY_RETRIES, } from '../src/api/turn-recovery.js';
|
|
8
10
|
import { formatCliHelpText } from '../src/help-text.js';
|
|
9
11
|
import { createSession, disposeSession } from '../src/session.js';
|
|
10
12
|
import { applySessionSnapshot, listSessionMetadata, loadSessionSnapshot, saveSessionState, sessionHasUserMessage, } from '../src/session-store.js';
|
|
@@ -172,16 +174,24 @@ export async function main() {
|
|
|
172
174
|
const authConfig = await ensureCliAuthConfig();
|
|
173
175
|
const serverSessionClient = sessions.createServerSessionClient({ config: authConfig });
|
|
174
176
|
const cachedModels = models.selectCacheForServer(models.readCachedServerModels(), authConfig.serverUrl);
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
177
|
+
const { models: modelsOutcome, whoami: whoamiOutcome } = await loadStartupHandshake({
|
|
178
|
+
config: authConfig,
|
|
179
|
+
canStartOffline: Boolean(cachedModels?.models.length),
|
|
180
|
+
onStatus: (status, lastFailure) => {
|
|
181
|
+
if (status.phase === 'waiting') {
|
|
182
|
+
const reason = lastFailure instanceof ServerApiError
|
|
183
|
+
? `HTTP ${lastFailure.status}`
|
|
184
|
+
: unreachableReason(lastFailure);
|
|
185
|
+
console.error(chalk.yellow(`⚠ Couldn't reach TheGitAI (${reason}) · retrying in ${TURN_RECOVERY_DELAY_MS / 1000}s · retry ${status.retry}/${TURN_RECOVERY_RETRIES}`));
|
|
186
|
+
}
|
|
187
|
+
else if (status.phase === 'reconnecting') {
|
|
188
|
+
console.error(chalk.dim(` Reconnecting · retry ${status.retry}/${TURN_RECOVERY_RETRIES}`));
|
|
189
|
+
}
|
|
190
|
+
else if (status.phase === 'restored') {
|
|
191
|
+
console.error(chalk.green('✓ Reconnected to TheGitAI'));
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
});
|
|
185
195
|
let offlineNotice = null;
|
|
186
196
|
let serverModels;
|
|
187
197
|
if (modelsOutcome.status === 'fulfilled') {
|