From fd7c1e7ac23c68c414b3dfacefecda2c64721912 Mon Sep 17 00:00:00 2001 From: Maximilian Kaske Date: Sun, 9 Aug 2026 19:04:09 +0200 Subject: [PATCH] wip: --- .github/workflows/claude-code-review.yml | 38 ++----------- .github/workflows/claude.yml | 63 +++++++--------------- AGENTS.md | 1 + packages/ui/AGENTS.md | 69 ++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 79 deletions(-) create mode 100644 packages/ui/AGENTS.md diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 26465ace..ec47a6e3 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -12,13 +12,10 @@ on: jobs: claude-review: - # `pull_request` from a fork gets no secrets — not even for a MEMBER author — - # so without the head-repo check the job fails unfixably on fork PRs. + # Optional: Filter by PR author if: | - github.event.pull_request.head.repo.full_name == github.repository && ( - github.event.pull_request.author_association == 'MEMBER' || - github.event.pull_request.author_association == 'OWNER' - ) + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.author_association == 'OWNER' runs-on: ubuntu-latest permissions: @@ -33,30 +30,6 @@ jobs: with: fetch-depth: 0 - # Without a toolchain the reviewer can only read the diff; every review - # then opens with "I couldn't run anything in this sandbox". - - name: Set up pnpm - uses: pnpm/action-setup@v6 - - - name: ⎔ Setup node - uses: actions/setup-node@v6 - with: - node-version: 24.12.0 - cache: "pnpm" - - - name: 🦕 Setup Deno - uses: denoland/setup-deno@v2 - with: - deno-version: 2.9.4 - - # Remote-cache secrets stay on this step. The review step below runs an LLM - # with Bash tools, and job-level env would hand them straight to it. - - name: 📥 Download deps - run: pnpm install - env: - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - - name: Run Claude Code Review id: claude-review uses: anthropics/claude-code-action@v1 @@ -65,10 +38,5 @@ jobs: plugin_marketplaces: 'https://github.com/anthropics/claude-code.git' plugins: 'code-review@claude-code-plugins' prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}' - # `pnpm verify` is the no-database tier: format, lint, deno check. - # DB-backed tests need an sqld service container and are out of reach here. - claude_args: >- - --allowed-tools - "Bash(pnpm verify),Bash(pnpm lint),Bash(pnpm check),Bash(pnpm check:docs),Bash(pnpm format:check),Bash(pnpm turbo run check:*),Bash(git diff:*),Bash(git log:*),Bash(git show:*)" # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md # or https://code.claude.com/docs/en/cli-reference for available options diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index a1d385ca..a037b353 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -12,29 +12,26 @@ on: jobs: claude: - # Forks have no CLAUDE_CODE_OAUTH_TOKEN, so the job would fail unfixably there. if: | - github.repository_owner == 'openstatusHQ' && ( - ( - github.event_name == 'issue_comment' && - contains(github.event.comment.body, '@claude') && - (github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'COLLABORATOR') - ) || - ( - github.event_name == 'pull_request_review_comment' && - contains(github.event.comment.body, '@claude') && - (github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'COLLABORATOR') - ) || - ( - github.event_name == 'pull_request_review' && - contains(github.event.review.body, '@claude') && - (github.event.review.author_association == 'OWNER' || github.event.review.author_association == 'MEMBER' || github.event.review.author_association == 'COLLABORATOR') - ) || - ( - github.event_name == 'issues' && - (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) && - (github.event.issue.author_association == 'OWNER' || github.event.issue.author_association == 'MEMBER' || github.event.issue.author_association == 'COLLABORATOR') - ) + ( + github.event_name == 'issue_comment' && + contains(github.event.comment.body, '@claude') && + (github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'COLLABORATOR') + ) || + ( + github.event_name == 'pull_request_review_comment' && + contains(github.event.comment.body, '@claude') && + (github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'COLLABORATOR') + ) || + ( + github.event_name == 'pull_request_review' && + contains(github.event.review.body, '@claude') && + (github.event.review.author_association == 'OWNER' || github.event.review.author_association == 'MEMBER' || github.event.review.author_association == 'COLLABORATOR') + ) || + ( + github.event_name == 'issues' && + (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) && + (github.event.issue.author_association == 'OWNER' || github.event.issue.author_association == 'MEMBER' || github.event.issue.author_association == 'COLLABORATOR') ) runs-on: ubuntu-latest timeout-minutes: 30 @@ -50,28 +47,6 @@ jobs: with: fetch-depth: 0 - # Same reason as claude-code-review.yml: without a toolchain, `@claude` - # can only read the diff and every answer is caveated as unverified. - - name: Set up pnpm - uses: pnpm/action-setup@v6 - - - name: ⎔ Setup node - uses: actions/setup-node@v6 - with: - node-version: 24.12.0 - cache: "pnpm" - - - name: 🦕 Setup Deno - uses: denoland/setup-deno@v2 - with: - deno-version: 2.9.4 - - - name: 📥 Download deps - run: pnpm install - env: - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - - name: Run Claude Code id: claude uses: anthropics/claude-code-action@v1 diff --git a/AGENTS.md b/AGENTS.md index 8c561b9d..da50576a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -78,6 +78,7 @@ boundaries with external SDKs or at registry-style dispatch. When you need one: ## Package context - `packages/services/AGENTS.md` — service verbs, audit log, scope enforcement +- `packages/ui/AGENTS.md` — stock shadcn vs. the published blocks registry - `apps/dashboard/AGENTS.md` — Next.js runtimes, client boundary, UI verification - `apps/server/AGENTS.md` — Hono API, API-key scopes - `apps/status-page/AGENTS.md` — public surfaces and gated content diff --git a/packages/ui/AGENTS.md b/packages/ui/AGENTS.md new file mode 100644 index 00000000..037f0251 --- /dev/null +++ b/packages/ui/AGENTS.md @@ -0,0 +1,69 @@ +# AGENTS.md — @openstatus/ui + +Three directories under `src/components/`, three different contracts. Getting +the wrong one is the most common mistake here. + +| Directory | What it is | Who else sees it | +|---|---|---| +| `ui/` | Stock shadcn/ui primitives | Nobody — never shipped | +| `blocks/` | The openstatus shadcn registry (status page) | Every external consumer | +| `custom/` | openstatus-only components | Our apps only | + +`blocks/README.md` documents the composition API and `REGISTRY.md` the publish +flow. This file is only the rules those two assume you already know. + +## Do not customize `src/components/ui/` + +These 41 files are shadcn's, and the registry ships **zero** of them. Blocks +instead declare `registryDependencies: ["button", "tooltip", …]`, which resolve +to the **consumer's own** shadcn components at install time. + +So a block that depends on a local tweak to `button.tsx` renders correctly in +this repo and incorrectly for everyone who installs it — with no error anywhere. +Patching also means the next `shadcn add` either clobbers the change or silently +skips the upgrade. + +When a primitive isn't enough, in order of preference: pass `className`, compose +a wrapper in `blocks/` or `custom/`, or add a variant to the block that needs it. + +Editing a `ui/` file is a last resort, and only for a defect stock shadcn has +too. `input-group.tsx` is the precedent — `FormControl`'s Slot injected a +`data-slot` that clobbered the group's own, breaking the focus ring. It carries +a comment saying why the prop order matters. Do the same, or don't touch them. + +## `blocks/` is a published registry, not internal code + +Anything you add here ends up on `openstatus.dev/r` and gets installed into +codebases that are not this one. + +- **Register it.** A new file needs an entry in `registry.json` with its + `registryDependencies`. Forget that and it works in the monorepo and 404s for + consumers — nothing in CI catches it. +- **No app imports.** No `next/link`, no `next-intl`, no `@openstatus/db`, no + tRPC. Every direct dependency becomes a mandatory install for consumers, and + most of them aren't even on Next.js. Routing, markdown and translation come in + through slot props (`renderEvent`, `renderMessage`, `asChild`) and the + `StatusBlocksI18nProvider` context. +- **Imports must exist in a stock shadcn install.** `pnpm registry:build` + rewrites `@openstatus/ui/*` to `@/*`, so `@openstatus/ui/components/ui/button` + becomes `@/components/ui/button` on the consumer's machine. Importing a + primitive we have but they don't produces a build error there, not here. +- **New color tokens go in `registry.json` `cssVars`.** That is how `--success`, + `--warning` and `--info` reach consumers; a token used only in `globals.css` + is undefined for them. +- **Defaults must render unconfigured.** Slots are optional, i18n falls back to + English. The registry preview has no wiring. + +## Generated output + +`dist/` and `public/r/` are build artifacts of `pnpm registry:build` (which +`apps/web`'s build runs). Both are gitignored. Never edit them, and never fix a +registry bug by editing `dist/` — change `src/` and rebuild. + +## Imports + +Exports are path-based, with no barrel: +`@openstatus/ui/components/ui/button`, `@openstatus/ui/components/blocks/status-bar`, +`@openstatus/ui/hooks/use-media-query`. Import the exact file. + +Shared UI belongs here, not forked into an app — see `docs/adr/0003-shared-ui-comes-from-openstatus-ui.md`. -- 2.51.2