pi notify and kitty mac
This commit is contained in:
@@ -6,7 +6,7 @@ include colors.conf
|
|||||||
# END_KITTY_THEME
|
# END_KITTY_THEME
|
||||||
|
|
||||||
#: Startup {{{
|
#: Startup {{{
|
||||||
shell /usr/bin/fish -l -c "zellij; exec fish -l"
|
shell /bin/sh -c 'FISH=/usr/bin/fish; [ -x /opt/homebrew/bin/fish ] && FISH=/opt/homebrew/bin/fish; exec $FISH -l -c "zellij; exec $FISH -l"'
|
||||||
#: }}
|
#: }}
|
||||||
|
|
||||||
#: Keybindings (disable kitty tabs for Zellij) {{{
|
#: Keybindings (disable kitty tabs for Zellij) {{{
|
||||||
@@ -1838,7 +1838,7 @@ background_opacity 0.9
|
|||||||
#: background_opacity. If you want to use both, you are probably
|
#: background_opacity. If you want to use both, you are probably
|
||||||
#: better off just hiding the titlebar with hide_window_decorations.
|
#: better off just hiding the titlebar with hide_window_decorations.
|
||||||
|
|
||||||
# macos_option_as_alt no
|
macos_option_as_alt yes
|
||||||
|
|
||||||
#: Use the Option key as an Alt key on macOS. With this set to no,
|
#: Use the Option key as an Alt key on macOS. With this set to no,
|
||||||
#: kitty will use the macOS native Option+Key to enter Unicode
|
#: kitty will use the macOS native Option+Key to enter Unicode
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Pi Done Notify Extension
|
* Pi Done Notify Extension
|
||||||
*
|
*
|
||||||
* Sends a native terminal notification when Pi finishes a prompt
|
* Sends a native terminal notification when Pi finishes a prompt
|
||||||
* and is waiting for input.
|
* and is waiting for input. Optionally plays a sound.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
||||||
@@ -74,9 +74,106 @@ function notify(title: string, body: string): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sound playback
|
||||||
|
function playSound(soundPath?: string): void {
|
||||||
|
const { execFile } = require("child_process");
|
||||||
|
|
||||||
|
if (process.platform === "darwin") {
|
||||||
|
// macOS: use afplay with system sound or custom path
|
||||||
|
const sound = soundPath || "/System/Library/Sounds/Glass.aiff";
|
||||||
|
execFile("afplay", [sound], (error: Error | null) => {
|
||||||
|
if (error) console.error("Failed to play sound:", error);
|
||||||
|
});
|
||||||
|
} else if (process.platform === "linux") {
|
||||||
|
// Linux: try paplay (PulseAudio), then pw-play (PipeWire), then aplay (ALSA)
|
||||||
|
const sound =
|
||||||
|
soundPath || "/usr/share/sounds/freedesktop/stereo/complete.oga";
|
||||||
|
execFile("paplay", [sound], (error: Error | null) => {
|
||||||
|
if (error) {
|
||||||
|
execFile("pw-play", [sound], (error2: Error | null) => {
|
||||||
|
if (error2) {
|
||||||
|
execFile("aplay", [sound]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (process.platform === "win32") {
|
||||||
|
// Windows: use PowerShell to play system sound
|
||||||
|
const sound =
|
||||||
|
soundPath || "C:\\Windows\\Media\\Windows Notify System Generic.wav";
|
||||||
|
execFile("powershell.exe", [
|
||||||
|
"-NoProfile",
|
||||||
|
"-Command",
|
||||||
|
`(New-Object Media.SoundPlayer '${sound}').PlaySync()`,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Settings state
|
||||||
|
interface NotifySettings {
|
||||||
|
soundEnabled: boolean;
|
||||||
|
soundPath?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CUSTOM_TYPE = "pi-done-notify-settings";
|
||||||
|
|
||||||
export default function (pi: ExtensionAPI) {
|
export default function (pi: ExtensionAPI) {
|
||||||
|
let settings: NotifySettings = {
|
||||||
|
soundEnabled: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Restore settings from session
|
||||||
|
pi.on("session_start", async (_event, ctx) => {
|
||||||
|
for (const entry of ctx.sessionManager.getEntries()) {
|
||||||
|
if (entry.type === "custom" && entry.customType === CUSTOM_TYPE) {
|
||||||
|
settings = entry.data as NotifySettings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Register /notify command
|
||||||
|
pi.registerCommand("notify", {
|
||||||
|
description: "Configure notification settings (sound on/off, or set sound path)",
|
||||||
|
handler: async (args, ctx) => {
|
||||||
|
const arg = args?.trim().toLowerCase();
|
||||||
|
|
||||||
|
if (!arg || arg === "status") {
|
||||||
|
ctx.ui.notify(
|
||||||
|
`Sound: ${settings.soundEnabled ? "on" : "off"}${settings.soundPath ? ` (${settings.soundPath})` : ""}`,
|
||||||
|
"info"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg === "on") {
|
||||||
|
settings.soundEnabled = true;
|
||||||
|
pi.appendEntry(CUSTOM_TYPE, settings);
|
||||||
|
ctx.ui.notify("Notification sound enabled", "success");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg === "off") {
|
||||||
|
settings.soundEnabled = false;
|
||||||
|
pi.appendEntry(CUSTOM_TYPE, settings);
|
||||||
|
ctx.ui.notify("Notification sound disabled", "info");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Treat as a sound path
|
||||||
|
settings.soundPath = args?.trim() || undefined;
|
||||||
|
pi.appendEntry(CUSTOM_TYPE, settings);
|
||||||
|
ctx.ui.notify(`Sound path set to: ${settings.soundPath}`, "success");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Notify on agent end
|
||||||
pi.on("agent_end", async (_event, ctx) => {
|
pi.on("agent_end", async (_event, ctx) => {
|
||||||
if (!ctx.hasUI) return;
|
if (!ctx.hasUI) return;
|
||||||
|
|
||||||
notify("Pi", "Done. Ready for input.");
|
notify("Pi", "Done. Ready for input.");
|
||||||
|
|
||||||
|
if (settings.soundEnabled) {
|
||||||
|
playSound(settings.soundPath);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user