/** * 🔔 pi-sounds 声音提醒系统(@jwbz/pi-sounds) * * 所有「卡流程」的地方用不同音调提醒用户: * - done agent 整个流程结束(agent_settled) * - permission 需要用户批准权限(由 permission-gate.ts 调用) * - question 需要用户回答问题(由 pi-deck-ask-question.ts 调用) * - error 网络/服务错误(after_provider_response >= 400) * * 其他扩展接入:`const { playSound } = await import("@jwbz/pi-sounds/index.ts")` * (动态 import + try-catch,模块缺失时静默降级) * * 安装:`pi install npm:@jwbz/pi-sounds` * 单文件部署:复制本文件到 ~/.pi/agent/extensions/,重启 pi 或 /reload 生效 */ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { spawn } from "node:child_process"; /** 每种场景的 beep 序列(freq Hz, 时长 ms) */ const SOUNDS = { done: "[console]::beep(880,180);[console]::beep(1174,240)", permission: "[console]::beep(659,150);[console]::beep(659,150);[console]::beep(659,150)", question: "[console]::beep(784,200);[console]::beep(988,250)", error: "[console]::beep(392,300);[console]::beep(330,300);[console]::beep(262,500)", } as const; export type SoundKind = keyof typeof SOUNDS; /** 异步播放 beep,不阻塞调用方;失败静默 */ export function playSound(kind: SoundKind): void { try { const child = spawn( "powershell.exe", [ "-NoProfile", "-NonInteractive", "-Command", `try{${SOUNDS[kind]}}catch{}`, ], { windowsHide: true, stdio: "ignore" } ); child.unref(); } catch { // 静默 } } export default function (pi: ExtensionAPI) { // agent 完全结束(无重试/压缩/后续消息) pi.on("agent_settled", () => playSound("done")); // 网络/服务错误(4xx/5xx) pi.on("after_provider_response", (event) => { if (event.status >= 400) playSound("error"); }); }