mirror of
https://github.com/RYDE-WORK/autoresearch.git
synced 2026-07-22 07:31:38 +08:00
dam, erase experimental file from before that snuck through in my purge
This commit is contained in:
parent
2a70301b10
commit
1e207aaf21
248
spawn.sh
248
spawn.sh
@ -1,248 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# spawn.sh — launch and manage autonomous research groups
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# bash spawn.sh launch <tag> <agent:gpu> [agent:gpu ...]
|
|
||||||
# bash spawn.sh stop <tag>
|
|
||||||
# bash spawn.sh status
|
|
||||||
#
|
|
||||||
# Examples:
|
|
||||||
# bash spawn.sh launch mar5 claude:0 claude:1 claude:2 claude:3
|
|
||||||
# bash spawn.sh launch mar5 opus:0 sonnet:1 codex:2 codex:3
|
|
||||||
# bash spawn.sh stop mar5
|
|
||||||
# bash spawn.sh status
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
REPO_ROOT="$(cd "$(dirname "$0")" && pwd)"
|
|
||||||
WORKTREE_DIR="${REPO_ROOT}/worktrees"
|
|
||||||
INITIAL_PROMPT="Read program.md and follow the instructions."
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# Helpers
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
echo "Usage:"
|
|
||||||
echo " $0 launch <tag> <agent:gpu> [agent:gpu ...]"
|
|
||||||
echo " $0 stop <tag>"
|
|
||||||
echo " $0 status"
|
|
||||||
echo ""
|
|
||||||
echo "Examples:"
|
|
||||||
echo " $0 launch mar5 claude:0 claude:1 claude:2 claude:3"
|
|
||||||
echo " $0 launch mar5 opus:0 sonnet:1 codex:2 codex:3"
|
|
||||||
echo " $0 stop mar5"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_worker() {
|
|
||||||
local tag="$1" gpu="$2" agent="$3"
|
|
||||||
local branch="autoresearch/${tag}-gpu${gpu}"
|
|
||||||
local worktree="${WORKTREE_DIR}/gpu${gpu}"
|
|
||||||
local claude_model="${CLAUDE_MODEL:-sonnet}"
|
|
||||||
|
|
||||||
# Create branch (must be fresh)
|
|
||||||
cd "$REPO_ROOT"
|
|
||||||
if git show-ref --verify --quiet "refs/heads/${branch}"; then
|
|
||||||
echo "ERROR: Branch '${branch}' already exists. Use a different tag or clean up first." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
git checkout -q master
|
|
||||||
git checkout -q -b "$branch"
|
|
||||||
git checkout -q master
|
|
||||||
|
|
||||||
# Set up worktree
|
|
||||||
if [ -d "$worktree" ]; then
|
|
||||||
git worktree remove "$worktree" --force 2>/dev/null || rm -rf "$worktree"
|
|
||||||
fi
|
|
||||||
mkdir -p "$(dirname "$worktree")"
|
|
||||||
git worktree add "$worktree" "$branch"
|
|
||||||
|
|
||||||
# Symlink .venv so uv/python work
|
|
||||||
ln -sf "${REPO_ROOT}/.venv" "${worktree}/.venv"
|
|
||||||
|
|
||||||
# Build agent command
|
|
||||||
case "$agent" in
|
|
||||||
claude|sonnet|opus|haiku)
|
|
||||||
case "$agent" in
|
|
||||||
sonnet|opus|haiku) claude_model="$agent" ;;
|
|
||||||
esac
|
|
||||||
echo "cd ${worktree} && CUDA_VISIBLE_DEVICES=${gpu} claude --dangerously-skip-permissions --model ${claude_model} \"${INITIAL_PROMPT}\""
|
|
||||||
;;
|
|
||||||
codex)
|
|
||||||
echo "cd ${worktree} && CUDA_VISIBLE_DEVICES=${gpu} codex --dangerously-bypass-approvals-and-sandbox --model gpt-5.3-codex-spark \"${INITIAL_PROMPT}\""
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "ERROR: Unknown agent '${agent}'. Supported: claude, sonnet, opus, haiku, codex" >&2
|
|
||||||
git worktree remove "$worktree" --force 2>/dev/null || true
|
|
||||||
git branch -D "$branch" 2>/dev/null || true
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# Commands
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
cmd_launch() {
|
|
||||||
if [ $# -lt 2 ]; then
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
|
|
||||||
local tag="$1"
|
|
||||||
shift
|
|
||||||
local specs=("$@")
|
|
||||||
local tmux_session="autoresearch-${tag}"
|
|
||||||
local num_workers=${#specs[@]}
|
|
||||||
|
|
||||||
# Kill existing session
|
|
||||||
tmux kill-session -t "$tmux_session" 2>/dev/null || true
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "============================================"
|
|
||||||
echo " RESEARCH GROUP: ${tag}"
|
|
||||||
echo "============================================"
|
|
||||||
echo " Workers: ${num_workers}"
|
|
||||||
|
|
||||||
local pane_cmds=()
|
|
||||||
local labels=()
|
|
||||||
local agents=()
|
|
||||||
|
|
||||||
for spec in "${specs[@]}"; do
|
|
||||||
local agent="${spec%%:*}"
|
|
||||||
local gpu="${spec#*:}"
|
|
||||||
|
|
||||||
echo " - GPU ${gpu}: ${agent}"
|
|
||||||
|
|
||||||
local cmd
|
|
||||||
cmd=$(setup_worker "$tag" "$gpu" "$agent")
|
|
||||||
pane_cmds+=("$cmd")
|
|
||||||
labels+=("$spec")
|
|
||||||
case "$agent" in
|
|
||||||
sonnet|opus|haiku|claude) agents+=("claude") ;;
|
|
||||||
*) agents+=("$agent") ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
echo " tmux: ${tmux_session}"
|
|
||||||
echo "============================================"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Create tmux session with tiled grid
|
|
||||||
tmux new-session -d -s "$tmux_session" -n workers \
|
|
||||||
"${pane_cmds[0]}; echo ''; echo 'Session ended. Press any key to exit.'; read"
|
|
||||||
|
|
||||||
for ((i=1; i<num_workers; i++)); do
|
|
||||||
tmux split-window -t "$tmux_session:workers" \
|
|
||||||
"${pane_cmds[$i]}; echo ''; echo 'Session ended. Press any key to exit.'; read"
|
|
||||||
tmux select-layout -t "$tmux_session:workers" tiled
|
|
||||||
done
|
|
||||||
tmux select-layout -t "$tmux_session:workers" tiled
|
|
||||||
|
|
||||||
echo " Attach: tmux attach -t ${tmux_session}"
|
|
||||||
echo " Detach: Ctrl-b d"
|
|
||||||
echo " Zoom: Ctrl-b z (toggle pane fullscreen)"
|
|
||||||
echo " Navigate: Ctrl-b arrow keys"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Background watcher — nudge idle agents
|
|
||||||
local nudge_interval=120
|
|
||||||
echo "Watcher running (nudge interval: ${nudge_interval}s). Ctrl-C to stop watcher only."
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
declare -A prev_hash
|
|
||||||
|
|
||||||
while tmux has-session -t "$tmux_session" 2>/dev/null; do
|
|
||||||
sleep "$nudge_interval"
|
|
||||||
|
|
||||||
for ((i=0; i<num_workers; i++)); do
|
|
||||||
tmux has-session -t "$tmux_session" 2>/dev/null || break
|
|
||||||
|
|
||||||
local pane="${tmux_session}:workers.${i}"
|
|
||||||
local content curr_hash
|
|
||||||
|
|
||||||
content=$(tmux capture-pane -t "$pane" -p 2>/dev/null) || continue
|
|
||||||
curr_hash=$(echo "$content" | md5sum | cut -d' ' -f1)
|
|
||||||
|
|
||||||
if [ "${prev_hash[$i]:-}" != "$curr_hash" ]; then
|
|
||||||
prev_hash[$i]="$curr_hash"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
local is_idle=false
|
|
||||||
if echo "$content" | grep -qP '^❯\s*$'; then
|
|
||||||
is_idle=true
|
|
||||||
elif echo "$content" | grep -qP '^›\s*$'; then
|
|
||||||
is_idle=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$is_idle" = true ]; then
|
|
||||||
local nudge_msg="Keep going. Do not stop — continue your research loop."
|
|
||||||
if [ "${agents[$i]}" = "codex" ]; then
|
|
||||||
tmux send-keys -t "$pane" "$nudge_msg" Enter
|
|
||||||
else
|
|
||||||
tmux send-keys -t "$pane" "$nudge_msg" C-m
|
|
||||||
fi
|
|
||||||
echo "[$(date +%H:%M:%S)] Nudged pane ${i} (${labels[$i]})"
|
|
||||||
prev_hash[$i]=""
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "tmux session ended. Watcher exiting."
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd_stop() {
|
|
||||||
if [ $# -lt 1 ]; then
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
|
|
||||||
local tag="$1"
|
|
||||||
local tmux_session="autoresearch-${tag}"
|
|
||||||
|
|
||||||
# Kill tmux session
|
|
||||||
if tmux kill-session -t "$tmux_session" 2>/dev/null; then
|
|
||||||
echo "Killed tmux session '${tmux_session}'"
|
|
||||||
else
|
|
||||||
echo "No tmux session '${tmux_session}' found"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Remove worktrees
|
|
||||||
local removed=0
|
|
||||||
for wt in "${WORKTREE_DIR}"/gpu*; do
|
|
||||||
[ -d "$wt" ] || continue
|
|
||||||
git -C "$REPO_ROOT" worktree remove "$wt" --force 2>/dev/null && removed=$((removed + 1))
|
|
||||||
done
|
|
||||||
echo "Removed ${removed} worktree(s)"
|
|
||||||
echo "Branches kept for review (git branch -l 'autoresearch/${tag}-*')"
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd_status() {
|
|
||||||
echo "Active tmux sessions:"
|
|
||||||
tmux list-sessions 2>/dev/null | grep "^autoresearch-" || echo " (none)"
|
|
||||||
echo ""
|
|
||||||
echo "Active worktrees:"
|
|
||||||
git -C "$REPO_ROOT" worktree list 2>/dev/null | grep "worktrees/" || echo " (none)"
|
|
||||||
echo ""
|
|
||||||
echo "Research branches:"
|
|
||||||
git -C "$REPO_ROOT" branch -l 'autoresearch/*' 2>/dev/null || echo " (none)"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# Main
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
if [ $# -lt 1 ]; then
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
|
|
||||||
COMMAND="$1"
|
|
||||||
shift
|
|
||||||
|
|
||||||
case "$COMMAND" in
|
|
||||||
launch) cmd_launch "$@" ;;
|
|
||||||
stop) cmd_stop "$@" ;;
|
|
||||||
status) cmd_status "$@" ;;
|
|
||||||
*) usage ;;
|
|
||||||
esac
|
|
||||||
Loading…
x
Reference in New Issue
Block a user