Skip to content
2 changes: 1 addition & 1 deletion src/agency-agents/devcontainer-feature.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"id": "agency-agents",
"version": "0.3.8",
"version": "0.3.9",
"name": "Agency Agents",
"description": "A complete AI agency at your fingertips - From frontend wizards to Reddit community ninjas, from whimsy injectors to reality checkers. Each agent is a specialized expert with personality, processes, and proven deliverables. Credits: https://github.com/msitarzewski/agency-agents.",
"documentationURL": "https://github.com/wcgomes/devcontainer-features?tab=readme-ov-file#feature-agency-agents",
Expand Down
230 changes: 5 additions & 225 deletions src/agency-agents/install.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/bin/sh

set -eu

log() {
Expand Down Expand Up @@ -59,12 +58,10 @@ ensure_prerequisites() {
missing="${missing} curl"
fi

# Minimal images may lack a CA bundle required for HTTPS downloads.
if [ ! -f /etc/ssl/certs/ca-certificates.crt ]; then
missing="${missing} ca-certificates"
fi

# Trim leading spaces for cleaner logs and checks.
missing="$(echo "$missing" | sed 's/^ *//')"

[ -n "$missing" ] || return 0
Expand All @@ -73,240 +70,23 @@ ensure_prerequisites() {
fail "Missing dependencies: $missing. Rebuild as root or preinstall them in the base image."
fi

log "Installing missing dependencies:$missing"
log "Installing missing dependencies: $missing"
install_packages $missing

command -v unzip >/dev/null 2>&1 || fail "Dependency installation failed: unzip is still missing"
command -v curl >/dev/null 2>&1 || command -v wget >/dev/null 2>&1 || fail "Dependency installation failed: curl/wget are still missing"
[ -f /etc/ssl/certs/ca-certificates.crt ] || fail "Dependency installation failed: CA certificates are still missing"
}

get_remote_commit() {
curl -fsSL "https://api.github.com/repos/msitarzewski/agency-agents/commits/main" 2>/dev/null | \
grep -o '"sha": "[a-f0-9]*' | cut -d'"' -f4 | cut -c1-7
}

autoupdate_check() {
if [ "$autoupdate" != "true" ]; then
return 0
fi

if [ ! -f "$commit_file" ]; then
log "Autoupdate: skipped (no commit file found)"
return 0
fi

installed_commit="$(cat "$commit_file")"
if [ -z "$installed_commit" ]; then
log "Autoupdate: skipped (empty commit file)"
return 0
fi

log "Autoupdate: checking for updates..."

remote_commit="$(get_remote_commit)"
if [ -z "$remote_commit" ]; then
log "Autoupdate: skipped (unable to fetch remote commit)"
return 0
fi

if [ "$remote_commit" = "$installed_commit" ]; then
log "Autoupdate: already on latest version ($remote_commit)"
return 0
fi

log "Autoupdate: new version available ($installed_commit → $remote_commit), updating..."

rm -f "$marker_file"
rm -f "$commit_file"
return 1
}

# Dev Container Features export options as uppercase env vars (e.g. TOOL).
# Keep FEATURE_OPTION_TOOL as a compatibility fallback.
tool="${TOOL:-${FEATURE_OPTION_TOOL:-auto}}"
autoupdate="${AGENCY_AGENTS_AUTOUPDATE:-${AUTOUPDATE:-true}}"

case "$tool" in
"")
fail "Option 'tool' cannot be empty."
;;
*[!a-zA-Z0-9_-]*)
fail "Option 'tool' contains invalid characters: '$tool'."
;;
esac

detect_user() {
local user=""

if [ -n "${_REMOTE_USER:-}" ]; then
user="$_REMOTE_USER"
elif [ -n "$USERNAME" ]; then
user="$USERNAME"
else
user="$(getent passwd 1000 | cut -d: -f1)" || true
[ -z "$user" ] && user="$(whoami 2>/dev/null)" || true
[ -z "$user" ] && user="vscode"
fi

local valid_users
valid_users="$(getent passwd | awk -F: 'BEGIN {first=""} $3 >= 1000 && $1 !~ /^(nobody|nfsnobody)$/ {first=$1; exit} END {print first}')" || true

if [ -n "$user" ]; then
local user_shell
user_shell="$(getent passwd "$user" | cut -d: -f7)" || true
case "$user_shell" in
*/nologin|*/false)
user="$valid_users"
;;
esac
fi

if [ -z "$user" ] || [ ! -d "/home/$user" ]; then
user="$valid_users"
fi

[ -z "$user" ] && user="vscode"
echo "$user"
command -v unzip >/dev/null 2>&1 || fail "Dependency installation failed: unzip"
command -v curl >/dev/null 2>&1 || command -v wget >/dev/null 2>&1 || fail "Dependency installation failed: curl/wget"
[ -f /etc/ssl/certs/ca-certificates.crt ] || fail "Dependency installation failed: CA certificates"
}

ensure_prerequisites

marker_dir="/usr/local/share/devcontainer-features"

TARGET_USER="$(detect_user)"
TARGET_HOME="$(getent passwd "$TARGET_USER" | cut -d: -f6)"
[ -z "$TARGET_HOME" ] && TARGET_HOME="/home/$TARGET_USER"

# v1 marker is tool-agnostic since postStartCommand uses auto tool detection.
# Also maintain per-tool markers for test compatibility.
marker_file="$marker_dir/agency-agents-v1-${TARGET_USER}.done"
commit_file="$marker_dir/agency-agents-v1.commit"
tool_marker="$marker_dir/agency-agents-v1-${tool}-${TARGET_USER}.done"

if [ -f "$marker_file" ] || [ -f "$tool_marker" ]; then
log "Installation already completed for tool '$tool'."
if [ -f "$commit_file" ] && [ -s "$commit_file" ]; then
autoupdate_check
else
remote_final_commit="$(get_remote_commit)"
if [ -n "$remote_final_commit" ]; then
echo "$remote_final_commit" > "$commit_file"
log "Saved commit: $remote_final_commit"
fi
fi
exit 0
fi

if [ -f "$commit_file" ]; then
autoupdate_check || true
fi

mkdir -p "$marker_dir"

tmp_dir="$(mktemp -d /tmp/agency-agents-XXXXXX)"
cleanup() {
rm -rf "$tmp_dir"
}
trap cleanup EXIT

zip_file="$tmp_dir/agency-agents.zip"

log "Downloading repository ZIP..."
if command -v curl >/dev/null 2>&1; then
curl -fsSL "https://github.com/msitarzewski/agency-agents/archive/refs/heads/main.zip" -o "$zip_file" \
|| curl -fsSL "https://github.com/msitarzewski/agency-agents/archive/refs/heads/master.zip" -o "$zip_file" \
|| fail "Unable to download repository ZIP (main/master)."
else
wget -qO "$zip_file" "https://github.com/msitarzewski/agency-agents/archive/refs/heads/main.zip" \
|| wget -qO "$zip_file" "https://github.com/msitarzewski/agency-agents/archive/refs/heads/master.zip" \
|| fail "Unable to download repository ZIP (main/master)."
fi

log "Extracting repository ZIP..."
unzip -q "$zip_file" -d "$tmp_dir"

repo_dir="$(find "$tmp_dir" -mindepth 1 -maxdepth 1 -type d | head -n1 || true)"
[ -n "$repo_dir" ] || fail "Could not locate extracted repository directory."

[ -f "$repo_dir/scripts/convert.sh" ] || fail "Missing script: scripts/convert.sh"
[ -f "$repo_dir/scripts/install.sh" ] || fail "Missing script: scripts/install.sh"

chmod +x "$repo_dir/scripts/convert.sh" "$repo_dir/scripts/install.sh"

log "Running convert.sh..."
(
cd "$repo_dir"
./scripts/convert.sh
)

if [ "$tool" = "auto" ]; then
log "Running install.sh --no-interactive --parallel (auto tool detection)..."
else
log "Running install.sh --tool $tool --no-interactive..."
fi

opencode_agents_src="$repo_dir/integrations/opencode/agents"
opencode_agents_global="$TARGET_HOME/.config/opencode/agents"

should_install_opencode() {
case "$tool" in
auto|all|opencode) return 0 ;;
*) return 1 ;;
esac
}

if [ "$(id -u)" -eq 0 ] && [ "$TARGET_USER" != "root" ] && id "$TARGET_USER" >/dev/null 2>&1; then
log "Installing for user '$TARGET_USER' (HOME=$TARGET_HOME)..."
chown -R "$TARGET_USER":"$TARGET_USER" "$tmp_dir"
chmod -R u+rwX,go+rX "$tmp_dir"
if [ "$tool" = "auto" ]; then
su - "$TARGET_USER" -c "cd '$repo_dir' && HOME='$TARGET_HOME' ./scripts/install.sh --no-interactive --parallel"
else
su - "$TARGET_USER" -c "cd '$repo_dir' && HOME='$TARGET_HOME' ./scripts/install.sh --tool '$tool' --no-interactive"
fi
if should_install_opencode && [ -d "$opencode_agents_src" ]; then
log "Installing OpenCode agents globally to $opencode_agents_global..."
mkdir -p "$opencode_agents_global"
cp "$opencode_agents_src"/*.md "$opencode_agents_global/" 2>/dev/null || true
chown -R "$TARGET_USER":"$TARGET_USER" "$opencode_agents_global"
log "OpenCode agents installed globally."
fi
else
log "Installing for current user '$(id -un)' (HOME=${HOME:-unknown})..."
(
cd "$repo_dir"
if [ "$tool" = "auto" ]; then
./scripts/install.sh --no-interactive --parallel
else
./scripts/install.sh --tool "$tool" --no-interactive
fi
)
if should_install_opencode && [ -d "$opencode_agents_src" ]; then
log "Installing OpenCode agents globally to $opencode_agents_global..."
mkdir -p "$opencode_agents_global"
cp "$opencode_agents_src"/*.md "$opencode_agents_global/" 2>/dev/null || true
log "OpenCode agents installed globally."
fi
fi

touch "$marker_file"
touch "$tool_marker"

remote_final_commit="$(get_remote_commit)"
if [ -n "$remote_final_commit" ]; then
echo "$remote_final_commit" > "$commit_file"
fi

# Copy install.sh for postStartCommand autoupdate
cp "$0" "$marker_dir/agency-agents-install.sh"
chmod +x "$marker_dir/agency-agents-install.sh"

# Copy postStartCommand.sh
poststart_script="$(dirname "$0")/postStartCommand.sh"
if [ -f "$poststart_script" ]; then
cp "$poststart_script" "$marker_dir/agency-agents-postStartCommand.sh"
chmod +x "$marker_dir/agency-agents-postStartCommand.sh"
fi

log "Installation completed for tool '$tool'."
log "Scripts copied. Installation will run in postStartCommand."
Loading
Loading