This repository has been archived on 2026-03-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Timmy-time-dashboard/scripts/agent_workspace.sh

246 lines
8.7 KiB
Bash
Raw Permalink Normal View History

#!/usr/bin/env bash
# ── Agent Workspace Manager ────────────────────────────────────────────
# Creates and maintains fully isolated environments per agent.
# ~/Timmy-Time-dashboard is SACRED — never touched by agents.
#
# Each agent gets:
# - Its own git clone (from Gitea, not the local repo)
# - Its own port range (no collisions)
# - Its own data/ directory (databases, files)
# - Its own TIMMY_HOME (approvals.db, etc.)
# - Shared Ollama backend (single GPU, shared inference)
# - Shared Gitea (single source of truth for issues/PRs)
#
# Layout:
# /tmp/timmy-agents/
# hermes/ — Hermes loop orchestrator
# repo/ — git clone
# home/ — TIMMY_HOME (approvals.db, etc.)
# env.sh — source this for agent's env vars
# kimi-0/ — Kimi pane 0
# repo/
# home/
# env.sh
# ...
# smoke/ — dedicated for smoke-testing main
# repo/
# home/
# env.sh
#
# Usage:
# agent_workspace.sh init <agent> — create or refresh
# agent_workspace.sh reset <agent> — hard reset to origin/main
# agent_workspace.sh branch <agent> <br> — fresh branch from main
# agent_workspace.sh path <agent> — print repo path
# agent_workspace.sh env <agent> — print env.sh path
# agent_workspace.sh init-all — init all workspaces
# agent_workspace.sh destroy <agent> — remove workspace entirely
# ───────────────────────────────────────────────────────────────────────
set -o pipefail
CANONICAL="$HOME/Timmy-Time-dashboard"
AGENTS_DIR="/tmp/timmy-agents"
GITEA_REMOTE="http://localhost:3000/rockachopa/Timmy-time-dashboard.git"
TOKEN_FILE="$HOME/.hermes/gitea_token"
# ── Port allocation (each agent gets a unique range) ──────────────────
# Dashboard ports: 8100, 8101, 8102, ... (avoids real dashboard on 8000)
# Serve ports: 8200, 8201, 8202, ...
agent_index() {
case "$1" in
hermes) echo 0 ;; kimi-0) echo 1 ;; kimi-1) echo 2 ;;
kimi-2) echo 3 ;; kimi-3) echo 4 ;; smoke) echo 9 ;;
*) echo 0 ;;
esac
}
get_dashboard_port() { echo $(( 8100 + $(agent_index "$1") )); }
get_serve_port() { echo $(( 8200 + $(agent_index "$1") )); }
log() { echo "[workspace] $*"; }
# ── Get authenticated remote URL ──────────────────────────────────────
get_remote_url() {
if [ -f "$TOKEN_FILE" ]; then
local token=""
token=$(cat "$TOKEN_FILE" 2>/dev/null || true)
if [ -n "$token" ]; then
echo "http://hermes:${token}@localhost:3000/rockachopa/Timmy-time-dashboard.git"
return
fi
fi
echo "$GITEA_REMOTE"
}
# ── Create env.sh for an agent ────────────────────────────────────────
write_env() {
local agent="$1"
local ws="$AGENTS_DIR/$agent"
local repo="$ws/repo"
local home="$ws/home"
local dash_port=$(get_dashboard_port "$agent")
local serve_port=$(get_serve_port "$agent")
cat > "$ws/env.sh" << EOF
# Auto-generated agent environment — source this before running Timmy
# Agent: $agent
export TIMMY_WORKSPACE="$repo"
export TIMMY_HOME="$home"
export TIMMY_AGENT_NAME="$agent"
# Ports (isolated per agent)
export PORT=$dash_port
export TIMMY_SERVE_PORT=$serve_port
# Ollama (shared — single GPU)
export OLLAMA_URL="http://localhost:11434"
# Gitea (shared — single source of truth)
export GITEA_URL="http://localhost:3000"
# Test mode defaults
export TIMMY_TEST_MODE=1
export TIMMY_DISABLE_CSRF=1
export TIMMY_SKIP_EMBEDDINGS=1
# Override data paths to stay inside the clone
export TIMMY_DATA_DIR="$repo/data"
export TIMMY_BRAIN_DB="$repo/data/brain.db"
# Working directory
cd "$repo"
EOF
chmod +x "$ws/env.sh"
}
# ── Init ──────────────────────────────────────────────────────────────
init_workspace() {
local agent="$1"
local ws="$AGENTS_DIR/$agent"
local repo="$ws/repo"
local home="$ws/home"
local remote
remote=$(get_remote_url)
mkdir -p "$ws" "$home"
if [ -d "$repo/.git" ]; then
log "$agent: refreshing existing clone..."
cd "$repo"
git remote set-url origin "$remote" 2>/dev/null
git fetch origin --prune --quiet 2>/dev/null
git checkout main --quiet 2>/dev/null
git reset --hard origin/main --quiet 2>/dev/null
git clean -fdx -e data/ --quiet 2>/dev/null
else
log "$agent: cloning from Gitea..."
git clone "$remote" "$repo" --quiet 2>/dev/null
cd "$repo"
git fetch origin --prune --quiet 2>/dev/null
fi
# Ensure data directory exists
mkdir -p "$repo/data"
# Write env file
write_env "$agent"
log "$agent: ready at $repo (port $(get_dashboard_port "$agent"))"
}
# ── Reset ─────────────────────────────────────────────────────────────
reset_workspace() {
local agent="$1"
local repo="$AGENTS_DIR/$agent/repo"
if [ ! -d "$repo/.git" ]; then
init_workspace "$agent"
return
fi
cd "$repo"
git merge --abort 2>/dev/null || true
git rebase --abort 2>/dev/null || true
git cherry-pick --abort 2>/dev/null || true
git fetch origin --prune --quiet 2>/dev/null
git checkout main --quiet 2>/dev/null
git reset --hard origin/main --quiet 2>/dev/null
git clean -fdx -e data/ --quiet 2>/dev/null
log "$agent: reset to origin/main"
}
# ── Branch ────────────────────────────────────────────────────────────
branch_workspace() {
local agent="$1"
local branch="$2"
local repo="$AGENTS_DIR/$agent/repo"
if [ ! -d "$repo/.git" ]; then
init_workspace "$agent"
fi
cd "$repo"
git fetch origin --prune --quiet 2>/dev/null
git branch -D "$branch" 2>/dev/null || true
git checkout -b "$branch" origin/main --quiet 2>/dev/null
log "$agent: on branch $branch (from origin/main)"
}
# ── Path ──────────────────────────────────────────────────────────────
print_path() {
echo "$AGENTS_DIR/$1/repo"
}
print_env() {
echo "$AGENTS_DIR/$1/env.sh"
}
# ── Init all ──────────────────────────────────────────────────────────
init_all() {
for agent in hermes kimi-0 kimi-1 kimi-2 kimi-3 smoke; do
init_workspace "$agent"
done
log "All workspaces initialized."
echo ""
echo " Agent Port Path"
echo " ────── ──── ────"
for agent in hermes kimi-0 kimi-1 kimi-2 kimi-3 smoke; do
printf " %-9s %d %s\n" "$agent" "$(get_dashboard_port "$agent")" "$AGENTS_DIR/$agent/repo"
done
}
# ── Destroy ───────────────────────────────────────────────────────────
destroy_workspace() {
local agent="$1"
local ws="$AGENTS_DIR/$agent"
if [ -d "$ws" ]; then
rm -rf "$ws"
log "$agent: destroyed"
else
log "$agent: nothing to destroy"
fi
}
# ── CLI dispatch ──────────────────────────────────────────────────────
case "${1:-help}" in
init) init_workspace "${2:?Usage: $0 init <agent>}" ;;
reset) reset_workspace "${2:?Usage: $0 reset <agent>}" ;;
branch) branch_workspace "${2:?Usage: $0 branch <agent> <branch>}" \
"${3:?Usage: $0 branch <agent> <branch>}" ;;
path) print_path "${2:?Usage: $0 path <agent>}" ;;
env) print_env "${2:?Usage: $0 env <agent>}" ;;
init-all) init_all ;;
destroy) destroy_workspace "${2:?Usage: $0 destroy <agent>}" ;;
*)
echo "Usage: $0 {init|reset|branch|path|env|init-all|destroy} [agent] [branch]"
echo ""
echo "Agents: hermes, kimi-0, kimi-1, kimi-2, kimi-3, smoke"
exit 1
;;
esac