Skip to content

Commit 10535b4

Browse files
committed
feat: Make checkpoint on new task
Ensures that invoking the `newTaskTool` always creates a checkpoint, even if no files have changed. This provides a consistent state snapshot before a sub-task is initiated.
1 parent 568fb87 commit 10535b4

File tree

4 files changed

+18
-7
lines changed

4 files changed

+18
-7
lines changed

src/core/checkpoints/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ async function getInitializedCheckpointService(
152152
}
153153
}
154154

155-
export async function checkpointSave(cline: Task) {
155+
export async function checkpointSave(cline: Task, force = false) {
156156
const service = getCheckpointService(cline)
157157

158158
if (!service) {
@@ -169,7 +169,7 @@ export async function checkpointSave(cline: Task) {
169169
telemetryService.captureCheckpointCreated(cline.taskId)
170170

171171
// Start the checkpoint process in the background.
172-
return service.saveCheckpoint(`Task: ${cline.taskId}, Time: ${Date.now()}`).catch((err) => {
172+
return service.saveCheckpoint(`Task: ${cline.taskId}, Time: ${Date.now()}`, { allowEmpty: force }).catch((err) => {
173173
console.error("[Cline#checkpointSave] caught unexpected error, disabling checkpoints", err)
174174
cline.enableCheckpoints = false
175175
})

src/core/task/Task.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,8 +1658,8 @@ export class Task extends EventEmitter<ClineEvents> {
16581658

16591659
// Checkpoints
16601660

1661-
public async checkpointSave() {
1662-
return checkpointSave(this)
1661+
public async checkpointSave(force: boolean = false) {
1662+
return checkpointSave(this, force)
16631663
}
16641664

16651665
public async checkpointRestore(options: CheckpointRestoreOptions) {

src/core/tools/newTaskTool.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ export async function newTaskTool(
6969
return
7070
}
7171

72+
if (cline.enableCheckpoints) {
73+
cline.checkpointSave(true)
74+
await delay(350)
75+
}
76+
7277
// Preserve the current mode so we can resume with it later.
7378
cline.pausedModeSlug = (await provider.getState()).mode ?? defaultModeSlug
7479

src/services/checkpoints/ShadowCheckpointService.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,17 +214,23 @@ export abstract class ShadowCheckpointService extends EventEmitter {
214214
return this.shadowGitConfigWorktree
215215
}
216216

217-
public async saveCheckpoint(message: string): Promise<CheckpointResult | undefined> {
217+
public async saveCheckpoint(
218+
message: string,
219+
options?: { allowEmpty?: boolean },
220+
): Promise<CheckpointResult | undefined> {
218221
try {
219-
this.log(`[${this.constructor.name}#saveCheckpoint] starting checkpoint save`)
222+
this.log(
223+
`[${this.constructor.name}#saveCheckpoint] starting checkpoint save (allowEmpty: ${options?.allowEmpty ?? false})`,
224+
)
220225

221226
if (!this.git) {
222227
throw new Error("Shadow git repo not initialized")
223228
}
224229

225230
const startTime = Date.now()
226231
await this.stageAll(this.git)
227-
const result = await this.git.commit(message)
232+
const commitArgs = options?.allowEmpty ? { "--allow-empty": null } : undefined
233+
const result = await this.git.commit(message, commitArgs)
228234
const isFirst = this._checkpoints.length === 0
229235
const fromHash = this._checkpoints[this._checkpoints.length - 1] ?? this.baseHash!
230236
const toHash = result.commit || fromHash

0 commit comments

Comments
 (0)