#!/bin/bash set -euo pipefail # DevSnoop Native Host Installer # Usage: curl -fsSL https://devsnoop.com/install.sh | bash # Specific version: curl -fsSL https://devsnoop.com/install.sh | bash -s -- 1.0.0 HOST_NAME="com.devsnoop.agent" EXTENSION_ID="kkhkcpgpklnofjgnflkciekppiokdilp" INSTALL_DIR="$HOME/.devsnoop" BINARY_NAME="devsnoop-host" EXTENSION_IDS=() add_extension_id() { local extension_id="$1" if [[ ! "$extension_id" =~ ^[a-p]{32}$ ]]; then echo "Error: Invalid Chrome extension ID: $extension_id" exit 1 fi if [ "${#EXTENSION_IDS[@]}" -gt 0 ]; then for existing_id in "${EXTENSION_IDS[@]}"; do if [ "$existing_id" = "$extension_id" ]; then return fi done fi EXTENSION_IDS+=("$extension_id") } add_extra_extension_ids() { local raw_ids="$1" local normalized_ids normalized_ids="$(echo "$raw_ids" | tr ',;' ' ')" for extension_id in $normalized_ids; do add_extension_id "$extension_id" done } add_existing_extension_ids() { local manifest_path="$1" if [ ! -f "$manifest_path" ]; then return fi while IFS= read -r extension_id; do add_extension_id "$extension_id" done < <(grep -Eo 'chrome-extension://[a-p]{32}/' "$manifest_path" | sed -E 's#chrome-extension://([a-p]{32})/#\1#' || true) } write_allowed_origins() { local count="${#EXTENSION_IDS[@]}" for index in "${!EXTENSION_IDS[@]}"; do local suffix="," if [ "$index" -eq "$((count - 1))" ]; then suffix="" fi echo " \"chrome-extension://${EXTENSION_IDS[$index]}/\"$suffix" done } # --- Detect platform --- OS="$(uname -s)" ARCH="$(uname -m)" case "$OS" in Darwin) PLATFORM="darwin" ;; Linux) PLATFORM="linux" ;; *) echo "Error: Unsupported OS: $OS" exit 1 ;; esac case "$ARCH" in x86_64|amd64) ARCH="x64" ;; arm64|aarch64) ARCH="arm64" ;; *) echo "Error: Unsupported architecture: $ARCH" exit 1 ;; esac TARGET="${BINARY_NAME}-${PLATFORM}-${ARCH}" echo "DevSnoop Native Host Installer" echo "Detected: ${PLATFORM}-${ARCH}" # --- Download binary --- mkdir -p "$INSTALL_DIR" BINARY_PATH="$INSTALL_DIR/$BINARY_NAME" TMP_PATH="${BINARY_PATH}.tmp" if [ -n "${1:-}" ]; then VERSION="$1" BASE_URL="https://devsnoop.com/downloads/v${VERSION}" echo "Downloading ${TARGET} v${VERSION}..." else BASE_URL="https://devsnoop.com/downloads/latest" echo "Downloading ${TARGET} (latest)..." fi curl -fSL "${BASE_URL}/${TARGET}" -o "$TMP_PATH" mv "$TMP_PATH" "$BINARY_PATH" chmod +x "$BINARY_PATH" # --- Write native messaging manifest --- case "$PLATFORM" in darwin) MANIFEST_DIR="$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts" ;; linux) MANIFEST_DIR="$HOME/.config/google-chrome/NativeMessagingHosts" ;; esac mkdir -p "$MANIFEST_DIR" MANIFEST_PATH="$MANIFEST_DIR/$HOST_NAME.json" add_extension_id "$EXTENSION_ID" add_existing_extension_ids "$MANIFEST_PATH" if [ -n "${DEVSNOOP_EXTRA_EXTENSION_IDS:-}" ]; then add_extra_extension_ids "$DEVSNOOP_EXTRA_EXTENSION_IDS" fi cat > "$MANIFEST_PATH" << EOF { "name": "$HOST_NAME", "description": "DevSnoop Native Messaging Host", "path": "$BINARY_PATH", "type": "stdio", "allowed_origins": [ $(write_allowed_origins) ] } EOF echo "Manifest written: $MANIFEST_PATH" echo "Allowed extension IDs: ${EXTENSION_IDS[*]}" # --- Install skill file --- SKILL_PATH="$INSTALL_DIR/SKILL.md" TMP_SKILL="${SKILL_PATH}.tmp" echo "Downloading skill file..." curl -fSL "${BASE_URL}/SKILL.md" -o "$TMP_SKILL" mv "$TMP_SKILL" "$SKILL_PATH" # --- Done --- echo "" echo "DevSnoop installed successfully!" echo " Binary: $BINARY_PATH" echo " Manifest: $MANIFEST_PATH" echo " Skill: $SKILL_PATH" echo "" echo "Next steps:" echo " 1. Install the Chrome extension: https://chromewebstore.google.com/detail/devsnoop/kkhkcpgpklnofjgnflkciekppiokdilp" echo " 2. Configure SKILL.md for your coding agent (see https://devsnoop.com/install)"