peon is done
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Notify Extension
|
||||
*
|
||||
* Sends a notification when Pi finishes a prompt or when interactive tools are called.
|
||||
* If on SSH/remote, SSHs back to Linux PC to play sound + show notification.
|
||||
*/
|
||||
|
||||
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
// ============ CONFIGURATION ============
|
||||
const REMOTE_HOST = "linux-pc"; // SSH host for remote notifications
|
||||
const LOCAL_SOUND_MAC = "/System/Library/Sounds/Glass.aiff";
|
||||
const LOCAL_SOUND_LINUX = "/run/current-system/sw/share/sounds/freedesktop/stereo/window-attention.oga";
|
||||
// =======================================
|
||||
|
||||
function isSSH(): boolean {
|
||||
if (
|
||||
process.env.SSH_CONNECTION ||
|
||||
process.env.SSH_CLIENT ||
|
||||
process.env.SSH_TTY
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
// Check for sshd-session process (works in tmux/zellij)
|
||||
try {
|
||||
const { execSync } = require("child_process");
|
||||
const result = execSync("pgrep -u $USER -f sshd-session 2>/dev/null", {
|
||||
encoding: "utf-8",
|
||||
timeout: 1000,
|
||||
});
|
||||
return result.trim().length > 0;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function notifyRemote(message: string): void {
|
||||
const { exec } = require("child_process");
|
||||
exec(
|
||||
`ssh -o ConnectTimeout=2 -o BatchMode=yes ${REMOTE_HOST} "pw-play /run/current-system/sw/share/sounds/freedesktop/stereo/window-attention.oga & notify-send -i ~/.pi/agent/extensions/assets/pi-logo.svg 'Pi' '${message}'"`,
|
||||
{ timeout: 5000 },
|
||||
);
|
||||
}
|
||||
|
||||
function notifyLocal(message: string): void {
|
||||
const { execFile, exec } = require("child_process");
|
||||
if (process.platform === "darwin") {
|
||||
execFile("afplay", [LOCAL_SOUND_MAC]);
|
||||
} else if (process.platform === "linux") {
|
||||
execFile(
|
||||
"pw-play",
|
||||
[LOCAL_SOUND_LINUX],
|
||||
(err: any) => {
|
||||
if (err) console.error("pw-play error:", err);
|
||||
},
|
||||
);
|
||||
exec(
|
||||
`notify-send -i ~/.pi/agent/extensions/assets/pi-logo.svg 'Pi' '${message}'`,
|
||||
(err: any) => {
|
||||
if (err) console.error("notify-send error:", err);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function sendNotification(message: string = "Done. Ready for input."): void {
|
||||
if (process.platform === "darwin" || isSSH()) {
|
||||
notifyRemote(message);
|
||||
}
|
||||
|
||||
// always notify locally too
|
||||
notifyLocal(message);
|
||||
}
|
||||
|
||||
const ACTION_NOTIFY_TOOLS = new Set(["question", "questionnaire"]);
|
||||
|
||||
export default function (pi: ExtensionAPI) {
|
||||
pi.on("agent_end", async (_event, ctx) => {
|
||||
if (!ctx.hasUI) return;
|
||||
sendNotification();
|
||||
});
|
||||
|
||||
// Notify when interactive tools are called so the user notices prompts immediately
|
||||
pi.on("tool_call", async (event, ctx) => {
|
||||
if (!ctx.hasUI) return;
|
||||
if (!ACTION_NOTIFY_TOOLS.has(event.toolName)) return;
|
||||
sendNotification("Question requires input");
|
||||
});
|
||||
|
||||
// Simple test command
|
||||
pi.registerCommand("notify", {
|
||||
description: "Test notification",
|
||||
handler: async (_args, ctx) => {
|
||||
sendNotification();
|
||||
ctx.ui.notify("Notification sent!", "info");
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user