- bin: add hermes-claim, hermes-dispatch, hermes-enqueue (queue scripts) - bin: update timmy-loop-prompt.md (Phase 1 fix-broken-PRs, --no-verify ban) - bin: update timmy-loop.sh (timeout cleanup, claim TTL) - bin: update timmy-status.sh (watchdog auto-restart for dead loop) - bin: update timmy-tmux.sh (pane layout fixes) - bin: update timmy-watchdog.sh (minor fixes) - skills: add hermes-agent skill (was missing from repo) - memories: sync MEMORY.md and USER.md to current state - cron/channel_directory: sync runtime state - .gitignore: whitelist new bin scripts, fix hermes-agent/ scope
73 lines
1.8 KiB
Bash
Executable File
73 lines
1.8 KiB
Bash
Executable File
#!/bin/bash
|
||
# hermes-dispatch — watch the queue, feed tasks into the hermes tmux pane
|
||
# Fire-and-forget: dispatches next task as soon as the prompt is visible.
|
||
# Does NOT wait for completion — just ensures hermes is idle before sending.
|
||
|
||
set -euo pipefail
|
||
|
||
QUEUE_DIR="$HOME/.hermes/queue"
|
||
TARGET_PANE="${HERMES_PANE:-Hermes:0.0}"
|
||
POLL_INTERVAL="${POLL_INTERVAL:-2}"
|
||
|
||
log() { echo "[$(date +%H:%M:%S)] $*"; }
|
||
|
||
is_hermes_idle() {
|
||
# Strip blank lines, check bottom of pane for the input prompt
|
||
local content
|
||
content=$(tmux capture-pane -t "$TARGET_PANE" -p 2>/dev/null | grep -v '^$' | tail -4)
|
||
echo "$content" | grep -qE '⚕ ❯|type a message'
|
||
}
|
||
|
||
pick_next_task() {
|
||
for pri in high normal low; do
|
||
local task
|
||
task=$(ls "$QUEUE_DIR/pending/${pri}_"*.task 2>/dev/null | head -1)
|
||
if [[ -n "$task" ]]; then
|
||
echo "$task"
|
||
return
|
||
fi
|
||
done
|
||
}
|
||
|
||
dispatch_task() {
|
||
local task_file="$1"
|
||
local basename=$(basename "$task_file")
|
||
|
||
local prompt
|
||
prompt=$(grep '^PROMPT=' "$task_file" | sed 's/^PROMPT=//')
|
||
|
||
if [[ -z "$prompt" ]]; then
|
||
log "ERROR: empty prompt in $basename"
|
||
mv "$task_file" "$QUEUE_DIR/failed/$basename"
|
||
return
|
||
fi
|
||
|
||
log "DISPATCH: $basename"
|
||
log " → ${prompt:0:100}"
|
||
|
||
# Move to done immediately (fire-and-forget)
|
||
mv "$task_file" "$QUEUE_DIR/done/$basename"
|
||
|
||
# Send to pane
|
||
tmux send-keys -t "$TARGET_PANE" "$prompt" Enter
|
||
}
|
||
|
||
# --- Main loop ---
|
||
log "hermes-dispatch started (fire-and-forget mode)"
|
||
log "Pane: $TARGET_PANE | Poll: ${POLL_INTERVAL}s"
|
||
log "Watching: $QUEUE_DIR/pending/"
|
||
|
||
while true; do
|
||
task=$(pick_next_task)
|
||
|
||
if [[ -n "$task" ]]; then
|
||
if is_hermes_idle; then
|
||
dispatch_task "$task"
|
||
# Give hermes a moment to start processing before next poll
|
||
sleep 8
|
||
fi
|
||
fi
|
||
|
||
sleep "$POLL_INTERVAL"
|
||
done
|