Harden installer: partial-install detection, complete runtime docs, explicit copy checks

This commit is contained in:
2026-06-24 10:43:08 +09:00
parent 387b43d8e3
commit b37407874d
+39 -16
View File
@@ -57,18 +57,35 @@ cd "$TARGET_DIR"
REPO_URL="https://git.godopu.com/tmpl/multi-agent-mux.git" REPO_URL="https://git.godopu.com/tmpl/multi-agent-mux.git"
ARCHIVE_URL="https://git.godopu.com/tmpl/multi-agent-mux/archive/main.tar.gz" ARCHIVE_URL="https://git.godopu.com/tmpl/multi-agent-mux/archive/main.tar.gz"
# Fetch the orchestration assets if missing (for curl one-liner installs). # Helper to verify presence of all core runtime files.
# Keying off a set of core files helps detect and recover from partial/interrupted installations.
check_assets_present() {
local dir="${1:-.}"
local core_files=(
".agents/skills/lib.sh"
".agents/skills/multi-agent-mux-create/scripts/create_session.sh"
".agents/skills/multi-agent-mux-delegate-job/scripts/registry.py"
".agents/skills/multi-agent-mux-status/scripts/status.sh"
)
for f in "${core_files[@]}"; do
if [ ! -f "$dir/$f" ]; then
return 1
fi
done
return 0
}
# Fetch the orchestration assets if missing or incomplete (for curl one-liner installs).
# #
# Safety model (FW-D1): we NEVER extract the repo archive directly into the # Safety model (FW-D1): we NEVER extract the repo archive directly into the
# target. Running inside an existing project must not overwrite the target's # target. Running inside an existing project must not overwrite the target's
# own files (README.md, FUTURE_WORKS.md, …) or litter it with this repo's # own files (README.md, FUTURE_WORKS.md, …) or litter it with this repo's
# development docs. Instead we stage the download into a throwaway temp dir, # development docs. Instead we stage the download into a throwaway temp dir,
# verify it, then copy ONLY the runtime assets (.agents/, AGENT.md, .env.example) # verify it, then copy ONLY the runtime assets (.agents/, documents, .env.example)
# into the target with per-file no-clobber guards so a pre-existing target file # into the target with per-file no-clobber guards so a pre-existing target file
# always wins. We key off lib.sh (a file), not the .agents/skills directory, so # always wins.
# an empty/partial dir can't masquerade as a valid install. if ! check_assets_present "."; then
if [ ! -f ".agents/skills/lib.sh" ]; then echo "📥 Orchestration skills not found or incomplete. Fetching from Gitea repository..."
echo "📥 Orchestration skills not found. Fetching from Gitea repository..."
STAGE_DIR="$(mktemp -d)" STAGE_DIR="$(mktemp -d)"
trap 'rm -rf "$STAGE_DIR"' EXIT trap 'rm -rf "$STAGE_DIR"' EXIT
@@ -84,8 +101,8 @@ if [ ! -f ".agents/skills/lib.sh" ]; then
fi fi
# Verify the staged tree before we trust and copy from it. # Verify the staged tree before we trust and copy from it.
if [ ! -f "$STAGE_DIR/.agents/skills/lib.sh" ]; then if ! check_assets_present "$STAGE_DIR"; then
echo "❌ Error: fetched source is missing '.agents/skills/lib.sh'. Aborting (no files copied)." >&2 echo "❌ Error: fetched source is missing core runtime assets. Aborting (no files copied)." >&2
exit 1 exit 1
fi fi
@@ -99,14 +116,20 @@ if [ ! -f ".agents/skills/lib.sh" ]; then
dest=".agents/${rel#./}" dest=".agents/${rel#./}"
if [ ! -e "$dest" ]; then if [ ! -e "$dest" ]; then
mkdir -p "$(dirname "$dest")" mkdir -p "$(dirname "$dest")"
cp "$STAGE_DIR/.agents/$rel" "$dest" cp "$STAGE_DIR/.agents/$rel" "$dest" || { echo "❌ Error: Failed to copy $rel" >&2; exit 1; }
fi fi
done done
if [ -f "$STAGE_DIR/AGENT.md" ] && [ ! -e "AGENT.md" ]; then
cp "$STAGE_DIR/AGENT.md" . # Copy non-dev documents if they don't already exist.
# We skip dev-specific docs like README.md, DONE.md, and FUTURE_WORKS.md.
for doc in AGENT.md AGENT.ko.md MESSAGING.md BOOTSTRAP.md BOOTSTRAP.ko.md INSTRUCTION.md; do
if [ -f "$STAGE_DIR/$doc" ] && [ ! -e "$doc" ]; then
cp "$STAGE_DIR/$doc" . || { echo "❌ Error: Failed to copy $doc" >&2; exit 1; }
fi fi
done
if [ -f "$STAGE_DIR/.env.example" ] && [ ! -e ".env.example" ]; then if [ -f "$STAGE_DIR/.env.example" ] && [ ! -e ".env.example" ]; then
cp "$STAGE_DIR/.env.example" . cp "$STAGE_DIR/.env.example" . || { echo "❌ Error: Failed to copy .env.example" >&2; exit 1; }
fi fi
rm -rf "$STAGE_DIR" rm -rf "$STAGE_DIR"
@@ -114,10 +137,10 @@ if [ ! -f ".agents/skills/lib.sh" ]; then
echo "✅ Skills staged into workspace (existing files preserved)." echo "✅ Skills staged into workspace (existing files preserved)."
fi fi
# Sanity check: verify a FILE, not just the directory — an empty .agents/skills # Sanity check: verify all core files, not just a single one — an empty or
# would otherwise pass and yield a silently broken install. # incomplete layout would yield a silently broken install.
if [ ! -f ".agents/skills/lib.sh" ]; then if ! check_assets_present "."; then
echo "❌ Error: '.agents/skills/lib.sh' missing after setup. Target layout might be invalid." >&2 echo "❌ Error: Core runtime assets missing after setup. Target layout might be invalid." >&2
exit 1 exit 1
fi fi
echo "✅ Orchestration skills present." echo "✅ Orchestration skills present."