feat(install): all-in-one bootstrap — install OpenCode then the fork

- install.sh now ensures the OpenCode runtime is present: detects it on PATH or at $HOME/.opencode/bin, and otherwise runs the official installer (opencode.ai/v2/install)
- new flags: --with-opencode, --no-opencode, --opencode-version V, --opencode-no-path
- --dry-run never installs the runtime; OPENCODE_INSTALLER_URL can be overridden (mirrors/tests)
- README documents the all-in-one behaviour and the new runtime flags
This commit is contained in:
Claus Lohmar 2026-10-13 06:25:16 +00:00
parent c8347acfe4
commit 2e1f8ca525
2 changed files with 126 additions and 5 deletions

View file

@ -136,6 +136,8 @@ env.example template for the optional .env (Telegram/Gemini integrations)
This repository is **private**, so the installer needs access to it. The simplest path is to clone it once and run the installer from the clone — your existing git credentials are used, no token to paste.
The installer is **all-in-one**: if OpenCode isn't already installed, it bootstraps the runtime first (from the official installer at [`opencode.ai/v2/install`](https://opencode.ai/v2/install)), then installs the fork.
### Recommended — clone, then install
```bash
@ -165,6 +167,10 @@ The installer offers **Local** (`.opencode/` in the current project), **Global**
| `--install-dir PATH` | install into an exact path |
| `--source DIR` | install from a local clone instead of downloading |
| `--branch REF` | branch/tag to install from (default `main`) |
| `--with-opencode` | install/update OpenCode even if it is already present |
| `--no-opencode` | skip the OpenCode runtime install |
| `--opencode-version V` | install a specific OpenCode version |
| `--opencode-no-path` | don't let the OpenCode installer edit your shell PATH |
| `--yes` / `-y` | non-interactive; skip existing files |
| `--force` | non-interactive; overwrite existing files |
| `--dry-run` | show what would happen, change nothing |
@ -180,6 +186,12 @@ cp -R /tmp/oac/agent /tmp/oac/command /tmp/oac/context \
/tmp/oac/package.json .opencode/
```
This copies the **fork only** — install the OpenCode **runtime** first if it's missing:
```bash
curl -fsSL https://opencode.ai/v2/install | bash
```
Then start OpenCode and pick your agent:
```bash

View file

@ -2,8 +2,9 @@
#
# OpenAgents Control — Architect Fork · installer
# ============================================================================
# Installs the OAC Architect Fork — the agents, subagents, commands, context,
# skills and tools — into a project's .opencode/ directory or the global
# All-in-one bootstrap: installs OpenCode (the runtime) when it is missing, then
# the OAC Architect Fork — the agents, subagents, commands, context, skills and
# tools — into a project's .opencode/ directory or the global
# ~/.config/opencode/ directory.
#
# Adapted from Darren Hinde's OpenAgents Control installer (MIT).
@ -22,6 +23,7 @@
# ./install.sh --source DIR # install from a local clone
# ./install.sh --global --yes # non-interactive, skip existing files
# ./install.sh --global --force # non-interactive, overwrite existing
# ./install.sh --no-opencode # install the fork only (skip OpenCode)
# ./install.sh --dry-run # show the plan, change nothing
#
# Environment:
@ -46,6 +48,10 @@ TOKEN="${OAC_TOKEN:-}"
PAYLOAD_DIRS="agent command context skills tool"
PAYLOAD_FILES="env.example package.json"
# OpenCode runtime — the official installer places the binary in $HOME/.opencode/bin
OPENCODE_INSTALLER_URL="${OPENCODE_INSTALLER_URL:-https://opencode.ai/v2/install}"
OPENCODE_BIN_DIR="${HOME}/.opencode/bin"
# ---------------------------------------------------------------------------
# Colours (only when writing to a terminal)
# ---------------------------------------------------------------------------
@ -81,7 +87,8 @@ usage() {
cat <<EOF
OpenAgents Control — Architect Fork · installer
Installs the OAC Architect Fork into a project's .opencode/ or the global
All-in-one bootstrap: installs OpenCode (the runtime) if it is missing, then
the OAC Architect Fork into a project's .opencode/ or the global
~/.config/opencode/ directory.
Usage:
@ -98,6 +105,12 @@ Source:
--branch REF Branch/tag to fetch (default: main)
--token TOKEN Forgejo token with repo:read (private fetch)
Runtime:
--with-opencode Install/update OpenCode even if it is already present
--no-opencode Skip the OpenCode install
--opencode-version V Install a specific OpenCode version
--opencode-no-path Don't let the OpenCode installer edit your shell PATH
Behaviour:
-y, --yes Non-interactive; skip files that already exist
--force Non-interactive; overwrite existing files
@ -125,6 +138,9 @@ ASSUME_YES=0
FORCE=0
DRY_RUN=0
SOURCE=""
OPENCODE_MODE="auto" # auto | yes | no
OPENCODE_VERSION=""
OPENCODE_NO_PATH=0
while [ $# -gt 0 ]; do
case "$1" in
@ -141,6 +157,11 @@ while [ $# -gt 0 ]; do
-y|--yes) ASSUME_YES=1 ;;
--force) ASSUME_YES=1; FORCE=1 ;;
--dry-run) DRY_RUN=1 ;;
--with-opencode|--opencode) OPENCODE_MODE="yes" ;;
--no-opencode) OPENCODE_MODE="no" ;;
--opencode-version) [ $# -ge 2 ] || die "--opencode-version needs a version"; OPENCODE_VERSION="$2"; shift ;;
--opencode-version=*) OPENCODE_VERSION="${1#*=}" ;;
--opencode-no-path) OPENCODE_NO_PATH=1 ;;
-h|--help) usage; exit 0 ;;
*) error "Unknown option: $1"; echo; usage; exit 1 ;;
esac
@ -158,6 +179,88 @@ if [ -n "$TOKEN" ]; then
command -v curl >/dev/null 2>&1 || die "curl is required when using --token"
fi
# ---------------------------------------------------------------------------
# OpenCode runtime (all-in-one bootstrap)
# ---------------------------------------------------------------------------
have_opencode() {
command -v opencode >/dev/null 2>&1 && return 0
[ -x "${OPENCODE_BIN_DIR}/opencode" ] && return 0
return 1
}
opencode_path() {
if command -v opencode >/dev/null 2>&1; then
command -v opencode
else
printf '%s' "${OPENCODE_BIN_DIR}/opencode"
fi
}
ensure_opencode() {
if [ "$DRY_RUN" = 1 ]; then
if have_opencode; then
info "[dry-run] OpenCode already present — $(opencode_path)"
elif [ "$OPENCODE_MODE" = "no" ]; then
info "[dry-run] would skip OpenCode (--no-opencode)"
else
info "[dry-run] would install OpenCode from ${OPENCODE_INSTALLER_URL}"
fi
return 0
fi
if have_opencode && [ "$OPENCODE_MODE" != "yes" ]; then
success "OpenCode is already installed — $(opencode_path)"
return 0
fi
if [ "$OPENCODE_MODE" = "no" ]; then
info "Skipping the OpenCode install (--no-opencode)"
return 0
fi
if [ "$OPENCODE_MODE" = "auto" ] && ! have_opencode && [ -t 0 ] && [ -t 1 ]; then
printf "${BOLD}OpenCode is not installed. Install it now?${NC} [Y/n]: "
ans=""
read -r ans || true
case "$ans" in
[Nn]*) info "Skipping OpenCode."; return 0 ;;
esac
fi
command -v curl >/dev/null 2>&1 || die "curl is required to install OpenCode"
step "Installing OpenCode…"
local tmp
tmp="$(mktemp 2>/dev/null || mktemp -t oac)"
if ! curl -fsSL "$OPENCODE_INSTALLER_URL" -o "$tmp"; then
rm -f "$tmp"
die "Could not download the OpenCode installer (${OPENCODE_INSTALLER_URL})"
fi
local ok=0
if [ -n "$OPENCODE_VERSION" ] && [ "$OPENCODE_NO_PATH" = 1 ]; then
bash "$tmp" --no-modify-path --version "$OPENCODE_VERSION" && ok=1
elif [ -n "$OPENCODE_VERSION" ]; then
bash "$tmp" --version "$OPENCODE_VERSION" && ok=1
elif [ "$OPENCODE_NO_PATH" = 1 ]; then
bash "$tmp" --no-modify-path && ok=1
else
bash "$tmp" && ok=1
fi
rm -f "$tmp"
[ "$ok" = 1 ] || die "OpenCode installation failed"
if have_opencode; then
success "OpenCode installed — $(opencode_path)"
case ":$PATH:" in
*":${OPENCODE_BIN_DIR}:"*) : ;;
*) warn "Add OpenCode to your PATH: export PATH=\"${OPENCODE_BIN_DIR}:\$PATH\"" ;;
esac
else
warn "The OpenCode installer finished, but 'opencode' is not on PATH yet. Re-open your shell and try again."
fi
}
# ---------------------------------------------------------------------------
# Resolve the source payload
# ---------------------------------------------------------------------------
@ -377,8 +480,13 @@ show_post_install() {
if [ -f "$INSTALL_DIR/env.example" ]; then
echo "2. (Optional) configure integrations: ${CYAN}cp ${INSTALL_DIR}/env.example .env${NC}"
fi
echo "3. Start OpenCode and pick an agent:"
echo -e " ${CYAN}opencode${NC} → choose ${BOLD}OpenArchitect${NC} to spec/verify, ${BOLD}OpenAgent${NC} to build"
if have_opencode; then
echo "3. Start OpenCode and pick an agent:"
echo -e " ${CYAN}opencode${NC} → choose ${BOLD}OpenArchitect${NC} to spec/verify, ${BOLD}OpenAgent${NC} to build"
else
echo "3. Install OpenCode, then pick an agent:"
echo -e " ${CYAN}curl -fsSL ${OPENCODE_INSTALLER_URL} | bash${NC}"
fi
echo
info "Docs: ${REPO_URL}"
}
@ -388,6 +496,7 @@ show_post_install() {
# ---------------------------------------------------------------------------
main() {
print_header
ensure_opencode
resolve_source
resolve_install_dir