Skip to content

Commit 8d2c5dd

Browse files
committed
fix: remove timeout for initial checkpoint service initialization in large repos
- Added isInitialCall parameter to getCheckpointService function - When isInitialCall is true, no timeout is applied to allow large repositories to complete initialization - Modified initiateTaskLoop to pass isInitialCall=true for the initial checkpoint service call - Updated tests to verify the new behavior Fixes #7843
1 parent 7cd6520 commit 8d2c5dd

File tree

3 files changed

+57
-11
lines changed

3 files changed

+57
-11
lines changed

src/core/checkpoints/__tests__/checkpoint.test.ts

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"
1+
import { describe, it, expect, vi, beforeEach, afterEach, beforeAll, afterAll } from "vitest"
22
import { Task } from "../../task/Task"
33
import { ClineProvider } from "../../webview/ClineProvider"
44
import { checkpointSave, checkpointRestore, checkpointDiff, getCheckpointService } from "../index"
@@ -394,11 +394,40 @@ describe("Checkpoint functionality", () => {
394394
expect(service).toBeUndefined()
395395
})
396396

397-
it("should return undefined if service is still initializing", async () => {
397+
it("should handle initialization with isInitialCall flag", async () => {
398+
// Test that isInitialCall=true doesn't use timeout
398399
mockTask.checkpointService = undefined
399-
mockTask.checkpointServiceInitializing = true
400+
mockTask.checkpointServiceInitializing = false
401+
mockTask.enableCheckpoints = true
402+
403+
// Mock the RepoPerTaskCheckpointService.create to return our mock service
404+
const checkpointsModule = await import("../../../services/checkpoints")
405+
vi.mocked(checkpointsModule.RepoPerTaskCheckpointService.create).mockReturnValue(mockCheckpointService)
406+
407+
// Call with isInitialCall=true
408+
const service = await getCheckpointService(mockTask, { isInitialCall: true })
409+
410+
// Should create and return the service
411+
expect(service).toBe(mockCheckpointService)
412+
expect(mockTask.checkpointService).toBe(mockCheckpointService)
413+
})
414+
415+
it("should handle initialization without isInitialCall flag", async () => {
416+
// Test that without isInitialCall, it uses the default timeout
417+
mockTask.checkpointService = undefined
418+
mockTask.checkpointServiceInitializing = false
419+
mockTask.enableCheckpoints = true
420+
421+
// Mock the RepoPerTaskCheckpointService.create to return our mock service
422+
const checkpointsModule = await import("../../../services/checkpoints")
423+
vi.mocked(checkpointsModule.RepoPerTaskCheckpointService.create).mockReturnValue(mockCheckpointService)
424+
425+
// Call without isInitialCall (defaults to false)
400426
const service = await getCheckpointService(mockTask)
401-
expect(service).toBeUndefined()
427+
428+
// Should create and return the service
429+
expect(service).toBe(mockCheckpointService)
430+
expect(mockTask.checkpointService).toBe(mockCheckpointService)
402431
})
403432

404433
it("should create new service if none exists", async () => {

src/core/checkpoints/index.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ import { CheckpointServiceOptions, RepoPerTaskCheckpointService } from "../../se
1818

1919
export async function getCheckpointService(
2020
task: Task,
21-
{ interval = 250, timeout = 15_000 }: { interval?: number; timeout?: number } = {},
21+
{
22+
interval = 250,
23+
timeout = 15_000,
24+
isInitialCall = false,
25+
}: { interval?: number; timeout?: number; isInitialCall?: boolean } = {},
2226
) {
2327
if (!task.enableCheckpoints) {
2428
return undefined
@@ -67,13 +71,25 @@ export async function getCheckpointService(
6771
}
6872

6973
if (task.checkpointServiceInitializing) {
70-
await pWaitFor(
71-
() => {
74+
// For initial call during task startup, don't use timeout to allow large repos to initialize
75+
const waitOptions = isInitialCall ? { interval } : { interval, timeout }
76+
77+
try {
78+
await pWaitFor(() => {
7279
console.log("[Task#getCheckpointService] waiting for service to initialize")
7380
return !!task.checkpointService && !!task?.checkpointService?.isInitialized
74-
},
75-
{ interval, timeout },
76-
)
81+
}, waitOptions)
82+
} catch (err) {
83+
// Only disable checkpoints if this is not the initial call and we hit a timeout
84+
if (!isInitialCall) {
85+
log("[Task#getCheckpointService] timeout waiting for service initialization, disabling checkpoints")
86+
task.enableCheckpoints = false
87+
return undefined
88+
}
89+
// For initial call, continue waiting or handle the error differently
90+
throw err
91+
}
92+
7793
if (!task?.checkpointService) {
7894
task.enableCheckpoints = false
7995
return undefined

src/core/task/Task.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1661,7 +1661,8 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
16611661

16621662
private async initiateTaskLoop(userContent: Anthropic.Messages.ContentBlockParam[]): Promise<void> {
16631663
// Kicks off the checkpoints initialization process in the background.
1664-
getCheckpointService(this)
1664+
// For the initial call, don't use a timeout to allow large repositories to complete initialization
1665+
getCheckpointService(this, { isInitialCall: true })
16651666

16661667
let nextUserContent = userContent
16671668
let includeFileDetails = true

0 commit comments

Comments
 (0)