diff --git a/.github/workflows/build-opencode-cli-docker.yml b/.github/workflows/build-opencode-cli-docker.yml index 555835e..f507e36 100644 --- a/.github/workflows/build-opencode-cli-docker.yml +++ b/.github/workflows/build-opencode-cli-docker.yml @@ -1,4 +1,4 @@ -name: Build OpenCode CLI and Docker Image +name: Build OpenCode CLI on: push: @@ -7,34 +7,16 @@ on: - master paths: - opencode/** - - Dockerfile - - .github/workflows/build-opencode-cli-docker.yml workflow_dispatch: - inputs: - image_name: - description: "Docker image name (including registry if desired)" - required: false - push_image: - description: "Push the image to the registry" - type: boolean - default: false permissions: contents: read - packages: write actions: read jobs: build-cli: - name: Build OpenCode CLI (${{ matrix.arch }}) - runs-on: ${{ matrix.runner }} - strategy: - fail-fast: false - matrix: - include: - - arch: amd64 - runner: ubuntu-24.04 - cli_dir: opencode-linux-x64 + name: Build OpenCode CLI (x86_64) + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@v4 @@ -55,118 +37,30 @@ jobs: - name: Upload CLI artifact uses: actions/upload-artifact@v4 with: - name: opencode-cli-${{ matrix.arch }} - path: opencode/packages/opencode/dist/${{ matrix.cli_dir }} + name: opencode-cli-x86_64 + path: opencode/packages/opencode/dist/opencode-linux-x64 + retention-days: 1 - build-image: - name: Build Docker image - needs: build-cli - runs-on: ubuntu-24.04 - env: - IMAGE_NAME: ${{ inputs.image_name || format('ghcr.io/{0}/shopify-ai-builder', github.repository_owner) }} - PUSH_IMAGE: ${{ inputs.push_image || false }} - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Download CLI artifacts - uses: actions/download-artifact@v4 - with: - pattern: opencode-cli-* - path: opencode/packages/opencode/dist - merge-multiple: true - - - name: Verify artifact structure - run: | - echo "Contents of dist directory:" - ls -la opencode/packages/opencode/dist/ - echo "Looking for opencode binary..." - find opencode/packages/opencode/dist -name "opencode" -type f 2>/dev/null || echo "Binary not found" - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - with: - driver-opts: | - image=moby/buildkit:latest - buildkitd-flags: --debug - - - name: Cache Docker layers - uses: actions/cache@v4 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- - - - name: Login to GHCR - if: ${{ env.PUSH_IMAGE == 'true' }} - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build image (amd64 push) - if: ${{ env.PUSH_IMAGE == 'true' }} - run: | - docker buildx build \ - --platform linux/amd64 \ - --cache-from type=local,src=/tmp/.buildx-cache \ - --cache-to type=local,dest=/tmp/.buildx-cache-new,mode=max \ - -t "$IMAGE_NAME" \ - --push \ - . - - - name: Move cache - if: ${{ env.PUSH_IMAGE == 'true' }} - run: | - rm -rf /tmp/.buildx-cache - mv /tmp/.buildx-cache-new /tmp/.buildx-cache - - - name: Build image (amd64) and verify CLI - if: ${{ env.PUSH_IMAGE != 'true' }} - run: | - docker buildx build \ - --platform linux/amd64 \ - --cache-from type=local,src=/tmp/.buildx-cache \ - --cache-to type=local,dest=/tmp/.buildx-cache-new,mode=max \ - -t "$IMAGE_NAME" \ - --load \ - . - docker run --rm "$IMAGE_NAME" opencode --version - - - name: Move cache - if: ${{ env.PUSH_IMAGE != 'true' }} - run: | - rm -rf /tmp/.buildx-cache - mv /tmp/.buildx-cache-new /tmp/.buildx-cache - - - name: Cleanup old package versions - if: ${{ env.PUSH_IMAGE == 'true' && github.event_name == 'push' }} + - name: Cleanup old CLI artifacts uses: actions/github-script@v7 with: script: | - const packageName = 'shopify-ai-builder'; - const packageType = 'container'; - - // List all versions of the package - const { data: versions } = await github.rest.packages.getAllPackageVersionsForPackageOwnedByOrg({ - package_type: packageType, - package_name: packageName, - org: context.repo.owner, - per_page: 100 + const artifactName = 'opencode-cli-x86_64'; + const { data: artifacts } = await github.rest.actions.listArtifactsForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + name: artifactName, + per_page: 10 }); - // Keep only the most recent version, delete the rest - if (versions.length > 1) { - const versionsToDelete = versions.slice(1); - for (const version of versionsToDelete) { - await github.rest.packages.deletePackageVersionForOrg({ - package_type: packageType, - package_name: packageName, - org: context.repo.owner, - package_version_id: version.id + if (artifacts.length > 1) { + const artifactsToDelete = artifacts.slice(1); + for (const artifact of artifactsToDelete) { + await github.rest.actions.deleteArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: artifact.id }); - console.log(`Deleted package version ${version.id}`); + console.log(`Deleted old artifact: ${artifact.id}`); } } diff --git a/Dockerfile b/Dockerfile index feaa6ec..a6b6592 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,20 +1,73 @@ # Web-based PowerShell + SST OpenCode terminal # x86_64 architecture support only -FROM ubuntu:24.04 +FROM ubuntu:24.04 AS builder + +ARG PWSH_VERSION=7.4.6 +ARG NODE_VERSION=20.18.1 +ARG TTYD_VERSION=1.7.7 +ARG BUN_VERSION=1.3.8 + +ENV DEBIAN_FRONTEND=noninteractive \ + TERM=xterm-256color \ + LANG=C.UTF-8 \ + LC_ALL=C.UTF-8 + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + ca-certificates \ + curl \ + wget \ + git \ + tar \ + xz-utils \ + gzip \ + libicu-dev \ + libssl-dev \ + unzip \ + && rm -rf /var/lib/apt/lists/* + +RUN curl -fsSL -o /tmp/bun.zip "https://github.com/oven-sh/bun/releases/download/bun-v${BUN_VERSION}/bun-linux-x64.zip" \ + && unzip -q /tmp/bun.zip -d /usr/local/bin \ + && chmod +x /usr/local/bin/bun \ + && rm /tmp/bun.zip + +RUN curl -fsSL -o /tmp/powershell.tar.gz \ + "https://github.com/PowerShell/PowerShell/releases/download/v${PWSH_VERSION}/powershell-${PWSH_VERSION}-linux-x64.tar.gz" \ + && mkdir -p /opt/microsoft/powershell/7 \ + && tar -xzf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/7 \ + && chmod +x /opt/microsoft/powershell/7/pwsh \ + && ln -sf /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh \ + && rm -f /tmp/powershell.tar.gz + +RUN curl -fsSL -o /usr/local/bin/ttyd \ + "https://github.com/tsl0922/ttyd/releases/download/${TTYD_VERSION}/ttyd.x86_64" \ + && chmod +x /usr/local/bin/ttyd + +RUN curl -fsSL -o /tmp/node.tar.xz \ + "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz" \ + && tar -xJf /tmp/node.tar.xz -C /usr/local --strip-components=1 \ + && ln -sf /usr/local/bin/node /usr/bin/node \ + && ln -sf /usr/local/bin/npm /usr/bin/npm \ + && rm -f /tmp/node.tar.xz + +COPY opencode /opt/opencode-src + +WORKDIR /opt/opencode-src + +RUN bun install \ + && bun run ./packages/opencode/script/build.ts --single + +FROM ubuntu:24.04 ARG PWSH_VERSION=7.4.6 ARG NODE_VERSION=20.18.1 ARG TTYD_VERSION=1.7.7 -ARG TARGETARCH -ARG BUILDPLATFORM -ARG TARGETPLATFORM ENV DEBIAN_FRONTEND=noninteractive \ TERM=xterm-256color \ LANG=C.UTF-8 \ LC_ALL=C.UTF-8 -# Install minimal system dependencies only (no PowerShell or Node.js from apt) RUN apt-get update \ && apt-get install -y --no-install-recommends \ ca-certificates \ @@ -29,90 +82,52 @@ RUN apt-get update \ libssl-dev \ && rm -rf /var/lib/apt/lists/* -# Install PowerShell 7.x from official binary release (architecture-aware) -# Prefer Docker build args (TARGETARCH) so cross-arch builds work reliably in Portainer/buildx. -RUN ARCH="${TARGETARCH:-}" && \ - if [ -z "$ARCH" ]; then ARCH="$(dpkg --print-architecture)"; fi && \ - if [ "$ARCH" = "amd64" ]; then \ - PWSH_ARCH="x64"; \ - elif [ "$ARCH" = "arm64" ]; then \ - PWSH_ARCH="arm64"; \ - else \ - echo "Unsupported architecture: $ARCH (TARGETPLATFORM=${TARGETPLATFORM:-unknown}, BUILDPLATFORM=${BUILDPLATFORM:-unknown})" && exit 1; \ - fi && \ - curl -fsSL -o /tmp/powershell.tar.gz \ - "https://github.com/PowerShell/PowerShell/releases/download/v${PWSH_VERSION}/powershell-${PWSH_VERSION}-linux-${PWSH_ARCH}.tar.gz" \ +RUN curl -fsSL -o /tmp/powershell.tar.gz \ + "https://github.com/PowerShell/PowerShell/releases/download/v${PWSH_VERSION}/powershell-${PWSH_VERSION}-linux-x64.tar.gz" \ && mkdir -p /opt/microsoft/powershell/7 \ && tar -xzf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/7 \ && chmod +x /opt/microsoft/powershell/7/pwsh \ && ln -sf /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh \ && rm -f /tmp/powershell.tar.gz -# Install Node.js 20.x from official binary release (architecture-aware) -RUN ARCH="${TARGETARCH:-}" && \ - if [ -z "$ARCH" ]; then ARCH="$(dpkg --print-architecture)"; fi && \ - if [ "$ARCH" = "amd64" ]; then \ - NODE_ARCH="x64"; \ - elif [ "$ARCH" = "arm64" ]; then \ - NODE_ARCH="arm64"; \ - else \ - echo "Unsupported architecture: $ARCH (TARGETPLATFORM=${TARGETPLATFORM:-unknown}, BUILDPLATFORM=${BUILDPLATFORM:-unknown})" && exit 1; \ - fi && \ - curl -fsSL -o /tmp/node.tar.xz \ - "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${NODE_ARCH}.tar.xz" \ +RUN curl -fsSL -o /usr/local/bin/ttyd \ + "https://github.com/tsl0922/ttyd/releases/download/${TTYD_VERSION}/ttyd.x86_64" \ + && chmod +x /usr/local/bin/ttyd + +RUN curl -fsSL -o /tmp/node.tar.xz \ + "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz" \ && tar -xJf /tmp/node.tar.xz -C /usr/local --strip-components=1 \ && ln -sf /usr/local/bin/node /usr/bin/node \ && ln -sf /usr/local/bin/npm /usr/bin/npm \ && rm -f /tmp/node.tar.xz -# Install ttyd (static binary, architecture-aware) -RUN ARCH="${TARGETARCH:-}" && \ - if [ -z "$ARCH" ]; then ARCH="$(dpkg --print-architecture)"; fi && \ - if [ "$ARCH" = "amd64" ]; then \ - TTYD_ARCH="x86_64"; \ - elif [ "$ARCH" = "arm64" ]; then \ - TTYD_ARCH="aarch64"; \ - else \ - echo "Unsupported architecture: $ARCH (TARGETPLATFORM=${TARGETPLATFORM:-unknown}, BUILDPLATFORM=${BUILDPLATFORM:-unknown})" && exit 1; \ - fi && \ - curl -fsSL -o /usr/local/bin/ttyd \ - "https://github.com/tsl0922/ttyd/releases/download/${TTYD_VERSION}/ttyd.${TTYD_ARCH}" \ - && chmod +x /usr/local/bin/ttyd +COPY --from=builder /opt/opencode-src/opencode/packages/opencode/dist/opencode-linux-x64/bin/opencode /usr/local/bin/opencode -# Install OpenCode from locally built CLI artifacts -# CI builds these binaries from the opencode folder. -COPY opencode /opt/opencode-src -COPY opencode/packages/opencode/dist/bin/opencode /usr/local/bin/opencode RUN chmod +x /usr/local/bin/opencode -# Removed Gemini CLI - not needed for Shopify AI App Builder - -# Add Windows-like PowerShell profile (aliases and PSReadLine style) RUN mkdir -p /root/.config/powershell COPY profile/Microsoft.PowerShell_profile.ps1 /root/.config/powershell/Microsoft.PowerShell_profile.ps1 RUN chmod 644 /root/.config/powershell/Microsoft.PowerShell_profile.ps1 -# Copy entrypoint, health check, and diagnostic logger scripts COPY scripts/entrypoint.sh /usr/local/bin/entrypoint.sh COPY scripts/healthcheck.sh /usr/local/bin/healthcheck.sh COPY scripts/diagnostic-logger.sh /usr/local/bin/diagnostic-logger.sh RUN chmod +x /usr/local/bin/entrypoint.sh /usr/local/bin/healthcheck.sh /usr/local/bin/diagnostic-logger.sh -# Chat web service assets COPY chat /opt/webchat RUN cd /opt/webchat && npm install --production && chmod -R 755 /opt/webchat + COPY chat_v2 /opt/webchat_v2 RUN chmod -R 755 /opt/webchat_v2 -# Create workspace directory and set as workdir so pwsh starts where repo/workspace is mounted RUN mkdir -p /home/web/data \ && mkdir -p /var/log/shopify-ai \ && chown -R root:root /home/web/data /var/log/shopify-ai + WORKDIR /home/web/data -# Container defaults - Shopify AI App Builder -# Port 4500: Web UI (chat/builder interface) EXPOSE 4500 + HEALTHCHECK --interval=30s --timeout=15s --start-period=60s --retries=5 \ CMD /usr/local/bin/healthcheck.sh || exit 1