-
Notifications
You must be signed in to change notification settings - Fork 2.3k
feat: add custom checkpoint functionality #8351
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,6 +54,7 @@ export const commandIds = [ | |
"acceptInput", | ||
"focusPanel", | ||
"toggleAutoApprove", | ||
"saveCustomCheckpoint", | ||
] as const | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P2] New command id 'saveCustomCheckpoint' added. Ensure it is contributed in the extension package.json (contributes.commands) so users can invoke it from the Command Palette. |
||
|
||
export type CommandId = (typeof commandIds)[number] | ||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -233,6 +233,42 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt | |||||||||
action: "toggleAutoApprove", | ||||||||||
}) | ||||||||||
}, | ||||||||||
saveCustomCheckpoint: async () => { | ||||||||||
const visibleProvider = getVisibleProviderOrLog(outputChannel) | ||||||||||
|
||||||||||
if (!visibleProvider) { | ||||||||||
return | ||||||||||
} | ||||||||||
|
||||||||||
// Get the current task | ||||||||||
const currentTask = visibleProvider.getCurrentTask() | ||||||||||
if (!currentTask) { | ||||||||||
vscode.window.showInformationMessage(t("common:errors.no_active_task")) | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P1] i18n key mismatch: t("common:errors.no_active_task"). The en/common.json addition places 'no_active_task' at the common root, not under errors. Either switch to t("common:no_active_task") (and t("common:checkpoints_disabled")) or move these keys under common.errors in the locale file. |
||||||||||
return | ||||||||||
} | ||||||||||
|
||||||||||
// Check if checkpoints are enabled | ||||||||||
if (!currentTask.enableCheckpoints) { | ||||||||||
vscode.window.showInformationMessage(t("common:errors.checkpoints_disabled")) | ||||||||||
return | ||||||||||
} | ||||||||||
|
||||||||||
// Save a custom checkpoint with a user-provided message | ||||||||||
const message = await vscode.window.showInputBox({ | ||||||||||
prompt: t("common:checkpoint.custom_prompt"), | ||||||||||
placeHolder: t("common:checkpoint.custom_placeholder"), | ||||||||||
value: t("common:checkpoint.custom_default"), | ||||||||||
}) | ||||||||||
|
||||||||||
if (message !== undefined) { | ||||||||||
// Force save checkpoint even if no file changes with custom message | ||||||||||
await currentTask.checkpointSave(true, false, message) | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P3] Avoid blank custom checkpoint messages by defaulting on empty input.
Suggested change
|
||||||||||
await currentTask.say("checkpoint_saved_custom", message, undefined, false, undefined, undefined, { | ||||||||||
isNonInteractive: true, | ||||||||||
}) | ||||||||||
vscode.window.showInformationMessage(t("common:checkpoint.custom_saved")) | ||||||||||
} | ||||||||||
}, | ||||||||||
}) | ||||||||||
|
||||||||||
export const openClineInNewTab = async ({ context, outputChannel }: Omit<RegisterCommandOptions, "provider">) => { | ||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1000,6 +1000,35 @@ export const webviewMessageHandler = async ( | |
|
||
break | ||
} | ||
case "saveCustomCheckpoint": { | ||
const currentTask = provider.getCurrentTask() | ||
if (!currentTask) { | ||
vscode.window.showErrorMessage(t("common:checkpoint.no_active_task")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P1] i18n key mismatch: uses t("common:checkpoint.no_active_task") but en/common.json defines this key at the common root (not under checkpoint). Align to t("common:no_active_task") (same for checkpoints_disabled) or move keys under common.checkpoint consistently. |
||
break | ||
} | ||
|
||
if (!getGlobalState("enableCheckpoints")) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P2] Mixed enablement checks: here we check getGlobalState("enableCheckpoints") while the command path checks currentTask.enableCheckpoints. Pick a single source of truth (prefer task-scoped) to avoid divergence. |
||
vscode.window.showErrorMessage(t("common:checkpoint.checkpoints_disabled")) | ||
break | ||
} | ||
|
||
// Use the message text as the custom checkpoint message | ||
const customMessage = message.text || t("common:checkpoint.custom_checkpoint_default") | ||
|
||
try { | ||
// Force checkpoint creation with custom message | ||
// Parameters: force=true (create even without changes), suppressMessage=false (show in UI), customMessage | ||
await currentTask.checkpointSave(true, false, customMessage) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P2] UX consistency: the command path also emits a chat event via currentTask.say("checkpoint_saved_custom", …). Consider emitting the same here so the checkpoint appears in chat history, not just a toast. |
||
vscode.window.showInformationMessage(t("common:checkpoint.custom_checkpoint_saved")) | ||
} catch (error) { | ||
vscode.window.showErrorMessage( | ||
t("common:checkpoint.custom_checkpoint_failed", { | ||
error: error instanceof Error ? error.message : String(error), | ||
}), | ||
) | ||
} | ||
break | ||
} | ||
case "cancelTask": | ||
await provider.cancelTask() | ||
break | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ import type { HistoryItem } from "@roo-code/types" | |
|
||
import { vscode } from "@/utils/vscode" | ||
import { useCopyToClipboard } from "@/utils/clipboard" | ||
import { useExtensionState } from "@/context/ExtensionStateContext" | ||
|
||
import { DeleteTaskDialog } from "../history/DeleteTaskDialog" | ||
import { IconButton } from "./IconButton" | ||
|
@@ -20,9 +21,25 @@ export const TaskActions = ({ item, buttonsDisabled }: TaskActionsProps) => { | |
const [deleteTaskId, setDeleteTaskId] = useState<string | null>(null) | ||
const { t } = useTranslation() | ||
const { copyWithFeedback, showCopyFeedback } = useCopyToClipboard() | ||
const { enableCheckpoints } = useExtensionState() | ||
|
||
const handleCustomCheckpoint = () => { | ||
const message = prompt(t("chat:checkpoint.custom_prompt"), t("chat:checkpoint.custom_default")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P3] Using window.prompt() blocks the UI and is inconsistent with the rest of the UI patterns. Consider using a non-blocking Dialog component with proper i18n and focus handling. |
||
if (message !== null) { | ||
vscode.postMessage({ type: "saveCustomCheckpoint", text: message }) | ||
} | ||
} | ||
|
||
return ( | ||
<div className="flex flex-row items-center"> | ||
{enableCheckpoints && ( | ||
<IconButton | ||
iconClass="codicon-save" | ||
title={t("chat:checkpoint.save_custom")} | ||
disabled={buttonsDisabled} | ||
onClick={handleCustomCheckpoint} | ||
/> | ||
)} | ||
<IconButton | ||
iconClass="codicon-desktop-download" | ||
title={t("chat:task.export")} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[P3] New say type 'checkpoint_saved_custom' added. Verify all renderers that map say types handle this with an appropriate label/icon to avoid generic presentation.