2026-10-07 23:34:59 -04:00
|
|
|
#!/bin/bash
|
|
|
|
|
# devdesk-notify-matrix SESSION SINCE
|
2026-10-11 23:28:11 -04:00
|
|
|
# devdesk-notify-matrix --usage PCT RESETS_AT
|
2026-10-07 23:34:59 -04:00
|
|
|
#
|
|
|
|
|
# Started (detached) by devdesk-state-hook when a session starts waiting on you.
|
2026-10-11 23:28:11 -04:00
|
|
|
# After DEVDESK_MATRIX_DELAY seconds, if that same wait is still on, no DevDesk
|
|
|
|
|
# tab is in view, and this session hasn't posted in DEVDESK_MATRIX_QUIET seconds,
|
|
|
|
|
# post what Claude is asking to the hookshot webhook in DEVDESK_MATRIX_WEBHOOK_FILE
|
|
|
|
|
# (devdesk#28, #50).
|
2026-10-07 23:34:59 -04:00
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
# shellcheck source=libexec/devdesk-lib.sh
|
|
|
|
|
. "${DEVDESK_LIBEXEC:-/usr/lib/devdesk}/devdesk-lib.sh"
|
|
|
|
|
|
2026-10-11 23:28:11 -04:00
|
|
|
# Post BODY (JSON with a .text) to the hookshot webhook. The URL is a secret
|
|
|
|
|
# (anyone holding it can post to the room): it goes to curl on stdin, never on
|
|
|
|
|
# the command line.
|
|
|
|
|
post() {
|
|
|
|
|
local webhook
|
|
|
|
|
# shellcheck disable=SC1003 # tr deletes whitespace, quotes and backslashes from the URL
|
|
|
|
|
webhook=$(tr -d '[:space:]"\\' <"$DEVDESK_MATRIX_WEBHOOK_FILE")
|
|
|
|
|
printf 'url = "%s"\n' "$webhook" |
|
|
|
|
|
curl -fsS --max-time 10 --retry 2 -K - -H 'Content-Type: application/json' --data-binary "$1" >/dev/null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# devdesk-notify-matrix --usage PCT RESETS_AT (devdesk#45): started by the status
|
|
|
|
|
# line when the 5-hour plan window passes DEVDESK_USAGE_WARN percent. Once per
|
|
|
|
|
# window, and only when no client is attached to any session (you're away; a
|
|
|
|
|
# browser tab shows its own warning).
|
|
|
|
|
if [ "${1:-}" = --usage ]; then
|
|
|
|
|
pct=${2:-} resets=${3:-}
|
|
|
|
|
[[ $pct =~ ^[0-9]+$ && $resets =~ ^[0-9]+$ ]] || exit 0
|
|
|
|
|
marker="$DEVDESK_STATE_DIR/usage-warned"
|
|
|
|
|
exec 9>>"$marker.lock"
|
|
|
|
|
flock -n 9 || exit 0
|
|
|
|
|
[ "$(cat "$marker" 2>/dev/null)" != "$resets" ] || exit 0
|
|
|
|
|
printf '%s\n' "$resets" >"$marker"
|
|
|
|
|
[ -r "$DEVDESK_MATRIX_WEBHOOK_FILE" ] || exit 0
|
|
|
|
|
[ -z "$(dd_tmux list-clients -F x 2>/dev/null)" ] || exit 0
|
|
|
|
|
at=$(date -d "@$resets" '+%H:%M %Z')
|
|
|
|
|
post "$(jq -cMn --arg p "$pct" --arg at "$at" --arg h "$(hostname)" \
|
|
|
|
|
'{kind: "usage", host: $h, text: "Claude plan usage is at \($p)% of the 5-hour window; it resets at \($at)."}')"
|
|
|
|
|
exit 0
|
|
|
|
|
fi
|
|
|
|
|
|
2026-10-07 23:34:59 -04:00
|
|
|
session=${1:-}
|
|
|
|
|
since=${2:-}
|
|
|
|
|
dd_valid_name "$session" || exit 0
|
|
|
|
|
[[ $since =~ ^[0-9]+$ ]] || exit 0
|
|
|
|
|
[ -r "$DEVDESK_MATRIX_WEBHOOK_FILE" ] || exit 0
|
|
|
|
|
|
|
|
|
|
sleep "$DEVDESK_MATRIX_DELAY"
|
|
|
|
|
|
|
|
|
|
state_file="$DEVDESK_STATUS_DIR/$session.json"
|
|
|
|
|
# Still the same wait? (Answering it moves the state on; a new wait has its own notifier.)
|
|
|
|
|
[ "$(jq -rM '"\(.state) \(.since)"' "$state_file" 2>/dev/null)" = "waiting $since" ] || exit 0
|
2026-10-11 23:28:11 -04:00
|
|
|
# You're at DevDesk if any tab has shown a session in the last ~2 minutes
|
|
|
|
|
# (presence markers, devdesk#26): the browser tells you itself (devdesk#50).
|
|
|
|
|
[ -z "$(find "$DEVDESK_PRESENCE_DIR" -type f 2>/dev/null | head -n 1)" ] || exit 0
|
|
|
|
|
# The idle reminder isn't a request (the state hook drops it; old states may have it).
|
|
|
|
|
message=$(jq -rM '.message // ""' "$state_file" 2>/dev/null)
|
|
|
|
|
request=$(jq -cM '.request // null' "$state_file" 2>/dev/null) || request=null
|
|
|
|
|
if [ "$request" = null ] && { [ -z "$message" ] || [[ $message == *"waiting for your input"* ]]; }; then exit 0; fi
|
|
|
|
|
# At most one message per session per DEVDESK_MATRIX_QUIET seconds.
|
|
|
|
|
sent="$DEVDESK_STATE_DIR/matrix-sent/$session"
|
|
|
|
|
mkdir -p "${sent%/*}"
|
|
|
|
|
if [ -n "$(find "$sent" -newermt "-$DEVDESK_MATRIX_QUIET seconds" 2>/dev/null)" ]; then exit 0; fi
|
|
|
|
|
touch "$sent"
|
|
|
|
|
|
2026-10-07 23:34:59 -04:00
|
|
|
url=""
|
2026-10-10 19:57:52 -04:00
|
|
|
# existing=1: if the session was ended by the time you tap, say so instead of
|
|
|
|
|
# starting a new Claude there (devdesk#38).
|
|
|
|
|
[ -z "$DEVDESK_PUBLIC_URL" ] || url="${DEVDESK_PUBLIC_URL%/}/?arg=$session&existing=1"
|
2026-10-11 23:28:11 -04:00
|
|
|
# What exactly it wants: "alpha: Claude wants to run Bash (Remove x)" and the command.
|
|
|
|
|
body=$(jq -cMn --arg s "$session" --arg m "$message" --argjson r "$request" --arg u "$url" --arg h "$(hostname)" '
|
|
|
|
|
(if $r then "\($s): Claude wants to run \($r.tool)\(if $r.description then " (\($r.description))" else "" end)"
|
|
|
|
|
else "\($s): \($m)" end) as $head
|
|
|
|
|
| ($r.detail // null | if . then .[0:300] else null end) as $d
|
|
|
|
|
| {session: $s, message: $m, url: (if $u == "" then null else $u end), host: $h,
|
|
|
|
|
text: ($head + (if $d then "\n" + $d else "" end) + (if $u == "" then "" else "\nAnswer: " + $u end))}')
|
|
|
|
|
|
|
|
|
|
post "$body"
|