diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a065100..87d4c37 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -59,6 +59,12 @@ jobs: - features: auto-header baseImage: ubuntu:latest + # peon-ping - works on any base image with curl and python3 + - features: peon-ping + baseImage: ubuntu:latest + - features: peon-ping + baseImage: mcr.microsoft.com/devcontainers/base:ubuntu + steps: - name: Checkout uses: actions/checkout@v4 diff --git a/README.md b/README.md index bc07f4e..3e7a5c9 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,19 @@ Automatically configures file headers with customizable templates based on proje [๐Ÿ“– Documentation](./features/auto-header/README.md) +### peon-ping + +Installs [peon-ping](https://peonping.com/) for game character voice notifications when your AI coding agent finishes or needs permission. Includes the Peon Pet VS Code extension. + +**Key benefits:** +- Sound notifications from 165+ packs (Warcraft, StarCraft, Portal, Zeldaโ€ฆ) +- Multi-IDE hooks: Claude Code, Copilot, Cursor, Codex, and more +- Animated Peon Pet sidebar companion in VS Code +- Devcontainer-aware audio relay to host machine +- Non-interactive, idempotent installation + +[๐Ÿ“– Documentation](./features/peon-ping/README.md) + ## Usage Features from this repository are available via GitHub Container Registry. Reference them in your `devcontainer.json`: @@ -142,7 +155,8 @@ Features from this repository are available via GitHub Container Registry. Refer "ghcr.io/helpers4/devcontainer/angular-dev:1": {}, "ghcr.io/helpers4/devcontainer/shell-history-per-project:1": {}, "ghcr.io/helpers4/devcontainer/git-absorb:1": {}, - "ghcr.io/helpers4/devcontainer/local-mounts:1": {} + "ghcr.io/helpers4/devcontainer/local-mounts:1": {}, + "ghcr.io/helpers4/devcontainer/peon-ping:1": {} } } ``` @@ -160,6 +174,7 @@ Features from this repository are available via GitHub Container Registry. Refer | [shell-history-per-project](./features/shell-history-per-project) | Per-project shell history persistence with multi-shell auto-detection | [README](./features/shell-history-per-project/README.md) | | [git-absorb](./features/git-absorb) | Automatic absorption of staged changes into logical commits | [README](./features/git-absorb/README.md) | | [local-mounts](./features/local-mounts) | Mount local Git, SSH, GPG, and npm config into devcontainer | [README](./features/local-mounts/README.md) | +| [peon-ping](./features/peon-ping) | AI agent sound notifications with multi-IDE hooks and Peon Pet extension | [README](./features/peon-ping/README.md) | ## Development diff --git a/src/peon-ping/README.md b/src/peon-ping/README.md new file mode 100644 index 0000000..302424f --- /dev/null +++ b/src/peon-ping/README.md @@ -0,0 +1,139 @@ +# Peon Ping โ€” AI Agent Sound Notifications (peon-ping) + +Installs [peon-ping](https://peonping.com/) and the [Peon Pet](https://marketplace.visualstudio.com/items?itemName=smcqueen.vscode-peon-pet) VS Code extension for game character voice notifications when your AI coding agent finishes or needs permission. + +Supports **Claude Code**, **GitHub Copilot**, **Cursor**, **OpenAI Codex**, and [many more IDEs](https://github.com/PeonPing/peon-ping#multi-ide-support). + +## Features + +- **Sound notifications**: Warcraft, StarCraft, Portal, Zelda and 165+ sound packs +- **Multi-IDE hooks**: Claude Code (built-in), Copilot, Cursor, Codex via adapters +- **Peon Pet extension**: Animated orc sidebar companion reacting to agent events +- **Devcontainer-aware**: Auto-routes audio to host via relay (`host.docker.internal:19998`) +- **Non-interactive**: Fully automated, idempotent installation + +## Usage + +### Basic Usage + +```json +{ + "features": { + "ghcr.io/helpers4/devcontainer/peon-ping:1": {} + } +} +``` + +This installs peon-ping with the default 5 packs (peon, peasant, sc_kerrigan, sc_battlecruiser, glados), registers Claude Code hooks, and installs the Peon Pet VS Code extension. + +### With All Packs + +```json +{ + "features": { + "ghcr.io/helpers4/devcontainer/peon-ping:1": { + "packs": "all" + } + } +} +``` + +### Copilot Only + Specific Packs + +```json +{ + "features": { + "ghcr.io/helpers4/devcontainer/peon-ping:1": { + "packs": "peon,glados,murloc", + "ideSetup": "vscode", + "volume": "0.3" + } + } +} +``` + +## Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `packs` | string | `default` | Sound packs: `default` (5 curated), `all` (165+), or CSV (e.g. `peon,glados,murloc`) | +| `noRc` | boolean | `true` | Skip `.bashrc`/`.zshrc` modifications (recommended for devcontainers) | +| `ideSetup` | string | `vscode` | IDEs to configure: `all` (vscode + cursor + codex), `none`, or CSV (e.g. `vscode,cursor`) | +| `volume` | string | `0.5` | Default volume level (0.0โ€“1.0) | + +## Audio in Devcontainers + +peon-ping auto-detects devcontainer environments and routes audio to your host machine via a lightweight relay. **You must start the relay on your host:** + +```bash +# On your HOST machine โ€” not inside the container +peon relay --daemon +``` + +The container sends audio requests to `host.docker.internal:19998` automatically. No port forwarding configuration needed. + +### Relay Commands + +```bash +peon relay --daemon # Start in background +peon relay --stop # Stop relay +peon relay --status # Check status +peon relay --port=12345 # Custom port +``` + +> **Note**: Install peon-ping on your host machine first: `brew install PeonPing/tap/peon-ping` (macOS) or `curl -fsSL https://peonping.com/install | bash` + +## IDE-Specific Setup + +### Claude Code + +Hooks are registered automatically by the peon-ping installer in `~/.claude/settings.json`. No extra configuration needed. + +### GitHub Copilot + +The feature installs a helper script. Run it from your workspace root to generate `.github/hooks/hooks.json`: + +```bash +peon-ping-copilot-setup +``` + +Or add it to your devcontainer.json: + +```json +{ + "postCreateCommand": "peon-ping-copilot-setup" +} +``` + +This creates hooks for `sessionStart`, `userPromptSubmitted`, `postToolUse`, and `errorOccurred` events using the Copilot adapter. + +### Cursor + +When `setupCursorHooks` is `true`, hooks are written to `~/.cursor/hooks.json` automatically. Events: `afterAgentResponse`, `stop`. + +### OpenAI Codex + +When `setupCodexHooks` is `true`, the notify config is added to `~/.codex/config.toml` automatically. + +### Other IDEs + +peon-ping provides adapters for [15+ IDEs](https://github.com/PeonPing/peon-ping#multi-ide-support) including Amp, Gemini CLI, Windsurf, Kiro, OpenCode, and more. After installation, adapters are available at `~/.claude/hooks/peon-ping/adapters/`. + +## Peon Pet Extension + +The [Peon Pet](https://marketplace.visualstudio.com/items?itemName=smcqueen.vscode-peon-pet) VS Code extension adds an animated orc to your sidebar that reacts to peon-ping events. It polls `~/.claude/hooks/peon-ping/.state.json` every 200ms โ€” no daemon needed. + +Settings: +- `peon-pet.size`: `small`, `medium` (default), or `large` +- `peon-pet.character`: `orc` (default) + +## Quick Controls (Inside Container) + +```bash +peon status # Check if active +peon pause # Mute sounds +peon resume # Unmute +peon volume 0.3 # Change volume +peon packs use glados # Switch pack +peon packs list # List installed packs +``` diff --git a/src/peon-ping/devcontainer-feature.json b/src/peon-ping/devcontainer-feature.json new file mode 100644 index 0000000..e07d3bf --- /dev/null +++ b/src/peon-ping/devcontainer-feature.json @@ -0,0 +1,42 @@ +{ + "id": "peon-ping", + "version": "1.0.0", + "name": "Peon Ping โ€” AI Agent Sound Notifications", + "description": "Installs peon-ping and the Peon Pet VS Code extension for game character voice notifications when your AI coding agent finishes or needs permission. Supports VS Code/Copilot, Cursor, and Codex with audio relay for devcontainers.", + "documentationURL": "https://github.com/helpers4/devcontainer/tree/main/src/peon-ping", + "options": { + "packs": { + "type": "string", + "default": "default", + "description": "Sound packs to install: 'default' (peon, peasant, sc_kerrigan, sc_battlecruiser, glados), 'all', or a comma-separated list (e.g. 'peon,glados,murloc')" + }, + "noRc": { + "type": "boolean", + "default": true, + "description": "Skip .bashrc/.zshrc modifications (recommended for devcontainers)" + }, + "ideSetup": { + "type": "string", + "default": "vscode", + "description": "IDEs to configure: 'all' (vscode + cursor + codex), 'none', or a comma-separated list (e.g. 'vscode,cursor')" + }, + "volume": { + "type": "string", + "default": "0.5", + "description": "Default volume level (0.0 โ€“ 1.0)" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "smcqueen.vscode-peon-pet" + ], + "settings": { + "peon-pet.size": "medium" + } + } + }, + "installsAfter": [ + "ghcr.io/devcontainers/features/common-utils" + ] +} \ No newline at end of file diff --git a/src/peon-ping/install.sh b/src/peon-ping/install.sh new file mode 100644 index 0000000..df30407 --- /dev/null +++ b/src/peon-ping/install.sh @@ -0,0 +1,326 @@ +#!/usr/bin/env bash + +# Peon Ping DevContainer Feature +# Copyright (c) 2025 helpers4 +# Licensed under AGPL-3.0 - see LICENSE file for details +# +# Installs peon-ping and configures multi-IDE hooks for AI agent sound notifications + +set -e + +# Feature options (env vars auto-generated from devcontainer-feature.json) +PACKS="${PACKS:-"default"}" +NO_RC="${NORC:-"true"}" +IDE_SETUP="${IDESETUP:-"vscode"}" +VOLUME="${VOLUME:-"0.5"}" + +USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}" + +if [ "$(id -u)" -ne 0 ]; then + echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' + exit 1 +fi + +# Determine the appropriate non-root user +if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then + USERNAME="" + POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)") + for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do + if id -u "${CURRENT_USER}" > /dev/null 2>&1; then + USERNAME="${CURRENT_USER}" + break + fi + done + if [ "${USERNAME}" = "" ]; then + USERNAME=root + fi +elif [ "${USERNAME}" = "none" ] || ! id -u "${USERNAME}" > /dev/null 2>&1; then + USERNAME=root +fi + +USER_HOME=$(eval echo "~${USERNAME}") + +# Clean up +cleanup() { + rm -rf /var/lib/apt/lists/* +} + +trap cleanup EXIT + +# Ensure apt is in non-interactive mode +export DEBIAN_FRONTEND=noninteractive + +echo "๐ŸŽฎ Installing peon-ping feature..." +echo " Username: ${USERNAME}" +echo " Packs: ${PACKS}" +echo " Volume: ${VOLUME}" + +# โ”€โ”€ Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +apt_get_update() { + if [ "$(find /var/lib/apt/lists/* 2>/dev/null | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update -y + fi +} + +check_packages() { + if ! dpkg -s "$@" > /dev/null 2>&1; then + apt_get_update + apt-get -y install --no-install-recommends "$@" + fi +} + +# โ”€โ”€ Prerequisites โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +echo "๐Ÿ”ง Installing prerequisites..." +check_packages curl ca-certificates python3 alsa-utils + +# โ”€โ”€ Install peon-ping โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +echo "๐Ÿ”ง Installing peon-ping..." + +INSTALLER_ARGS="--global" + +if [ "${PACKS}" = "all" ]; then + INSTALLER_ARGS="${INSTALLER_ARGS} --all" +elif [ "${PACKS}" != "default" ]; then + INSTALLER_ARGS="${INSTALLER_ARGS} --packs=${PACKS}" +fi + +if [ "${NO_RC}" = "true" ]; then + INSTALLER_ARGS="${INSTALLER_ARGS} --no-rc" +fi + +# Run installer as the target user (peon-ping handles non-interactive detection) +# The installer may exit non-zero if its sound test fails (no audio device during +# Docker build). We tolerate that and verify the actual installation ourselves. +su - "${USERNAME}" -c "curl -fsSL https://raw.githubusercontent.com/PeonPing/peon-ping/main/install.sh | bash -s -- ${INSTALLER_ARGS}" || \ + echo "โš ๏ธ peon-ping installer exited with errors (sound test failure during build is expected)" + +# Verify the binary was actually installed (fail now if curl/download truly failed) +PEON_BIN="${USER_HOME}/.local/bin/peon" +if [ ! -x "${PEON_BIN}" ] && ! su - "${USERNAME}" -c "command -v peon" > /dev/null 2>&1; then + echo "โŒ peon binary not found after installation โ€” install truly failed" + exit 1 +fi + +# โ”€โ”€ Set volume โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +PEON_CONFIG_DIR="${USER_HOME}/.claude/hooks/peon-ping" +PEON_CONFIG="${PEON_CONFIG_DIR}/config.json" + +if [ -f "${PEON_CONFIG}" ] && command -v python3 > /dev/null 2>&1; then + echo "๐Ÿ”ง Setting volume to ${VOLUME}..." + python3 << PYEOF +import json +path = "${PEON_CONFIG}" +with open(path) as f: + cfg = json.load(f) +cfg["volume"] = float("${VOLUME}") +with open(path, "w") as f: + json.dump(cfg, f, indent=2) + f.write("\n") +PYEOF +fi + +# โ”€โ”€ Hook configuration helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +# Parse ideSetup option into a lookup function +# "all" โ†’ every IDE, "none" โ†’ skip, csv โ†’ only listed +# "vscode" and "copilot" are treated as synonyms +ide_enabled() { + local ide="$1" + local setup="${IDE_SETUP}" + case "${setup}" in + all) return 0 ;; + none) return 1 ;; + *) echo ",${setup}," | sed 's/copilot/vscode/gi; s/vscode/vscode/gi' | grep -qi ",${ide}," ;; + esac +} + +# Merge peon-ping hooks into a JSON hooks file (idempotent). +# Usage: merge_hooks_json +merge_hooks_json() { + local target="$1" + local new_hooks="$2" + + python3 << PYEOF +import json, os + +target_path = "${target}" +new_hooks = json.loads("""${new_hooks}""") + +if os.path.exists(target_path): + with open(target_path) as f: + data = json.load(f) +else: + os.makedirs(os.path.dirname(target_path), exist_ok=True) + data = {"version": 1, "hooks": {}} + +existing_hooks = data.setdefault("hooks", {}) + +for event, entries in new_hooks.items(): + event_list = existing_hooks.setdefault(event, []) + existing_cmds = [e.get("bash", e.get("command", "")) for e in event_list] + for entry in entries: + cmd = entry.get("bash", entry.get("command", "")) + if not any("peon-ping" in c for c in existing_cmds): + event_list.append(entry) + +data["hooks"] = existing_hooks +with open(target_path, "w") as f: + json.dump(data, f, indent=2) + f.write("\n") +PYEOF +} + +# โ”€โ”€ GitHub Copilot hooks โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +if ide_enabled vscode; then + echo "๐Ÿ”ง Configuring GitHub Copilot hooks..." + + # Create a helper script that generates .github/hooks/hooks.json in the + # current workspace. Users can call it manually or via postCreateCommand. + cat > /usr/local/bin/peon-ping-copilot-setup << 'SETUPEOF' +#!/usr/bin/env bash +# Generate .github/hooks/hooks.json for GitHub Copilot agent mode. +# Run from the workspace root or pass the target directory as $1. +set -e + +TARGET_DIR="${1:-.}" +HOOKS_DIR="${TARGET_DIR}/.github/hooks" +HOOKS_FILE="${HOOKS_DIR}/hooks.json" + +mkdir -p "${HOOKS_DIR}" + +if [ -f "${HOOKS_FILE}" ]; then + python3 << 'PYEOF' +import json, os + +path = os.environ.get("HOOKS_FILE", ".github/hooks/hooks.json") +if not os.path.exists(path): + exit(0) + +with open(path) as f: + data = json.load(f) + +hooks = data.setdefault("hooks", {}) +new_entries = { + "sessionStart": [{"type": "command", "bash": "bash ~/.claude/hooks/peon-ping/adapters/copilot.sh sessionStart"}], + "userPromptSubmitted": [{"type": "command", "bash": "bash ~/.claude/hooks/peon-ping/adapters/copilot.sh userPromptSubmitted"}], + "postToolUse": [{"type": "command", "bash": "bash ~/.claude/hooks/peon-ping/adapters/copilot.sh postToolUse"}], + "errorOccurred": [{"type": "command", "bash": "bash ~/.claude/hooks/peon-ping/adapters/copilot.sh errorOccurred"}] +} + +for event, entries in new_entries.items(): + event_list = hooks.setdefault(event, []) + existing_cmds = [e.get("bash", e.get("command", "")) for e in event_list] + for entry in entries: + if not any("peon-ping" in c for c in existing_cmds): + event_list.append(entry) + +data["hooks"] = hooks +with open(path, "w") as f: + json.dump(data, f, indent=2) + f.write("\n") +PYEOF +else + cat > "${HOOKS_FILE}" << 'JSONEOF' +{ + "version": 1, + "hooks": { + "sessionStart": [ + { "type": "command", "bash": "bash ~/.claude/hooks/peon-ping/adapters/copilot.sh sessionStart" } + ], + "userPromptSubmitted": [ + { "type": "command", "bash": "bash ~/.claude/hooks/peon-ping/adapters/copilot.sh userPromptSubmitted" } + ], + "postToolUse": [ + { "type": "command", "bash": "bash ~/.claude/hooks/peon-ping/adapters/copilot.sh postToolUse" } + ], + "errorOccurred": [ + { "type": "command", "bash": "bash ~/.claude/hooks/peon-ping/adapters/copilot.sh errorOccurred" } + ] + } +} +JSONEOF +fi + +echo "โœ… Copilot hooks written to ${HOOKS_FILE}" +SETUPEOF + chmod +x /usr/local/bin/peon-ping-copilot-setup + + echo " โœ… Helper installed: peon-ping-copilot-setup" + echo " Run it from your workspace root (or add to postCreateCommand) to generate .github/hooks/hooks.json" +fi + +# โ”€โ”€ Cursor hooks โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +if ide_enabled cursor; then + echo "๐Ÿ”ง Configuring Cursor hooks..." + + CURSOR_HOOKS_JSON='{ + "afterAgentResponse": [{"command": "bash ~/.claude/hooks/peon-ping/adapters/cursor.sh afterAgentResponse"}], + "stop": [{"command": "bash ~/.claude/hooks/peon-ping/adapters/cursor.sh stop"}] + }' + + CURSOR_HOOKS_FILE="${USER_HOME}/.cursor/hooks.json" + merge_hooks_json "${CURSOR_HOOKS_FILE}" "${CURSOR_HOOKS_JSON}" + chown -R "${USERNAME}:${USERNAME}" "${USER_HOME}/.cursor" 2>/dev/null || true + + echo " โœ… Cursor hooks written to ${CURSOR_HOOKS_FILE}" +fi + +# โ”€โ”€ OpenAI Codex hooks โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +if ide_enabled codex; then + echo "๐Ÿ”ง Configuring Codex hooks..." + + CODEX_CONFIG_DIR="${USER_HOME}/.codex" + CODEX_CONFIG="${CODEX_CONFIG_DIR}/config.toml" + + mkdir -p "${CODEX_CONFIG_DIR}" + + if [ -f "${CODEX_CONFIG}" ]; then + if ! grep -q "peon-ping" "${CODEX_CONFIG}"; then + printf '\nnotify = ["bash", "~/.claude/hooks/peon-ping/adapters/codex.sh"]\n' >> "${CODEX_CONFIG}" + fi + else + cat > "${CODEX_CONFIG}" << 'EOF' +notify = ["bash", "~/.claude/hooks/peon-ping/adapters/codex.sh"] +EOF + fi + + chown -R "${USERNAME}:${USERNAME}" "${CODEX_CONFIG_DIR}" 2>/dev/null || true + + echo " โœ… Codex hooks written to ${CODEX_CONFIG}" +fi + +# โ”€โ”€ Verify installation โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +echo "" +echo "๐Ÿ” Verifying installation..." + +if [ -x "${PEON_BIN}" ] || su - "${USERNAME}" -c "command -v peon" > /dev/null 2>&1; then + echo " โœ… peon binary found" +else + echo " โš ๏ธ peon binary not found in PATH (may need shell restart)" +fi + +if [ -d "${PEON_CONFIG_DIR}" ]; then + echo " โœ… peon-ping config directory found at ${PEON_CONFIG_DIR}" +else + echo " โš ๏ธ peon-ping config directory not found" +fi + +echo "" +echo "๐ŸŽฎ peon-ping installation complete!" +echo "" +echo " โš ๏ธ IMPORTANT โ€” Audio in devcontainers:" +echo " Start the relay on your HOST machine:" +echo "" +echo " peon relay --daemon" +echo "" +echo " The container routes audio to host.docker.internal:19998 automatically." +echo "" diff --git a/test/peon-ping/test.sh b/test/peon-ping/test.sh new file mode 100644 index 0000000..64966ab --- /dev/null +++ b/test/peon-ping/test.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +# Test script for peon-ping feature +# Copyright (c) 2025 helpers4 +# Licensed under AGPL-3.0 - see LICENSE file for details + +set -e + +echo "Testing peon-ping feature..." + +# Test 1: Check if peon binary is accessible +if command -v peon >/dev/null 2>&1; then + echo "โœ… PASS: peon binary is accessible" +else + # Check common install location directly + PEON_BIN="${HOME}/.local/bin/peon" + if [ -x "${PEON_BIN}" ]; then + echo "โœ… PASS: peon binary found at ${PEON_BIN}" + else + echo "โŒ FAIL: peon binary not found" + exit 1 + fi +fi + +# Test 2: Check peon-ping runtime directory +PEON_DIR="${HOME}/.claude/hooks/peon-ping" +if [ -d "${PEON_DIR}" ]; then + echo "โœ… PASS: peon-ping runtime directory exists at ${PEON_DIR}" +else + echo "โŒ FAIL: peon-ping runtime directory not found at ${PEON_DIR}" + exit 1 +fi + +# Test 3: Check config.json exists +PEON_CONFIG="${PEON_DIR}/config.json" +if [ -f "${PEON_CONFIG}" ]; then + echo "โœ… PASS: config.json exists" +else + echo "โŒ FAIL: config.json not found at ${PEON_CONFIG}" + exit 1 +fi + +# Test 4: Check that adapters directory exists +ADAPTERS_DIR="${PEON_DIR}/adapters" +if [ -d "${ADAPTERS_DIR}" ]; then + echo "โœ… PASS: adapters directory exists" +else + echo "โš ๏ธ WARN: adapters directory not found at ${ADAPTERS_DIR}" +fi + +# Test 5: Check copilot adapter is available +if [ -f "${ADAPTERS_DIR}/copilot.sh" ]; then + echo "โœ… PASS: copilot adapter found" +else + echo "โš ๏ธ WARN: copilot adapter not found" +fi + +# Test 6: Check peon-ping-copilot-setup helper is installed +if [ -x /usr/local/bin/peon-ping-copilot-setup ]; then + echo "โœ… PASS: peon-ping-copilot-setup helper installed" +else + echo "โš ๏ธ WARN: peon-ping-copilot-setup helper not found" +fi + +# Test 7: Check that python3 is available (required dependency) +if command -v python3 >/dev/null 2>&1; then + echo "โœ… PASS: python3 is available" +else + echo "โŒ FAIL: python3 is not available" + exit 1 +fi + +echo "" +echo "โœ… All peon-ping feature tests passed!"