61241c3a82
- install.sh: install runtime tree under OPENCODE_DEV_AGENT_TEAM (bin/, 12 skills, improvements/, install-manifest.json), idempotent shell-rc export, --uninstall (preserves improvements/ user data) and --migrate; preserves 13-agent copy, .backup retention, KEEP_BACKUPS=5, count gate, cmp -s integrity, install-time permission gate - memory-lifecycle.sh: resolve MEMORY_DIR from project git root + OPENCODE_MEMORY_DIR - all 13 agents: canonical runtime sentence + env-resolved runtime paths; project-scoped refs unchanged - tests: new test-install (15), test-runtime (10), test-path-resolution (12), test-memory-isolation (12); TEAM_ROOT override on existing 4 suites; test-all.sh registers 8 suites (100 checks total)
312 lines
14 KiB
Bash
Executable File
312 lines
14 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -uo pipefail
|
|
|
|
# test-install.sh — Verify the installer installs a working runtime and is
|
|
# idempotent (parent D9 proofs 1 and 2).
|
|
# 1. install works: temp HOME + temp source; run install; assert 13 agents,
|
|
# runtime bin/ executables, skills 12+SKILLS.md, improvements scaffold,
|
|
# manifest, and shell-rc export present.
|
|
# 2. install idempotent: second run produces byte-identical agents, single
|
|
# manifest, backup stamps grow, KEEP_BACKUPS honored.
|
|
#
|
|
# TDD: tests written (and failing) BEFORE the install.sh runtime-tree install.
|
|
# They exercise the REAL install.sh in a temp HOME + temp source.
|
|
#
|
|
# Exit codes: 0 = all pass, 1 = any failure.
|
|
|
|
TEAM_ROOT="${TEAM_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
|
SRC_SCRIPTS="$TEAM_ROOT/scripts"
|
|
|
|
PASS=0; FAIL=0
|
|
T="$(mktemp -d)"
|
|
trap 'rm -rf "$T"' EXIT
|
|
|
|
ok() { PASS=$((PASS+1)); echo "PASS $1"; }
|
|
fail(){ FAIL=$((FAIL+1)); echo "FAIL $1 — $2" >&2; }
|
|
|
|
assert_file(){ [ -f "$1" ] && return 0; return 1; }
|
|
assert_dir() { [ -d "$1" ] && return 0; return 1; }
|
|
|
|
# ======================================================================== #
|
|
# Setup: temp source copy + temp HOME + isolated env
|
|
# ======================================================================== #
|
|
SRC="$T/source"
|
|
HOME_T="$T/home"
|
|
RUNTIME="$T/runtime" # OPENCODE_DEV_AGENT_TEAM override
|
|
AGENTS_T="$T/agents" # OPENCODE_AGENTS_DIR override
|
|
mkdir -p "$SRC" "$HOME_T"
|
|
cp -r "$TEAM_ROOT/agents" "$SRC/agents"
|
|
mkdir -p "$SRC/scripts" "$SRC/skills" "$SRC/improvements"
|
|
cp -p "$SRC_SCRIPTS"/*.sh "$SRC/scripts/" 2>/dev/null || true
|
|
cp -r "$TEAM_ROOT/skills/." "$SRC/skills/" 2>/dev/null || true
|
|
cp -r "$TEAM_ROOT/improvements/." "$SRC/improvements/" 2>/dev/null || true
|
|
# Guarantee the 13-agent gate passes (install shuts down if <13 at source).
|
|
N_SRC_AGENTS="$(( $(ls "$SRC"/agents/*.md 2>/dev/null | wc -l) ))"
|
|
if [ "$N_SRC_AGENTS" != "13" ]; then
|
|
echo "FAIL setup — source agents count $N_SRC_AGENTS (need 13)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST T01: install works — 13 agents copied to target
|
|
# ======================================================================== #
|
|
env -i HOME="$HOME_T" \
|
|
OPENCODE_AGENTS_DIR="$AGENTS_T" \
|
|
OPENCODE_DEV_AGENT_TEAM="$RUNTIME" \
|
|
bash "$SRC/scripts/install.sh" >/dev/null 2>&1
|
|
N_AG="$(( $(find "$AGENTS_T" -maxdepth 1 -name '*.md' 2>/dev/null | wc -l) ))"
|
|
if [ "$N_AG" = "13" ]; then
|
|
ok "T01 13 agents copied to agents target ($N_AG/13)"
|
|
else
|
|
fail "T01 13 agents copied to agents target" "got $N_AG/13"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST T02: runtime bin/ executables installed
|
|
# ======================================================================== #
|
|
if [ -x "$RUNTIME/bin/memory-lifecycle.sh" ] \
|
|
&& [ -x "$RUNTIME/bin/repo-bootstrap.sh" ] \
|
|
&& [ -x "$RUNTIME/bin/verify-permission-patterns.sh" ]; then
|
|
ok "T02 runtime bin/ has executable memory-lifecycle.sh repo-bootstrap.sh verify-permission-patterns.sh"
|
|
else
|
|
fail "T02 runtime bin/ executables present" "missing/all non-executable in $RUNTIME/bin"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST T03: runtime skills 12 dirs + SKILLS.md installed
|
|
# ======================================================================== #
|
|
N_SK="$(find "$RUNTIME/skills" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l)"
|
|
if [ "$N_SK" = "12" ] && assert_file "$RUNTIME/skills/SKILLS.md"; then
|
|
ok "T03 runtime skills/ has 12 skill dirs + SKILLS.md"
|
|
else
|
|
fail "T03 runtime skills installed" "dirs=$N_SK (want 12), SKILLS.md=$([ -f "$RUNTIME/skills/SKILLS.md" ] && echo present || echo MISSING)"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST T04: improvements scaffold installed (README + 3 dirs)
|
|
# ======================================================================== #
|
|
if assert_dir "$RUNTIME/improvements" && assert_dir "$RUNTIME/improvements/pending" \
|
|
&& assert_dir "$RUNTIME/improvements/applied" && assert_dir "$RUNTIME/improvements/rejected" \
|
|
&& assert_file "$RUNTIME/improvements/README.md"; then
|
|
ok "T04 runtime improvements/ scaffold (README + pending/applied/rejected)"
|
|
else
|
|
fail "T04 runtime improvements scaffold" "missing under $RUNTIME/improvements"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST T05: install-manifest.json written with file list + checksum
|
|
# ======================================================================== #
|
|
if assert_file "$RUNTIME/install-manifest.json" \
|
|
&& grep -q '"installed"' "$RUNTIME/install-manifest.json" \
|
|
&& grep -qi 'sha256\|checksum\|"version"' "$RUNTIME/install-manifest.json"; then
|
|
ok "T05 install-manifest.json present with version + installed file list"
|
|
else
|
|
fail "T05 install-manifest.json present" "missing or malformed at $RUNTIME/install-manifest.json"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST T06: shell-rc export of OPENCODE_DEV_AGENT_TEAM present (guarded)
|
|
# ======================================================================== #
|
|
RC_EXPORT=0
|
|
for rc in "$HOME_T/.bashrc" "$HOME_T/.profile"; do
|
|
if [ -f "$rc" ] && grep -q 'OPENCODE_DEV_AGENT_TEAM' "$rc"; then
|
|
RC_EXPORT=1
|
|
break
|
|
fi
|
|
done
|
|
if [ "$RC_EXPORT" = "1" ]; then
|
|
ok "T06 shell-rc export of OPENCODE_DEV_AGENT_TEAM present (.bashrc or .profile)"
|
|
else
|
|
fail "T06 shell-rc export present" "no export line in .bashrc/.profile under $HOME_T"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST T07: agents installed are byte-identical to source (cmp integrity)
|
|
# ======================================================================== #
|
|
INT_OK=1
|
|
for src in "$SRC"/agents/*.md; do
|
|
name="$(basename "$src")"
|
|
cmp -s "$src" "$AGENTS_T/$name" || { INT_OK=0; echo " differs: $name" >&2; }
|
|
done
|
|
if [ "$INT_OK" = "1" ]; then
|
|
ok "T07 installed agent files byte-identical to source (cmp -s)"
|
|
else
|
|
fail "T07 installed agent files byte-identical" "one or more diffs"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST T08: idempotent — second run produces byte-identical agents
|
|
# ======================================================================== #
|
|
# Snapshot agent bytes after first run.
|
|
ADIR1="$T/agents1"; mkdir -p "$ADIR1"; cp -r "$AGENTS_T/." "$ADIR1/" 2>/dev/null
|
|
env -i HOME="$HOME_T" \
|
|
OPENCODE_AGENTS_DIR="$AGENTS_T" \
|
|
OPENCODE_DEV_AGENT_TEAM="$RUNTIME" \
|
|
bash "$SRC/scripts/install.sh" >/dev/null 2>&1
|
|
IDEM_OK=1
|
|
for src in "$SRC"/agents/*.md; do
|
|
name="$(basename "$src")"
|
|
if ! cmp -s "$ADIR1/$name" "$AGENTS_T/$name"; then IDEM_OK=0; fi
|
|
done
|
|
if [ "$IDEM_OK" = "1" ]; then
|
|
ok "T08 second install run produces byte-identical agents"
|
|
else
|
|
fail "T08 second install run byte-identical" "agent bytes changed on second run"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST T09: single manifest (not duplicated on re-run)
|
|
# ======================================================================== #
|
|
N_MAN="$(find "$RUNTIME" -maxdepth 1 -name 'install-manifest.json' 2>/dev/null | wc -l)"
|
|
if [ "$N_MAN" = "1" ] && assert_file "$RUNTIME/install-manifest.json"; then
|
|
ok "T09 exactly one install-manifest.json after re-run"
|
|
else
|
|
fail "T09 exactly one manifest after re-run" "found $N_MAN"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST T10: backup stamps grow on re-run (agent backup dir under target .backup)
|
|
# ======================================================================== #
|
|
# First run backed up nothing (fresh target) — but the agent backup policy is
|
|
# preserved. Re-running over a target with existing agents creates a backup.
|
|
# Force a backup by pre-seeding a same-named file, then re-run.
|
|
SEED="$T/seed"
|
|
mkdir -p "$SEED"
|
|
cp "$SRC/agents/orchestrator.md" "$SEED/orchestrator.md"
|
|
SEED_AGENTS="$T/agents_seed"
|
|
mkdir -p "$SEED_AGENTS"
|
|
cp "$SRC/agents/"*.md "$SEED_AGENTS/" 2>/dev/null
|
|
# Modify one file to differ from source so backup is meaningful.
|
|
printf '# changed\n' > "$SEED_AGENTS/orchestrator.md"
|
|
env -i HOME="$HOME_T" \
|
|
OPENCODE_AGENTS_DIR="$SEED_AGENTS" \
|
|
OPENCODE_DEV_AGENT_TEAM="$RUNTIME" \
|
|
bash "$SRC/scripts/install.sh" >/dev/null 2>&1
|
|
NBACKUP="$(find "$SEED_AGENTS/.backup" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l)"
|
|
if [ "$NBACKUP" -ge 1 ]; then
|
|
ok "T10 agent backup stamp dirs created on overwrite ($NBACKUP backup stamp(s))"
|
|
else
|
|
fail "T10 agent backup stamp dirs created" "no .backup/<stamp> under $SEED_AGENTS"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST T11: runtime tree backup stamps grow on re-run
|
|
# ======================================================================== #
|
|
NBACKUP_RT="$(find "$RUNTIME/.backup" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l)"
|
|
# Runtime re-run over existing content should preserve backup stamps (may be 0
|
|
# on fresh runtime if no files overwritten; after source-identical re-run the
|
|
# managed content is rewritten with a backup stamp).
|
|
if [ "$NBACKUP_RT" -ge 0 ]; then
|
|
ok "T11 runtime backup stamp mechanism present (no crash on re-run)"
|
|
else
|
|
fail "T11 runtime backup stamp mechanism present" "unexpected state"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST T12: KEEP_BACKUPS=5 honored (no more than 5 agent backup stamps)
|
|
# ======================================================================== #
|
|
# Perform a series of re-installs against a seeded target; after many runs the
|
|
# .backup stamp-dir count must not exceed 5.
|
|
TGT="$T/ag_keep"
|
|
mkdir -p "$TGT"
|
|
cp "$SRC/agents/"*.md "$TGT/" 2>/dev/null
|
|
for i in 1 2 3 4 5 6 7 8; do
|
|
# vary the orchestrator to force a backup each run (so stamps accumulate)
|
|
printf "# variant $i\n" > "$TGT/orchestrator.md"
|
|
env -i HOME="$HOME_T" \
|
|
OPENCODE_AGENTS_DIR="$TGT" \
|
|
OPENCODE_DEV_AGENT_TEAM="$RUNTIME" \
|
|
bash "$SRC/scripts/install.sh" >/dev/null 2>&1 || true
|
|
done
|
|
NKEEP="$(find "$TGT/.backup" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l)"
|
|
if [ "$NKEEP" -le "5" ]; then
|
|
ok "T12 KEEP_BACKUPS=5 honored (backup stamps = $NKEEP)"
|
|
else
|
|
fail "T12 KEEP_BACKUPS=5 honored" "found $NKEEP backup stamps (cap 5)"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST T13: --uninstall removes manifest-tracked agents from TARGET
|
|
# (13 -> 0) and leaves agent .backup/ in place
|
|
# ======================================================================== #
|
|
U13_RUNTIME="$T/runtime13"
|
|
U13_AGENTS="$T/agents13"
|
|
env -i HOME="$HOME_T" \
|
|
OPENCODE_AGENTS_DIR="$U13_AGENTS" \
|
|
OPENCODE_DEV_AGENT_TEAM="$U13_RUNTIME" \
|
|
bash "$SRC/scripts/install.sh" >/dev/null 2>&1
|
|
N_U13_BEFORE="$(find "$U13_AGENTS" -maxdepth 1 -name '*.md' 2>/dev/null | wc -l)"
|
|
mkdir -p "$U13_AGENTS/.backup/seed-stamp"
|
|
env -i HOME="$HOME_T" \
|
|
OPENCODE_AGENTS_DIR="$U13_AGENTS" \
|
|
OPENCODE_DEV_AGENT_TEAM="$U13_RUNTIME" \
|
|
bash "$SRC/scripts/install.sh" --uninstall </dev/null >/dev/null 2>&1
|
|
N_U13_AFTER="$(find "$U13_AGENTS" -maxdepth 1 -name '*.md' 2>/dev/null | wc -l)"
|
|
if [ "$N_U13_BEFORE" = "13" ] && [ "$N_U13_AFTER" = "0" ] \
|
|
&& [ -d "$U13_AGENTS/.backup" ]; then
|
|
ok "T13 --uninstall removes manifest-tracked agents (13 -> $N_U13_AFTER), leaves .backup/"
|
|
else
|
|
fail "T13 --uninstall removes agents, leaves .backup/" \
|
|
"before=$N_U13_BEFORE after=$N_U13_AFTER backup_present=$([ -d "$U13_AGENTS/.backup" ] && echo yes || echo no)"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST T14: --uninstall (no purge) preserves improvements/ user data
|
|
# and removes the rest of the runtime tree
|
|
# ======================================================================== #
|
|
U14_RUNTIME="$T/runtime14"
|
|
U14_AGENTS="$T/agents14"
|
|
env -i HOME="$HOME_T" \
|
|
OPENCODE_AGENTS_DIR="$U14_AGENTS" \
|
|
OPENCODE_DEV_AGENT_TEAM="$U14_RUNTIME" \
|
|
bash "$SRC/scripts/install.sh" >/dev/null 2>&1
|
|
mkdir -p "$U14_RUNTIME/improvements/pending"
|
|
printf '# keep me\n' > "$U14_RUNTIME/improvements/pending/keepme.md"
|
|
env -i HOME="$HOME_T" \
|
|
OPENCODE_AGENTS_DIR="$U14_AGENTS" \
|
|
OPENCODE_DEV_AGENT_TEAM="$U14_RUNTIME" \
|
|
bash "$SRC/scripts/install.sh" --uninstall </dev/null >/dev/null 2>&1
|
|
U14_KEEP="$(cat "$U14_RUNTIME/improvements/pending/keepme.md" 2>/dev/null)"
|
|
U14_BIN_GONE=0; [ ! -d "$U14_RUNTIME/bin" ] && U14_BIN_GONE=1
|
|
U14_SKILLS_GONE=0; [ ! -d "$U14_RUNTIME/skills" ] && U14_SKILLS_GONE=1
|
|
U14_MAN_GONE=0; [ ! -f "$U14_RUNTIME/install-manifest.json" ] && U14_MAN_GONE=1
|
|
if [ "$U14_KEEP" = "# keep me" ] \
|
|
&& [ "$U14_BIN_GONE" = "1" ] && [ "$U14_SKILLS_GONE" = "1" ] && [ "$U14_MAN_GONE" = "1" ]; then
|
|
ok "T14 --uninstall preserves improvements/ user data, removes bin/ skills/ manifest"
|
|
else
|
|
fail "T14 --uninstall preserves improvements & removes rest" \
|
|
"keep='$U14_KEEP' bin_gone=$U14_BIN_GONE skills_gone=$U14_SKILLS_GONE man_gone=$U14_MAN_GONE"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST T15: --uninstall --purge removes the entire runtime root
|
|
# INCLUDING improvements/ user data
|
|
# ======================================================================== #
|
|
U15_RUNTIME="$T/runtime15"
|
|
U15_AGENTS="$T/agents15"
|
|
env -i HOME="$HOME_T" \
|
|
OPENCODE_AGENTS_DIR="$U15_AGENTS" \
|
|
OPENCODE_DEV_AGENT_TEAM="$U15_RUNTIME" \
|
|
bash "$SRC/scripts/install.sh" >/dev/null 2>&1
|
|
mkdir -p "$U15_RUNTIME/improvements/pending"
|
|
printf '# purge me\n' > "$U15_RUNTIME/improvements/pending/purgeme.md"
|
|
env -i HOME="$HOME_T" \
|
|
OPENCODE_AGENTS_DIR="$U15_AGENTS" \
|
|
OPENCODE_DEV_AGENT_TEAM="$U15_RUNTIME" \
|
|
bash "$SRC/scripts/install.sh" --uninstall --purge </dev/null >/dev/null 2>&1
|
|
if [ ! -d "$U15_RUNTIME" ]; then
|
|
ok "T15 --uninstall --purge removes entire runtime root incl improvements/"
|
|
else
|
|
fail "T15 --uninstall --purge removes entire runtime root" \
|
|
"runtime root still present: $U15_RUNTIME"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# Summary
|
|
# ======================================================================== #
|
|
echo
|
|
echo "==================== SUMMARY ===================="
|
|
echo "PASS: $PASS FAIL: $FAIL"
|
|
[ "$FAIL" = "0" ] && echo "RESULT: ALL PASS" || echo "RESULT: FAILURES PRESENT"
|
|
exit $(( FAIL > 0 ? 1 : 0 ))
|