Skip to content

Instantly share code, notes, and snippets.

@DV8FromTheWorld
Last active July 17, 2025 15:52
Show Gist options
  • Save DV8FromTheWorld/adbe2eb3b5ba50620706a702989dd413 to your computer and use it in GitHub Desktop.
Save DV8FromTheWorld/adbe2eb3b5ba50620706a702989dd413 to your computer and use it in GitHub Desktop.
Notify vscode when remote server script is complete
Spawns a notification & sound on mac when a remote command executed via VS Code's ssh based Remote Host system has completed.
Only triggers when VS Code is not focused.
Follow ths instructions in `.zshrc` and the header of each file.
# This goes in your ~/.zshrc file on your Coder box
function with_ssh_err_detection() {
# Color definitions
local RED=$'\033[0;31m'
local BLUE=$'\033[0;34m'
local YELLOW=$'\033[0;33m'
local BOLD=$'\033[1m'
local RESET=$'\033[0m'
local age_of_shell_in_seconds=$(ps -p $$ -o etimes=)
local logfile="$(mktemp)"
# Run the command (assumed to be an ssh commands), capture the output to check for connection errors.
{
"$@" > /dev/null 2>"$logfile" < /dev/null
} &!
{
# Let the log file populate a bit
sleep 0.5
log_contains_connection_error=false
if grep -qE "Could not resolve|Connection refused|Permission denied|No route to host|timed out" "$logfile"; then
log_contains_connection_error=true
fi
# We grant ourselves a 20 second reprieve to let the reverse ssh server get setup
if $log_contains_connection_error && ((age_of_shell_in_seconds > 20 )); then
echo ""
echo "${BOLD}${YELLOW}[VSCode SSH command notification]${RESET} ${RED}Failed to show notification across reverse SSH tunnel:${RESET}"
while IFS= read -r line; do
echo "${RED} >${RESET} $line"
done < "$logfile"
echo ""
echo "${BOLD}${BLUE}💡 Did you remember to turn on the Reverse SSH Tunnel from your Mac?${RESET}"
echo ""
fi
rm -f "$logfile"
} &!
}
# Connects to the mac that is remoted into this coder box and triggers a notification any time a command completes.
# The notification script determines if the notification should go out or not based on if VSCode is foregrounded or not.
# This relies on having ssh setup correctly
# 1. Enable Remote Login on Mac
#
# 2. You need to make sure that you have the reverse SSH server setup on port 2222 on your mac
# On your Mac:
# > ssh -R 2222:localhost:22 <coder-ssh-host>
# My coder-ssh-host is coder.austin-keener-workspace2
#
# THIS MUST ALWAYS BE ON IN THE FUTURE FOR THIS TO WORK.
# This will be maintained by launchd and ~/bin/coder/manage-coder-terminal.sh
#
# 3. You need to generate a key on the coder box and send it to the mac so coder box can use passwordless ssh
# On your Coder
# > ssh-keygen -t ed25519 -C "remote-to-mac"
# > ssh-copy-id -p 2222 -i ~/.ssh/id_ed25519.pub <user.name>@localhost
# My username was austin.keener@localhost
#
# 4. You need the correct ssh config in ~/.ssh/config on your Coder
#
# Host mac-notify
# HostName localhost
# Port 2222
# User austin.keener
# ControlMaster auto
# ControlPath ~/.ssh/cm-%r@%h:%p
# ControlPersist 10m
#
# 5. You need the shell file on your mac at ~/bin/coder/notify-if-vscode-is-not-focused.sh with chmod +x
# File available at https://gist.github.com/DV8FromTheWorld/adbe2eb3b5ba50620706a702989dd413
if [[ "$TERM_PROGRAM" == "vscode" ]]; then
precmd() {
with_ssh_err_detection ssh -o ConnectTimeout=2 mac-notify '~/bin/coder/notify-if-vscode-is-not-focused.sh'
}
fi
<!--
Goes in ~/Library/LaunchAgents/com.discord.coder-tunnel-watcher.plist on your mac
!!!Make sure to update the REPLACE_THIS_HERE with the correct path.
PList requires that all paths be absolute, so I cannot pre-fill it for you.
Mine is:
<string>/Users/austin.keener/bin/coder/manage-coder-tunnel.sh</string>
You'll need yours to have _your_ username.
Add to launchd via:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.discord.coder-tunnel-watcher.plist
-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.discord.coder-tunnel-watcher</string>
<key>ProgramArguments</key>
<array>
<string>REPLACE_THIS_HERE</string>
</array>
<key>KeepAlive</key>
<true />
<key>ThrottleInterval</key>
<integer>15</integer>
<key>RunAtLoad</key>
<true/>
<key>StandardOutPath</key>
<string>/tmp/coder-tunnel-watcher.log</string>
<key>StandardErrorPath</key>
<string>/tmp/coder-tunnel-watcher.err</string>
</dict>
</plist>
#!/bin/zsh
# This goes in ~/bin/coder/manage-coder-tunnel.sh on your mac
# Make sure to run set execution permissions
# chmod +x ~/bin/coder/manage-coder-tunnel.sh
#
# Also, you must set the CODER_HOST below to the ssh host where your coderbox is setup
# You can likely find this information in your ~/.ssh/config or VSCode
# Austin's is "coder.austin-keener-workspace2"
CODER_HOST=""
TUNNEL_PORT="2222"
GROUP_ID="reverse-tunnel-notifier"
# Safely add Homebrew paths without removing existing system paths. We rely on executables installed via brew
if [[ -x /opt/homebrew/bin/brew ]]; then
export PATH="/opt/homebrew/bin:$PATH"
elif [[ -x /usr/local/bin/brew ]]; then
export PATH="/usr/local/bin:$PATH"
fi
# --- Helper Functions ------------------------------------
is_vscode_ssh_active() {
ps -eo ppid,pid,command | grep '[s]sh' | grep "$CODER_HOST" | while read -r ppid pid cmd; do
parent_cmd=$(ps -p "$ppid" -o command=)
if echo "$parent_cmd" | grep -qE 'coder2|code|code-insiders'; then
return 0
fi
done
return 1
}
get_active_reverse_tunnel_pid() {
ps -eo pid,command | grep '[s]sh' | grep "$CODER_HOST" | grep "$TUNNEL_PORT" | while read -r pid command; do
echo "$pid"
return 0
done
return 1
}
wait_for_pid() {
local pid="$1"
while kill -0 "$pid" 2>/dev/null; do
sleep 1
done
}
# --- Notification Wrapper ------------------------------------
function notify() {
local title="Reverse SSH Tunnel"
local message="$1"
local group="${2:-$GROUP_ID}" # default group for notification deduplication
if command -v terminal-notifier >/dev/null 2>&1; then
terminal-notifier \
-title "$title" \
-message "$message" \
-group "$group"
elif command -v osascript >/dev/null 2>&1; then
osascript -e "display notification \"${message}\" with title \"${title}\""
else
echo "[notify fallback] $title: $message"
fi
}
# --- Main Tunnel Logic ------------------------------------
if [[ -z "$CODER_HOST" ]]; then
notify "❌ CODER_HOST is not set in ~/bin/manage-coder-terminal.sh. Checking again in 60 seconds"
sleep 60
exit 1
fi
# Tunnel is already running. launchd got out of sync a bit, but we'll wait for this tunnel to be done
existing_tunnel_pid=$(get_active_reverse_tunnel_pid)
if [[ -n "$existing_tunnel_pid" ]]; then
wait_for_pid "$existing_tunnel_pid"
fi
# Check if forward SSH session is active
if is_vscode_ssh_active; then
notify "Starting reverse SSH tunnel to $CODER_HOST..."
ssh -N \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=15 \
-o ServerAliveCountMax=2 \
-R ${TUNNEL_PORT}:localhost:22 ${CODER_HOST} &
ssh_pid=$!
# Wait a bit to let the SSH connection go through the handshake and either succeed or fail
# If it fails, the child ssh process will die, and then we can detect that
sleep 4
if [[ -n "$ssh_pid" ]] && kill -0 "$ssh_pid" 2>/dev/null; then
notify "Tunnel is up ✅"
wait "$ssh_pid"
notify "Tunnel has disconnected ❌"
else
notify "Tunnel failed to establish ❌"
fi
fi
#!/bin/zsh
# This goes in ~/bin/coder/notify-if-vscode-is-not-focused.sh on your mac
# Make sure to run set execution permissions
# chmod +x ~/bin/coder/notify-if-vscode-is-not-focused.sh
GROUP_ID="reverse-tunnel-notifier"
# Safely add Homebrew paths without removing existing system paths
if [[ -x /opt/homebrew/bin/brew ]]; then
export PATH="/opt/homebrew/bin:$PATH"
elif [[ -x /usr/local/bin/brew ]]; then
export PATH="/usr/local/bin:$PATH"
fi
# Notify + install terminal-notifier if missing
if ! command -v terminal-notifier >/dev/null 2>&1; then
osascript -e 'display notification "Installing terminal-notifier..." with title "VSCode SSH"'
if command -v brew >/dev/null 2>&1; then
if brew install terminal-notifier >/dev/null 2>&1; then
osascript -e 'display notification "terminal-notifier installed successfully." with title "VSCode SSH"'
else
osascript -e 'display notification "Failed to install terminal-notifier." with title "VSCode SSH"'
exit 1
fi
else
osascript -e 'display notification "Homebrew not found. Cannot install terminal-notifier." with title "VSCode SSH"'
exit 1
fi
fi
# Get bundle ID of the frontmost app
frontmost_bundle_id=$(osascript -e '
tell application "System Events"
set frontApp to first application process whose frontmost is true
return bundle identifier of frontApp
end tell
')
# Only notify if VSCode is NOT frontmost
if [[ "$frontmost_bundle_id" != "com.microsoft.VSCode" ]]; then
terminal-notifier \
-title "VSCode SSH" \
-message "Remote command finished" \
-activate "com.microsoft.VSCode"
-group "$GROUP_ID" \
-sound "Glass.aiff" # sounds come from /System/Library/Sounds/
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment