agent-container/setup.sh

105 lines
No EOL
3.1 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# Set up shared agent state for agent-container.
#
# Moves agent state (Claude Code, Pi, OpenCode) from the real $HOME into the
# container home and symlinks it back, so the containerized tools (claude, pi,
# opencode) and the local variants (claude-local, pi-local, opencode-local)
# share logins, settings, and history. See README.md, section "Sharing agent
# state between host and container via symlinks".
#
# Safe to re-run: already shared items are detected and left alone.
set -euo pipefail
XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
CONTAINER_HOME="$XDG_DATA_HOME/agent-container/container-home"
# State directories to share. Created in the container home (and linked into
# $HOME) even if they don't exist yet, so both sides share from the start.
DIRS=(
.claude
.pi
.agents
.config/opencode
.local/share/opencode
)
# Single files to share. Only linked when they exist on one side, tools create
# them on first use.
FILES=(
.claude.json
)
info() { printf ' %s\n' "$*"; }
warn() { printf ' warning: %s\n' "$*" >&2; }
# Print the action taken for an item, shared by both helpers below.
_report() {
local action="$1" item="$2"
case "$action" in
moved) info "moved $item into the container home, symlinked from \$HOME" ;;
linked) info "linked $item (container home already had it)" ;;
created) info "created $item in the container home, symlinked from \$HOME" ;;
ok) info "ok $item (already shared)" ;;
skip) info "skip $item (does not exist yet, the tool will create it)" ;;
esac
}
share_item() {
local item="$1" must_exist="$2"
local host="$HOME/$item" target="$CONTAINER_HOME/$item"
if [ -L "$host" ]; then
case "$(readlink -f "$host")" in
"$CONTAINER_HOME"/*)
_report ok "$item"
return
;;
*)
warn "$item is a symlink to $(readlink "$host"), not touching it"
return
;;
esac
fi
if [ -e "$host" ] && [ -e "$target" ]; then
warn "$item exists in both \$HOME and the container home"
warn "reconcile the two copies manually, then re-run this script"
return
fi
if [ ! -e "$host" ] && [ ! -e "$target" ]; then
if [ "$must_exist" = "yes" ]; then
_report skip "$item"
return
fi
mkdir -p "$target"
_report created "$item"
elif [ -e "$host" ]; then
mkdir -p "$(dirname "$target")"
mv "$host" "$target"
_report moved "$item"
else
_report linked "$item"
fi
mkdir -p "$(dirname "$host")"
ln -s "$target" "$host"
}
main() {
printf 'Sharing agent state via %s\n\n' "$CONTAINER_HOME"
local item
for item in "${DIRS[@]}"; do share_item "$item" no; done
for item in "${FILES[@]}"; do share_item "$item" yes; done
if [ -f "$HOME/.gitconfig" ] && [ ! -e "$CONTAINER_HOME/.gitconfig" ]; then
printf '\n'
info "Tip: share your git config too (see README):"
info " ln $HOME/.gitconfig $CONTAINER_HOME/.gitconfig"
fi
}
main "$@"