/** * Confirm Destructive Actions Extension * * Prompts for confirmation before destructive session actions (clear, switch, branch). * Demonstrates how to cancel session events using the before_* events. */ import type { ExtensionAPI, SessionBeforeSwitchEvent, SessionMessageEntry } from "@mariozechner/pi-coding-agent"; // Flag to track if we're in the middle of an edit-session reload let skipNextSwitchConfirm = false; export default function (pi: ExtensionAPI) { // Listen for edit-session reload signal pi.events.on("edit-session:reload", () => { skipNextSwitchConfirm = true; }); pi.on("session_before_switch", async (event: SessionBeforeSwitchEvent, ctx) => { // Skip confirmation if this is an edit-session reload if (skipNextSwitchConfirm) { skipNextSwitchConfirm = false; // Reset the flag return; } if (event.reason === "new") { // Emit event for sound extensions (before hasUI check) pi.events.emit("peon:input_required", { source: "confirm-destructive", action: "clear-session" }); if (!ctx.hasUI) return; const confirmed = await ctx.ui.confirm( "Clear session?", "This will delete all messages in the current session.", ); if (!confirmed) { ctx.ui.notify("Clear cancelled", "info"); return { cancel: true }; } return; } // reason === "resume" - check if there are unsaved changes (messages since last assistant response) const entries = ctx.sessionManager.getEntries(); const hasUnsavedWork = entries.some( (e): e is SessionMessageEntry => e.type === "message" && e.message.role === "user", ); if (hasUnsavedWork) { // Emit event for sound extensions (before hasUI check) pi.events.emit("peon:input_required", { source: "confirm-destructive", action: "switch-session" }); if (!ctx.hasUI) return; const confirmed = await ctx.ui.confirm( "Switch session?", "You have messages in the current session. Switch anyway?", ); if (!confirmed) { ctx.ui.notify("Switch cancelled", "info"); return { cancel: true }; } } }); pi.on("session_before_fork", async (event, ctx) => { // Emit event for sound extensions (before hasUI check) pi.events.emit("peon:input_required", { source: "confirm-destructive", action: "fork-session" }); if (!ctx.hasUI) return; const choice = await ctx.ui.select(`Fork from entry ${event.entryId.slice(0, 8)}?`, [ "Yes, create fork", "No, stay in current session", ]); if (choice !== "Yes, create fork") { ctx.ui.notify("Fork cancelled", "info"); return { cancel: true }; } }); }