Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/core/checkpoints/__tests__/checkpoint.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ describe("Checkpoint functionality", () => {
]
})

it("should show diff for full mode", async () => {
it("should show diff for to-current mode", async () => {
const mockChanges = [
{
paths: { absolute: "/test/file.ts", relative: "file.ts" },
Expand All @@ -295,7 +295,7 @@ describe("Checkpoint functionality", () => {
await checkpointDiff(mockTask, {
ts: 4,
commitHash: "commit2",
mode: "full",
mode: "to-current",
})

expect(mockCheckpointService.getDiff).toHaveBeenCalledWith({
Expand All @@ -304,7 +304,7 @@ describe("Checkpoint functionality", () => {
})
expect(vscode.commands.executeCommand).toHaveBeenCalledWith(
"vscode.changes",
"Changes since task started",
"Changes to current workspace",
expect.any(Array),
)
})
Expand Down Expand Up @@ -361,7 +361,7 @@ describe("Checkpoint functionality", () => {
await checkpointDiff(mockTask, {
ts: 4,
commitHash: "commit2",
mode: "full",
mode: "to-current",
})

expect(vscode.window.showInformationMessage).toHaveBeenCalledWith("No changes found.")
Expand All @@ -374,7 +374,7 @@ describe("Checkpoint functionality", () => {
await checkpointDiff(mockTask, {
ts: 4,
commitHash: "commit2",
mode: "full",
mode: "to-current",
})

expect(mockTask.enableCheckpoints).toBe(false)
Expand Down
61 changes: 47 additions & 14 deletions src/core/checkpoints/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,10 +270,16 @@ export async function checkpointRestore(
}

export type CheckpointDiffOptions = {
ts: number
ts?: number
previousCommitHash?: string
commitHash: string
mode: "full" | "checkpoint"
/**
* from-init: Compare from the first checkpoint to the selected checkpoint.
* checkpoint: Compare the selected checkpoint to the next checkpoint.
* to-current: Compare the selected checkpoint to the current workspace.
* full: Compare from the first checkpoint to the current workspace.
*/
mode: "from-init" | "checkpoint" | "to-current" | "full"
}

export async function checkpointDiff(task: Task, { ts, previousCommitHash, commitHash, mode }: CheckpointDiffOptions) {
Expand All @@ -285,21 +291,48 @@ export async function checkpointDiff(task: Task, { ts, previousCommitHash, commi

TelemetryService.instance.captureCheckpointDiffed(task.taskId)

let prevHash = commitHash
let nextHash: string | undefined = undefined
let fromHash: string | undefined
let toHash: string | undefined
let title: string

if (mode !== "full") {
const checkpoints = task.clineMessages.filter(({ say }) => say === "checkpoint_saved").map(({ text }) => text!)
const idx = checkpoints.indexOf(commitHash)
if (idx !== -1 && idx < checkpoints.length - 1) {
nextHash = checkpoints[idx + 1]
} else {
nextHash = undefined
}
const checkpoints = task.clineMessages.filter(({ say }) => say === "checkpoint_saved").map(({ text }) => text!)

if (["from-init", "full"].includes(mode) && checkpoints.length < 1) {
vscode.window.showInformationMessage("No first checkpoint to compare.")
return
}

const idx = checkpoints.indexOf(commitHash)
switch (mode) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider extracting this switch logic into a separate function for better testability and readability. Something like:

This would make the logic easier to unit test independently.

case "checkpoint":
fromHash = commitHash
toHash = idx !== -1 && idx < checkpoints.length - 1 ? checkpoints[idx + 1] : undefined
title = "Changes compare with next checkpoint"
break
case "from-init":
fromHash = checkpoints[0]
toHash = commitHash
title = "Changes since first checkpoint"
break
case "to-current":
fromHash = commitHash
toHash = undefined
title = "Changes to current workspace"
break
case "full":
fromHash = checkpoints[0]
toHash = undefined
title = "Changes since first checkpoint"
break
}

if (!fromHash) {
vscode.window.showInformationMessage("No previous checkpoint to compare.")
return
}

try {
const changes = await service.getDiff({ from: prevHash, to: nextHash })
const changes = await service.getDiff({ from: fromHash, to: toHash })

if (!changes?.length) {
vscode.window.showInformationMessage("No changes found.")
Expand All @@ -308,7 +341,7 @@ export async function checkpointDiff(task: Task, { ts, previousCommitHash, commi

await vscode.commands.executeCommand(
"vscode.changes",
mode === "full" ? "Changes since task started" : "Changes compare with next checkpoint",
title,
changes.map((change) => [
vscode.Uri.file(change.paths.absolute),
vscode.Uri.parse(`${DIFF_VIEW_URI_SCHEME}:${change.paths.relative}`).with({
Expand Down
4 changes: 2 additions & 2 deletions src/shared/WebviewMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,10 +306,10 @@ export interface WebviewMessage {
}

export const checkoutDiffPayloadSchema = z.object({
ts: z.number(),
ts: z.number().optional(),
previousCommitHash: z.string().optional(),
commitHash: z.string(),
mode: z.enum(["full", "checkpoint"]),
mode: z.enum(["full", "checkpoint", "from-init", "to-current"]),
})

export type CheckpointDiffPayload = z.infer<typeof checkoutDiffPayloadSchema>
Expand Down
1 change: 1 addition & 0 deletions webview-ui/src/components/chat/ChatRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ interface ChatRowProps {
onFollowUpUnmount?: () => void
isFollowUpAnswered?: boolean
editable?: boolean
hasCheckpoint?: boolean
}

// eslint-disable-next-line @typescript-eslint/no-empty-object-type
Expand Down
2 changes: 2 additions & 0 deletions webview-ui/src/components/chat/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1525,6 +1525,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
/>
)
}
const hasCheckpoint = modifiedMessages.some((message) => message.say === "checkpoint_saved")

// regular message
return (
Expand Down Expand Up @@ -1559,6 +1560,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
return tool.tool === "updateTodoList" && enableButtons && !!primaryButtonText
})()
}
hasCheckpoint={hasCheckpoint}
/>
)
},
Expand Down
Loading
Loading