Add AI launcher sound notifications
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user