diff --git a/bin/start.sh b/bin/start.sh new file mode 100755 index 0000000..3558024 --- /dev/null +++ b/bin/start.sh @@ -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