Skip to content
Merged
1 change: 1 addition & 0 deletions packages/types/src/global-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export const globalSettingsSchema = z.object({
cachedChromeHostUrl: z.string().optional(),

enableCheckpoints: z.boolean().optional(),
checkpointTimeout: z.number().optional(),

ttsEnabled: z.boolean().optional(),
ttsSpeed: z.number().optional(),
Expand Down
1 change: 1 addition & 0 deletions src/__tests__/extension.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ vi.mock("../activate", () => ({

vi.mock("../i18n", () => ({
initializeI18n: vi.fn(),
t: vi.fn((key) => key),
}))

describe("extension.ts", () => {
Expand Down
45 changes: 39 additions & 6 deletions src/core/checkpoints/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,18 @@ import { DIFF_VIEW_URI_SCHEME } from "../../integrations/editor/DiffViewProvider

import { CheckpointServiceOptions, RepoPerTaskCheckpointService } from "../../services/checkpoints"

export async function getCheckpointService(
task: Task,
{ interval = 250, timeout = 15_000 }: { interval?: number; timeout?: number } = {},
) {
const WARNING_THRESHOLD_MS = 5000
const waitWarn = t("common:errors.wait_checkpoint_long_time")
const failWarn = t("common:errors.init_checkpoint_fail_long_time")

function sendCheckpointInitWarn(task: Task, checkpointWarning: string) {
task.providerRef.deref()?.postMessageToWebview({
type: "checkpointInitWarning",
checkpointWarning,
})
}

export async function getCheckpointService(task: Task, { interval = 250 }: { interval?: number } = {}) {
if (!task.enableCheckpoints) {
return undefined
}
Expand All @@ -30,6 +38,9 @@ export async function getCheckpointService(

const provider = task.providerRef.deref()

// Get checkpoint timeout from task settings (converted to milliseconds)
const checkpointTimeoutMs = task.checkpointTimeout * 1000

const log = (message: string) => {
console.log(message)

Expand Down Expand Up @@ -67,16 +78,32 @@ export async function getCheckpointService(
}

if (task.checkpointServiceInitializing) {
const checkpointInitStartTime = Date.now()
let warningShown = false

await pWaitFor(
() => {
console.log("[Task#getCheckpointService] waiting for service to initialize")
const elapsed = Date.now() - checkpointInitStartTime

// Show warning if we're past the threshold and haven't shown it yet
if (!warningShown && elapsed >= WARNING_THRESHOLD_MS) {
warningShown = true
sendCheckpointInitWarn(task, waitWarn)
}

console.log(
`[Task#getCheckpointService] waiting for service to initialize (${Math.round(elapsed / 1000)}s)`,
)
return !!task.checkpointService && !!task?.checkpointService?.isInitialized
},
{ interval, timeout },
{ interval, timeout: checkpointTimeoutMs },
)
if (!task?.checkpointService) {
sendCheckpointInitWarn(task, failWarn)
task.enableCheckpoints = false
return undefined
} else {
sendCheckpointInitWarn(task, "")
}
return task.checkpointService
}
Expand All @@ -89,8 +116,14 @@ export async function getCheckpointService(
task.checkpointServiceInitializing = true
await checkGitInstallation(task, service, log, provider)
task.checkpointService = service
if (task.enableCheckpoints) {
sendCheckpointInitWarn(task, "")
}
return service
} catch (err) {
if (err.name === "TimeoutError" && task.enableCheckpoints) {
sendCheckpointInitWarn(task, failWarn)
}
log(`[Task#getCheckpointService] ${err.message}`)
task.enableCheckpoints = false
task.checkpointServiceInitializing = false
Expand Down
4 changes: 4 additions & 0 deletions src/core/task/Task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export interface TaskOptions extends CreateTaskOptions {
apiConfiguration: ProviderSettings
enableDiff?: boolean
enableCheckpoints?: boolean
checkpointTimeout?: number
enableBridge?: boolean
fuzzyMatchThreshold?: number
consecutiveMistakeLimit?: number
Expand Down Expand Up @@ -266,6 +267,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {

// Checkpoints
enableCheckpoints: boolean
checkpointTimeout: number
checkpointService?: RepoPerTaskCheckpointService
checkpointServiceInitializing = false

Expand Down Expand Up @@ -302,6 +304,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
apiConfiguration,
enableDiff = false,
enableCheckpoints = true,
checkpointTimeout = 15,
enableBridge = false,
fuzzyMatchThreshold = 1.0,
consecutiveMistakeLimit = DEFAULT_CONSECUTIVE_MISTAKE_LIMIT,
Expand Down Expand Up @@ -361,6 +364,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
this.globalStoragePath = provider.context.globalStorageUri.fsPath
this.diffViewProvider = new DiffViewProvider(this.cwd, this)
this.enableCheckpoints = enableCheckpoints
this.checkpointTimeout = checkpointTimeout
this.enableBridge = enableBridge

this.parentTask = parentTask
Expand Down
7 changes: 7 additions & 0 deletions src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,7 @@ export class ClineProvider
apiConfiguration,
diffEnabled: enableDiff,
enableCheckpoints,
checkpointTimeout,
fuzzyMatchThreshold,
experiments,
cloudUserInfo,
Expand All @@ -875,6 +876,7 @@ export class ClineProvider
apiConfiguration,
enableDiff,
enableCheckpoints,
checkpointTimeout,
fuzzyMatchThreshold,
consecutiveMistakeLimit: apiConfiguration.consecutiveMistakeLimit,
historyItem,
Expand Down Expand Up @@ -1717,6 +1719,7 @@ export class ClineProvider
ttsSpeed,
diffEnabled,
enableCheckpoints,
checkpointTimeout,
taskHistory,
soundVolume,
browserViewportSize,
Expand Down Expand Up @@ -1829,6 +1832,7 @@ export class ClineProvider
ttsSpeed: ttsSpeed ?? 1.0,
diffEnabled: diffEnabled ?? true,
enableCheckpoints: enableCheckpoints ?? true,
checkpointTimeout: checkpointTimeout ?? 15,
shouldShowAnnouncement:
telemetrySetting !== "unset" && lastShownAnnouncementId !== this.latestAnnouncementId,
allowedCommands: mergedAllowedCommands,
Expand Down Expand Up @@ -2049,6 +2053,7 @@ export class ClineProvider
ttsSpeed: stateValues.ttsSpeed ?? 1.0,
diffEnabled: stateValues.diffEnabled ?? true,
enableCheckpoints: stateValues.enableCheckpoints ?? true,
checkpointTimeout: stateValues.checkpointTimeout ?? 15,
soundVolume: stateValues.soundVolume,
browserViewportSize: stateValues.browserViewportSize ?? "900x600",
screenshotQuality: stateValues.screenshotQuality ?? 75,
Expand Down Expand Up @@ -2478,6 +2483,7 @@ export class ClineProvider
organizationAllowList,
diffEnabled: enableDiff,
enableCheckpoints,
checkpointTimeout,
fuzzyMatchThreshold,
experiments,
cloudUserInfo,
Expand All @@ -2493,6 +2499,7 @@ export class ClineProvider
apiConfiguration,
enableDiff,
enableCheckpoints,
checkpointTimeout,
fuzzyMatchThreshold,
consecutiveMistakeLimit: apiConfiguration.consecutiveMistakeLimit,
task: text,
Expand Down
1 change: 1 addition & 0 deletions src/core/webview/__tests__/ClineProvider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,7 @@ describe("ClineProvider", () => {
remoteControlEnabled: false,
taskSyncEnabled: false,
featureRoomoteControlEnabled: false,
checkpointTimeout: 15,
}

const message: ExtensionMessage = {
Expand Down
5 changes: 5 additions & 0 deletions src/core/webview/webviewMessageHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1259,6 +1259,11 @@ export const webviewMessageHandler = async (
await updateGlobalState("enableCheckpoints", enableCheckpoints)
await provider.postStateToWebview()
break
case "checkpointTimeout":
const checkpointTimeout = message.value ?? 15
await updateGlobalState("checkpointTimeout", checkpointTimeout)
await provider.postStateToWebview()
break
case "browserViewportSize":
const browserViewportSize = message.text ?? "900x600"
await updateGlobalState("browserViewportSize", browserViewportSize)
Expand Down
2 changes: 2 additions & 0 deletions src/i18n/locales/ca/common.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/i18n/locales/de/common.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/i18n/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
"checkpoint_failed": "Failed to restore checkpoint.",
"git_not_installed": "Git is required for the checkpoints feature. Please install Git to enable checkpoints.",
"nested_git_repos_warning": "Checkpoints are disabled because a nested git repository was detected at: {{path}}. To use checkpoints, please remove or relocate this nested git repository.",
"wait_checkpoint_long_time": "Checkpoint initialization is taking longer than expected. This may indicate a large repository or slow Git operations.",
"init_checkpoint_fail_long_time": "Checkpoint initialization failed after taking long time. Checkpoints have been disabled for this task. You can disable checkpoints entirely or increase the timeout in settings.",
"no_workspace": "Please open a project folder first",
"update_support_prompt": "Failed to update support prompt",
"reset_support_prompt": "Failed to reset support prompt",
Expand Down
2 changes: 2 additions & 0 deletions src/i18n/locales/es/common.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/i18n/locales/fr/common.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/i18n/locales/hi/common.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/i18n/locales/id/common.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/i18n/locales/it/common.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/i18n/locales/ja/common.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/i18n/locales/ko/common.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/i18n/locales/nl/common.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading