@thegitai/cli 1.0.0-preview.52 → 1.0.0-preview.53
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/background-jobs.js +4 -0
- package/dist/src/job-follow-up.js +35 -6
- package/dist/src/ui/repl.js +7 -10
- package/package.json +6 -6
|
@@ -403,6 +403,10 @@ export function drainBackgroundJobNotifications({ sessionId } = {}) {
|
|
|
403
403
|
const hasReadableFinalOutput = pending.some((snapshot) => snapshot.status !== 'killed');
|
|
404
404
|
return `${lines.join(' ')}${hasReadableFinalOutput ? ' Use shell_job_output to read any final output.' : ''}`;
|
|
405
405
|
}
|
|
406
|
+
export function hasUnreportedBackgroundJobUpdate(id, { sessionId } = {}) {
|
|
407
|
+
const filter = sessionFilter(sessionId);
|
|
408
|
+
return pendingModelNotifications.some((snapshot) => snapshot.id === id && (!filter || snapshot.sessionId === filter));
|
|
409
|
+
}
|
|
406
410
|
function unknownJobError(id) {
|
|
407
411
|
const known = listBackgroundJobs().map((job) => job.id);
|
|
408
412
|
const hint = known.length
|
|
@@ -1,11 +1,40 @@
|
|
|
1
|
-
import { getBackgroundJob } from './background-jobs.js';
|
|
1
|
+
import { getBackgroundJob, hasUnreportedBackgroundJobUpdate } from './background-jobs.js';
|
|
2
2
|
export const MAX_CHAINED_JOB_FOLLOW_UPS = 3;
|
|
3
|
+
function exitedOnItsOwn(id, sessionId) {
|
|
4
|
+
const job = getBackgroundJob(id, { sessionId });
|
|
5
|
+
return job !== null && job.status !== 'running' && job.status !== 'killed';
|
|
6
|
+
}
|
|
3
7
|
export function decideJobFollowUp(jobIds, chainedFollowUps, sessionId) {
|
|
4
|
-
|
|
5
|
-
const job = getBackgroundJob(id, { sessionId });
|
|
6
|
-
return job !== null && job.status !== 'running' && job.status !== 'killed';
|
|
7
|
-
});
|
|
8
|
-
if (!finished)
|
|
8
|
+
if (!jobIds.some((id) => exitedOnItsOwn(id, sessionId)))
|
|
9
9
|
return 'wait';
|
|
10
10
|
return chainedFollowUps >= MAX_CHAINED_JOB_FOLLOW_UPS ? 'stop' : 'start';
|
|
11
11
|
}
|
|
12
|
+
export function remainingJobWait(jobIds, sessionId) {
|
|
13
|
+
return jobIds.filter((id) => {
|
|
14
|
+
const job = getBackgroundJob(id, { sessionId });
|
|
15
|
+
if (job?.status === 'running')
|
|
16
|
+
return true;
|
|
17
|
+
return exitedOnItsOwn(id, sessionId) && hasUnreportedBackgroundJobUpdate(id, { sessionId });
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export function createJobWaitTracker(sessionId) {
|
|
21
|
+
let waiting = [];
|
|
22
|
+
let chained = 0;
|
|
23
|
+
return {
|
|
24
|
+
get waiting() {
|
|
25
|
+
return waiting;
|
|
26
|
+
},
|
|
27
|
+
turnStarted(jobFollowUp) {
|
|
28
|
+
chained = jobFollowUp ? chained + 1 : 0;
|
|
29
|
+
},
|
|
30
|
+
turnEnded(waitingForJobs) {
|
|
31
|
+
waiting = waitingForJobs ? [...waitingForJobs] : remainingJobWait(waiting, sessionId());
|
|
32
|
+
},
|
|
33
|
+
takeDecision() {
|
|
34
|
+
const decision = decideJobFollowUp(waiting, chained, sessionId());
|
|
35
|
+
if (decision !== 'wait')
|
|
36
|
+
waiting = [];
|
|
37
|
+
return decision;
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
package/dist/src/ui/repl.js
CHANGED
|
@@ -14,7 +14,7 @@ import { agentModeLabel, nextAgentMode, } from '../agent-mode.js';
|
|
|
14
14
|
import { chat, models } from '../api/index.js';
|
|
15
15
|
import { isTurnCancelledError, isTurnOutcomeKnown } from '../api/chat.js';
|
|
16
16
|
import { formatTurnRecoveryStatus } from '../api/turn-recovery.js';
|
|
17
|
-
import {
|
|
17
|
+
import { createJobWaitTracker } from '../job-follow-up.js';
|
|
18
18
|
import { getJobBufferedOutput, getJobOutputPreview, hasRunningBackgroundJobs, killAllBackgroundJobs, killBackgroundJob, listBackgroundJobs, setBackgroundJobSession, setBackgroundJobUpdateHook, } from '../background-jobs.js';
|
|
19
19
|
import { clearTodos, listTodos, setTodoSession } from '../todo-list.js';
|
|
20
20
|
import { setScratchSession } from '../scratch-dir.js';
|
|
@@ -2492,8 +2492,7 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
2492
2492
|
rollback('turn ended — sending as the next prompt');
|
|
2493
2493
|
}
|
|
2494
2494
|
};
|
|
2495
|
-
|
|
2496
|
-
let chainedJobFollowUps = 0;
|
|
2495
|
+
const jobWait = createJobWaitTracker(() => session.sessionId);
|
|
2497
2496
|
const handleSubmit = async (rawInput, { jobFollowUp = false } = {}) => {
|
|
2498
2497
|
const chunks = jobFollowUp ? [] : store.getState().pastedChunks;
|
|
2499
2498
|
const expanded = chunks.length
|
|
@@ -2795,8 +2794,7 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
2795
2794
|
await flushQueuedMessage();
|
|
2796
2795
|
return;
|
|
2797
2796
|
}
|
|
2798
|
-
|
|
2799
|
-
chainedJobFollowUps = jobFollowUp ? chainedJobFollowUps + 1 : 0;
|
|
2797
|
+
jobWait.turnStarted(jobFollowUp);
|
|
2800
2798
|
latestUsageSummary = null;
|
|
2801
2799
|
disarmExitConfirm();
|
|
2802
2800
|
unacknowledged = new Map();
|
|
@@ -2917,7 +2915,7 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
2917
2915
|
status: result.waitingForApproval ? 'Awaiting approval' : 'Ready',
|
|
2918
2916
|
tokenUsage: formatClientTokenUsage(Date.now() - turnStartedAt, latestUsageSummary),
|
|
2919
2917
|
}));
|
|
2920
|
-
|
|
2918
|
+
jobWait.turnEnded(result.waitingForJobs);
|
|
2921
2919
|
recoverUnacknowledgedMessages();
|
|
2922
2920
|
await flushQueuedMessage();
|
|
2923
2921
|
}
|
|
@@ -3110,16 +3108,15 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
3110
3108
|
}));
|
|
3111
3109
|
};
|
|
3112
3110
|
const scheduleJobFollowUp = () => {
|
|
3113
|
-
if (
|
|
3111
|
+
if (jobWait.waiting.length === 0)
|
|
3114
3112
|
return;
|
|
3115
3113
|
setTimeout(async () => {
|
|
3116
3114
|
const state = store.getState();
|
|
3117
3115
|
if (exiting || state.busy || state.modelPickerOpen || state.resumePickerOpen)
|
|
3118
3116
|
return;
|
|
3119
|
-
const decision =
|
|
3117
|
+
const decision = jobWait.takeDecision();
|
|
3120
3118
|
if (decision === 'wait')
|
|
3121
3119
|
return;
|
|
3122
|
-
waitingJobIds = [];
|
|
3123
3120
|
if (decision === 'stop') {
|
|
3124
3121
|
appendStaticEntry({
|
|
3125
3122
|
body: 'A background job finished. Send a message to continue.',
|
|
@@ -3212,7 +3209,7 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
|
|
|
3212
3209
|
};
|
|
3213
3210
|
const unsubscribe = store.subscribe(() => {
|
|
3214
3211
|
renderCurrentFrame();
|
|
3215
|
-
if (
|
|
3212
|
+
if (jobWait.waiting.length > 0 && !store.getState().busy)
|
|
3216
3213
|
scheduleJobFollowUp();
|
|
3217
3214
|
});
|
|
3218
3215
|
const spinnerTimer = setInterval(() => {
|
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.53",
|
|
4
4
|
"description": "TheGitAI is an agentic AI coding tool for your terminal. It reads and searches your repository, writes and edits files, runs your tests, and verifies the change before handing it back.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agentic-ai",
|
|
@@ -45,11 +45,11 @@
|
|
|
45
45
|
"@lydell/node-pty-linux-x64": "1.1.0",
|
|
46
46
|
"@lydell/node-pty-win32-arm64": "1.1.0",
|
|
47
47
|
"@lydell/node-pty-win32-x64": "1.1.0",
|
|
48
|
-
"@thegitai/tui-darwin-arm64": "1.0.0-preview.
|
|
49
|
-
"@thegitai/tui-darwin-x64": "1.0.0-preview.
|
|
50
|
-
"@thegitai/tui-linux-arm64": "1.0.0-preview.
|
|
51
|
-
"@thegitai/tui-linux-x64": "1.0.0-preview.
|
|
52
|
-
"@thegitai/tui-win32-x64": "1.0.0-preview.
|
|
48
|
+
"@thegitai/tui-darwin-arm64": "1.0.0-preview.53",
|
|
49
|
+
"@thegitai/tui-darwin-x64": "1.0.0-preview.53",
|
|
50
|
+
"@thegitai/tui-linux-arm64": "1.0.0-preview.53",
|
|
51
|
+
"@thegitai/tui-linux-x64": "1.0.0-preview.53",
|
|
52
|
+
"@thegitai/tui-win32-x64": "1.0.0-preview.53",
|
|
53
53
|
"@vscode/ripgrep": "1.18.0"
|
|
54
54
|
},
|
|
55
55
|
"repository": {
|