name: CI

# 只认 main：push 到 main、以及任何以 main 为目标的 PR。
# 开发分支（feat/*）自己 push 不跑 CI，靠合入 main 前的 PR 把关。
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

# 同一分支新 push 取消上一次未完成的运行，省 CI 时间。
concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

jobs:
  go:
    name: Go · build + vet + test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: "1.25"
          cache-dependency-path: "**/go.sum"
      - name: build + vet + test（4 模块；bus 用内嵌 NATS，无需外部服务）
        run: |
          set -e
          for m in sundynix-shared sundynix-gateway sundynix-dispatcher sundynix-mcp-go; do
            echo "::group::$m"
            (cd "$m" && go build ./... && go vet ./... && go test ./...)
            echo "::endgroup::"
          done

  web:
    name: Frontend · tsc + vitest
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        dir: [sundynix-desktop/frontend, sundynix-admin, sundynix-web]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: npm
          cache-dependency-path: ${{ matrix.dir }}/package-lock.json
      - name: install + typecheck + test（三个前端都有 vitest，此前只跑 tsc，测试从没进过关卡）
        working-directory: ${{ matrix.dir }}
        run: |
          npm ci
          npx tsc --noEmit
          npm test

  # desktop 的 Go 模块不在 go.work 里，上面的 go job 从来没测过它（app.go 的
  # download/另存为等桥方法有单测但 CI 一次没跑过）。用 macos runner：一来免装
  # gtk/webkit（linux 编 wails 要一堆 CGO 头），二来 darwin 才是实际发行目标。
  # go:embed frontend/dist 要求先出前端产物，故先 npm build。
  desktop:
    name: Desktop · go build + test (macOS)
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: "1.25"
          cache-dependency-path: sundynix-desktop/go.sum
      - uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: npm
          cache-dependency-path: sundynix-desktop/frontend/package-lock.json
      - name: 前端构建（供 go:embed）
        working-directory: sundynix-desktop/frontend
        run: |
          npm ci
          npm run build
      - name: go build + vet + test
        working-directory: sundynix-desktop
        env:
          GOWORK: "off" # 必须加引号：YAML 裸 off 会被解析成布尔 false
        run: |
          go build ./...
          go vet ./...
          go test ./...

  py:
    name: mcp-py · sandbox guard
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"
          cache: pip
      - name: install + test（无 Docker 时测降级路径）
        working-directory: sundynix-mcp-py
        run: |
          python -m pip install --upgrade pip
          python -m pip install -e . pytest
          PYTHONPATH=src:tests python -m pytest tests/ -q || \
          PYTHONPATH=src:tests python -c "import test_sandbox as t; \
            fns=[getattr(t,n) for n in dir(t) if n.startswith('test_')]; \
            [ (f(),print('PASS',f.__name__)) for f in fns ]; print(f'{len(fns)} passed')"
