name: Sync Marketplace Templates

# Runs after every stable release to auto-PR version bumps
# to Coolify, Dokploy, and EasyPanel template repos.
on:
  workflow_call:
    inputs:
      release_tag:
        required: true
        type: string
  workflow_dispatch:
    inputs:
      release_tag:
        description: "Release tag (e.g. v2026.4.21)"
        required: true
        type: string

permissions:
  contents: read

jobs:
  sync-coolify:
    name: PR to Coolify
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Derive version
        id: ver
        run: |
          TAG="${{ inputs.release_tag }}"
          VERSION="${TAG#v}"
          echo "version=${VERSION}" >> "$GITHUB_OUTPUT"

      - name: Checkout Coolify fork
        uses: actions/checkout@v4
        with:
          repository: KumihoIO/coolify
          token: ${{ secrets.MARKETPLACE_PAT }}
          ref: next
          path: coolify

      - name: Update or create template
        working-directory: coolify
        env:
          VERSION: ${{ steps.ver.outputs.version }}
        run: |
          cat > templates/compose/construct.yaml << 'TEMPLATE'
          # documentation: https://github.com/KumihoIO/construct-os
          # slogan: Fast, small, fully autonomous AI personal assistant infrastructure — deploy anywhere, swap anything
          # tags: ai, agent, assistant, self-hosted, llm, chatbot, rust
          # logo: svgs/construct.png
          # port: 42617

          services:
            construct:
              image: ghcr.io/kumihoio/construct-os:latest
              restart: unless-stopped
              environment:
                - API_KEY=${SERVICE_PASSWORD_APIKEY:-}
                - PROVIDER=${PROVIDER:-openrouter}
                - CONSTRUCT_ALLOW_PUBLIC_BIND=true
                - CONSTRUCT_GATEWAY_PORT=42617
              volumes:
                - construct-data:/construct-data
              ports:
                - "42617:42617"
              deploy:
                resources:
                  limits:
                    cpus: "2"
                    memory: 512M
                  reservations:
                    cpus: "0.5"
                    memory: 32M
              healthcheck:
                test: ["CMD", "construct", "status", "--format=exit-code"]
                interval: 60s
                timeout: 10s
                retries: 3
                start_period: 10s

          volumes:
            construct-data:
          TEMPLATE

      - name: Copy logo if missing
        working-directory: coolify
        run: |
          if [ ! -f svgs/construct.png ]; then
            curl -fsSL -o svgs/construct.png \
              "https://raw.githubusercontent.com/KumihoIO/construct-os/main/.github/assets/construct-logo.png"
          fi

      - name: Create PR
        working-directory: coolify
        env:
          GH_TOKEN: ${{ secrets.MARKETPLACE_PAT }}
          VERSION: ${{ steps.ver.outputs.version }}
        run: |
          BRANCH="construct/update-v${VERSION}"
          git checkout -b "$BRANCH"
          git add -A
          git diff --cached --quiet && echo "No changes" && exit 0

          git config user.name "Construct Bot"
          git config user.email "bot@construct.com"
          git commit -m "feat: add/update Construct service template (v${VERSION})"
          git push -u origin "$BRANCH"

          gh pr create \
            --repo coollabsio/coolify \
            --base next \
            --title "feat: add Construct service template (v${VERSION})" \
            --body "$(cat <<'EOF'
          ## Summary
          - Adds/updates the Construct one-click service template
          - Image: `ghcr.io/kumihoio/construct-os:latest`
          - Construct is a fast, small, fully autonomous AI personal assistant (100% Rust)
          - Multi-arch: linux/amd64 + linux/arm64

          ## Testing
          - Deployed via Docker Compose Empty option
          - Health check passes: `construct status --format=exit-code`
          - Gateway accessible on port 42617

          ## Links
          - https://github.com/KumihoIO/construct-os
          - https://github.com/orgs/KumihoIO/packages/container/package/construct
          EOF
          )"

  sync-dokploy:
    name: PR to Dokploy
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Derive version
        id: ver
        run: |
          TAG="${{ inputs.release_tag }}"
          VERSION="${TAG#v}"
          echo "version=${VERSION}" >> "$GITHUB_OUTPUT"

      - name: Checkout Dokploy templates fork
        uses: actions/checkout@v4
        with:
          repository: KumihoIO/templates
          token: ${{ secrets.MARKETPLACE_PAT }}
          ref: main
          path: templates

      - name: Update or create template
        working-directory: templates
        env:
          VERSION: ${{ steps.ver.outputs.version }}
        run: |
          mkdir -p blueprints/construct

          # docker-compose.yml — pin to exact version (Dokploy requirement)
          cat > blueprints/construct/docker-compose.yml << COMPOSE
          version: "3.8"
          services:
            construct:
              image: ghcr.io/kumihoio/construct-os:${VERSION}
              restart: unless-stopped
              environment:
                - API_KEY=\${API_KEY}
                - PROVIDER=\${PROVIDER:-openrouter}
                - CONSTRUCT_ALLOW_PUBLIC_BIND=true
                - CONSTRUCT_GATEWAY_PORT=42617
              volumes:
                - construct-data:/construct-data
              expose:
                - 42617
          volumes:
            construct-data: {}
          COMPOSE

          # template.toml
          cat > blueprints/construct/template.toml << 'TOML'
          [variables]
          main_domain = "${domain}"
          api_key = "${password:64}"

          [config]
          env = [
            "API_KEY=${api_key}",
            "PROVIDER=openrouter",
            "CONSTRUCT_ALLOW_PUBLIC_BIND=true",
            "CONSTRUCT_GATEWAY_PORT=42617"
          ]

          [[config.domains]]
          serviceName = "construct"
          port = 42617
          host = "${main_domain}"
          TOML

          # Copy logo if missing
          if [ ! -f blueprints/construct/construct.png ]; then
            curl -fsSL -o blueprints/construct/construct.png \
              "https://raw.githubusercontent.com/KumihoIO/construct-os/main/.github/assets/construct-logo.png"
          fi

      - name: Update meta.json
        working-directory: templates
        env:
          VERSION: ${{ steps.ver.outputs.version }}
        run: |
          ENTRY=$(cat <<JSON
          {
            "id": "construct",
            "name": "Construct",
            "version": "${VERSION}",
            "description": "Fast, small, and fully autonomous AI personal assistant infrastructure. Deploy anywhere, swap anything. 100% Rust.",
            "logo": "construct.png",
            "links": {
              "github": "https://github.com/KumihoIO/construct-os",
              "website": "https://construct.com/",
              "docs": "https://github.com/KumihoIO/construct-os#readme"
            },
            "tags": ["ai", "self-hosted"]
          }
          JSON
          )

          if jq -e '.[] | select(.id == "construct")' meta.json > /dev/null 2>&1; then
            jq --argjson entry "$ENTRY" '
              [.[] | if .id == "construct" then $entry else . end] | sort_by(.id)
            ' meta.json > meta.tmp && mv meta.tmp meta.json
          else
            jq --argjson entry "$ENTRY" '. + [$entry] | sort_by(.id)' meta.json > meta.tmp && mv meta.tmp meta.json
          fi

      - name: Run validation
        working-directory: templates
        run: |
          if [ -f dedupe-and-sort-meta.js ]; then
            node dedupe-and-sort-meta.js
          fi

      - name: Create PR
        working-directory: templates
        env:
          GH_TOKEN: ${{ secrets.MARKETPLACE_PAT }}
          VERSION: ${{ steps.ver.outputs.version }}
        run: |
          BRANCH="construct/update-v${VERSION}"
          git checkout -b "$BRANCH"
          git add -A
          git diff --cached --quiet && echo "No changes" && exit 0

          git config user.name "Construct Bot"
          git config user.email "bot@construct.com"
          git commit -m "feat: add/update Construct template (v${VERSION})"
          git push -u origin "$BRANCH"

          gh pr create \
            --repo Dokploy/templates \
            --base main \
            --title "feat: add/update Construct template (v${VERSION})" \
            --body "$(cat <<'EOF'
          ## Summary
          - Adds/updates Construct template to v${VERSION}
          - Image: `ghcr.io/kumihoio/construct-os:${VERSION}`
          - Construct is a fast, small, fully autonomous AI personal assistant (100% Rust)
          - Multi-arch: linux/amd64 + linux/arm64

          ## Checklist
          - [x] Read README.md suggestions
          - [x] Tested template in personal Dokploy instance
          - [x] Confirmed all requirements met

          ## Testing
          - Deployed via Compose service import
          - Service starts and gateway is accessible on port 42617
          - Health check passes

          ## Links
          - https://github.com/KumihoIO/construct-os
          - https://github.com/orgs/KumihoIO/packages/container/package/construct
          EOF
          )"

  sync-easypanel:
    name: PR to EasyPanel
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Derive version
        id: ver
        run: |
          TAG="${{ inputs.release_tag }}"
          VERSION="${TAG#v}"
          echo "version=${VERSION}" >> "$GITHUB_OUTPUT"

      - name: Checkout EasyPanel templates fork
        uses: actions/checkout@v4
        with:
          repository: KumihoIO/templates-1
          token: ${{ secrets.MARKETPLACE_PAT }}
          ref: main
          path: easypanel

      - name: Update or create template
        working-directory: easypanel
        env:
          VERSION: ${{ steps.ver.outputs.version }}
        run: |
          mkdir -p templates/construct/assets

          # Copy logo if missing
          if [ ! -f templates/construct/assets/logo.png ]; then
            curl -fsSL -o templates/construct/assets/logo.png \
              "https://raw.githubusercontent.com/KumihoIO/construct-os/main/.github/assets/construct-logo.png"
          fi

          # meta.yaml — update version and changelog
          cat > templates/construct/meta.yaml << META
          name: Construct
          description: |
            Construct is a fast, small, and fully autonomous AI personal assistant
            infrastructure built in 100% Rust. Deploy anywhere, swap anything.
            Connect any LLM provider (OpenRouter, OpenAI, Anthropic, Ollama) and
            interact via a built-in web dashboard, REST API, or WebSocket gateway.
            Supports multi-channel communication (Discord, Telegram, Matrix, Slack,
            WhatsApp, Nostr, Lark), persistent memory, scheduled tasks, and
            autonomous tool use.

          instructions: |
            After deployment, access the Construct gateway at the assigned domain
            on port 42617. Set your LLM provider API key in the environment
            variables. The default provider is OpenRouter — get a key at
            https://openrouter.ai/keys. You can switch to OpenAI, Anthropic,
            or a local Ollama instance by changing the PROVIDER variable.

          changeLog:
            - date: $(date +%Y-%m-%d)
              description: Update to v${VERSION}

          links:
            - label: Website
              url: https://construct.com
            - label: Documentation
              url: https://github.com/KumihoIO/construct-os#readme
            - label: Github
              url: https://github.com/KumihoIO/construct-os

          contributors:
            - name: Kumiho Inc.
              url: https://github.com/KumihoIO

          schema:
            type: object
            required:
              - appServiceName
              - appServiceImage
              - apiKey
              - provider
            properties:
              appServiceName:
                type: string
                title: App Service Name
                default: construct
              appServiceImage:
                type: string
                title: App Service Image
                default: ghcr.io/kumihoio/construct-os:${VERSION}
              apiKey:
                type: string
                title: LLM Provider API Key
                description: Your API key for the selected LLM provider
                default: ""
              provider:
                type: string
                title: LLM Provider
                default: openrouter
                oneOf:
                  - enum:
                      - openrouter
                    title: OpenRouter
                  - enum:
                      - openai
                    title: OpenAI
                  - enum:
                      - anthropic
                    title: Anthropic
                  - enum:
                      - ollama
                    title: Ollama (Local)

          benefits:
            - title: Lightning Fast
              description: Built in 100% Rust with optimized binary size. Starts in milliseconds, runs on minimal resources.
            - title: Deploy Anywhere
              description: Runs on Linux (amd64/arm64), macOS, Windows, Raspberry Pi, and Android.
            - title: Provider Agnostic
              description: Swap between OpenRouter, OpenAI, Anthropic, or local Ollama with a single env var change.

          features:
            - title: Web Dashboard
              description: Built-in web UI for chatting with your AI assistant.
            - title: Multi-Channel
              description: Connect to Discord, Telegram, Matrix, Slack, WhatsApp, Nostr, Lark simultaneously.
            - title: Persistent Memory
              description: SQLite-backed memory and conversation history that survives restarts.
            - title: Autonomous Tools
              description: File operations, web search, code execution, git operations, and custom skill creation.
            - title: Scheduled Tasks
              description: Built-in cron system for recurring autonomous tasks.
            - title: REST & WebSocket API
              description: Full gateway API for programmatic access and real-time streaming.

          tags:
            - AI
            - Self-Hosted
            - Chatbot
            - Agent
            - Assistant
          META

          # index.ts — update default image version
          cat > templates/construct/index.ts << 'TYPESCRIPT'
          import { Output, Services } from "~templates-utils";
          import { Input } from "./meta";

          export function generate(input: Input): Output {
            const services: Services = [];

            const appEnv = [
              `API_KEY=${input.apiKey}`,
              `PROVIDER=${input.provider}`,
              `CONSTRUCT_ALLOW_PUBLIC_BIND=true`,
              `CONSTRUCT_GATEWAY_PORT=42617`,
            ];

            services.push({
              type: "app",
              data: {
                serviceName: input.appServiceName,
                env: appEnv.join("\n"),
                source: {
                  type: "image",
                  image: input.appServiceImage,
                },
                domains: [
                  {
                    host: "$(EASYPANEL_DOMAIN)",
                    port: 42617,
                  },
                ],
                mounts: [
                  {
                    type: "volume",
                    name: "data",
                    mountPath: "/construct-data",
                  },
                ],
              },
            });

            return { services };
          }
          TYPESCRIPT

      - name: Build and validate
        working-directory: easypanel
        run: |
          if [ -f package.json ]; then
            npm ci
            npm run build || true
            npm run prettier || true
          fi

      - name: Create PR
        working-directory: easypanel
        env:
          GH_TOKEN: ${{ secrets.MARKETPLACE_PAT }}
          VERSION: ${{ steps.ver.outputs.version }}
        run: |
          BRANCH="construct/update-v${VERSION}"
          git checkout -b "$BRANCH"
          git add -A
          git diff --cached --quiet && echo "No changes" && exit 0

          git config user.name "Construct Bot"
          git config user.email "bot@construct.com"
          git commit -m "feat: add/update Construct template (v${VERSION})"
          git push -u origin "$BRANCH"

          gh pr create \
            --repo easypanel-io/templates \
            --base main \
            --title "feat: add/update Construct template (v${VERSION})" \
            --body "$(cat <<'EOF'
          ## Summary
          - Adds/updates Construct template to v${VERSION}
          - Image: `ghcr.io/kumihoio/construct-os:${VERSION}`
          - Construct is a fast, small, fully autonomous AI personal assistant (100% Rust)
          - Multi-arch: linux/amd64 + linux/arm64

          ## PR Checklist
          - [x] Logo: high quality PNG, square
          - [x] meta.yaml: static pinned version, all links, instructions included
          - [x] index.ts: no unused variables, no hardcoded secrets, volumes included
          - [x] Uses official GHCR image from KumihoIO org
          - [x] Tested via templates playground

          ## Testing
          - Deployed via EasyPanel template import
          - Service starts and gateway is accessible on port 42617
          - Health check passes

          ## Links
          - https://github.com/KumihoIO/construct-os
          - https://github.com/orgs/KumihoIO/packages/container/package/construct
          EOF
          )"
