Skip to content

chore(release): v2026.4.26 — verification fixes, roadmap wired, 100% … #623

chore(release): v2026.4.26 — verification fixes, roadmap wired, 100% …

chore(release): v2026.4.26 — verification fixes, roadmap wired, 100% … #623

Workflow file for this run

name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
changes:
name: Detect Changes
runs-on: ubuntu-latest
timeout-minutes: 2
outputs:
code: ${{ steps.filter.outputs.code }}
schemas: ${{ steps.filter.outputs.schemas }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
code:
- 'packages/**'
- 'pnpm-workspace.yaml'
- 'package.json'
- 'pnpm-lock.yaml'
- 'tsconfig*.json'
- 'vitest.config.ts'
- 'build.mjs'
schemas:
- 'packages/*/schemas/**'
- 'packages/*/templates/**'
biome:
name: Lint & Format
runs-on: ubuntu-latest
timeout-minutes: 2
steps:
- uses: actions/checkout@v4
- uses: biomejs/setup-biome@v2
with:
version: '2.4.8'
- run: biome ci .
typecheck:
name: Type Check
needs: [biome, changes]
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24'
- uses: pnpm/action-setup@v4
with:
version: '10.30.0'
run_install: false
- name: Get pnpm store directory
id: pnpm-cache
run: echo "store=$(pnpm store path --silent)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
with:
path: ${{ steps.pnpm-cache.outputs.store }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- run: pnpm install --frozen-lockfile
- name: Type check with project references
run: pnpm run typecheck
unit-tests:
name: Unit Tests (${{ matrix.os }}, shard ${{ matrix.shard }})
needs: [biome, changes]
if: needs.changes.outputs.code == 'true'
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
matrix:
os: ${{ fromJson(github.event_name == 'pull_request' && github.base_ref == 'main' && '["ubuntu-latest","macos-latest","windows-latest"]' || '["ubuntu-latest"]') }}
shard: [1, 2]
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24'
- uses: pnpm/action-setup@v4
with:
version: '10.30.0'
run_install: false
- name: Get pnpm store directory
id: pnpm-cache
shell: bash
run: echo "store=$(pnpm store path --silent)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
with:
path: ${{ steps.pnpm-cache.outputs.store }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- run: pnpm install --frozen-lockfile
- name: Build packages (required for cross-package imports)
run: pnpm run build
- name: Run unit tests (shard ${{ matrix.shard }}/2)
run: pnpm exec vitest run --shard=${{ matrix.shard }}/2
build-verify:
name: Build & Verify (${{ matrix.os }})
needs: [biome, changes]
if: needs.changes.outputs.code == 'true'
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
matrix:
os: ${{ fromJson(github.event_name == 'pull_request' && github.base_ref == 'main' && '["ubuntu-latest","macos-latest","windows-latest"]' || '["ubuntu-latest"]') }}
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24'
- uses: pnpm/action-setup@v4
with:
version: '10.30.0'
run_install: false
- name: Get pnpm store directory
id: pnpm-cache
shell: bash
run: echo "store=$(pnpm store path --silent)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
with:
path: ${{ steps.pnpm-cache.outputs.store }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- run: pnpm install --frozen-lockfile
# ──────────────────────────────────────────────────────────────────
# COLD-STATE BUILD GATE
#
# Purpose: catch workspace-dependency-order regressions in build.mjs
# at PR-time, never at release-time.
#
# Background: in v2026.4.8 the release workflow failed at the Build
# step because caamp's tsup DTS resolver couldn't find @cleocode/cant
# — caamp had grown a new import that depended on cant's .d.ts files
# being present on disk before caamp built, but build.mjs's order had
# caamp building first. The bug only reproduced from a fully clean
# state (no dist, no tsbuildinfo) because local re-builds left stale
# dist files behind that masked the gap.
#
# CI checkouts are already fresh, so this defensive `rm -rf` is
# belt-and-braces — it guarantees the build runs from zero state
# regardless of any future caching changes to actions/checkout or
# actions/cache. If someone reorders build.mjs incorrectly again,
# this step fails and blocks the merge.
# ──────────────────────────────────────────────────────────────────
- name: Cold-state cleanup (defense against build-order regressions)
shell: bash
run: |
rm -rf packages/*/dist packages/*/tsconfig.tsbuildinfo
echo "Cleaned dist and tsbuildinfo from all packages."
- name: Build all packages from cold state (catches dep-order regressions)
run: node build.mjs
- name: Verify core dist exists
shell: bash
run: |
test -f packages/core/dist/index.js || (echo "packages/core/dist/index.js missing" && exit 1)
- name: Verify lafs dist exists
shell: bash
run: |
test -f packages/lafs/dist/src/index.js || (echo "packages/lafs/dist/src/index.js missing" && exit 1)
- name: Verify caamp dist exists
shell: bash
run: |
test -f packages/caamp/dist/index.js || (echo "packages/caamp/dist/index.js missing" && exit 1)
- name: Verify cant dist exists
shell: bash
run: |
test -f packages/cant/dist/index.js || (echo "packages/cant/dist/index.js missing" && exit 1)
- name: Verify runtime dist exists
shell: bash
run: |
test -f packages/runtime/dist/index.js || (echo "packages/runtime/dist/index.js missing" && exit 1)
- name: Verify CLI binary
shell: bash
run: node packages/cleo/dist/cli/index.js version
- name: Verify MCP server starts
if: matrix.os != 'windows-latest'
shell: bash
run: timeout 5 node packages/cleo/dist/mcp/index.js 2>&1 || true
validate-json:
name: Validate JSON Schemas
needs: [biome, changes]
if: needs.changes.outputs.schemas == 'true'
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- name: Install jq
run: sudo apt-get install -y jq
- name: Validate JSON schema files
run: |
find packages -name '*.json' -path '*/schemas/*' | while read file; do
echo "Validating: $file"
jq empty "$file"
done
install-test:
name: Install Test
needs: [biome, changes]
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24'
- uses: pnpm/action-setup@v4
with:
version: '10.30.0'
run_install: false
- name: Get pnpm store directory
id: pnpm-cache
run: echo "store=$(pnpm store path --silent)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
with:
path: ${{ steps.pnpm-cache.outputs.store }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies and build
run: pnpm install --frozen-lockfile && node build.mjs
- name: Test global link (simulates global install)
run: |
cd packages/cleo && pnpm link --global && cd ../..
cleo version
cleo --help
- name: Test MCP server flag
run: timeout 5 cleo --mcp-server 2>&1 || true
- name: Test project initialization
run: |
mkdir -p /tmp/test-project
cd /tmp/test-project
cleo init test-project
ls -la .cleo/
- name: Cleanup
if: always()
run: pnpm unlink --global @cleocode/cleo
forge-ts-check:
name: Documentation Coverage (forge-ts)
needs: [biome, changes]
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-latest
timeout-minutes: 5
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24'
- uses: pnpm/action-setup@v4
with:
run_install: false
- name: Get pnpm store directory
id: pnpm-cache
run: echo "store=$(pnpm store path --silent)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
with:
path: ${{ steps.pnpm-cache.outputs.store }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- run: pnpm install --frozen-lockfile
- name: Check TSDoc coverage
run: pnpm exec forge-ts check --human || true
- name: Build documentation
run: pnpm exec forge-ts build || true