#!/usr/bin/env bash set -euo pipefail for command in bun jq; do command -v "$command" >/dev/null || { printf 'Required command not found: %s\n' "$command" >&2; exit 1; } done checkout=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P) config="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}" mkdir -p "$config" config=$(cd "$config" && pwd -P) mkdir -p "$config/plugins" install=$(mktemp -d "$config/install.stanp-opencode.XXXXXXXX") staged="" backup="" cleanup() { [[ -z "$install" ]] || rm -rf "$install" [[ -z "$staged" ]] || rm -rf "$staged" } trap cleanup EXIT (cd "$checkout" && bun install --frozen-lockfile && bun run build) bun -e ' if (!await Bun.file(process.argv[1]).exists()) { throw new Error("Local build lacks the OpenCode V2 directory entrypoint."); } const { default: plugin } = await import(process.argv[1]); if (!plugin || plugin.id !== "stanp-opencode" || typeof plugin.setup !== "function") { throw new Error("Local build is not a native OpenCode V2 plugin."); } const tuiFile = Bun.file(process.argv[2]); const manifest = await Bun.file(process.argv[3]).json(); const exportsTui = manifest?.exports?.["./tui"]; if (!await tuiFile.exists() || !new Bun.Transpiler({ loader: "js" }).scan(await tuiFile.text()).exports.includes("default") || (typeof exportsTui !== "string" && typeof exportsTui?.import !== "string")) { throw new Error("Local build lacks the ChatGPT quota TUI plugin."); } ' "$checkout/dist/index.js" "$checkout/dist/tui.js" "$checkout/package.json" config_file="$config/opencode.json" config_source="$config_file" if [[ ! -e "$config_source" ]]; then config_source="$install/empty-config.json" printf '{}\n' > "$config_source" fi jq -e ' if type != "object" then error("opencode.json must contain an object") else . end | if (.plugins // []) | type != "array" then error("opencode.json plugins must be an array") else . end | .["$schema"] = (.["$schema"] // "https://opencode.ai/config.json") | .plugins = (.plugins // []) | if any(.plugins[]?; .package == "./plugins/stanp-opencode") then . else .plugins += [{ package: "./plugins/stanp-opencode", options: { mode: "gpt", provider: "openai", lunaPriority: true } }] end ' "$config_source" > "$install/opencode.json" target="$config/plugins/stanp-opencode" staged="$config/plugins/.stanp-opencode.new.$$" backup="$config/plugins/.stanp-opencode.old.$$" mkdir "$staged" cp "$checkout/dist/index.js" "$staged/index.js" cp "$checkout/dist/tui.js" "$staged/tui.js" cat > "$staged/package.json" <<'EOF' {"name":"stanp-opencode","type":"module","main":"./index.js","exports":{".":"./index.js","./tui":"./tui.js"}} EOF if [[ -e "$target" || -L "$target" ]]; then mv "$target" "$backup"; fi if ! mv "$staged" "$target"; then if [[ -e "$backup" || -L "$backup" ]]; then mv "$backup" "$target"; fi printf 'Could not activate plugin; installation unchanged\n' >&2 exit 1 fi staged="" rm -rf "$backup" backup="" rm -f "$config/plugins/stanp-opencode.js" mv "$install/opencode.json" "$config_file" printf 'Built and installed stanp-opencode from %s into %s/plugins/stanp-opencode and updated %s\nRestart opencode2 to load it.\n' "$checkout" "$config" "$config_file"