192 lines
5.2 KiB
Bash
Executable File
192 lines
5.2 KiB
Bash
Executable File
#!/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" <<'INNEREOF'
|
|
# BEGIN ORQUESTRA
|
|
__pycache__/
|
|
*.pyc
|
|
.pytest_cache/
|
|
.codegraph/
|
|
.atl/
|
|
|
|
# Build artifacts
|
|
.next/
|
|
dist/
|
|
build/
|
|
*.log
|
|
|
|
# Dependencies
|
|
node_modules/
|
|
|
|
# Environment
|
|
.env
|
|
.env.local
|
|
.env.*.local
|
|
|
|
# IDE
|
|
.vscode/
|
|
.idea/
|
|
*.swp
|
|
*.swo
|
|
|
|
# OS
|
|
.DS_Store
|
|
Thumbs.db
|
|
# END ORQUESTRA
|
|
INNEREOF
|
|
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"
|
|
copy_dir_update "$SOURCE_DIR/docs" "$TARGET_DIR/docs"
|
|
|
|
for file in scripts/verify.sh scripts/agent_status.py scripts/new_ticket.py scripts/pi_orquestra.sh scripts/run_stage.py scripts/commit_feature.sh scripts/close_feature.py scripts/validate_conventional_commit.py scripts/version.py scripts/install_git_hooks.sh scripts/install.sh; do
|
|
copy_file_update "$SOURCE_DIR/$file" "$TARGET_DIR/$file"
|
|
done
|
|
copy_dir_update "$SOURCE_DIR/scripts/git-hooks" "$TARGET_DIR/scripts/git-hooks"
|
|
|
|
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/run_stage.py" "$TARGET_DIR/scripts/install.sh" "$TARGET_DIR/scripts/validate_conventional_commit.py" "$TARGET_DIR/scripts/version.py" "$TARGET_DIR/scripts/install_git_hooks.sh" "$TARGET_DIR/scripts/git-hooks/commit-msg"
|
|
|
|
cat <<EOF
|
|
|
|
Orquestra installed/updated safely in: $TARGET_DIR
|
|
|
|
Next steps:
|
|
cd "$TARGET_DIR"
|
|
./scripts/install_git_hooks.sh
|
|
./scripts/verify.sh
|
|
./scripts/pi_orquestra.sh
|
|
EOF
|