@thegitai/cli 1.0.0-preview.21 → 1.0.0-preview.23
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 +1 -1
- package/dist/src/api/chat.js +5 -2
- package/dist/src/api/http.js +39 -2
- package/dist/src/background-jobs.js +2 -2
- package/dist/src/executor.js +24 -2
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ always be viewed or resumed from that computer. Continuing it through the
|
|
|
34
34
|
service requires the TheGitAI account used for that session. Local sessions can
|
|
35
35
|
also be listed while signed out or offline.
|
|
36
36
|
|
|
37
|
-
CLI login tokens use a rolling
|
|
37
|
+
CLI login tokens use a rolling 48-hour inactivity timeout. If one expires during
|
|
38
38
|
any server request, the CLI saves the local session, removes the expired
|
|
39
39
|
credential, and asks you to run `ai login` before resuming.
|
|
40
40
|
|
package/dist/src/api/chat.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createPromptCheckpoint, sanitizeSessionSafetyForServer, } from '../sess
|
|
|
3
3
|
import { applySessionSnapshot, saveSessionState, snapshotFromSession, } from '../session-store.js';
|
|
4
4
|
import { executeLocalToolCall } from '../tool-executor.js';
|
|
5
5
|
import { isUserInputQuestionArray } from './contracts.js';
|
|
6
|
-
import { createTraceContext, normalizeServerUrl, readErrorResponse, } from './http.js';
|
|
6
|
+
import { createTraceContext, gatewayFailureCategory, normalizeServerUrl, readErrorResponse, } from './http.js';
|
|
7
7
|
import { collectClientEnvironment } from '../client-environment.js';
|
|
8
8
|
import { collectProjectOrientation } from '../project-orientation.js';
|
|
9
9
|
import { autoAttachImages } from '../core/image-path-extractor.js';
|
|
@@ -587,7 +587,10 @@ export async function sendServerUserMessage({ config, projectIndex, session, inp
|
|
|
587
587
|
? error
|
|
588
588
|
: new TurnCancelledError();
|
|
589
589
|
}
|
|
590
|
-
const category = error instanceof ChatTurnFailedError
|
|
590
|
+
const category = error instanceof ChatTurnFailedError
|
|
591
|
+
? error.category
|
|
592
|
+
:
|
|
593
|
+
gatewayFailureCategory(error) ?? 'unknown_error';
|
|
591
594
|
const partial = error instanceof ChatTurnFailedError ? error.partialSnapshot : undefined;
|
|
592
595
|
if (partial) {
|
|
593
596
|
applySessionSnapshot(session, partial, { preserveAgentMode: true });
|
package/dist/src/api/http.js
CHANGED
|
@@ -84,6 +84,41 @@ export function normalizeServerUrl(serverUrl) {
|
|
|
84
84
|
}
|
|
85
85
|
return normalized;
|
|
86
86
|
}
|
|
87
|
+
const MAX_NON_JSON_BODY_CHARS = 200;
|
|
88
|
+
const GATEWAY_STATUS_MESSAGES = {
|
|
89
|
+
502: 'Could not reach the TheGitAI server (bad gateway).',
|
|
90
|
+
503: 'The TheGitAI server is temporarily unavailable.',
|
|
91
|
+
504: 'The TheGitAI server did not respond in time (gateway timeout).',
|
|
92
|
+
520: 'The connection to the TheGitAI server failed (edge error 520).',
|
|
93
|
+
521: 'The TheGitAI server is not accepting connections (edge error 521).',
|
|
94
|
+
522: 'The connection to the TheGitAI server timed out (edge error 522).',
|
|
95
|
+
523: 'The TheGitAI server is unreachable (edge error 523).',
|
|
96
|
+
524: 'The TheGitAI server did not respond in time (edge error 524).',
|
|
97
|
+
};
|
|
98
|
+
function truncateByCodePoint(text, maxChars) {
|
|
99
|
+
if (text.length <= maxChars)
|
|
100
|
+
return text;
|
|
101
|
+
const points = Array.from(text);
|
|
102
|
+
if (points.length <= maxChars)
|
|
103
|
+
return text;
|
|
104
|
+
return `${points.slice(0, maxChars).join('').trimEnd()}…`;
|
|
105
|
+
}
|
|
106
|
+
export function nonJsonErrorMessage(body, status) {
|
|
107
|
+
const rayId = /Cloudflare Ray ID:\s*(?:<[^>]*>\s*)*([0-9a-f]{8,})/i.exec(body)?.[1];
|
|
108
|
+
const gateway = GATEWAY_STATUS_MESSAGES[status];
|
|
109
|
+
const summary = truncateByCodePoint(body
|
|
110
|
+
.replace(/<(script|style)\b[^>]*>[\s\S]*?<\/\1>/gi, ' ')
|
|
111
|
+
.replace(/<[^>]*>/g, ' ')
|
|
112
|
+
.replace(/\s+/g, ' ')
|
|
113
|
+
.trim(), MAX_NON_JSON_BODY_CHARS);
|
|
114
|
+
const base = gateway ?? (summary || `Request failed with ${status}`);
|
|
115
|
+
return rayId ? `${base} (Cloudflare Ray ID: ${rayId})` : base;
|
|
116
|
+
}
|
|
117
|
+
export function gatewayFailureCategory(error) {
|
|
118
|
+
if (!(error instanceof ServerApiError))
|
|
119
|
+
return null;
|
|
120
|
+
return error.status in GATEWAY_STATUS_MESSAGES ? 'gateway_error' : null;
|
|
121
|
+
}
|
|
87
122
|
export async function readJsonResponse(response) {
|
|
88
123
|
const text = await response.text();
|
|
89
124
|
if (!text.trim())
|
|
@@ -92,7 +127,9 @@ export async function readJsonResponse(response) {
|
|
|
92
127
|
return JSON.parse(text);
|
|
93
128
|
}
|
|
94
129
|
catch {
|
|
95
|
-
return {
|
|
130
|
+
return {
|
|
131
|
+
error: { message: nonJsonErrorMessage(text, response.status) },
|
|
132
|
+
};
|
|
96
133
|
}
|
|
97
134
|
}
|
|
98
135
|
export function failureMessage(data, status) {
|
|
@@ -106,7 +143,7 @@ export function isAuthenticationError(error) {
|
|
|
106
143
|
}
|
|
107
144
|
export function authenticationErrorMessage(error) {
|
|
108
145
|
return error.code === 'AUTH_TOKEN_EXPIRED'
|
|
109
|
-
? 'Your login expired after
|
|
146
|
+
? 'Your login expired after 48 hours of inactivity. Run `ai login` and resume this saved session.'
|
|
110
147
|
: 'Your login is no longer valid. Run `ai login` and resume this saved session.';
|
|
111
148
|
}
|
|
112
149
|
export async function readErrorResponse(response, traceId = response.headers.get(TRACE_ID_HEADER) ?? '') {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from './colors.js';
|
|
2
2
|
import { spawn } from 'child_process';
|
|
3
|
-
import { buildCommandEnv, commandUsesSudo, sanitizeCommandText, terminateChild, } from './executor.js';
|
|
3
|
+
import { buildCommandEnv, commandUsesSudo, resolveCommandShell, sanitizeCommandText, terminateChild, } from './executor.js';
|
|
4
4
|
import { isTuiMode } from './runtime-mode.js';
|
|
5
5
|
import { redactConnectionStringCredentials } from './secret-preview.js';
|
|
6
6
|
const MAX_RUNNING_JOBS = 8;
|
|
@@ -196,7 +196,7 @@ export async function startBackgroundJob(command, cwd, { startupWaitMs, sessionI
|
|
|
196
196
|
const id = `bg_${++jobCounter}`;
|
|
197
197
|
const child = spawn(command, {
|
|
198
198
|
cwd,
|
|
199
|
-
shell:
|
|
199
|
+
shell: resolveCommandShell(),
|
|
200
200
|
detached: process.platform !== 'win32',
|
|
201
201
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
202
202
|
env: buildCommandEnv(cwd),
|
package/dist/src/executor.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from './colors.js';
|
|
2
2
|
import { execFileSync, spawn } from 'child_process';
|
|
3
|
-
import { existsSync, statSync } from 'fs';
|
|
3
|
+
import { accessSync, constants as fsConstants, existsSync, statSync } from 'fs';
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
5
|
import os from 'os';
|
|
6
6
|
import path from 'path';
|
|
@@ -637,6 +637,28 @@ export function buildCommandEnv(cwd) {
|
|
|
637
637
|
THEGITAI_SCRATCH_DIR: ensureSessionScratchDir(),
|
|
638
638
|
};
|
|
639
639
|
}
|
|
640
|
+
let cachedCommandShell;
|
|
641
|
+
function findBashPath() {
|
|
642
|
+
const fromPath = (process.env.PATH ?? '')
|
|
643
|
+
.split(path.delimiter)
|
|
644
|
+
.filter(Boolean)
|
|
645
|
+
.map((dir) => path.join(dir, 'bash'));
|
|
646
|
+
for (const candidate of [...fromPath, '/bin/bash', '/usr/bin/bash']) {
|
|
647
|
+
try {
|
|
648
|
+
accessSync(candidate, fsConstants.X_OK);
|
|
649
|
+
return candidate;
|
|
650
|
+
}
|
|
651
|
+
catch { }
|
|
652
|
+
}
|
|
653
|
+
return null;
|
|
654
|
+
}
|
|
655
|
+
export function resolveCommandShell() {
|
|
656
|
+
if (cachedCommandShell !== undefined)
|
|
657
|
+
return cachedCommandShell;
|
|
658
|
+
cachedCommandShell =
|
|
659
|
+
process.platform === 'win32' ? true : (findBashPath() ?? true);
|
|
660
|
+
return cachedCommandShell;
|
|
661
|
+
}
|
|
640
662
|
function sanitizePtyOutput(command, output, cwd, secrets) {
|
|
641
663
|
return sanitizeCommandText(command, stripSudoPromptText(redactSecrets(output, secrets)), cwd);
|
|
642
664
|
}
|
|
@@ -822,7 +844,7 @@ export async function runCommand(command, cwd, { requestSudoPassword, timeout, }
|
|
|
822
844
|
let killTimer = null;
|
|
823
845
|
const child = spawn(command, {
|
|
824
846
|
cwd,
|
|
825
|
-
shell:
|
|
847
|
+
shell: resolveCommandShell(),
|
|
826
848
|
detached: process.platform !== 'win32',
|
|
827
849
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
828
850
|
env: buildCommandEnv(cwd),
|
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.23",
|
|
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.23",
|
|
41
|
+
"@thegitai/tui-darwin-x64": "1.0.0-preview.23",
|
|
42
|
+
"@thegitai/tui-linux-x64": "1.0.0-preview.23",
|
|
43
|
+
"@thegitai/tui-win32-x64": "1.0.0-preview.23",
|
|
44
44
|
"@vscode/ripgrep": "1.18.0"
|
|
45
45
|
},
|
|
46
46
|
"publishConfig": {
|