feat: tmux orchestrator start/stop/status
This commit is contained in:
Executable
+112
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env bash
|
||||
# autoresearch tmux session orchestrator
|
||||
# Usage: start.sh [start|stop|status]
|
||||
set -euo pipefail
|
||||
|
||||
SESSION="autoresearch"
|
||||
CONFIG="${HOME}/.claude/autoresearch.yaml"
|
||||
LOGDIR="${HOME}/.claude/autoresearch"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
get_projects() {
|
||||
python3 -c "
|
||||
import yaml, os, sys
|
||||
try:
|
||||
cfg = yaml.safe_load(open('${CONFIG}'))
|
||||
for p in cfg.get('projects', []):
|
||||
print(os.path.expanduser(p['path']))
|
||||
except Exception as e:
|
||||
print(f'ERROR: {e}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
"
|
||||
}
|
||||
|
||||
cmd_start() {
|
||||
if tmux has-session -t "$SESSION" 2>/dev/null; then
|
||||
echo "autoresearch: session '$SESSION' already running"
|
||||
echo " attach: tmux attach -t $SESSION"
|
||||
return 0
|
||||
fi
|
||||
|
||||
mkdir -p "$LOGDIR"
|
||||
|
||||
# Window 0: overview — left: log viewer, right (30%): metrics
|
||||
tmux new-session -d -s "$SESSION" -n "overview" -x 220 -y 50
|
||||
tmux split-window -h -t "${SESSION}:overview" -p 30
|
||||
tmux send-keys -t "${SESSION}:overview.left" \
|
||||
"watch -n5 python3 '${SCRIPT_DIR}/log_view.py'" Enter
|
||||
tmux send-keys -t "${SESSION}:overview.right" \
|
||||
"watch -n10 python3 '${SCRIPT_DIR}/metrics.py'" Enter
|
||||
|
||||
# One window per project
|
||||
local win=1
|
||||
while IFS= read -r project_path; do
|
||||
local project_name
|
||||
project_name=$(basename "$project_path")
|
||||
tmux new-window -t "${SESSION}:${win}" -n "$project_name"
|
||||
# Start claude in the project directory
|
||||
tmux send-keys -t "${SESSION}:${win}" \
|
||||
"cd '${project_path}' && claude --name 'autoresearch-${project_name}'" Enter
|
||||
# Wait for claude to initialize, then invoke the loop skill
|
||||
sleep 3
|
||||
tmux send-keys -t "${SESSION}:${win}" \
|
||||
"/ralph-loop Run one autoresearch experiment iteration per the autoresearch-loop skill. --completion-promise STOP" Enter
|
||||
win=$((win + 1))
|
||||
done < <(get_projects)
|
||||
|
||||
tmux select-window -t "${SESSION}:0"
|
||||
local project_count=$(( win - 1 ))
|
||||
echo "autoresearch: started — ${project_count} project window(s)"
|
||||
echo " attach: tmux attach -t $SESSION"
|
||||
}
|
||||
|
||||
cmd_stop() {
|
||||
if ! tmux has-session -t "$SESSION" 2>/dev/null; then
|
||||
echo "autoresearch: not running"
|
||||
return 0
|
||||
fi
|
||||
tmux kill-session -t "$SESSION"
|
||||
echo "autoresearch: stopped"
|
||||
}
|
||||
|
||||
cmd_status() {
|
||||
if ! tmux has-session -t "$SESSION" 2>/dev/null; then
|
||||
echo "autoresearch: not running"
|
||||
return 1
|
||||
fi
|
||||
echo "autoresearch: running"
|
||||
tmux list-windows -t "$SESSION"
|
||||
echo ""
|
||||
echo "Last experiment per project:"
|
||||
python3 - <<'PYEOF'
|
||||
import json, os
|
||||
from collections import OrderedDict
|
||||
|
||||
log = os.path.expanduser('~/.claude/autoresearch/log.jsonl')
|
||||
if not os.path.exists(log):
|
||||
print(" (no experiments yet)")
|
||||
else:
|
||||
latest = OrderedDict()
|
||||
with open(log) as f:
|
||||
for line in f:
|
||||
try:
|
||||
e = json.loads(line)
|
||||
latest[e.get('project')] = e
|
||||
except Exception:
|
||||
pass
|
||||
for proj, e in latest.items():
|
||||
kept = '✓' if e.get('kept') else '✗'
|
||||
desc = (e.get('description') or '')[:50]
|
||||
print(f" {proj}: exp {e.get('exp', '?')} {kept} — {desc}")
|
||||
PYEOF
|
||||
}
|
||||
|
||||
case "${1:-start}" in
|
||||
start) cmd_start ;;
|
||||
stop) cmd_stop ;;
|
||||
status) cmd_status ;;
|
||||
*)
|
||||
echo "Usage: $(basename "$0") [start|stop|status]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user