name: CI on: push: branches: [main] pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - name: Cache npm dependencies uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-npm- # NOTE: the switch to `npm ci` (deterministic, lockfile-faithful) is deferred # to the deps/lockfile hardening pass, after the root package-lock.json is # regenerated in sync with every workspace manifest. `npm install` is the # safe, lockfile-tolerant install until then. - run: npm install # Real typecheck gate. The old step ran `npx tsc --noEmit` against the root # tsconfig.json, whose `"files": ["apps/web/src/vite-env.d.ts"]` (and no # `include`) typechecks essentially nothing. build:packages is the actual # `tsc --build` chain for every @waggle/* package (shared → hive-mind-core → # core → agent → server) and also emits the dist/ that apps/web unit tests # import; typecheck:web is the real apps/web check (tsc -p tsconfig.app.json). - name: Type check — workspace packages (tsc --build chain) run: npm run build:packages - name: Type check — web (apps/web, tsc -p tsconfig.app.json) run: npm run typecheck:web - name: Lint (root flat config) run: npm run lint - name: Tauri TS typecheck (app/scripts) run: npx tsc -p app/tsconfig.json # Runtime tests pack and install workspace packages. Build every ignored # dist/ payload explicitly so CI proves a fresh checkout. - name: Build package-install test runtimes run: | npm run build:hook-runtime npm run build --workspace @waggle/cli npm run build --workspace @waggle-ai/waggle npm run build --workspace waggle-memory-mcp - name: Unit tests — packages + cross-cutting (root vitest) run: | npm test -- \ --exclude=packages/cli/tests/cli-runtime.test.ts \ --exclude=packages/hive-mind-cli/tests/cli-help.test.ts \ --exclude=packages/hive-mind-mcp-server/tests/runtime.test.ts \ --exclude=packages/launcher/tests/cli.test.ts \ --exclude=packages/memory-mcp/tests/runtime.test.ts # These tests each create a temporary project and run npm install. Running # several cold installs in parallel makes individual test timeouts measure # runner contention rather than package correctness. - name: Package-install runtime tests (serial) run: | npx vitest run \ packages/cli/tests/cli-runtime.test.ts \ packages/hive-mind-cli/tests/cli-help.test.ts \ packages/hive-mind-mcp-server/tests/runtime.test.ts \ packages/launcher/tests/cli.test.ts \ packages/memory-mcp/tests/runtime.test.ts \ --maxWorkers=1 \ --no-file-parallelism # The root vitest.config.ts excludes `apps/**`, so apps/web's own 131-file # suite never ran in CI. Run it via its own vitest config (jsdom). Blocking. - name: Unit tests — apps/web run: npm run test -w apps/web - name: Security audit (informational) run: npm audit --audit-level=high continue-on-error: true # ADVISORY / NON-BLOCKING. `continue-on-error: true` means a red e2e run does # NOT block merges — by design. These specs are broad product/audit journeys # (full-product-audit, power-user-stress, competitive-benchmarks, …) that are # historically flake-prone, so gating merges on them would produce false reds. # The blocking `e2e-smoke` job above covers the stable launch, settings, # memory, workspace, and mobile regression slice. This broad job stays # advisory so exploratory audit coverage can report flakes without blocking # merges. e2e-smoke: runs-on: ubuntu-latest needs: test steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - name: Cache npm dependencies uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-npm- - run: npm install - name: Build packages run: npm run build:packages - name: Build frontend run: npm run build - name: Install Playwright browsers run: npx playwright install --with-deps chromium - name: Run blocking Playwright smoke journeys run: npm run test:e2e:smoke env: WAGGLE_ECHO_MODE: "1" NODE_ENV: test WAGGLE_TRUST_LOCALHOST: "1" e2e: runs-on: ubuntu-latest needs: test continue-on-error: true steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - name: Cache npm dependencies uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-npm- - run: npm install # apps/web's tsc build imports @waggle/shared etc. which export dist/; # build the workspace packages first (the deploy does this via build:all). - name: Build packages run: npm run build:packages - name: Build frontend run: npm run build - name: Install Playwright browsers run: npx playwright install --with-deps chromium - name: Run Playwright E2E tests run: npx playwright test tests/e2e/ env: WAGGLE_ECHO_MODE: "1" NODE_ENV: test # D1: the e2e suite hits /api/* directly without a bearer token; trust # loopback in CI's test server (prod default stays secure). Mirrors # vitest.setup.ts and playwright.config.ts webServer.env. WAGGLE_TRUST_LOCALHOST: "1" - name: Upload Playwright report if: failure() uses: actions/upload-artifact@v4 with: name: playwright-report path: playwright-report/ retention-days: 14