#!/usr/bin/env bash set -euo pipefail banner() { cat <<'EOF' ___ ____ ___ _ _ _____ ____ _____ ____ _ / _ \| _ \ / _ \| | | | ____/ ___|_ _| _ \ / \ | | | | |_) | | | | | | | _| \___ \ | | | |_) | / _ \ | |_| | _ <| |_| | |_| | |___ ___) || | | _ < / ___ \ \___/|_| \_\\__\_\\___/|_____|____/ |_| |_| \_\/_/ \_\ sequential orchestration runtime EOF } usage() { cat <<'EOF' Usage: ./scripts/install.sh /path/to/project-repo Install or update Orquestra from this source checkout into a target project repo. Project-owned progress files are created only when missing and are never overwritten. EOF } fail() { printf '[FAIL] %s\n' "$1" >&2 exit 1 } warn() { printf '[WARN] %s\n' "$1" >&2 } info() { printf '[OK] %s\n' "$1" } copy_file_update() { local src=$1 local dst=$2 mkdir -p "$(dirname "$dst")" cp "$src" "$dst" } copy_file_if_missing() { local src=$1 local dst=$2 mkdir -p "$(dirname "$dst")" if [ ! -e "$dst" ]; then cp "$src" "$dst" fi } copy_dir_update() { local src=$1 local dst=$2 mkdir -p "$dst" cp -R "$src"/. "$dst"/ } copy_dir_if_missing_contents() { local src=$1 local dst=$2 local dir file rel mkdir -p "$dst" if [ -d "$src" ]; then find "$src" -type d | while IFS= read -r dir; do rel=${dir#"$src"} mkdir -p "$dst$rel" done find "$src" -type f | while IFS= read -r file; do rel=${file#"$src"/} copy_file_if_missing "$file" "$dst/$rel" done fi } append_gitignore_block() { local gitignore=$1 touch "$gitignore" if ! grep -q '^# BEGIN ORQUESTRA$' "$gitignore"; then cat >>"$gitignore" <<'EOF' # BEGIN ORQUESTRA __pycache__/ *.pyc .pytest_cache/ .codegraph/ .atl/ # END ORQUESTRA EOF fi } if [ "$#" -ne 1 ]; then usage >&2 exit 2 fi banner command -v pi >/dev/null 2>&1 || fail "pi is required in PATH before installing Orquestra" command -v python3 >/dev/null 2>&1 || fail "python3 is required in PATH before installing Orquestra" SOURCE_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P) TARGET_ARG=$1 TARGET_DIR=$(python3 -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$TARGET_ARG") if [ "$TARGET_DIR" = "$SOURCE_DIR" ]; then fail "target repo must be different from the Orquestra source repo" fi mkdir -p "$TARGET_DIR" if [ ! -d "$TARGET_DIR/.git" ]; then git -C "$TARGET_DIR" init >/dev/null info "Initialized git repo in $TARGET_DIR" fi # Harness-owned files: update on every run. for file in AGENTS.md README.md HOWTO.md CHECKPOINTS.md; do copy_file_update "$SOURCE_DIR/$file" "$TARGET_DIR/$file" done copy_dir_update "$SOURCE_DIR/harness" "$TARGET_DIR/harness" copy_dir_update "$SOURCE_DIR/platforms/pi" "$TARGET_DIR/platforms/pi" for file in scripts/verify.sh scripts/agent_status.py scripts/new_ticket.py scripts/pi_orquestra.sh scripts/install.sh; do copy_file_update "$SOURCE_DIR/$file" "$TARGET_DIR/$file" done append_gitignore_block "$TARGET_DIR/.gitignore" # Project-owned/state files: create only when missing. copy_dir_if_missing_contents "$SOURCE_DIR/project" "$TARGET_DIR/project" copy_file_if_missing "$SOURCE_DIR/backlog/features.json" "$TARGET_DIR/backlog/features.json" copy_dir_if_missing_contents "$SOURCE_DIR/spec" "$TARGET_DIR/spec" copy_file_if_missing "$SOURCE_DIR/work/current.md" "$TARGET_DIR/work/current.md" copy_file_if_missing "$SOURCE_DIR/work/history.md" "$TARGET_DIR/work/history.md" copy_file_if_missing "$SOURCE_DIR/work/runtime-status.json" "$TARGET_DIR/work/runtime-status.json" mkdir -p "$TARGET_DIR/work/artifacts" if [ -f "$SOURCE_DIR/work/artifacts/.gitkeep" ] && [ ! -e "$TARGET_DIR/work/artifacts/.gitkeep" ]; then cp "$SOURCE_DIR/work/artifacts/.gitkeep" "$TARGET_DIR/work/artifacts/.gitkeep" fi # Pi project-local runtime extensions. mkdir -p "$TARGET_DIR/.pi/extensions" copy_dir_update "$SOURCE_DIR/platforms/pi/extensions/orquestra-status" "$TARGET_DIR/.pi/extensions/orquestra-status" copy_file_update "$SOURCE_DIR/platforms/pi/extensions/orquestra-web-fetch.ts" "$TARGET_DIR/.pi/extensions/orquestra-web-fetch.ts" if [ -d "$TARGET_DIR/.pi/subagents" ] || [ -f "$TARGET_DIR/.pi/subagents.json" ]; then warn "Found .pi/subagents or .pi/subagents.json in target. Orquestra does not delete user Pi config automatically; remove Orquestra-owned stale subagent files manually before running verify.sh." fi chmod +x "$TARGET_DIR/scripts/verify.sh" "$TARGET_DIR/scripts/pi_orquestra.sh" "$TARGET_DIR/scripts/install.sh" cat <