Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .claude/agents/recce-pr-verifier.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ uv run pytest tests/test_foo.py --cov=recce.module --cov-report=term-missing

### Frontend (TypeScript) — only if `js/` changed

For frontend tooling specifics (pnpm v11 quirks, Biome config, style conventions), see **[`js/CLAUDE.md`](../../js/CLAUDE.md)**.
For frontend tooling specifics (pnpm v12 quirks, Biome config, style conventions), see **[`js/CLAUDE.md`](../../js/CLAUDE.md)**.

```bash
cd js
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/address-dependabot/skill.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ digraph address_dependabot {

This repo contains `@datarecce/ui`, a **published npm package** consumed by external projects. Its `dependencies` field is a contract with consumers. This shapes how dependency updates are applied.

For frontend tooling context (pnpm v11 `strictDepBuilds`/`allowBuilds`, Biome migration on bump, Node.js 26 via `nave`), reference **[`js/CLAUDE.md`](../../../js/CLAUDE.md)** before applying npm updates.
For frontend tooling context (pnpm v12 `strictDepBuilds`/`allowBuilds`, Biome migration on bump, Node.js 26 via `nave`), reference **[`js/CLAUDE.md`](../../../js/CLAUDE.md)** before applying npm updates.

### The Three Zones

Expand Down
6 changes: 3 additions & 3 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Recce Copilot Instructions

> Claude Code and other agents using `CLAUDE.md` should also consult **[`js/CLAUDE.md`](../js/CLAUDE.md)** for frontend tooling specifics (pnpm commands, Biome, Vitest, `@datarecce/ui` publishing, pnpm v11 `strictDepBuilds`/`allowBuilds`, style conventions). This file remains the canonical Copilot context.
> Claude Code and other agents using `CLAUDE.md` should also consult **[`js/CLAUDE.md`](../js/CLAUDE.md)** for frontend tooling specifics (pnpm commands, Biome, Vitest, `@datarecce/ui` publishing, pnpm v12 `strictDepBuilds`/`allowBuilds`, style conventions). This file remains the canonical Copilot context.

## Project Overview

Expand Down Expand Up @@ -86,7 +86,7 @@ below:

```bash
cd js
pnpm install # Uses pnpm 11, NOT npm or yarn
pnpm install # Uses pnpm 12, NOT npm or yarn
```

**Development Server:**
Expand Down Expand Up @@ -218,7 +218,7 @@ recce/

```
js/
├── package.json # pnpm 11, Node >=26.5.0, React 19, Next.js 16
├── package.json # pnpm 12, Node >=26.5.0, React 19, Next.js 16
├── tsconfig.json # TypeScript config
├── next.config.js # Next.js config (output: 'export')
├── app/ # OSS Next.js App Router shell (routes/layout only)
Expand Down
10 changes: 5 additions & 5 deletions .github/instructions/frontend-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ applyTo: "js/**/*.ts,js/**/*.tsx,js/**/*.js,js/**/*.jsx,js/**/*.json,js/**/*.mjs

# Frontend Build Instructions (js/ Directory)

> This file is the **Copilot-targeted** frontend guide (scoped via `applyTo:` frontmatter). Claude Code and other agents using `CLAUDE.md` should consult **[`js/CLAUDE.md`](../../js/CLAUDE.md)** for the equivalent guidance — both should stay in sync on tooling specifics (pnpm v11, Biome, `@datarecce/ui` publishing, style conventions).
> This file is the **Copilot-targeted** frontend guide (scoped via `applyTo:` frontmatter). Claude Code and other agents using `CLAUDE.md` should consult **[`js/CLAUDE.md`](../../js/CLAUDE.md)** for the equivalent guidance — both should stay in sync on tooling specifics (pnpm v12, Biome, `@datarecce/ui` publishing, style conventions).

## Critical Frontend Build Requirements

Expand All @@ -27,7 +27,7 @@ pnpm run build
## Package Manager - MUST use pnpm

```bash
# CORRECT - Always use pnpm (version 11)
# CORRECT - Always use pnpm (version 12)
pnpm install
pnpm dev
pnpm run build
Expand Down Expand Up @@ -87,7 +87,7 @@ pnpm run clean
## Tech Stack

- **Node.js >=26.5.0** - JavaScript runtime (required)
- **pnpm 11** - Package manager (NOT npm or yarn)
- **pnpm 12** - Package manager (NOT npm or yarn)
- **Next.js 16** - React framework with App Router
- **React 19.2** - UI library with new JSX transform
- **React DOM 19.2** - React renderer
Expand Down Expand Up @@ -130,7 +130,7 @@ js/

**package.json:**
- Requires Node.js >=26.5.0
- Uses pnpm@11.1.1 as package manager (pinned via Corepack)
- Uses pnpm@12.4.1 as package manager (pinned via Corepack)
- Key scripts:
- `dev`: Start development server with Turbopack
- `build`: Clean, build Next.js, move to ../recce/data
Expand Down Expand Up @@ -225,7 +225,7 @@ pnpm test # Watch mode

**What it checks:**
1. Node.js 26.5.0 setup from `js/.nvmrc`
2. pnpm 11 installation
2. pnpm 12 installation
3. Dependency install with frozen lockfile
4. Biome linting (`pnpm lint`)
5. Production build (`pnpm run build`)
Expand Down
16 changes: 14 additions & 2 deletions .github/workflows/address-dependabot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,21 @@ jobs:
with:
node-version-file: 'js/.nvmrc'

- uses: pnpm/action-setup@v6
- name: Set up pnpm
uses: pnpm/setup@84cb39b217b10273981911c288cd62326dc7c6d2 # v2.0.2
with:
version: 11.1.1
package-json-file: js/package.json
install: false
cache: true
cache-dependency-path: js/pnpm-lock.yaml

- name: Verify pnpm version
working-directory: ./js
run: |
expected=$(node -p "require('./package.json').packageManager.match(/^pnpm@([^+]+)/)[1]")
actual=$(pnpm --version)
echo "pnpm version: $actual"
test "$actual" = "$expected"

- name: Install frontend dependencies
working-directory: ./js
Expand Down
16 changes: 14 additions & 2 deletions .github/workflows/nightly.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,21 @@ jobs:
with:
node-version-file: 'js/.nvmrc'

- uses: pnpm/action-setup@v6
- name: Set up pnpm
uses: pnpm/setup@84cb39b217b10273981911c288cd62326dc7c6d2 # v2.0.2
with:
version: 11.1.1
package-json-file: js/package.json
install: false
cache: true
cache-dependency-path: js/pnpm-lock.yaml

- name: Verify pnpm version
working-directory: ./js
run: |
expected=$(node -p "require('./package.json').packageManager.match(/^pnpm@([^+]+)/)[1]")
actual=$(pnpm --version)
echo "pnpm version: $actual"
test "$actual" = "$expected"

- name: Install dependencies
run: |
Expand Down
22 changes: 16 additions & 6 deletions .github/workflows/release-ui.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,28 @@ jobs:
# For workflow_run, checkout the same ref that triggered the parent workflow
ref: ${{ github.event.workflow_run.head_sha || github.sha }}

- uses: pnpm/action-setup@v6
with:
version: 11.1.1

- name: Setup Node.js 26
uses: actions/setup-node@v7
with:
node-version-file: 'js/.nvmrc' # Node 26 includes npm 11+ with OIDC support
cache: 'pnpm'
cache-dependency-path: js/pnpm-lock.yaml
registry-url: 'https://registry.npmjs.org'

- name: Set up pnpm
uses: pnpm/setup@84cb39b217b10273981911c288cd62326dc7c6d2 # v2.0.2
with:
package-json-file: js/package.json
install: false
cache: true
cache-dependency-path: js/pnpm-lock.yaml

- name: Verify pnpm version
working-directory: ./js
run: |
expected=$(node -p "require('./package.json').packageManager.match(/^pnpm@([^+]+)/)[1]")
actual=$(pnpm --version)
echo "pnpm version: $actual"
test "$actual" = "$expected"

- name: Verify npm version
run: |
NPM_VERSION=$(npm --version)
Expand Down
16 changes: 14 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,21 @@ jobs:
with:
node-version-file: 'js/.nvmrc'

- uses: pnpm/action-setup@v6
- name: Set up pnpm
uses: pnpm/setup@84cb39b217b10273981911c288cd62326dc7c6d2 # v2.0.2
with:
version: 11.1.1
package-json-file: js/package.json
install: false
cache: true
cache-dependency-path: js/pnpm-lock.yaml

- name: Verify pnpm version
working-directory: ./js
run: |
expected=$(node -p "require('./package.json').packageManager.match(/^pnpm@([^+]+)/)[1]")
actual=$(pnpm --version)
echo "pnpm version: $actual"
test "$actual" = "$expected"

- name: Install dependencies
run: |
Expand Down
52 changes: 24 additions & 28 deletions .github/workflows/tests-js.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,21 @@ jobs:
with:
node-version-file: 'js/.nvmrc'

- uses: pnpm/action-setup@v6
- name: Set up pnpm
uses: pnpm/setup@84cb39b217b10273981911c288cd62326dc7c6d2 # v2.0.2
with:
version: 11.1.1
run_install: false
package-json-file: js/package.json
install: false
cache: true
cache-dependency-path: js/pnpm-lock.yaml

- name: Get pnpm store directory
shell: bash
- name: Verify pnpm version
working-directory: ./js
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV

- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
expected=$(node -p "require('./package.json').packageManager.match(/^pnpm@([^+]+)/)[1]")
actual=$(pnpm --version)
echo "pnpm version: $actual"
test "$actual" = "$expected"

- name: Install dependencies
working-directory: ./js
Expand All @@ -60,23 +58,21 @@ jobs:
with:
node-version-file: 'js/.nvmrc'

- uses: pnpm/action-setup@v6
- name: Set up pnpm
uses: pnpm/setup@84cb39b217b10273981911c288cd62326dc7c6d2 # v2.0.2
with:
version: 11.1.1
run_install: false
package-json-file: js/package.json
install: false
cache: true
cache-dependency-path: js/pnpm-lock.yaml

- name: Get pnpm store directory
shell: bash
- name: Verify pnpm version
working-directory: ./js
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV

- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
expected=$(node -p "require('./package.json').packageManager.match(/^pnpm@([^+]+)/)[1]")
actual=$(pnpm --version)
echo "pnpm version: $actual"
test "$actual" = "$expected"

- name: Install dependencies
working-directory: ./js
Expand Down
34 changes: 28 additions & 6 deletions .github/workflows/tests-python.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,21 @@ jobs:
with:
node-version-file: 'js/.nvmrc'

- uses: pnpm/action-setup@v6
- name: Set up pnpm
uses: pnpm/setup@84cb39b217b10273981911c288cd62326dc7c6d2 # v2.0.2
with:
version: 11.1.1
run_install: false
package-json-file: js/package.json
install: false
cache: true
cache-dependency-path: js/pnpm-lock.yaml

- name: Verify pnpm version
working-directory: ./js
run: |
expected=$(node -p "require('./package.json').packageManager.match(/^pnpm@([^+]+)/)[1]")
actual=$(pnpm --version)
echo "pnpm version: $actual"
test "$actual" = "$expected"

- name: Build frontend assets
run: make build-frontend
Expand Down Expand Up @@ -117,10 +128,21 @@ jobs:
with:
node-version-file: 'js/.nvmrc'

- uses: pnpm/action-setup@v6
- name: Set up pnpm
uses: pnpm/setup@84cb39b217b10273981911c288cd62326dc7c6d2 # v2.0.2
with:
version: 11.1.1
run_install: false
package-json-file: js/package.json
install: false
cache: true
cache-dependency-path: js/pnpm-lock.yaml

- name: Verify pnpm version
working-directory: ./js
run: |
expected=$(node -p "require('./package.json').packageManager.match(/^pnpm@([^+]+)/)[1]")
actual=$(pnpm --version)
echo "pnpm version: $actual"
test "$actual" = "$expected"

- name: Build frontend assets
run: make build-frontend
Expand Down
2 changes: 2 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ repos:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
# pnpm 12 lockfiles are valid multi-document YAML streams.
exclude: ^js/pnpm-lock\.yaml$
- id: check-added-large-files
exclude: ^uv\.lock$

Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
## Quick Reference

→ `docs/KNOWLEDGE_BASE.md` - Architecture, code patterns, frontend structure, testing, debugging
→ `js/CLAUDE.md` - Frontend conventions and tooling (Node.js 26 via `nave`, Biome, Vitest, pnpm v11
→ `js/CLAUDE.md` - Frontend conventions and tooling (Node.js 26 via `nave`, Biome, Vitest, pnpm v12
quirks, Storybook imports, CSS color format, rem vs px, shell vs shared code)

## Working Preferences
Expand Down
6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,10 @@ test-tox-python-versions:
@tox run-parallel -e 3.10,3.11,3.12,3.13

install-frontend-requires:
# Install pnpm if not installed
@command -v pnpm || npm install -g pnpm
# Install Corepack if needed, then provision the pnpm version pinned by js/package.json
@command -v corepack >/dev/null || npm install -g corepack@latest
@corepack enable
@cd js && corepack install
@cd js && pnpm install

dev: install-frontend-requires
Expand Down
2 changes: 1 addition & 1 deletion docs/KNOWLEDGE_BASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Separation of concerns across models, APIs, tasks, adapters, and state. Import r
Monorepo with `@datarecce/ui` shared package. OSS app (`js/app/`) stays thin; shared components, hooks, and API clients live in `js/packages/ui/`.

→ `docs/frontend.md` (structure, import rules, build process)
→ `js/CLAUDE.md` (tooling: pnpm, Biome, Vitest, @datarecce/ui publishing, style conventions, pnpm v11 quirks)
→ `js/CLAUDE.md` (tooling: pnpm, Biome, Vitest, @datarecce/ui publishing, style conventions, pnpm v12 quirks)

## Testing

Expand Down
2 changes: 1 addition & 1 deletion docs/frontend.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Frontend Structure

> For frontend tooling specifics (pnpm commands, Biome, Vitest, `@datarecce/ui` publishing, pnpm v11 `strictDepBuilds`/`allowBuilds`, and style conventions), see **[`js/CLAUDE.md`](../js/CLAUDE.md)**. This document focuses on monorepo structure, package boundaries, and the build pipeline.
> For frontend tooling specifics (pnpm commands, Biome, Vitest, `@datarecce/ui` publishing, pnpm v12 `strictDepBuilds`/`allowBuilds`, and style conventions), see **[`js/CLAUDE.md`](../js/CLAUDE.md)**. This document focuses on monorepo structure, package boundaries, and the build pipeline.

## Monorepo Layout

Expand Down
20 changes: 16 additions & 4 deletions js/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,29 @@ When updating frontend deps:

Packages requiring overrides (exist in multiple `package.json`): `@emotion/react`, `@mui/material`, `@tanstack/react-query`, `@xyflow/react`, `axios`, `date-fns`, `lodash`, `tailwindcss`, `typescript`, `vitest`.

## pnpm v11 — strictDepBuilds + allowBuilds
## pnpm v12 — strictDepBuilds + allowBuilds

The repo runs on pnpm v11.1.1 (since DRC-3439, 2026-05-13). Four non-obvious behaviors:
The repo runs on pnpm v12.4.1 (updated 2026-09-14). Five non-obvious behaviors:

1. **`strictDepBuilds: true` is on by default.** Any transitive package with a `postinstall` script that isn't explicitly listed in `pnpm-workspace.yaml#allowBuilds` will cause `pnpm install --frozen-lockfile` to hard-fail in CI with `ERR_PNPM_IGNORED_BUILDS`. When a new dep triggers this, add it to `allowBuilds` as `true` (run its postinstall) or `false` (acknowledge it exists, do NOT run postinstall).

2. **Local repro requires CI parity.** Use `CI=true pnpm install --frozen-lockfile` to match CI exactly. The `--ignore-scripts` flag will MASK this failure — do not use it as a verification path.

3. **pnpm 11 silently appends placeholder lines.** If you run `pnpm install` in a non-TTY context and it hits an ignored build, pnpm appends `<pkg>: set this to true or false` to `pnpm-workspace.yaml#allowBuilds`. Always `git status` after running install — never commit these placeholders.
3. **Never accept generated `allowBuilds` placeholders.** If a non-TTY install discovers an ignored build, inspect `pnpm-workspace.yaml#allowBuilds` for `<pkg>: set this to true or false`. Always run `git status` after an install and replace any placeholder with a reviewed boolean decision before committing.

4. **`packageManager` must be exact semver.** Corepack rejects ranges like `pnpm@11`. Pin the full `pnpm@11.x.y+sha512.<integrity>` via `corepack use pnpm@11.x.y` (note the `.` separator between `sha512` and the hash — not `:`).
4. **`packageManager` must be exact semver.** Do not use ranges or dist-tags such as `pnpm@12`, `latest`, or `next-12`. Pin the full `pnpm@12.x.y+sha512.<integrity>` via `corepack use pnpm@12.x.y` (note the `.` separator between `sha512` and the hash — not `:`).

5. **The lockfile pins pnpm's platform executables.** Changing `packageManager` requires regenerating `pnpm-lock.yaml` so its leading `packageManagerDependencies` document records pnpm and every supported platform package with integrity hashes. CI's frozen install rejects a mismatched pin. GitHub Actions must read the version from `js/package.json` through the SHA-pinned `pnpm/setup` action rather than duplicate the version in workflow YAML.

Release notes reviewed for this pin: [12.1](https://pnpm.io/blog/releases/12.1),
[12.2–12.3](https://pnpm.io/blog/releases/12.2-12.3), and
[12.4 / 12.4.1](https://pnpm.io/blog/releases/12.4).
The first install after 12.4 refetches registry metadata because cache keys now
include the full registry URL; the package store remains reusable. Version 12.4.1
also fixes filesystem copy fallbacks, workspace dependency links, and install
scripts whose side effects live outside their package directory. Verify both
fresh and repeat frozen installs when updating the pin. Python dependencies
continue to use uv; pnpm's experimental Python/Cargo support is opt-in.

Canonical `allowBuilds` examples live in recce-cloud-infra:
- `recce-cloud-infra/recce-cloud/pnpm-workspace.yaml`
Expand Down
Loading
Loading