Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
250ef81
test(e2e): boot the nested-default tree test on the server's own default
addiberra Sep 25, 2026
a823d9f
test(e2e): wait for the split to mount before returning to single layout
addiberra Sep 25, 2026
68aac4f
test(e2e): synchronize touch terminal tests on readiness and gated ou…
addiberra Sep 25, 2026
0959c31
test(e2e): record page diagnostics for self-launched browsers
addiberra Sep 25, 2026
ca0d959
fix(shell): stop idle clients from re-saving their document over a ne…
addiberra Sep 25, 2026
08a9e70
fix(chat): announce conversations created before a page's inventory a…
addiberra Sep 26, 2026
b357a46
test(e2e): wait for the enabled agent's inventory subscription before…
addiberra Sep 26, 2026
3ea512a
test(e2e): open the chat panel from its stamped state, not a one-shot…
addiberra Sep 26, 2026
b8d2694
test(e2e): hold chat uploads and prompts at the route instead of timi…
addiberra Sep 26, 2026
e45b3e9
test(e2e): drive chat history commands from the composer's asserted s…
addiberra Sep 26, 2026
d3fe3ef
test(e2e): replace chat sleeps with the conditions they stood in for
addiberra Sep 26, 2026
7330652
test(e2e): redo against the turn the held queue delivers
addiberra Sep 26, 2026
d022734
test(e2e): assert the transient copied state before reading the clipb…
addiberra Sep 26, 2026
5496aca
test(e2e): wait for shell row state and delivered events instead of r…
addiberra Sep 26, 2026
d972a6e
test(e2e): run timing-budget tests in their own perf project
addiberra Sep 26, 2026
0cc7067
ci: run e2e as parallel shard and perf jobs behind the validate gate
addiberra Sep 26, 2026
b9c8747
docs: correct the test command facts in CLAUDE.md
addiberra Sep 26, 2026
a155833
fix(preview): update the layout chooser in place instead of rebuildin…
addiberra Sep 26, 2026
c8e88de
test(e2e): hold the split render inside a layout click
addiberra Sep 26, 2026
a513a7f
fix(server): answer /api/document render failures with 500, not 404
addiberra Sep 26, 2026
39009fb
fix(preview): retry a document load the server failed transiently
addiberra Sep 26, 2026
0ca8e18
test(e2e): a transient document failure recovers without another click
addiberra Sep 26, 2026
7ced42b
test(e2e): step with ⌘G only from a settled find in the loaded document
addiberra Sep 26, 2026
0b723ee
fix(shell): keep switcher entries in place when the open menu refreshes
addiberra Sep 26, 2026
c57bd50
test(e2e): run the harness PTY on a deterministic shell
addiberra Sep 26, 2026
f97a333
test(e2e): reset the worker's hub before every hub-served test
addiberra Sep 26, 2026
12e3082
test(e2e): type into terminals only after attach readiness and a shel…
addiberra Sep 26, 2026
a2f9f0f
test(e2e): release held terminal reads explicitly and wait for events…
addiberra Sep 26, 2026
a5fe36d
test(e2e): let the hub switcher settle before acting on it in hub suites
addiberra Sep 26, 2026
4807b91
test(e2e): give the per-test hub reset its own timeout
addiberra Sep 26, 2026
a77d192
test(e2e): keep the e2e workspaces out of the checkout's git repository
addiberra Sep 26, 2026
bbe8a76
fix(preview): keep a clicked outline entry highlighted once its headi…
addiberra Sep 26, 2026
4653259
test(e2e): end the standard boot on real conditions, not sleeps
addiberra Sep 26, 2026
0f01b17
test(e2e): open documents from the tree through a retrying openTreeFile
addiberra Sep 26, 2026
573d6a4
test(e2e): wait for the events fixed sleeps stood in for
addiberra Sep 26, 2026
3d6c108
fix(sidebar): keep keyboard focus on a search hit while results re-re…
addiberra Sep 26, 2026
ce00f2a
test(e2e): let project search's fresh page finish booting before driv…
addiberra Sep 26, 2026
30db1b2
test(e2e): let a tree-idle sample that sees no frames count as not idle
addiberra Sep 26, 2026
cbab219
test(e2e): serve e2e pages as a production bundle
addiberra Sep 26, 2026
f7ee5d0
test(e2e): allocate e2e ports by parallel slot, clear of real hub ports
addiberra Sep 26, 2026
f6e53a9
test(e2e): toggle manual-selection directories without a scrolling click
addiberra Sep 26, 2026
8c6341e
test(e2e): release the departing terminal holder on the test's signal
addiberra Sep 26, 2026
b33e508
fix(shell): refuse live frames older than the state boot applied
addiberra Sep 26, 2026
72399c9
docs: name the boot entry to the state mutator in ARCHITECTURE.md
addiberra Sep 26, 2026
1af0d3a
test(e2e): share one browser per engine per worker
addiberra Sep 26, 2026
f0d194d
ci: split the e2e project into two legs balanced by worker time
addiberra Sep 26, 2026
a7c7e68
fix(hub): fold repeated live upstream failure lines in the hub log
addiberra Sep 26, 2026
16c64a6
test(hub): give the hub process test OS-assigned ports
addiberra Sep 26, 2026
7d00951
test: remove timing races that fail when test files share the cores
addiberra Sep 26, 2026
ac554fd
ci: run unit test files in parallel
addiberra Sep 26, 2026
5275f92
ci: move document-tree to e2e leg 1 to balance the legs
addiberra Sep 26, 2026
1a7a46d
test(e2e): mark the long scrollback and history flows slow
addiberra Sep 26, 2026
f88eb0a
fix(shell): keep keyboard focus on the tab when arrow keys reach the …
addiberra Sep 26, 2026
7589535
test(hub): give the failed-shutdown contender test a child-process bu…
addiberra Sep 26, 2026
b089e53
ci: move document-tree back to e2e leg 2 now that the slow flows comp…
addiberra Sep 27, 2026
d30b1a4
ci: gate on serial unit tests and run the parallel suite as a shadow job
addiberra Sep 27, 2026
d188a55
fix(shell): let initTabBar tear down the bar it wired
addiberra Sep 27, 2026
a1ea5b0
fix(hub): prove a recovered guardian's identity before telling it to …
addiberra Sep 27, 2026
2c70ba8
test(hub): wait for the recovered guardian's processes to exit
addiberra Sep 27, 2026
27d630b
fix(cli): install the serve shutdown handlers before printing the rea…
addiberra Sep 27, 2026
35202f4
test: flush stubbed animation frames before a suite removes its globals
addiberra Sep 27, 2026
833aca4
test(e2e): settle the answer owner at its live end before answering
addiberra Sep 27, 2026
9497b16
fix(hub): wait out transient lease contention instead of refusing eve…
addiberra Sep 27, 2026
a09fd33
test(e2e): synchronize notification presence on hub decisions, not sl…
addiberra Sep 27, 2026
38ba756
test(e2e): attach page diagnostics when a find test fails
addiberra Sep 27, 2026
ed731a0
fix(hub): hold the process open while a failed shutdown retains the l…
addiberra Sep 27, 2026
bb2a5a8
test(hub): wait for the killed config-query descendant to be reaped
addiberra Sep 27, 2026
2c3a94d
test(hub): order the mkfifo timeout fixture by events, not sleeps
addiberra Sep 27, 2026
c302cd9
test(hub): budget the real-Git worktree cases for parallel runs
addiberra Sep 27, 2026
2219585
test(terminal): wait for the disposeAll close instead of a 3 s deadline
addiberra Sep 27, 2026
aa0be09
fix(shared): read the source-run build identity from Git's files
addiberra Sep 27, 2026
f602f34
test(chat): wait for live events to be applied instead of sleeping
addiberra Sep 27, 2026
85d34c4
ci: make the parallel unit suite the required gate
addiberra Sep 27, 2026
4461e4a
docs: describe the e2e legs and the parallel unit gate in the contrib…
addiberra Sep 27, 2026
37a8f68
fix(hub): report a timed-out SSH public-key read as a timeout
addiberra Sep 27, 2026
eecf1b6
fix(shared): keep Node built-in imports out of the browser bundle
addiberra Sep 27, 2026
a3439b3
fix(server): log the cause when /api/document answers 500
addiberra Sep 27, 2026
d66b1bb
fix(preview): re-arm the document load retry when the user selects th…
addiberra Sep 27, 2026
dc5b013
perf(preview): cache the scroll root's scroll-padding-top for the out…
addiberra Sep 27, 2026
cbe4029
test(server): skip the chmod-based EACCES cases when running as root
addiberra Sep 27, 2026
821d0de
fix(shell): key the switcher menu reconcile on entry identity, not po…
addiberra Sep 27, 2026
01082fc
test(e2e): wait for a stopped hub child to exit before reusing its port
addiberra Sep 27, 2026
626f554
fix(hub): exit instead of retaining the lease when shutdown rejects
addiberra Sep 27, 2026
71ccc09
refactor(hub): drop the duplicate socket check before the guardian st…
addiberra Sep 27, 2026
e2fba83
test(e2e): retry a failed WebKit launch instead of caching the rejection
addiberra Sep 27, 2026
1e99f3b
fix(hub): check the recorded sockets before probing the guardian, not…
addiberra Sep 27, 2026
1ca81d6
fix(shell): key the switcher's fork control on its workspace, not its…
addiberra Sep 27, 2026
5c75d93
fix(shared): stop the source-run Git walk at GIT_CEILING_DIRECTORIES
addiberra Sep 27, 2026
ab07bfa
fix(hub): retire a replaced diagnostics sink's pending fold timers
addiberra Sep 27, 2026
b13f83c
fix(preview): start the document retry schedule over when a live fram…
addiberra Sep 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 212 additions & 22 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,11 @@ jobs:
- name: Check API site content and links
run: bun run site:check

validate:
changes:
runs-on: ubuntu-latest
timeout-minutes: 30
timeout-minutes: 5
outputs:
code: ${{ steps.changes.outputs.code }}

steps:
- name: Check out repository
Expand Down Expand Up @@ -128,50 +130,85 @@ jobs:

echo "code=$code" >> "$GITHUB_OUTPUT"

unit:
needs: changes
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false

- name: Set up Bun
if: steps.changes.outputs.code == 'true'
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.4.2

- name: Install dependencies
if: steps.changes.outputs.code == 'true'
run: bun install --frozen-lockfile

- name: Type check
if: steps.changes.outputs.code == 'true'
# Bun executes and bundles TypeScript without ever checking it, so
# tsc --noEmit (strict tsconfig) is the only thing standing between
# a type error and main. Cheapest check, so it runs first.
run: bun run typecheck

- name: Audit dependencies for vulnerabilities
if: steps.changes.outputs.code == 'true'
# Fails the build on a moderate-or-higher advisory against the
# installed tree, so new advisories surface on the PR rather than by
# manual `bun audit`. Low-severity advisories are reported but do not
# block. Renovate (lockFileMaintenance + osvVulnerabilityAlerts) is the
# primary remediation path; this is the backstop.
run: bun audit --audit-level=moderate

- name: Install Playwright Chromium and WebKit
if: steps.changes.outputs.code == 'true'
run: bunx playwright install --with-deps chromium webkit

- name: Run unit and integration tests
if: steps.changes.outputs.code == 'true'
run: bun test
# `bun test --parallel=4`: four worker processes, each running whole
# files in isolation, the committed timings starting the slowest
# files first. Real-process tests wait for the events they assert on
# rather than for fixed delays, so they hold under the contention of
# four workers on a four-core runner.
run: bun run test:ci

- name: Run license audit
if: steps.changes.outputs.code == 'true'
run: bun run check:licenses

- name: Build standalone executable
if: steps.changes.outputs.code == 'true'
run: bun run build

# The smoke test drives the compiled binary with Chromium; the unit
# suite needs no browser. Browsers are cached per Playwright version;
# the system libraries they link against are installed every run.
- name: Resolve Playwright version
id: playwright
run: echo "version=$(jq -r .version node_modules/playwright-core/package.json)" >> "$GITHUB_OUTPUT"

- name: Restore Playwright Chromium
id: browsers
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ runner.arch }}-${{ steps.playwright.outputs.version }}-chromium

- name: Install Playwright Chromium
if: steps.browsers.outputs.cache-hit != 'true'
run: bunx playwright install --with-deps chromium

- name: Install Playwright Chromium system dependencies
if: steps.browsers.outputs.cache-hit == 'true'
run: bunx playwright install-deps chromium

- name: Save Playwright Chromium
if: steps.browsers.outputs.cache-hit != 'true'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/ms-playwright
key: ${{ steps.browsers.outputs.cache-primary-key }}

- name: Smoke-test the compiled binary
if: steps.changes.outputs.code == 'true'
# Catches compile-mode-only bugs the e2e suite misses: it runs in
# dev mode against tests/e2e/server.ts, not against ./dist/uatu.
# The feature-folder refactor (PR #57) shipped two such bugs that
Expand All @@ -180,18 +217,171 @@ jobs:
# whose init never ran at boot.
run: bun run smoke

e2e:
needs: changes
if: needs.changes.outputs.code == 'true'
name: e2e (${{ matrix.name }})
runs-on: ubuntu-latest
timeout-minutes: 25
strategy:
# Every leg runs to the end so the merged report shows all failures.
fail-fast: false
matrix:
include:
# The functional project runs in two legs split by file list
# (UATU_E2E_LEG, see playwright.config.ts), balanced by measured
# worker time; each leg runs the config's 4 workers.
- name: leg 1 of 2
id: leg-1
leg: "1"
args: --project=e2e
- name: leg 2 of 2
id: leg-2
leg: "2"
args: --project=e2e
# The timing-budget suites (tagged @perf) run apart, with the perf
# project's own lower worker limit, so neighbouring workers cannot
# eat into their frame and interaction budgets.
- name: perf
id: perf
args: --project=perf

steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false

- name: Set up Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.4.2

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Resolve Playwright version
id: playwright
run: echo "version=$(jq -r .version node_modules/playwright-core/package.json)" >> "$GITHUB_OUTPUT"

- name: Restore Playwright Chromium and WebKit
id: browsers
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ runner.arch }}-${{ steps.playwright.outputs.version }}-chromium-webkit

- name: Install Playwright Chromium and WebKit
if: steps.browsers.outputs.cache-hit != 'true'
run: bunx playwright install --with-deps chromium webkit

- name: Install Playwright system dependencies
if: steps.browsers.outputs.cache-hit == 'true'
run: bunx playwright install-deps chromium webkit

- name: Save Playwright Chromium and WebKit
if: steps.browsers.outputs.cache-hit != 'true'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/ms-playwright
key: ${{ steps.browsers.outputs.cache-primary-key }}

- name: Run Playwright end-to-end tests
if: steps.changes.outputs.code == 'true'
run: bun run test:e2e
env:
# CI reports as a blob per leg; e2e-report merges them into the
# HTML report when a leg fails.
PLAYWRIGHT_BLOB_OUTPUT_NAME: report-${{ matrix.id }}.zip
UATU_E2E_LEG: ${{ matrix.leg }}
run: bun run test:e2e ${{ matrix.args }}

- name: Upload Playwright artifacts on failure
- name: Upload blob report
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: blob-report-${{ matrix.id }}
path: blob-report
retention-days: 3
if-no-files-found: ignore

- name: Upload Playwright test results on failure
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-artifacts
path: |
playwright-report
test-results
name: playwright-test-results-${{ matrix.id }}
path: test-results
if-no-files-found: ignore

e2e-report:
needs: [changes, e2e]
# Only a failed run needs the HTML report, as before the split.
if: ${{ always() && needs.changes.outputs.code == 'true' && needs.e2e.result != 'success' && needs.e2e.result != 'skipped' }}
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.4.2

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Download blob reports
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: blob-report-*
path: all-blob-reports
merge-multiple: true

- name: Merge into an HTML report
env:
PLAYWRIGHT_HTML_OPEN: never
run: bunx playwright merge-reports --reporter html ./all-blob-reports

- name: Upload Playwright report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-report
path: playwright-report

# The single required check. Unit, build and e2e run as separate jobs;
# this one keeps the `validate` name the merge ruleset requires and passes
# only when every one of them passed, or all were skipped for a change
# that touches no code.
validate:
needs: [changes, unit, e2e]
if: ${{ always() }}
runs-on: ubuntu-latest
timeout-minutes: 5

steps:
- name: Require every validation job
env:
CHANGES: ${{ needs.changes.result }}
CODE: ${{ needs.changes.outputs.code }}
UNIT: ${{ needs.unit.result }}
E2E: ${{ needs.e2e.result }}
run: |
if [ "$CHANGES" != "success" ]; then
echo "::error::Change classification finished '$CHANGES'."
exit 1
fi
if [ "$CODE" = "true" ]; then expected=success; else expected=skipped; fi
failed=0
for job in "unit:$UNIT" "e2e:$E2E"; do
if [ "${job#*:}" != "$expected" ]; then
echo "::error::Job ${job%%:*} finished '${job#*:}', expected '$expected'."
failed=1
fi
done
exit "$failed"

validate-specs:
runs-on: ubuntu-latest
Expand Down
3 changes: 2 additions & 1 deletion ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,7 @@ Failure paths:

- File no longer exists → Session throws → Routes returns 404 → `preview/mount.ts` shows the "no longer exists" empty state.
- File is binary → Session throws `"document is binary"` → Routes returns 415 → `preview/binary.ts` or `preview/image.ts` renders the appropriate fallback (image for `.png` / `.jpg` / etc., a "not viewable" notice otherwise).
- Anything else (a read error such as `EMFILE` or `EACCES`, a renderer that throws) → Routes returns 500 (`documentErrorStatus` in `server/render-dispatch.ts`) → `preview/mount.ts` says the file couldn't be loaded and retries with backoff (`preview/load-retry.ts`), as it does when the request gets no answer. A 404 is not retried: the `document` topic re-fetches when the file comes back.

Pushed updates take a different path. The child emits state events on its internal `/api/events` route, and the hub fans them out to every subscribed page over `/api/hub/live` (see [Live delivery](#live-delivery)).

Expand All @@ -503,7 +504,7 @@ Every `appState` field has exactly one owning module: direct assignment (`appSta
|---|---|
| `selectedId`, `previewMode` | `shell/selection.ts` |
| `followEnabled` | `shell/follow.ts` (the four follow-mode rules) |
| `roots`, `repositories`, `scope`, `unscopedFingerprint` | `shell/events.ts` (`applyServerSnapshot`) |
| `roots`, `repositories`, `scope`, `unscopedFingerprint` | `shell/events.ts` (`applyServerSnapshot`, module-private; boot enters through `adoptBootSnapshot`, which also records the snapshot's freshness so an older live frame is refused) |
| `viewMode`, `wrap` | `preview/view-mode.ts` |
| `viewLayout`, `splitRatio` | `preview/layout.ts` |
| `diffStyle` | `preview/diff.ts` |
Expand Down
26 changes: 24 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,32 @@ is path-filtered (`.github/workflows/desktop-ci.yml`); it builds with plain

- `bun run dev` — dev hub at `http://127.0.0.1:4702/` (`dev/hub.json`, user
`dev` / password `dev`) with `testdata/watch-docs` registered and opened
- `bun test` — unit suite (~18s)
- `bun test` — unit suite, one file at a time (about 3 min on a CI runner)
- `bun run test:ci` — the same suite in parallel, and what CI's required
`unit` job runs: `bun test --parallel=4` (four worker processes, each file
isolated) with `tests/unit-timings.json` starting the slowest files first;
the longest file, `src/hub/worktree-lifecycle.integration.test.ts`, sets
the floor (on a 6-core laptop about 70 s, against about 280 s one file at
a time). Under that contention a test must wait for the event it asserts
on (a process exit, a pump that has handled an event), never for a fixed
delay, and a test driving real processes or real Git may need a budget
above the 5 s default.
Refresh the timings with `bun run test:ci --update-timings` when files
move a lot
- When developing Uatu inside a Hub-managed workspace, credential tests may
discover Uatu's projected Git/SSH wrappers. Use a clean tool environment for
those tests; do not change product behavior to accommodate nested projection.
- `bun test:e2e` — Playwright suite (~5min, `workers: 1` serial)
- `bun run test:e2e` — the whole Playwright suite, both projects (about 870
tests, 4 workers, `fullyParallel`, retries only on CI). CI splits the `e2e`
project into two legs by file list (`UATU_E2E_LEG=1`/`2`, see
`playwright.config.ts`; each leg takes about 15–17 min on a 4-core runner)
and runs `perf` in its own job, then merges their blob reports into one
HTML report. Unset, `UATU_E2E_LEG` runs the whole project.
- `bun run test:e2e:perf` — only the `perf` project: tests tagged `@perf`
that hold a frame, interaction, or load budget (chat-follow-stability,
the long-output shell test, hub-live-stream), at most 2 workers.
`bun run test:e2e:no-perf` (the `e2e` project) skips them. Tag a new
budget test `@perf`; make deterministic work counters its pass criterion
and keep wall-clock time as evidence or a loose guard.
- `bun run build` — compile the single-file `dist/uatu` binary
- `bun run check:licenses` — license audit
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ same core checks as CI should pass:
```bash
bun run typecheck
bun audit --audit-level=moderate
bun test
bun run test:ci
bun run check:licenses
bun run build
bun run smoke
Expand Down
4 changes: 3 additions & 1 deletion api/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ type Streaming = { channels: Record<string, unknown>; schemas: Record<string, ob
describe("API contract structure", () => {
test("metadata, schemas, and all source examples validate", async () => {
await validateApi();
});
// CPU-bound: about a second alone, several when other test files share the
// cores (`bun test --parallel`), so the default five seconds is no bound.
}, 30_000);

test("OpenAPI operations exactly match the public inventory", async () => {
const [openapi, inventory] = await Promise.all([
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
"bench:render": "bun run scripts/bench-render.ts",
"bench:chat": "bun run scripts/bench-chat.ts",
"test": "bun test",
"test:ci": "bun test --parallel=4 --timings=tests/unit-timings.json",
"typecheck": "tsc --noEmit",
"check:licenses": "bun run src/shared/license-check.ts",
"coverage:agents": "bun run scripts/agent-coverage.ts",
"e2e:install": "playwright install chromium webkit",
"test:e2e": "playwright test",
"test:e2e:perf": "playwright test --project=perf",
"test:e2e:no-perf": "playwright test --project=e2e",
"test:e2e:headed": "playwright test --headed",
"test:e2e:ui": "playwright test --ui",
"test:e2e:debug": "playwright test --debug",
Expand Down
Loading
Loading