OverviewFilesCommitsIssuesDocsReleasesPeers

keet-tui / keet-bot.sh

91 lines · bash ref:
#!/bin/bash
# keet-bot.sh — Polls Keet for new messages and alerts via file
# A Claude Code session can then read the inbox and respond
# Usage: ./keet-bot.sh [roomId]

ROOM_ID="${1:-ar5jd5tc3od5hbxxg6818pw9ikpgeq39y8ybgonyu9n179cdz8po}"
PORT=3117
LOG="/tmp/keet-bot.log"
INBOX="/tmp/keet-inbox"
MY_MEMBER_ID="z9i4wpf3pmp3cwhh9nnwysbwxcgx1f8sminypcc63esbi8ih9iby"
LAST_SEQ_FILE="/tmp/keet-bot-lastseq"
POLL_INTERVAL=1

log() {
  local ts
  ts="$(date '+%Y-%m-%d %H:%M:%S')"
  echo "[$ts] $*" | tee -a "$LOG"
}

poll() {
  log "=== keet-bot started (polling mode) ==="
  log "Room: $ROOM_ID"
  log "Inbox: $INBOX"

  # Get current latest seq to skip history
  local init_data
  init_data=$(curl -s "http://localhost:${PORT}/rpc/messages/${ROOM_ID}?limit=1" 2>/dev/null)
  local last_seq
  last_seq=$(echo "$init_data" | python3 -c "
import json, sys
try:
    data = json.load(sys.stdin)
    msgs = data.get('data', [])
    if msgs: print(msgs[-1].get('seq', 0))
    else: print(0)
except: print(0)
" 2>/dev/null)

  echo "$last_seq" > "$LAST_SEQ_FILE"
  : > "$INBOX"  # clear inbox
  log "Starting from seq $last_seq"
  log "--- live ---"

  while true; do
    sleep "$POLL_INTERVAL"

    local saved_seq
    saved_seq=$(cat "$LAST_SEQ_FILE" 2>/dev/null || echo "0")

    local result
    result=$(curl -s "http://localhost:${PORT}/rpc/messages/${ROOM_ID}?limit=10" 2>/dev/null)
    [ -z "$result" ] && continue

    # Find new messages from others (process substitution avoids subshell)
    while IFS=$'\t' read -r type seq name text; do
      if [ "$type" = "MSG" ]; then
        local ts
        ts="$(date '+%H:%M')"
        log ">> $name: $text"
        echo "[$ts] $name: $text" >> "$INBOX"
      elif [ "$type" = "SEQ" ]; then
        echo "$seq" > "$LAST_SEQ_FILE"
      fi
    done < <(python3 -c "
import json, sys
try:
    data = json.loads(sys.argv[1])
    last_seq = int(sys.argv[2])
    my_id = sys.argv[3]
    msgs = data.get('data', [])
    max_seq = last_seq
    for m in msgs:
        seq = m.get('seq', 0)
        if seq > max_seq: max_seq = seq
        if seq <= last_seq: continue
        member_id = m.get('memberId', '')
        if member_id == my_id: continue
        name = m.get('name') or member_id[:8]
        text = m.get('text', '')
        system = m.get('system')
        if system or not text: continue
        print(f'MSG\t{seq}\t{name}\t{text}')
    print(f'SEQ\t{max_seq}')
except:
    pass
" "$result" "$saved_seq" "$MY_MEMBER_ID" 2>/dev/null)
  done
}

poll