81 lines
3.1 KiB
Bash
Executable File
81 lines
3.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Sync the user's pi config (from dotfiles) into docker/pi-agent/ so the
|
|
# worker image bakes it. Filtered: no secrets, no machine-local state.
|
|
set -euo pipefail
|
|
|
|
SRC="${LVMH_PI_AGENT_DIR:-$HOME/.dotfiles/pi/agent}"
|
|
DEST="${LVMH_PI_BAKE_DIR:-$(dirname "$0")/../docker/pi-agent}"
|
|
|
|
# DEST must exist even without dotfiles: the worker Dockerfile COPYs it
|
|
# unconditionally (a missing dir would fail the build).
|
|
mkdir -p "$DEST"
|
|
|
|
if [ ! -f "$SRC/settings.json" ]; then
|
|
echo "rsync-pi-agent: $SRC/settings.json not found — skipping dotfiles sync" >&2
|
|
exit 0
|
|
fi
|
|
rsync -a --delete \
|
|
--exclude 'auth.json' \
|
|
--exclude 'models-store.json' \
|
|
--exclude 'sessions/' \
|
|
--exclude 'cache/' \
|
|
--exclude 'npm/' \
|
|
--exclude 'git/' \
|
|
--exclude 'trust.json' \
|
|
--exclude 'mcp-*' \
|
|
--exclude 'run-history*' \
|
|
--exclude 'vibes' \
|
|
--exclude '*.log' \
|
|
--exclude 'scratch/' \
|
|
--exclude '.pi/' \
|
|
"$SRC/" "$DEST/"
|
|
|
|
# Pre-seed the git: package cache: clone each pinned git: package into
|
|
# docker/pi-agent/git/... where pi's package manager installs them, with
|
|
# lifecycle scripts ignored (postinstalls like husky crash headless).
|
|
# Keeps subagents/todo/async tooling present with no runtime network need.
|
|
# Requires network access to github.com at bake time.
|
|
python3 - "$DEST" <<'PY'
|
|
import json, os, re, shutil, subprocess, sys
|
|
from pathlib import Path
|
|
|
|
dest = Path(sys.argv[1])
|
|
settings = json.loads((dest / "settings.json").read_text())
|
|
git_root = dest / "git"
|
|
if git_root.exists():
|
|
shutil.rmtree(git_root)
|
|
|
|
for pkg in settings.get("packages") or []:
|
|
if not pkg.startswith("git:"):
|
|
continue
|
|
rest = pkg[4:]
|
|
m = re.match(r"^(.+)@([0-9a-f]{7,40})$", rest)
|
|
repo, ref = (m.group(1), m.group(2)) if m else (rest, None)
|
|
target = git_root / repo
|
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
url = f"https://{repo}" if not repo.startswith("https://") else repo
|
|
print(f"rsync-pi-agent: cloning {repo}@{ref or 'HEAD'}")
|
|
subprocess.run(["git", "clone", "--quiet", url, str(target)], check=True)
|
|
if ref:
|
|
subprocess.run(["git", "checkout", "--quiet", ref], cwd=target, check=True)
|
|
# keep .git: pi's package manager runs `git fetch` + `rev-parse` on
|
|
# existing installs; a stripped dir would fail resolution.
|
|
if (target / "package.json").exists():
|
|
npm = "/usr/bin/npm" if Path("/usr/bin/npm").exists() else "npm"
|
|
# --ignore-scripts: prepare scripts (husky) are devDependency-based
|
|
# and fail headless; extensions are plain TS needing runtime deps only.
|
|
subprocess.run(
|
|
[npm, "install", "--omit=dev", "--ignore-scripts", "--no-audit", "--no-fund"],
|
|
cwd=target, check=True, capture_output=True,
|
|
)
|
|
PY
|
|
|
|
# Append the lvmh deployment guide to the baked APPEND_SYSTEM.md so every
|
|
# spawned agent knows how to deploy hosts / push / open PRs.
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
if [ -f "$SCRIPT_DIR/../docker/agent-append-system.md" ]; then
|
|
printf '\n%s\n' "$(cat "$SCRIPT_DIR/../docker/agent-append-system.md")" >> "$DEST/APPEND_SYSTEM.md"
|
|
fi
|
|
|
|
echo "rsync-pi-agent: synced $(find "$DEST" -type f | wc -l) files from $SRC (git: packages preserved)"
|