import type { ExtensionAPI } from "@jaeswift/jae-coding-agent"; export default function (pi: ExtensionAPI) { let checkpointCount = 0; async function createCheckpoint(ctx: any, label: string): Promise { try { // Check if in git repo const statusResult = await pi.exec("git", ["status", "--porcelain"], { cwd: ctx.cwd }); if (statusResult.code !== 0) return false; // Only checkpoint if there are changes if (!statusResult.stdout.trim()) return false; // Stage all and create stash await pi.exec("git", ["add", "-A"], { cwd: ctx.cwd }); checkpointCount++; const tag = `jae-checkpoint-${checkpointCount}`; const result = await pi.exec( "git", ["stash", "push", "-m", `${tag}: ${label}`, "--include-untracked"], { cwd: ctx.cwd }, ); if (result.code === 0 && !result.stdout.includes("No local changes")) { // Immediately pop to restore working state - the stash entry remains in reflog await pi.exec("git", ["stash", "pop"], { cwd: ctx.cwd }); return true; } return false; } catch { return false; } } // Auto-checkpoint on file mutations pi.on("tool_execution_start", async (event, ctx) => { const mutatingTools = ["write", "edit"]; if (mutatingTools.includes(event.toolName)) { await createCheckpoint(ctx, `before ${event.toolName}`); } }); // Also checkpoint on bash commands that might modify files pi.on("tool_call", async (event, ctx) => { if (event.toolName === "bash") { const cmd = (event.input as any)?.command || ""; const dangerousPatterns = ["rm ", "mv ", "cp ", "sed ", "chmod ", "chown ", "truncate", "dd "]; if (dangerousPatterns.some((p) => cmd.includes(p))) { await createCheckpoint(ctx, `before bash: ${cmd.substring(0, 50)}`); } } }); pi.registerCommand("undo", { description: "Undo last file change by restoring from git stash checkpoint", handler: async (_args, ctx) => { try { // List stashes to find jae checkpoints const listResult = await pi.exec("git", ["stash", "list"], { cwd: ctx.cwd }); if (listResult.code !== 0) { ctx.ui.notify("Not in a git repository.", "error"); return; } const stashes = listResult.stdout.trim().split("\n").filter(Boolean); const jaeStashes = stashes.filter((s) => s.includes("jae-checkpoint-")); if (jaeStashes.length === 0) { ctx.ui.notify("No JAE checkpoints available to undo.", "warning"); return; } // Show what we're undoing const latest = jaeStashes[0]; const confirmed = await ctx.ui.confirm( "Undo Checkpoint", `Restore to: ${latest}\n\nThis will discard current changes and restore the checkpoint.`, ); if (!confirmed) { ctx.ui.notify("Undo cancelled.", "info"); return; } // Hard reset and apply stash const stashRef = latest.split(":")[0]; // e.g., "stash@{0}" await pi.exec("git", ["checkout", "."], { cwd: ctx.cwd }); await pi.exec("git", ["clean", "-fd"], { cwd: ctx.cwd }); const applyResult = await pi.exec("git", ["stash", "apply", stashRef], { cwd: ctx.cwd }); if (applyResult.code === 0) { ctx.ui.notify(`\u23EA Restored checkpoint: ${latest}`, "info"); } else { ctx.ui.notify(`Failed to apply stash: ${applyResult.stderr}`, "error"); } } catch (err) { ctx.ui.notify(`Undo error: ${err}`, "error"); } }, }); pi.registerCommand("checkpoints", { description: "List available JAE checkpoints", handler: async (_args, ctx) => { const listResult = await pi.exec("git", ["stash", "list"], { cwd: ctx.cwd }); if (listResult.code !== 0) { ctx.ui.notify("Not in a git repository.", "error"); return; } const stashes = listResult.stdout.trim().split("\n").filter(Boolean); const jaeStashes = stashes.filter((s) => s.includes("jae-checkpoint-")); if (jaeStashes.length === 0) { ctx.ui.notify("No JAE checkpoints found.", "info"); return; } ctx.ui.notify( `\u{1F4CC} JAE Checkpoints (${jaeStashes.length}):\n${jaeStashes.map((s) => ` ${s}`).join("\n")}`, "info", ); }, }); }