Skip to content

Commit 1e96ebc

Browse files
claudeMBclaude
andcommitted
Fix claudemb wake: use tmux send-keys instead of codex exec
The wake script had been rewritten to spawn a separate Codex agent instead of nudging the Claude Code tmux session with keystrokes. This broke autonomous room response -- the poller detected messages but never triggered the Claude Code UserPromptSubmit hook. Restored to tmux send-keys approach targeting the "claude" session. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent a8dfc27 commit 1e96ebc

2 files changed

Lines changed: 204 additions & 0 deletions

File tree

scripts/claudemb-poll.sh

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#!/usr/bin/env bash
2+
# claudemb_poll.sh — poll thinkoff-development room for new messages
3+
# Runs in a tmux session; wakes the Claude session on new messages.
4+
5+
set -euo pipefail
6+
7+
CONFIG_JSON="${IAK_CONFIG_JSON:-/Users/petrus/AndroidStudioProjects/ThinkOff/ide-agent-kit-codex.json}"
8+
read_json_value() {
9+
local path="$1"
10+
python3 - "$CONFIG_JSON" "$path" <<'PY'
11+
import json, sys
12+
cfg_path, dotted = sys.argv[1], sys.argv[2]
13+
try:
14+
with open(cfg_path, 'r', encoding='utf-8') as fh:
15+
data = json.load(fh)
16+
cur = data
17+
for part in dotted.split('.'):
18+
cur = cur[part]
19+
if isinstance(cur, str):
20+
print(cur)
21+
except Exception:
22+
pass
23+
PY
24+
}
25+
26+
CONFIG_API_KEY="$(read_json_value 'poller.api_key')"
27+
CONFIG_NUDGE_TEXT="$(read_json_value 'tmux.nudge_text')"
28+
29+
API_KEY="${IAK_API_KEY:-${ANTIGRAVITY_API_KEY:-${CONFIG_API_KEY:-}}}"
30+
ROOM="${ROOM:-thinkoff-development}"
31+
BASE_URL="${BASE_URL:-https://antfarm.world/api/v1}"
32+
POLL_INTERVAL="${POLL_INTERVAL:-15}"
33+
FETCH_LIMIT="${FETCH_LIMIT:-20}"
34+
HTTP_CONNECT_TIMEOUT_SEC="${HTTP_CONNECT_TIMEOUT_SEC:-5}"
35+
HTTP_TIMEOUT_SEC="${HTTP_TIMEOUT_SEC:-20}"
36+
SEEN_IDS_FILE="${SEEN_IDS_FILE:-/tmp/claudemb_seen_ids.txt}"
37+
SESSION="${SESSION:-claudemb-poll}"
38+
WAKE_SCRIPT="$(dirname "$0")/claudemb_wake.sh"
39+
WAKE_SESSION="${CLAUDEMB_SESSION:-claude}"
40+
NUDGE_TEXT="${IAK_NUDGE_TEXT:-${CONFIG_NUDGE_TEXT:-check rooms}}"
41+
WAKE_COOLDOWN_SEC="${WAKE_COOLDOWN_SEC:-45}"
42+
LAST_WAKE_FILE="${LAST_WAKE_FILE:-/tmp/claudemb_last_wake_epoch.txt}"
43+
NEW_FILE="${IAK_NEW_FILE:-/tmp/iak-new-messages.txt}"
44+
NEW_FILE_COMPAT="${IAK_NEW_FILE_COMPAT:-/tmp/iak_new_messages.txt}"
45+
46+
# --- tmux management ---
47+
if [[ "${1:-}" == "tmux" ]]; then
48+
cmd="${2:-start}"
49+
case "$cmd" in
50+
stop)
51+
if tmux has-session -t "$SESSION" 2>/dev/null; then
52+
tmux kill-session -t "$SESSION"
53+
echo "Stopped $SESSION"
54+
else
55+
echo "$SESSION is not running"
56+
fi
57+
;;
58+
status)
59+
if tmux has-session -t "$SESSION" 2>/dev/null; then
60+
echo "$SESSION is running ($(tmux list-panes -t "$SESSION" -F '#{pane_pid}'))"
61+
else
62+
echo "$SESSION is not running"
63+
fi
64+
;;
65+
logs)
66+
if tmux has-session -t "$SESSION" 2>/dev/null; then
67+
tmux attach-session -t "$SESSION"
68+
else
69+
echo "$SESSION is not running"
70+
exit 1
71+
fi
72+
;;
73+
start|"")
74+
if tmux has-session -t "$SESSION" 2>/dev/null; then
75+
echo "$SESSION already running — attaching"
76+
tmux attach-session -t "$SESSION"
77+
exit 0
78+
fi
79+
SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")"
80+
tmux new-session -d -s "$SESSION" "$SCRIPT_PATH"
81+
echo "Started $SESSION — polling $ROOM every ${POLL_INTERVAL}s"
82+
echo "Attach with: $0 tmux logs"
83+
;;
84+
*)
85+
echo "Usage: $0 tmux {start|stop|status|logs}"
86+
exit 1
87+
;;
88+
esac
89+
exit 0
90+
fi
91+
92+
# --- helpers ---
93+
can_wake_now() {
94+
local now last
95+
now="$(date +%s)"
96+
last=0
97+
if [[ -f "$LAST_WAKE_FILE" ]]; then
98+
last="$(cat "$LAST_WAKE_FILE" 2>/dev/null || echo 0)"
99+
fi
100+
if [[ ! "$last" =~ ^[0-9]+$ ]]; then
101+
last=0
102+
fi
103+
if (( now - last >= WAKE_COOLDOWN_SEC )); then
104+
echo "$now" > "$LAST_WAKE_FILE"
105+
return 0
106+
fi
107+
return 1
108+
}
109+
110+
# --- polling loop ---
111+
touch "$SEEN_IDS_FILE" "$NEW_FILE" "$NEW_FILE_COMPAT" "$LAST_WAKE_FILE"
112+
if [[ ! -s "$LAST_WAKE_FILE" ]]; then
113+
echo 0 > "$LAST_WAKE_FILE"
114+
fi
115+
116+
echo "[claudemb] Polling $ROOM every ${POLL_INTERVAL}s (limit=$FETCH_LIMIT)"
117+
echo "[claudemb] Seen IDs file: $SEEN_IDS_FILE ($(wc -l < "$SEEN_IDS_FILE" | tr -d ' ') known)"
118+
echo "[claudemb] Wake target session (exact): $WAKE_SESSION"
119+
echo "[claudemb] Nudge text: $NUDGE_TEXT (cooldown=${WAKE_COOLDOWN_SEC}s)"
120+
echo "[claudemb] New message files: $NEW_FILE and $NEW_FILE_COMPAT"
121+
echo ""
122+
123+
while true; do
124+
response=$(curl -sS --connect-timeout "$HTTP_CONNECT_TIMEOUT_SEC" --max-time "$HTTP_TIMEOUT_SEC" -H "X-API-Key: $API_KEY" \
125+
"$BASE_URL/rooms/$ROOM/messages?limit=$FETCH_LIMIT" 2>&1) || {
126+
echo "[$(date +%H:%M:%S)] fetch error: $response"
127+
sleep "$POLL_INTERVAL"
128+
continue
129+
}
130+
131+
new_count=0
132+
while IFS=$'\t' read -r msg_id msg_from msg_body; do
133+
[[ -z "$msg_id" ]] && continue
134+
if ! grep -qF "$msg_id" "$SEEN_IDS_FILE"; then
135+
echo "$msg_id" >> "$SEEN_IDS_FILE"
136+
new_count=$((new_count + 1))
137+
body_preview="${msg_body:0:120}"
138+
echo "[$(date +%H:%M:%S)] NEW ${msg_from}: ${body_preview}"
139+
140+
ts="$(date -u +%FT%TZ)"
141+
line="[${ts}] [${ROOM}] ${msg_from}: ${msg_body:0:600}"
142+
printf '%s\n---\n' "$line" >> "$NEW_FILE"
143+
printf '%s\n---\n' "$line" >> "$NEW_FILE_COMPAT"
144+
fi
145+
done < <(echo "$response" | python3 -c "
146+
import sys, json
147+
try:
148+
data = json.load(sys.stdin)
149+
for m in data.get('messages', []):
150+
mid = m.get('id', '')
151+
mfrom = m.get('from', '?')
152+
mbody = m.get('body', '').replace('\\n', ' ').replace('\\t', ' ')
153+
print(f'{mid}\\t{mfrom}\\t{mbody}')
154+
except Exception:
155+
pass
156+
" 2>/dev/null)
157+
158+
if [[ $new_count -gt 0 ]]; then
159+
echo "[$(date +%H:%M:%S)] $new_count new message(s)"
160+
if [[ -x "$WAKE_SCRIPT" ]]; then
161+
if can_wake_now; then
162+
if ! CLAUDEMB_SESSION="$WAKE_SESSION" "$WAKE_SCRIPT" "$NUDGE_TEXT"; then
163+
echo "[$(date +%H:%M:%S)] wake failed: target session '$WAKE_SESSION' not found (exact match required)"
164+
fi
165+
else
166+
echo "[$(date +%H:%M:%S)] wake skipped: cooldown active (${WAKE_COOLDOWN_SEC}s)"
167+
fi
168+
fi
169+
echo ""
170+
fi
171+
172+
sleep "$POLL_INTERVAL"
173+
done

scripts/claudemb-wake.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/usr/bin/env bash
2+
# ClaudeMB wake-up script
3+
# Sends a nudge keystroke into the Claude Code tmux session so it triggers
4+
# the UserPromptSubmit hook and reads new room messages.
5+
6+
set -euo pipefail
7+
8+
WAKE_SESSION="${CLAUDEMB_SESSION:-claude}"
9+
MSG="${1:-check rooms}"
10+
LOCK="/tmp/claudemb_wake.lock"
11+
LOG_FILE="${CLAUDEMB_WAKE_LOG:-/tmp/claudemb_wake.log}"
12+
13+
# Simple lock using mkdir (atomic on all systems)
14+
if ! mkdir "$LOCK" 2>/dev/null; then
15+
# Lock exists, exit quietly
16+
exit 0
17+
fi
18+
trap "rmdir \"$LOCK\"" EXIT
19+
20+
if ! tmux has-session -t "$WAKE_SESSION" 2>/dev/null; then
21+
printf "[%s] wake failed: tmux session '%s' not found\n" "$(date -u +%FT%TZ)" "$WAKE_SESSION" >> "$LOG_FILE"
22+
exit 1
23+
fi
24+
25+
{
26+
printf "[%s] wake: sending nudge to tmux session '%s': %s\n" "$(date -u +%FT%TZ)" "$WAKE_SESSION" "$MSG"
27+
tmux send-keys -t "$WAKE_SESSION" -l "$MSG"
28+
sleep 0.3
29+
tmux send-keys -t "$WAKE_SESSION" Enter
30+
printf "[%s] wake: nudge sent\n" "$(date -u +%FT%TZ)"
31+
} >> "$LOG_FILE" 2>&1

0 commit comments

Comments
 (0)