Add AI launcher sound notifications

This commit is contained in:
2026-06-21 09:46:33 +03:00
parent c0f27600cb
commit b99b9fcb7d

View File

@@ -1324,6 +1324,46 @@ with open(settings_path, "w") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
f.write("\n")
PYEOF
# Звук по завершении задачи: используем Claude Notifier из ~/.claude/hooks,
# либо минимальный fallback, если Notifier не установился.
if [ -f "$HOME/.claude/hooks/claude-notifier-on-stop.js" ]; then
stop_hook_cmd="node \"$HOME/.claude/hooks/claude-notifier-on-stop.js\""
else
cat > "$cfg/hooks/sound-on-stop.sh" <<'SOUNDEOF'
#!/usr/bin/env bash
# Minimal task-completion sound fallback
(
paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null ||
pw-play --volume=1 /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null ||
aplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null
) &
SOUNDEOF
chmod +x "$cfg/hooks/sound-on-stop.sh"
stop_hook_cmd="bash \"$cfg/hooks/sound-on-stop.sh\""
fi
python3 - "$cfg/settings.json" "$stop_hook_cmd" <<'PYEOF'
import sys, json, os
settings_path, hook_cmd = sys.argv[1:3]
data = {}
if os.path.exists(settings_path):
try:
with open(settings_path) as f:
data = json.load(f)
except Exception:
pass
data.setdefault("hooks", {}).setdefault("Stop", [{"hooks": []}])
stop_entries = data["hooks"]["Stop"]
already = any(
any(h.get("command", "") == hook_cmd for h in entry.get("hooks", []))
for entry in stop_entries
)
if not already:
stop_entries[0]["hooks"].append({"type": "command", "command": hook_cmd})
with open(settings_path, "w") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
f.write("\n")
PYEOF
}
# _apply_effort: per-launcher persistence уровня effort.
@@ -1373,8 +1413,92 @@ _build_ai_sys_prompt() {
done
echo -e "$sp"
}
_setup_codex_sound_hooks() {
local hooks_dir="$HOME/.codex/hooks"
local hooks_json="$HOME/.codex/hooks.json"
mkdir -p "$hooks_dir"
cat > "$hooks_dir/ai-setup-sound-on-stop.sh" <<'SOUNDEOF'
#!/usr/bin/env bash
# Minimal Codex turn-completion sound.
(
paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null ||
pw-play --volume=1 /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null ||
aplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null
) &
SOUNDEOF
cat > "$hooks_dir/ai-setup-sound-on-auto-compact.sh" <<'SOUNDEOF'
#!/usr/bin/env bash
# Minimal Codex context auto-compact warning sound.
(
paplay /usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga 2>/dev/null ||
pw-play --volume=1 /usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga 2>/dev/null ||
aplay /usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga 2>/dev/null
) &
SOUNDEOF
chmod +x "$hooks_dir/ai-setup-sound-on-stop.sh" "$hooks_dir/ai-setup-sound-on-auto-compact.sh"
python3 - "$hooks_json" <<'PYEOF'
import json
import os
import sys
path = sys.argv[1]
data = {}
if os.path.exists(path):
try:
with open(path) as f:
data = json.load(f)
except Exception:
print(f"WARNING: {path} is not valid JSON; Codex sound hooks were not installed", file=sys.stderr)
sys.exit(0)
if not isinstance(data, dict):
print(f"WARNING: {path} does not contain a JSON object; Codex sound hooks were not installed", file=sys.stderr)
sys.exit(0)
hooks = data.setdefault("hooks", {})
if not isinstance(hooks, dict):
print(f"WARNING: {path}.hooks is not a JSON object; Codex sound hooks were not installed", file=sys.stderr)
sys.exit(0)
def ensure_hook(event, command, matcher=None):
groups = hooks.setdefault(event, [])
for group in groups:
if matcher is not None and group.get("matcher") != matcher:
continue
if any(h.get("command") == command for h in group.get("hooks", [])):
return
target = None
for group in groups:
if matcher is None or group.get("matcher") == matcher:
target = group
break
if target is None:
target = {"hooks": []}
if matcher is not None:
target["matcher"] = matcher
groups.append(target)
target.setdefault("hooks", []).append({
"type": "command",
"command": command,
"timeout": 5,
})
ensure_hook("Stop", 'bash "$HOME/.codex/hooks/ai-setup-sound-on-stop.sh"')
ensure_hook("PreCompact", 'bash "$HOME/.codex/hooks/ai-setup-sound-on-auto-compact.sh"', "auto")
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
f.write("\n")
PYEOF
}
HELPEREOF
chmod +x "$HELPERS_FILE"
source "$HELPERS_FILE"
_setup_codex_sound_hooks || warn "Не удалось установить Codex sound hooks"
# === ai-gpt ===
cat > "$BIN_DIR/ai-gpt" << 'GPTEOF'
@@ -1405,6 +1529,7 @@ if [ -z "$codex_bin" ] || [ ! -f "$codex_bin" ]; then
fi
_build_ai_sys_prompt > /dev/null # сохраняет в ~/.codex/AGENTS.md (codex читает авто)
_setup_codex_sound_hooks
exec "$codex_bin" --dangerously-bypass-approvals-and-sandbox "$@"
GPTEOF
chmod +x "$BIN_DIR/ai-gpt"
@@ -1970,7 +2095,14 @@ source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/ai-api-helpers.sh" 2>/dev/
# agy нативно подтягивает правила и проектные .md файлы,
# поэтому ручная инъекция SYS_PROMPT больше не требуется.
exec "$agy_bin" --dangerously-skip-permissions "$@"
"$agy_bin" --dangerously-skip-permissions "$@"
agy_exit=$?
(
paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null ||
pw-play --volume=1 /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null ||
aplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null
) &
exit $agy_exit
GEMINIEOF
chmod +x "$BIN_DIR/ai-gemini"
# Подменяем путь к agy, если BIN_DIR отличается от ~/.local/bin
@@ -2002,7 +2134,7 @@ if [ "$USE_VLESS" -eq 1 ]; then
sed -i 's/^claude --dangerously-skip-permissions/proxychains4 -f "\$HOME\/\.proxychains-xray\.conf" claude --dangerously-skip-permissions/' "$BIN_DIR/ai-kimi"
sed -i 's/^claude --dangerously-skip-permissions/proxychains4 -f "\$HOME\/\.proxychains-xray\.conf" claude --dangerously-skip-permissions/' "$BIN_DIR/ai-glm"
sed -i 's/^claude --dangerously-skip-permissions/proxychains4 -f "\$HOME\/\.proxychains-xray\.conf" claude --dangerously-skip-permissions/' "$BIN_DIR/ai-openrouter"
sed -i 's/^\([[:space:]]*\)exec "\$agy_bin"/\1exec proxychains4 -f "\$HOME\/\.proxychains-xray\.conf" "\$agy_bin"/' "$BIN_DIR/ai-gemini"
sed -i 's|^\([[:space:]]*\)"\$agy_bin" --dangerously-skip-permissions "\$@"|\1proxychains4 -f "\$HOME/.proxychains-xray.conf" "\$agy_bin" --dangerously-skip-permissions "\$@"|' "$BIN_DIR/ai-gemini"
sed -i 's/^claude --dangerously-skip-permissions/proxychains4 -f "\$HOME\/\.proxychains-xray\.conf" claude --dangerously-skip-permissions/' "$BIN_DIR/ai-claude"
success "proxychains4 интегрирован"
fi