From eb80a556231c462c0a9200987728a5afd8c15410 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Fri, 18 Sep 2026 09:02:38 -0700 Subject: [PATCH 1/2] Set Node 24 LTS as the minimum engine Declare engines.node >=24, cover Node 24 in CI, and state the floor in the README install section. No prior floor was declared. --- .github/workflows/ci.yml | 25 +++++++++++++++++++++++++ README.md | 3 ++- package.json | 3 +++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..e6152bdd --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,25 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + verify: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [24] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + - uses: oven-sh/setup-bun@v2 + - run: bun install --frozen-lockfile + - run: bun run typecheck + - run: bun run lint + - run: bun run dep-guard + - run: bun test diff --git a/README.md b/README.md index 813620bf..47ca533f 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ Licensed LGPL-2.1-only (see `LICENSE`). ## Install -Not published to npm yet. +Not published to npm yet. Requires Node.js 24 LTS or later. + ```bash bun add github:corbitsdev/react-ui react react-dom lucide-react sonner @radix-ui/react-dialog @radix-ui/react-dropdown-menu @radix-ui/react-slot @radix-ui/react-tooltip diff --git a/package.json b/package.json index 7bfb7489..28d24833 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,9 @@ "description": "React components for agent and workflow surfaces.", "author": "Sawyer Cutler ", "license": "LGPL-2.1-only", + "engines": { + "node": ">=24" + }, "type": "module", "sideEffects": [ "**/*.css" From d512db8678e657d715c14f3d29078ed3da713579 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Sun, 20 Sep 2026 17:19:02 -0700 Subject: [PATCH 2/2] fix: restore console.error after test spies delete console.error left later React act() warnings throwing TypeError. Pin bun 1.4.0 in CI and run bun run build as the generate+contrast gate. --- .github/workflows/ci.yml | 3 +++ src/hooks/use-controllable-state.test.ts | 8 ++++++-- src/hooks/use-dismissable-popover.test.ts | 8 ++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6152bdd..4afa2546 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,8 +18,11 @@ jobs: with: node-version: ${{ matrix.node-version }} - uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.4.0 - run: bun install --frozen-lockfile - run: bun run typecheck - run: bun run lint - run: bun run dep-guard - run: bun test + - run: bun run build diff --git a/src/hooks/use-controllable-state.test.ts b/src/hooks/use-controllable-state.test.ts index 9ee2c582..baf9ecba 100644 --- a/src/hooks/use-controllable-state.test.ts +++ b/src/hooks/use-controllable-state.test.ts @@ -67,6 +67,7 @@ describe("useControllableState", () => { describe("controlled/uncontrolled transition warning", () => { let errorSpy: ReturnType; + const originalError = console.error; beforeEach(() => { errorSpy = mock(() => {}); @@ -74,8 +75,7 @@ describe("useControllableState", () => { }); afterEach(() => { - // @ts-expect-error restoring the built-in after stubbing it above - delete console.error; + console.error = originalError; }); test("logs once when an uncontrolled caller starts passing a value", () => { @@ -107,4 +107,8 @@ describe("useControllableState", () => { controlled.unmount(); }); }); + + test("console.error is a function after warning spies restore", () => { + expect(typeof console.error).toBe("function"); + }); }); diff --git a/src/hooks/use-dismissable-popover.test.ts b/src/hooks/use-dismissable-popover.test.ts index 20a201a6..d667ceaf 100644 --- a/src/hooks/use-dismissable-popover.test.ts +++ b/src/hooks/use-dismissable-popover.test.ts @@ -123,6 +123,7 @@ describe("useDismissablePopover", () => { describe("controlled/uncontrolled transition warning", () => { let errorSpy: ReturnType; + const originalError = console.error; beforeEach(() => { errorSpy = mock(() => {}); @@ -130,8 +131,7 @@ describe("useDismissablePopover", () => { }); afterEach(() => { - // @ts-expect-error restoring the built-in after stubbing it above - delete console.error; + console.error = originalError; }); test("logs once when an uncontrolled caller starts passing open", () => { @@ -143,4 +143,8 @@ describe("useDismissablePopover", () => { handle.unmount(); }); }); + + test("console.error is a function after warning spies restore", () => { + expect(typeof console.error).toBe("function"); + }); });