#!/usr/bin/env bash set -euo pipefail STATE_DIR="${STATE_DIR:-/home/node/.openclaw/workspace/state}" STATE_FILE="${STATE_FILE:-$STATE_DIR/gmail-unread-state.json}" ACCOUNT="${ACCOUNT:-claw@ben.io}" MAX_RESULTS="${MAX_RESULTS:-10}" OPENCLAW_BIN="${OPENCLAW_BIN:-openclaw}" CHANNEL="${CHANNEL:-discord}" DEST="${DEST:-channel:1467247377743347953}" ACCOUNT_ID="${ACCOUNT_ID:-default}" mkdir -p "$STATE_DIR" TMP_LIST=$(mktemp) trap 'rm -f "$TMP_LIST"' EXIT if ! gws gmail users messages list --params "{\"userId\":\"me\",\"maxResults\":$MAX_RESULTS,\"q\":\"is:unread\"}" --format json > "$TMP_LIST" 2>/dev/null; then echo "gmail-unread-poll: failed to query Gmail unread messages" >&2 exit 1 fi CURRENT_IDS=$(node -e ' const fs = require("fs"); const data = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); const ids = (data.messages || []).map(m => m.id).sort(); process.stdout.write(JSON.stringify(ids)); ' "$TMP_LIST") if [[ -f "$STATE_FILE" ]]; then PREV_IDS=$(node -e ' const fs = require("fs"); const p = process.argv[1]; const data = JSON.parse(fs.readFileSync(p, "utf8")); process.stdout.write(JSON.stringify((data.unreadIds || []).sort())); ' "$STATE_FILE") else PREV_IDS='[]' fi if [[ "$CURRENT_IDS" == "$PREV_IDS" ]]; then exit 0 fi NEW_IDS=$(node -e ' const prev = new Set(JSON.parse(process.argv[1])); const curr = JSON.parse(process.argv[2]); process.stdout.write(JSON.stringify(curr.filter(id => !prev.has(id)))); ' "$PREV_IDS" "$CURRENT_IDS") NEW_COUNT=$(node -e 'const a = JSON.parse(process.argv[1]); process.stdout.write(String(a.length));' "$NEW_IDS") TOTAL_UNREAD=$(node -e 'const a = JSON.parse(process.argv[1]); process.stdout.write(String(a.length));' "$CURRENT_IDS") if [[ "$NEW_COUNT" -gt 0 ]]; then SUMMARY=$(node - <<'NODE' "$NEW_IDS" const ids = JSON.parse(process.argv[2]); console.log(`claw@ben.io: ${ids.length} new unread mail(s)`); NODE ) DETAILS=() while IFS= read -r id; do [[ -z "$id" ]] && continue JSON=$(gws gmail +read --message-id "$id" --format json 2>/dev/null || true) if [[ -n "$JSON" ]]; then LINE=$(node -e ' const fs = require("fs"); const data = JSON.parse(fs.readFileSync(0, "utf8")); const from = data.from?.email || data.from?.name || "unknown"; const subject = data.subject || "(no subject)"; process.stdout.write(`- ${from} — ${subject}`); ' <<<"$JSON") DETAILS+=("$LINE") fi done < <(node -e 'for (const id of JSON.parse(process.argv[1])) console.log(id)' "$NEW_IDS") MSG="$SUMMARY Total unread: $TOTAL_UNREAD" if [[ ${#DETAILS[@]} -gt 0 ]]; then MSG+=" $(printf '%s ' "${DETAILS[@]}")" fi "$OPENCLAW_BIN" message send \ --account "$ACCOUNT_ID" \ --channel "$CHANNEL" \ --target "$DEST" \ --message "$MSG" >/dev/null 2>&1 || { echo "gmail-unread-poll: failed to send notification" >&2 exit 1 } fi node - <<'NODE' "$STATE_FILE" "$CURRENT_IDS" const fs = require('fs'); const path = process.argv[2]; const unreadIds = JSON.parse(process.argv[3]); fs.writeFileSync(path, JSON.stringify({ unreadIds, updatedAt: new Date().toISOString() }, null, 2)); NODE