Files
deepseek-harness/.github/workflows/ci.yml
T
Tianyi Cui 07f4047ff0 Use explicit ts specifiers for declarations
Restore explicit .ts relative specifiers in source and enable rewriteRelativeImportExtensions so emitted JS uses .js while declarations keep explicit .ts specifiers. Add a NodeNext declaration-consumer gate to prevent extensionless declaration regressions.
2026-06-22 06:11:00 +08:00

100 lines
3.9 KiB
YAML

name: CI
on:
push:
branches: [main, master]
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
checks:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node: [24, 26]
name: node ${{ matrix.node }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node }}
- name: Enable corepack (pnpm)
run: corepack enable
- name: Install (immutable)
run: pnpm install --frozen-lockfile
- name: Constraints
run: pnpm run constraints
# Before lint: root typecheck validates the package/vendor reference graph
# and refreshes TSC intermediates so type-aware ESLint sees the same project
# boundaries as the build.
- name: Typecheck (src + tests + examples)
run: pnpm run typecheck
- name: Lint
run: pnpm run lint
# Doc-sync gates (doc-sync-enforcement RFC). doc-typecheck compiles the
# fenced ts blocks against the root project-reference graph. The cordis
# catalog freshness check, type-equiv check, and markdown wrap/link checks
# only read source. Same `doc-sync` script the pre-push hook runs
# (quality-gates RFC: one source of truth).
- name: Doc-sync gates (doc code blocks + cordis catalog + type-equiv + markdown wrap/links)
run: pnpm run doc-sync
# Module-graph freshness: regenerate docs/module-graph.md from the
# packages' peerDependencies and fail if it differs from the committed
# file. Only reads source package.json — no build needed.
- name: Module-graph freshness
run: pnpm run verify-module-graph
- name: Tests with coverage gate (per-file 100%)
run: pnpm run test:coverage
# ACP snapshot tests (acp-snapshot-tests RFC): boot the real acp-agent
# subprocess and replay recorded session-log fixtures, diffing the
# normalized stdout transcript + re-persisted log against committed
# goldens. KEYLESS by design — the same `test:snapshot` script the pre-push
# hook runs (one source of truth), so the full-transcript regression net
# is part of every PR gate, not just local pre-push.
- name: Snapshot tests (ACP transcript replay)
run: pnpm run test:snapshot
# Before hygiene: publint validates the packed artifacts (lib/index.js),
# which only the tsdown bundling step emits, and verify-node-next-types
# validates the built declarations.
- name: Build (tsc -b + tsdown bundles)
run: pnpm run build
- name: Hygiene (knip + publint + constraints + NodeNext types)
run: pnpm run hygiene
- name: Demo smoke test
run: |
set -euo pipefail
out=$(printf 'echo ci smoke\n' | timeout 60 pnpm run demo:echo 2>&1)
echo "$out"
echo "$out" | grep -q '\[tool call\] echo({"text":"ci smoke"})'
echo "$out" | grep -q '\[tool result\] ECHO: CI SMOKE'
# The JSONL backend (root ./.sessions, no cwd → _no-cwd bucket) writes a
# per-run session log named main-session-<uuid>.jsonl. Assert one exists.
ls .sessions/_no-cwd/main-session-*.jsonl >/dev/null
rm -rf .sessions
# The published `bin` is `lib/bin.js`, run under plain `node` by a real
# consumer — NOT the tsx dev path the demo smoke and demo:* scripts use.
# These keyless smokes boot the BUILT bins (this step runs AFTER the build)
# in a temp dir that mirrors a real install, catching a regression in the
# published artifact that tsx would mask. They self-skip if lib/ is absent,
# so the e2e job (which does not build) does not run them.
- name: Built-bin smoke test (published lib/bin.js under node)
run: pnpm exec vitest run --config vitest.e2e.config.ts packages/ui/stdio-agent/tests/built-bin.e2e.ts packages/ui/acp-agent/tests/built-bin.e2e.ts