| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- #!/bin/bash
- # Opencode VSCode Extension Build Script
- # This script handles the complete build process for the Opencode VSCode extension.
- # Supports building two variants:
- # - Standard: bundles opencode binaries (default)
- # - GUI-only: no binaries, uses system opencode, embeds webgui-dist
- #
- # By default both variants are built. Use --gui-only or --standard-only to
- # build a single variant.
- set -e
- # Colors for output
- RED='\033[0;31m'
- GREEN='\033[0;32m'
- YELLOW='\033[1;33m'
- BLUE='\033[0;34m'
- NC='\033[0m' # No Color
- # Script directory references
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
- ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
- PLUGIN_DIR="$ROOT_DIR/hosts/vscode-plugin"
- WEBGUI_DIR="$ROOT_DIR/packages/opencode/webgui"
- WEBGUI_DIST="$ROOT_DIR/packages/opencode/webgui-dist"
- echo -e "${BLUE}Opencode VSCode Extension Build Script${NC}"
- echo "Plugin directory: $PLUGIN_DIR"
- echo "Root directory: $ROOT_DIR"
- # --- Package manager helpers ---
- PNPM_AVAILABLE=false
- if command -v pnpm >/dev/null 2>&1; then
- PNPM_AVAILABLE=true
- fi
- run_install() {
- if $PNPM_AVAILABLE; then
- pnpm install --frozen-lockfile
- else
- npm ci || npm install
- fi
- }
- run_script() {
- local script="$1"
- if $PNPM_AVAILABLE; then
- pnpm run "$script"
- else
- npm run "$script"
- fi
- }
- print_status() {
- echo -e "${GREEN}[INFO]${NC} $1"
- }
- print_warning() {
- echo -e "${YELLOW}[WARN]${NC} $1"
- }
- print_error() {
- echo -e "${RED}[ERROR]${NC} $1"
- }
- if [ ! -f "$PLUGIN_DIR/package.json" ]; then
- print_error "package.json not found. Please run this script from the repository root."
- exit 1
- fi
- BUILD_TYPE="development"
- SKIP_BINARIES=false
- SKIP_TESTS=false
- PACKAGE_ONLY=false
- BUILD_STANDARD=true
- BUILD_GUI_ONLY=true
- while [[ $# -gt 0 ]]; do
- case $1 in
- --production)
- BUILD_TYPE="production"
- shift
- ;;
- --skip-binaries)
- SKIP_BINARIES=true
- shift
- ;;
- --skip-tests)
- SKIP_TESTS=true
- shift
- ;;
- --package-only)
- PACKAGE_ONLY=true
- shift
- ;;
- --gui-only)
- BUILD_STANDARD=false
- BUILD_GUI_ONLY=true
- shift
- ;;
- --standard-only)
- BUILD_STANDARD=true
- BUILD_GUI_ONLY=false
- shift
- ;;
- --help)
- echo "Usage: $0 [OPTIONS]"
- echo "Options:"
- echo " --production Build for production (default: development)"
- echo " --skip-binaries Skip building backend binaries"
- echo " --skip-tests Skip running tests"
- echo " --package-only Only create the .vsix package (skip compilation)"
- echo " --gui-only Build only the gui-only variant (no binaries)"
- echo " --standard-only Build only the standard variant (with binaries)"
- echo " --help Show this help message"
- exit 0
- ;;
- *)
- print_error "Unknown option: $1"
- exit 1
- ;;
- esac
- done
- print_status "Building VSCode extension in $BUILD_TYPE mode"
- [ "$BUILD_STANDARD" = true ] && print_status " Variant: standard (with binaries)"
- [ "$BUILD_GUI_ONLY" = true ] && print_status " Variant: gui-only (system opencode)"
- cd "$PLUGIN_DIR"
- # ─── Shared preparation (compile once, package per-variant) ───────────────
- if [ "$PACKAGE_ONLY" = false ]; then
- print_status "Cleaning previous build artifacts..."
- set +e
- if [ ! -d node_modules ]; then
- print_warning "Dependencies not installed; skipping script clean and removing artifacts manually."
- rm -rf out
- rm -f ./*.vsix
- fi
- if [ -d node_modules ]; then
- run_script clean
- if [[ $? -ne 0 ]]; then
- print_warning "Clean command failed, applying fallback removal..."
- rm -rf out
- rm -f ./*.vsix
- fi
- fi
- set -e
- fi
- if [ "$PACKAGE_ONLY" = false ]; then
- print_status "Installing dependencies..."
- if ! command -v node >/dev/null 2>&1; then
- print_error "Node.js is required but not found in PATH. Please install Node.js."
- exit 1
- fi
- run_install
- fi
- if [ "$SKIP_BINARIES" = false ] && [ "$PACKAGE_ONLY" = false ] && [ "$BUILD_STANDARD" = true ]; then
- print_status "Building backend binaries..."
- "$SCRIPT_DIR/build_opencode.sh"
- fi
- if [ "$PACKAGE_ONLY" = false ]; then
- print_status "Compiling TypeScript..."
- if [ "$BUILD_TYPE" = "production" ]; then
- run_script compile:production
- else
- run_script compile
- fi
- fi
- if [ "$PACKAGE_ONLY" = false ]; then
- print_status "Running linter..."
- set +e
- run_script lint
- if [[ $? -ne 0 ]]; then
- print_warning "Linting failed, continuing with build..."
- fi
- set -e
- fi
- if [ "$SKIP_TESTS" = false ] && [ "$PACKAGE_ONLY" = false ]; then
- print_status "Running tests..."
- set +e
- run_script test
- if [[ $? -ne 0 ]]; then
- print_warning "Tests failed, continuing with build..."
- fi
- set -e
- fi
- # ─── Resolve vsce command ────────────────────────────────────────────────
- VSCE_CMD="vsce"
- if ! command -v vsce >/dev/null 2>&1; then
- if command -v npx >/dev/null 2>&1; then
- VSCE_CMD="npx -y @vscode/vsce"
- else
- print_warning "vsce not found and npx unavailable; attempting global install via npm"
- npm install -g @vscode/vsce
- fi
- fi
- TIMESTAMP="$(date +%Y%m%d-%H%M%S)"
- # ─── Build helper: package a single variant ──────────────────────────────
- build_variant() {
- local variant="$1" # "standard" or "gui-only"
- cd "$PLUGIN_DIR"
- if [ "$variant" = "standard" ]; then
- print_status "=== Packaging STANDARD variant ==="
- # Check for required binaries
- BINARY_PATHS=(
- "resources/bin/windows/amd64/opencode.exe"
- "resources/bin/macos/amd64/opencode"
- "resources/bin/macos/arm64/opencode"
- "resources/bin/linux/amd64/opencode"
- "resources/bin/linux/arm64/opencode"
- )
- MISSING_BINARIES=false
- for binary_path in "${BINARY_PATHS[@]}"; do
- if [ ! -f "$binary_path" ]; then
- print_warning "Missing binary: $binary_path"
- MISSING_BINARIES=true
- fi
- done
- if [ "$MISSING_BINARIES" = true ]; then
- print_warning "Some binaries are missing. The extension may not work on all platforms."
- print_warning "Run '$SCRIPT_DIR/build_opencode.sh' from the root directory to build all binaries."
- fi
- # Package with original package.json and .vscodeignore
- if [ "$BUILD_TYPE" = "production" ]; then
- eval "$VSCE_CMD package --no-dependencies --out 'opencode-vscode-${TIMESTAMP}.vsix'"
- else
- eval "$VSCE_CMD package --pre-release --no-dependencies --out 'opencode-vscode-dev-${TIMESTAMP}.vsix'"
- fi
- elif [ "$variant" = "gui-only" ]; then
- print_status "=== Packaging GUI-ONLY variant ==="
- # Always rebuild webgui to pick up source changes
- # The monorepo uses bun workspaces – deps are already installed at root level
- print_status "Building webgui..."
- if command -v bun >/dev/null 2>&1; then
- (cd "$WEBGUI_DIR" && bun run build)
- else
- (cd "$WEBGUI_DIR" && npm run build)
- fi
- if [ ! -d "$WEBGUI_DIST" ]; then
- print_error "webgui-dist not found at $WEBGUI_DIST after build"
- return 1
- fi
- # Copy webgui-dist into plugin resources for embedding
- print_status "Embedding webgui-dist into plugin resources..."
- rm -rf "$PLUGIN_DIR/resources/webgui-app"
- cp -r "$WEBGUI_DIST" "$PLUGIN_DIR/resources/webgui-app"
- # Move binaries completely outside the plugin tree so vsce cannot bundle them
- BIN_STASH="$(mktemp -d)"
- if [ -d "$PLUGIN_DIR/resources/bin" ]; then
- mv "$PLUGIN_DIR/resources/bin" "$BIN_STASH/bin"
- fi
- # Temporarily swap package.json with gui-only overrides and .vscodeignore
- cp "$PLUGIN_DIR/package.json" "$PLUGIN_DIR/package.json.bak"
- cp "$PLUGIN_DIR/.vscodeignore" "$PLUGIN_DIR/.vscodeignore.bak"
- # Ensure originals are restored even on failure
- gui_only_cleanup() {
- cd "$PLUGIN_DIR"
- [ -f package.json.bak ] && mv package.json.bak package.json
- [ -f .vscodeignore.bak ] && mv .vscodeignore.bak .vscodeignore
- [ -d "$BIN_STASH/bin" ] && mv "$BIN_STASH/bin" resources/bin
- rm -rf "$BIN_STASH"
- rm -rf resources/webgui-app
- }
- trap gui_only_cleanup EXIT
- # Deep-merge gui-only overrides into package.json
- node -e "
- const fs = require('fs');
- function deep(target, src) {
- for (const key of Object.keys(src)) {
- const s = src[key];
- const t = target[key];
- if (Array.isArray(s) && Array.isArray(t)) {
- for (let i = 0; i < s.length; i++) {
- if (i < t.length && typeof s[i] === 'object' && typeof t[i] === 'object') {
- deep(t[i], s[i]);
- } else {
- t[i] = s[i];
- }
- }
- } else if (s && typeof s === 'object' && !Array.isArray(s) && t && typeof t === 'object' && !Array.isArray(t)) {
- deep(t, s);
- } else {
- target[key] = s;
- }
- }
- return target;
- }
- const base = JSON.parse(fs.readFileSync('package.json', 'utf8'));
- const overrides = JSON.parse(fs.readFileSync('package.gui-only.json', 'utf8'));
- fs.writeFileSync('package.json', JSON.stringify(deep(base, overrides), null, 2) + '\n');
- "
- # Swap .vscodeignore
- cp "$PLUGIN_DIR/.vscodeignore.gui-only" "$PLUGIN_DIR/.vscodeignore"
- # Package gui-only variant
- if [ "$BUILD_TYPE" = "production" ]; then
- eval "$VSCE_CMD package --no-dependencies --out 'opencode-vscode-gui-only-${TIMESTAMP}.vsix'"
- else
- eval "$VSCE_CMD package --pre-release --no-dependencies --out 'opencode-vscode-gui-only-dev-${TIMESTAMP}.vsix'"
- fi
- # Restore originals (also handled by trap on failure)
- gui_only_cleanup
- trap - EXIT
- print_status "GUI-only variant packaged successfully"
- fi
- }
- # ─── Build requested variants ────────────────────────────────────────────
- if [ "$BUILD_STANDARD" = true ]; then
- build_variant "standard"
- fi
- if [ "$BUILD_GUI_ONLY" = true ]; then
- build_variant "gui-only"
- fi
- print_status "Build completed successfully!"
- print_status "Extension packages created in: $PLUGIN_DIR"
- shopt -s nullglob
- VSIX_FILES=( "$PLUGIN_DIR"/*.vsix )
- shopt -u nullglob
- if ((${#VSIX_FILES[@]} > 0)); then
- echo "Packages created:"
- for vsix in "${VSIX_FILES[@]}"; do
- echo " $(basename "$vsix")"
- done
- fi
|