add confirm-destructive, git-checkpoint, notify extensions
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Notify Extension
|
||||
*
|
||||
* Sends a native notification when the pi agent finishes and is waiting for
|
||||
* input. Useful when you step away during a long task.
|
||||
*
|
||||
* Only fires when the agent ran for longer than --notify-min-secs (default 8).
|
||||
* Short responses are silently skipped to avoid notification noise.
|
||||
*
|
||||
* Terminal detection (in priority order):
|
||||
* KITTY_WINDOW_ID → OSC 99 (Kitty)
|
||||
* WT_SESSION → Windows toast (Windows Terminal / WSL)
|
||||
* otherwise → OSC 777 (iTerm2, WezTerm, Ghostty, rxvt-unicode)
|
||||
*/
|
||||
|
||||
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
// ── Notification backends ─────────────────────────────────────────────────────
|
||||
|
||||
function notifyKitty(title: string, body: string): void {
|
||||
// OSC 99: two-part protocol — title first, then body
|
||||
process.stdout.write(`\x1b]99;i=1:d=0;${title}\x1b\\`);
|
||||
process.stdout.write(`\x1b]99;i=1:p=body;${body}\x1b\\`);
|
||||
}
|
||||
|
||||
function notifyOSC777(title: string, body: string): void {
|
||||
process.stdout.write(`\x1b]777;notify;${title};${body}\x07`);
|
||||
}
|
||||
|
||||
function notifyWindows(title: string, body: string): void {
|
||||
const type = "Windows.UI.Notifications";
|
||||
const script = [
|
||||
`[${type}.ToastNotificationManager, ${type}, ContentType = WindowsRuntime] > $null`,
|
||||
`$xml = [${type}.ToastNotificationManager]::GetTemplateContent([${type}.ToastTemplateType]::ToastText01)`,
|
||||
`$xml.GetElementsByTagName('text')[0].AppendChild($xml.CreateTextNode('${body}')) > $null`,
|
||||
`[${type}.ToastNotificationManager]::CreateToastNotifier('${title}').Show([${type}.ToastNotification]::new($xml))`,
|
||||
].join("; ");
|
||||
const { execFile } = require("node:child_process");
|
||||
execFile("powershell.exe", ["-NoProfile", "-Command", script]);
|
||||
}
|
||||
|
||||
function notify(title: string, body: string): void {
|
||||
if (process.env.KITTY_WINDOW_ID) {
|
||||
notifyKitty(title, body);
|
||||
} else if (process.env.WT_SESSION) {
|
||||
notifyWindows(title, body);
|
||||
} else {
|
||||
notifyOSC777(title, body);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Extension ─────────────────────────────────────────────────────────────────
|
||||
|
||||
export default function (pi: ExtensionAPI) {
|
||||
pi.registerFlag("notify-min-secs", {
|
||||
description: "Minimum agent run time in seconds before a notification fires (default: 8)",
|
||||
type: "number",
|
||||
default: 8,
|
||||
});
|
||||
|
||||
let startedAt: number | undefined;
|
||||
|
||||
pi.on("agent_start", async () => {
|
||||
startedAt = Date.now();
|
||||
});
|
||||
|
||||
pi.on("agent_end", async () => {
|
||||
if (startedAt === undefined) return;
|
||||
|
||||
const elapsed = (Date.now() - startedAt) / 1000;
|
||||
startedAt = undefined;
|
||||
|
||||
const minSecs = (pi.getFlag("notify-min-secs") as number | undefined) ?? 8;
|
||||
if (elapsed < minSecs) return;
|
||||
|
||||
notify("Pi", `Done (${Math.round(elapsed)}s)`);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user