* chore: close a batch of quality-gate & tidy gaps (#1785 #1787 #1789 #1790 #1767) Bundles five small, related tidy/gate items into one PR: - #1785: delete the dead src/types/navigation.ts InspectorTab (0 importers; duplicated/drifted from utils/inspectorTabs InspectorTabId). src/types/ now holds only ambient .d.ts stubs. - #1787: add src/hooks/** to the web coverage `include` (it was silently outside the ≥90 gate) and add tests for the two untested hooks, useServerJsonImport and useImportClientConfig, bringing every hook to ≥90 on lines/statements/functions/branches. - #1789: widen clients/{cli,tui,launcher} format/format:check to their top-level configs; add root format:shared / format:check:shared covering test-servers/src/**, vitest.shared.mts, and the repo-root eslint.config.js. - #1790: pin prettier to an exact version (3.8.4, dropping the ^3.8.1 caret) in all five package.json files so the format gate's verdict can't shift with an in-range patch bump; lockfiles synced. - #1767: its root-file format+lint gap is closed here (format:shared + a new lint:shared via a second files block in the root eslint.config.js; web/server/ was already gated in #1788). Its larger cli/tui __tests__ typecheck piece (76 type errors) is split out to #1791. Prettier-normalized the newly-covered files (pure formatting). No runtime behavior change. `npm run ci` green. Closes #1785 Closes #1787 Closes #1789 Closes #1790 Closes #1767 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5 * chore: address PR #1792 review findings - #1789 gap: widen clients/web format to include .storybook and clients/ launcher format to include scripts/; reformat the 3 .storybook files (were non-conforming under the pinned prettier 3.8.4). Audited all 885 tracked source files — now fully prettier-clean. - Export VALIDATE_DEBOUNCE_MS / COLLAPSE_DELAY_MS / HIGHLIGHT_DURATION_MS from useServerJsonImport and use them in the test instead of hardcoded 300/1000/250 (so a tuned constant can't silently desync the test). - Assert the symmetric renameErrors["alpha"] alongside ["beta"] so a one-directional collision-check regression fails. - Comment the blank-rename test as exercising a UI-unreachable defensive branch (canImport gates submit). - Un-stale the two specification/v2_ux_interfaces_plan.md references to the now-removed navigation.ts InspectorTab. npm run ci green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5 * docs: sync AGENTS.md format-surface description with the widened globs (#1792 review r2) 1ce3b64 added .storybook to clients/web's format glob and scripts/ to clients/launcher's, but AGENTS.md:222 still described the pre-fix scope. Bring it in line and note the non-recursive top-level glob is why nested dirs are named explicitly. Docs only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5 * chore: handle PR #1792 round-3 follow-ups in-place (format-coverage guard, uniform globs, theme gate) Rather than defer these to tickets, fold them into this PR: - Obs 2: widen every client + root format glob to a uniform *.{ts,tsx,mts,cts,js,jsx,mjs,cjs} so a future .mts/.cjs/.tsx top-level file can't silently slip the gate. - Obs 1: add scripts/verify-format-coverage.mjs (wired into `validate`) — it parses the format:check globs out of every package.json, enumerates all tracked source files, and fails listing any not covered by a glob. The durable, standing version of #1789's one-shot audit; negative-tested. - Obs 3: bring src/theme/** under the coverage gate (21/23 files were already ≥90 transitively; add Paper.test.tsx for the one laggard, Paper.ts). src/App.tsx (~4.5k lines, ~42% branches) is converted from a silent omission into an explicit, documented exclusion (comment on the coverage `include` + AGENTS.md) — gating it is a dedicated effort, not a whitelist tweak. npm run ci green (the new guard reports 885/885 tracked source files gated). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5 * chore: address PR #1792 round-4 findings (guard hardening, docs, exclusion list) - Harden verify-format-coverage: only harvest format:check globs from scripts transitively reachable from `validate` (via npm run refs), so an unwired/renamed format:check no longer counts as coverage. Negative-tested — renaming clients/web format:check to an unreferenced name now fails the guard (627 files flagged) instead of passing. - Name src/main.tsx and src/index.ts (browser + bin bootstraps) alongside src/App.tsx in the coverage-include comment and AGENTS.md, so the documented exclusion list is complete rather than claiming App.tsx is the only one. - Doc sync: document verify:format-coverage (AGENTS.md + README script table + scripts/ layout line), fix the `validate` ordering (verify:format- coverage now runs before validate:core) in AGENTS.md and README, and update the quoted globs to the uniform *.{ts,tsx,mts,cts,js,jsx,mjs,cjs} / test-servers *.{ts,tsx,mts,cts}. npm run ci green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5 * chore: address PR #1792 round-5 findings (airtight guard + doc/config sync) - verify-format-coverage: assert the root `validate` chain invokes each client's `validate` (cd <dir> && npm run validate), closing the last reachability edge — a client dropped from the root chain now fails the guard even though its own globs still exist. Negative-tested. - eslint.config.js: widen the shared `files` block to test-servers/src/**/*.{ts,tsx,mts,cts} to match the widened lint:shared glob, so a future .mts/.cts there is lint-gated, not just prettier-gated. - AGENTS.md: scope the "uniform extension set" claim to client globs (core stays {ts,tsx}, shared {ts,tsx,mts,cts}), with verify:format-coverage as the backstop — removing the self-contradiction with the line below. npm run ci green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5 --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
166ed38e7f
commit
4defa32ac6
35 changed files with 1221 additions and 220 deletions
12
AGENTS.md
12
AGENTS.md
|
|
@ -214,12 +214,12 @@ gh project item-edit --project-id PVT_kwDOCt2Azc4BJVxt --id "$ITEM_ID" --field-i
|
|||
- after making the changes, respond to each review comment with what was done (or why it was ignored)
|
||||
|
||||
### Mandatory pre-push gate
|
||||
- ALWAYS do `npm run format` before committing — the **root** `format` auto-fixes `core/` (`format:core`), the root `scripts/**/*.{mjs,js,cjs,ts}` (`format:scripts`), and every client's scope in one shot. `validate` runs `format:check` (the non-fixing variant, including `format:check:core` and `format:check:scripts`) and will fail in CI on any unformatted file, so always run the auto-fixer first rather than letting `format:check` catch it.
|
||||
- ALWAYS do `npm run format` before committing — the **root** `format` auto-fixes `core/` (`format:core`), the root `scripts/` tooling (`format:scripts`), the root "shared" surface (`format:shared` — `test-servers/src/**`, `vitest.shared.mts`, the root `eslint.config.js`), and every client's scope in one shot. Every **client** format glob uses the uniform extension set `*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}` (#1792) so a new-extension file can't slip the gate; `core/` stays `{ts,tsx}` and the shared surface `{ts,tsx,mts,cts}` (their surfaces can't hold the other extensions), and `npm run verify:format-coverage` (the first step of `validate`, #1792) is the backstop — it fails if any tracked source file is left uncovered by a `format:check` glob regardless of which glob was expected to catch it. `validate` runs `format:check` (the non-fixing variant, including `format:check:core`, `format:check:scripts`, and `format:check:shared`) and will fail in CI on any unformatted file, so always run the auto-fixer first rather than letting `format:check` catch it.
|
||||
- **`npm run ci` is the mandatory pre-push command** — it mirrors `.github/workflows/main.yml` (minus `npm install`): `validate` → `coverage` → `verify:build-gate` (the #1769 browser-externalized-builtin build gate) → `smoke` → Storybook play-function tests (installs Playwright chromium if needed). It now runs **`npm run coverage`**, the per-file ≥90 gate (lines/statements/functions/branches) that CI enforces — so `npm run ci` is a true superset of GitHub CI, and passing it locally means CI's gates will pass. Expect several minutes. **`npm run validate`** remains the fast inner-loop check during development (unit tests only — no coverage gate, no smoke, no Storybook), but it is **NOT** an acceptable substitute for `npm run ci` before pushing: `validate` runs `test`, not `test:coverage`, so it does **zero** coverage gating. Skipping the gate is how a push passes every fast local check and still fails CI (this exact gap broke PR #1601 on a function-coverage regression).
|
||||
- ALWAYS do `npm run format` before committing, then **`npm run ci`** before pushing. From the repo root, `validate` runs the **`core/` gate first** (`validate:core`) and then chains the four per-client validations (`validate:web` → `validate:cli` → `validate:tui` → `validate:launcher`); each client delegates to its own `npm run validate` in its own folder (no coverage — fast). Every client is self-validating and the top level just chains them, building each client's bundle along the way (no cross-client build dependencies).
|
||||
- **`validate:core` is the root-owned format + lint gate (#1689, widened in #1778).** Each client's `prettier`/`eslint` is scoped to its own dir, so nothing reached `core/` or the root `scripts/` before — `validate:core` closes that: it runs `format:check:core` (`prettier --check "core/**/*.{ts,tsx}"`) + `format:check:scripts` (`prettier --check "scripts/**/*.{mjs,js,cjs,ts}"`, the root build/verify tooling — #1778; a brace glob so a future non-`.mjs` script is auto-included) + `lint:core` (`eslint "core/**/*.{ts,tsx}"` via the **root** `eslint.config.js`). Use `npm run format:core` / `npm run format:scripts` to auto-fix (both folded into the root `format`). The `scripts/` gate is prettier-only — the root has no eslint config for `.mjs`. The root carries prettier/eslint as devDependencies for this; `core/` is isomorphic (browser + Node globals, no JSX today — the `{ts,tsx}` glob future-proofs against a `core/**/*.tsx`). The root `eslint.config.js` honors an `_`-prefix as the intentionally-unused marker (`argsIgnorePattern`/`varsIgnorePattern`/`caughtErrorsIgnorePattern: '^_'`).
|
||||
- ALWAYS do `npm run format` before committing, then **`npm run ci`** before pushing. From the repo root, `validate` runs **`verify:format-coverage` first** (the #1792 guard — asserts every tracked source file is covered by a `format:check` glob), then the **`core/` gate** (`validate:core`), then chains the four per-client validations (`validate:web` → `validate:cli` → `validate:tui` → `validate:launcher`); each client delegates to its own `npm run validate` in its own folder (no coverage — fast). Every client is self-validating and the top level just chains them, building each client's bundle along the way (no cross-client build dependencies).
|
||||
- **`validate:core` is the root-owned format + lint gate (#1689, widened in #1778 and #1767).** Each client's `prettier`/`eslint` is scoped to its own dir, so nothing reached `core/`, the root `scripts/`, or the root "shared" surface before — `validate:core` closes that: it runs `format:check:core` (`prettier --check "core/**/*.{ts,tsx}"`) + `format:check:scripts` (`prettier --check "scripts/**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}"`, the root build/verify tooling — #1778) + `format:check:shared` + `lint:core` (`eslint "core/**/*.{ts,tsx}"` via the **root** `eslint.config.js`) + `lint:shared`. Use `npm run format:core` / `npm run format:scripts` / `npm run format:shared` to auto-fix (all folded into the root `format`). The **shared surface** (#1767) is `test-servers/src/**/*.{ts,tsx,mts,cts}`, the root `vitest.shared.mts`, and the root `eslint.config.js` — first-party code no client's `eslint .` / `prettier` reaches; it is both prettier-gated (`format:check:shared`) and eslint-gated (`lint:shared`, via a second `files` block in the root `eslint.config.js` scoped to Node globals). The `scripts/` gate is prettier-only — the root has no eslint config for `.mjs`. The root carries prettier/eslint as devDependencies for this; `core/` is isomorphic (browser + Node globals, no JSX today — the `{ts,tsx}` glob future-proofs against a `core/**/*.tsx`). The root `eslint.config.js` honors an `_`-prefix as the intentionally-unused marker (`argsIgnorePattern`/`varsIgnorePattern`/`caughtErrorsIgnorePattern: '^_'`). **prettier is pinned to an exact version** (not a caret) in all five `package.json`s (#1790) so the gate's verdict can't shift with an in-range patch bump.
|
||||
- **cli and tui now typecheck their `src` (#1689).** Their `build`/`test` run through esbuild (no type check), so each has a `typecheck` script (`tsc --noEmit -p tsconfig.json`) folded into `validate`. Their `tsconfig.json` matches `clients/web/tsconfig.app.json`'s module/lib *resolution* options — DOM lib, `moduleResolution: bundler`, and **no** `noUncheckedIndexedAccess` (web's app config does not extend `tsconfig.base`, so re-enabling it would surface `core/` issues web never gates) — so the imported `core/` sources are validated the same way web validates them. It does **not** mirror web's extra strictness flags (`noUnusedLocals`, `verbatimModuleSyntax`, ES2023 target, …), so cli/tui's own `src` is checked slightly more loosely than web's. `core/` itself still typechecks through web's `tsc -b`.
|
||||
- The one CLI nuance: `clients/cli`'s out-of-process `e2e.test.ts` spawns the built binary, so its `test` **builds first** via `pretest` (`test-servers:build && build`). To avoid building it twice, `clients/cli`'s `validate` folds that in — it is `format:check && lint && typecheck && test` with **no** separate `build` step (the other clients, whose tests don't spawn their bundle, keep an explicit `build`). `validate:web`/`validate:tui`/`validate:launcher` are the uniform `format:check && lint && (typecheck &&) build && test`. (#1778) `clients/web`'s `format`/`format:check` covers `src`, `server`, and its top-level configs (`*.{ts,js}` — `vite.config.ts`, `tsup.runner.config.ts`, `eslint.config.js`, …), not just `src`, so the Node backend and Vite/build config are prettier-gated too.
|
||||
- The one CLI nuance: `clients/cli`'s out-of-process `e2e.test.ts` spawns the built binary, so its `test` **builds first** via `pretest` (`test-servers:build && build`). To avoid building it twice, `clients/cli`'s `validate` folds that in — it is `format:check && lint && typecheck && test` with **no** separate `build` step (the other clients, whose tests don't spawn their bundle, keep an explicit `build`). `validate:web`/`validate:tui`/`validate:launcher` are the uniform `format:check && lint && (typecheck &&) build && test`. (#1778, #1789, #1792) `clients/web`'s `format`/`format:check` covers `src`, `server`, `.storybook`, and its top-level configs (the uniform `*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}` glob — `vite.config.ts`, `tsup.runner.config.ts`, `eslint.config.js`, …), not just `src`, so the Node backend, Storybook config, and Vite/build config are prettier-gated too; `clients/launcher`'s covers `src`, `__tests__`, `scripts`, and its top-level configs (the `*.` top-level glob is non-recursive, so each nested dir — `.storybook`, `scripts` — is named explicitly). The `verify:format-coverage` guard (#1792) enforces that this coverage stays complete.
|
||||
- **`npm run coverage`** is the per-file ≥90 gate and is now part of `npm run ci` — never treat it as optional before a push. It supersedes the old standalone `test:integration` step: web's `test:coverage` runs the `unit` **and** `integration` projects under v8 instrumentation, so `coverage` both enforces the ≥90 gate and exercises the same web integration paths CI covers.
|
||||
- **`smoke` is NOT part of `validate`** — it is included in `npm run ci`. It runs `smoke:launcher` (`--help` dispatch) plus the prod `smoke:cli` / `smoke:tui` / `smoke:web` / `smoke:web:browser`, and contains **no build commands** — it assumes the cli/tui/launcher bundles already exist (a full `validate` builds them; `smoke:web` builds `clients/web/dist` on demand). CI runs `validate`, then the `coverage` gate (which also covers the web integration project), then `verify:build-gate` (the #1769 build gate — see below), then `smoke` (with Playwright chromium installed just before it, since `smoke:web:browser` needs it). GitHub CI runs this same chain as separate workflow steps, with the Storybook play-function tests last (see below).
|
||||
- `smoke:launcher` (`scripts/smoke-launcher.mjs`) runs the built launcher with `--help`, `--cli --help`, and `--tui --help`, asserting each exits 0 and prints that mode's usage banner (which also proves the launcher resolved and loaded the right client build). It's the cheap dispatch check before the heavier prod smokes below.
|
||||
|
|
@ -251,11 +251,11 @@ The web client keeps two grab-bag directories under `clients/web/src`, split by
|
|||
- _Importing from `@inspector/core`._ Two forms are fine: a **type-only** import is not a subsystem dependency (`pendingReauth` is pure type declarations), and **re-exporting pure functions or constants** from core is not subsystem ownership either (`oauthUx`/`oauthFlow` re-export core copy/predicates). What makes a module `lib` is wrapping core's *stateful runtime*, not merely importing from it.
|
||||
- **`src/lib/`** — infrastructure / integration / stateful adapters. Modules that instantiate or compose subsystems, wrap the `@inspector/core` **runtime** (not just its types), touch the DOM / `window` / `sessionStorage`, or otherwise produce side effects. (Anchors: `environmentFactory` composes `InspectorClientEnvironment`; `remoteOAuthStorage` is an adapter class over `core/auth`; `oauthResume` reads/writes `sessionStorage`; `browserTabVisibility` registers `visibilitychange` listeners; `clearServerOAuthState` drives the live `InspectorClient` / `OAuthStorage`; `downloadFile` triggers browser downloads.)
|
||||
|
||||
The top-level **`src/types/`** is a sibling of both and is not the place for new domain types — it's essentially the home for ambient `.d.ts` module stubs (e.g. the `react-syntax-highlighter` shims wired through `tsconfig.app.json` `paths`). One plain-`.ts` domain type still lingers there, the dead `navigation.ts` `InspectorTab`, which [#1785](https://github.com/modelcontextprotocol/inspector/issues/1785) will remove; until then a pure domain type belongs in `utils/`, not `src/types/`.
|
||||
The top-level **`src/types/`** is a sibling of both and is not the place for new domain types — it's now purely the home for ambient `.d.ts` module stubs (e.g. the `react-syntax-highlighter` shims wired through `tsconfig.app.json` `paths`). The last plain-`.ts` domain type there, the dead `navigation.ts` `InspectorTab`, was removed in #1785, so a pure domain type belongs in `utils/`, not `src/types/`.
|
||||
|
||||
Cross-directory imports point **one way, `lib → utils`** (infra depends on pure helpers, never the reverse). Keep it that way: if a `utils/` module needs a type currently exported from a `lib/` module, declare the type in `utils/` and re-export it from `lib/` (as `pendingReauth` owns `OAuthResumeAuthKind` and `oauthResume` re-exports it), rather than importing "up" from `utils` into `lib`.
|
||||
|
||||
Nothing **enforces** the boundary: no path alias keys off it, and the coverage `include` in `clients/web/vite.config.ts` lists **both** `src/lib/**` and `src/utils/**`, so a move between them is coverage-neutral (this is why the refactor was gate-safe). It's a human-legible signal at import time, valuable in a codebase this test-heavy (the ≥90% per-file gate). Note that `include` is a **whitelist** — it names `components`/`lib`/`utils`/`server` (plus the `core/*` runtime), so a module placed **outside** those directories (`hooks/`, `theme/`, `types/`, `App.tsx`, or a brand-new grab-bag) falls out of the ≥90 gate entirely, silently. When adding a module, place it by the rule and keep it inside a gated directory; when it genuinely mixes both (e.g. `downloadFile` bundles DOM-side-effect helpers with a couple of pure ones), keep it whole on its dominant side (`lib`) rather than splitting hairs.
|
||||
Nothing **enforces** the boundary: no path alias keys off it, and the coverage `include` in `clients/web/vite.config.ts` lists **both** `src/lib/**` and `src/utils/**`, so a move between them is coverage-neutral (this is why the refactor was gate-safe). It's a human-legible signal at import time, valuable in a codebase this test-heavy (the ≥90% per-file gate). Note that `include` is a **whitelist** — it names `components`/`hooks`/`theme`/`lib`/`utils`/`server` (plus the `core/*` runtime; `hooks` and `theme` were added in #1787), so a module placed **outside** those directories (`types/`, `App.tsx`, or a brand-new grab-bag) falls out of the ≥90 gate entirely, silently. The **deliberate, documented** top-level-file exceptions are `src/App.tsx` — a ~4.5k-line composition root at ~42% branch coverage (gating it is a dedicated testing/decomposition effort, not a whitelist tweak) — and the `src/main.tsx` / `src/index.ts` bootstraps (browser `createRoot` render and the bin `runWeb` re-export, the analog of `clients/cli`'s excluded `src/index.ts`). All three are called out in a comment on the `include` array itself rather than left silent. When adding a module, place it by the rule and keep it inside a gated directory; when it genuinely mixes both (e.g. `downloadFile` bundles DOM-side-effect helpers with a couple of pure ones), keep it whole on its dominant side (`lib`) rather than splitting hairs.
|
||||
|
||||
## React instructions
|
||||
- UI Components
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ inspector/
|
|||
│ ├── react/ # React hooks over the state stores
|
||||
│ └── storage/ # File I/O helpers for the OAuth persist backends
|
||||
├── test-servers/ # Composable MCP test servers + fixtures used by integration tests
|
||||
├── scripts/ # Root build/verify tooling (install cascade, smokes, verify-build-gate, pack:verify)
|
||||
├── scripts/ # Root build/verify tooling (install cascade, smokes, verify-build-gate, verify-format-coverage, pack:verify)
|
||||
├── specification/ # Design/build specifications
|
||||
├── AGENTS.md # Contribution rules for agents AND humans (see below)
|
||||
└── README.md # You are here
|
||||
|
|
@ -140,14 +140,15 @@ Each client self-validates from its own folder; the root scripts chain them. The
|
|||
|
||||
| Script | What it does |
|
||||
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `npm run validate` | Runs `validate:core` (the shared `core/` `format:check` + `lint` gate) first, then per client: `format:check` + `lint` + **`typecheck`** (cli/tui only) + `build` + fast unit tests. The quick inner-loop check. |
|
||||
| `npm run validate` | Runs `verify:format-coverage` (asserts every tracked source file is format-gated) first, then `validate:core` (the shared `core/` `format:check` + `lint` gate), then per client: `format:check` + `lint` + **`typecheck`** (cli/tui only) + `build` + fast unit tests. The quick inner-loop check. |
|
||||
| `npm run coverage` | The **per-file ≥90% gate** (lines/statements/functions/branches) under v8 instrumentation, per client. CI-enforced. For web this also runs the integration project and covers the shared `core/` runtime (including `core/json` and `core/client`). |
|
||||
| `npm run smoke` | End-to-end smokes through the built launcher (`--help` dispatch + prod cli/tui/web), plus a headless-Chromium boot smoke that runs the prod web bundle and asserts a clean first render (no uncaught error — sync exception or unhandled rejection, how a Node built-in reaching the browser bundle manifests). |
|
||||
| `npm run verify:build-gate` | Runs a real `vite build` with a Node built-in forced into the browser graph and asserts the build **fails** via the #1769 gate (which turns Vite's browser-externalization warning into a hard error). Guards against the warning phrasing drifting in a Vite bump and silently disabling the gate. Part of `npm run ci`. |
|
||||
| `npm run verify:format-coverage` | Parses the `format:check` globs out of every `package.json` (only those reachable from `validate`), enumerates all tracked source files, and **fails** listing any not covered by a glob — the durable guard for the "every first-party source file is format-gated" invariant (#1792). Runs first in `validate`. |
|
||||
| `npm run ci` | **Mandatory pre-push command.** `validate` → `coverage` → `verify:build-gate` → `smoke` → Storybook. A true superset of GitHub CI. |
|
||||
| `npm run pack:verify` | Publish smoke — see [Publishing](#publishing). |
|
||||
|
||||
Per-client scripts exist too (`validate:web`, `coverage:cli`, `smoke:tui`, …), plus root `validate:core` / `format:core` for the shared `core/` package and `format:scripts` for the root `scripts/` tooling. Run `npm run format` before committing — the root `format` fixes `core/`, the root `scripts/`, and every client; `validate` runs the non-fixing `format:check` and fails CI on any unformatted file.
|
||||
Per-client scripts exist too (`validate:web`, `coverage:cli`, `smoke:tui`, …), plus root `validate:core` / `format:core` for the shared `core/` package, `format:scripts` for the root `scripts/` tooling, and `format:shared` / `lint:shared` for the root "shared" surface (`test-servers/src/**`, `vitest.shared.mts`, the root `eslint.config.js`). Run `npm run format` before committing — the root `format` fixes `core/`, the root `scripts/`, the shared surface, and every client; `validate` runs the non-fixing `format:check` and fails CI on any unformatted file.
|
||||
|
||||
For the full testing rules — the ≥90% per-file gate, where test files live, the unit vs. integration vs. storybook projects, and the `v8 ignore` policy — see [`AGENTS.md`](./AGENTS.md).
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import js from '@eslint/js';
|
||||
import globals from 'globals';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import { defineConfig, globalIgnores } from 'eslint/config';
|
||||
import js from "@eslint/js";
|
||||
import globals from "globals";
|
||||
import tseslint from "typescript-eslint";
|
||||
import { defineConfig, globalIgnores } from "eslint/config";
|
||||
|
||||
// The CLI is plain Node TypeScript (no React/browser), so this mirrors the web
|
||||
// client's flat config minus the React/Storybook plugins.
|
||||
export default defineConfig([
|
||||
globalIgnores(['build', 'coverage']),
|
||||
globalIgnores(["build", "coverage"]),
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
files: ["**/*.ts"],
|
||||
extends: [js.configs.recommended, tseslint.configs.recommended],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2022,
|
||||
sourceType: 'module',
|
||||
sourceType: "module",
|
||||
globals: globals.node,
|
||||
},
|
||||
},
|
||||
|
|
|
|||
2
clients/cli/package-lock.json
generated
2
clients/cli/package-lock.json
generated
|
|
@ -29,7 +29,7 @@
|
|||
"@vitest/coverage-v8": "^4.1.0",
|
||||
"eslint": "^9.39.4",
|
||||
"globals": "^17.4.0",
|
||||
"prettier": "^3.8.1",
|
||||
"prettier": "3.8.4",
|
||||
"tsup": "^8.5.0",
|
||||
"typescript": "~5.9.3",
|
||||
"typescript-eslint": "^8.56.1",
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@
|
|||
"test:cli-metadata": "vitest run metadata.test.ts",
|
||||
"pretest": "npm run test-servers:build && npm run build",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier --write src __tests__",
|
||||
"format:check": "prettier --check src __tests__"
|
||||
"format": "prettier --write src __tests__ \"*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}\"",
|
||||
"format:check": "prettier --check src __tests__ \"*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/client": "2.0.0-beta.5",
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
"@vitest/coverage-v8": "^4.1.0",
|
||||
"eslint": "^9.39.4",
|
||||
"globals": "^17.4.0",
|
||||
"prettier": "^3.8.1",
|
||||
"prettier": "3.8.4",
|
||||
"tsup": "^8.5.0",
|
||||
"typescript": "~5.9.3",
|
||||
"typescript-eslint": "^8.56.1",
|
||||
|
|
|
|||
|
|
@ -1,32 +1,32 @@
|
|||
import { defineConfig } from 'tsup';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { defineConfig } from "tsup";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const repoRoot = path.resolve(dirname, '../..');
|
||||
const repoRoot = path.resolve(dirname, "../..");
|
||||
|
||||
export default defineConfig({
|
||||
entry: ['src/index.ts'],
|
||||
format: ['esm'],
|
||||
outDir: 'build',
|
||||
entry: ["src/index.ts"],
|
||||
format: ["esm"],
|
||||
outDir: "build",
|
||||
clean: true,
|
||||
// No source maps in the published bundle — they roughly double the on-disk
|
||||
// size and aren't needed at runtime (debug via `npm run dev` on the source).
|
||||
sourcemap: false,
|
||||
target: 'node22',
|
||||
platform: 'node',
|
||||
target: "node22",
|
||||
platform: "node",
|
||||
// Bundle core source; leave npm deps external.
|
||||
noExternal: [/^@inspector\/core/],
|
||||
external: [
|
||||
'@napi-rs/keyring',
|
||||
'@modelcontextprotocol/client',
|
||||
'@modelcontextprotocol/core',
|
||||
'commander',
|
||||
'pino',
|
||||
"@napi-rs/keyring",
|
||||
"@modelcontextprotocol/client",
|
||||
"@modelcontextprotocol/core",
|
||||
"commander",
|
||||
"pino",
|
||||
],
|
||||
esbuildOptions(options) {
|
||||
options.alias = {
|
||||
'@inspector/core': path.join(repoRoot, 'core'),
|
||||
"@inspector/core": path.join(repoRoot, "core"),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { defineConfig } from 'vitest/config';
|
||||
import { vitestSharedPaths } from '../../vitest.shared.mts';
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { defineConfig } from "vitest/config";
|
||||
import { vitestSharedPaths } from "../../vitest.shared.mts";
|
||||
|
||||
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const { projectResolve } = vitestSharedPaths(dirname);
|
||||
|
|
@ -10,8 +10,8 @@ export default defineConfig({
|
|||
resolve: projectResolve,
|
||||
test: {
|
||||
globals: false,
|
||||
environment: 'node',
|
||||
include: ['__tests__/**/*.test.ts'],
|
||||
environment: "node",
|
||||
include: ["__tests__/**/*.test.ts"],
|
||||
testTimeout: 15000,
|
||||
// The in-process runner (__tests__/helpers/cli-runner.ts) patches
|
||||
// process.std{out,err}.write to capture CLI output. Test files run in
|
||||
|
|
@ -19,18 +19,18 @@ export default defineConfig({
|
|||
// those global patches never overlap. `forks` is vitest's default, but pin
|
||||
// it explicitly so the capture isolation can't regress to a shared-thread
|
||||
// pool. See #1484.
|
||||
pool: 'forks',
|
||||
pool: "forks",
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
reporter: ['text', 'html', 'json-summary'],
|
||||
include: ['src/**/*.ts'],
|
||||
provider: "v8",
|
||||
reporter: ["text", "html", "json-summary"],
|
||||
include: ["src/**/*.ts"],
|
||||
exclude: [
|
||||
// Binary bootstrap: shebang + `isMain` guard + `runCli()`/`process.exit`
|
||||
// wiring that only runs when launched as the real binary. Exercised by
|
||||
// the out-of-process layer (__tests__/e2e.test.ts + scripts/smoke-cli.mjs),
|
||||
// which spawns build/index.js and so can't be measured under in-process
|
||||
// coverage. Mirrors web's `**/index.{ts,tsx}` exclusion.
|
||||
'src/index.ts',
|
||||
"src/index.ts",
|
||||
],
|
||||
thresholds: {
|
||||
perFile: true,
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import js from '@eslint/js';
|
||||
import globals from 'globals';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import { defineConfig, globalIgnores } from 'eslint/config';
|
||||
import js from "@eslint/js";
|
||||
import globals from "globals";
|
||||
import tseslint from "typescript-eslint";
|
||||
import { defineConfig, globalIgnores } from "eslint/config";
|
||||
|
||||
// The launcher is plain Node TypeScript (no React/browser), so this mirrors
|
||||
// the web client's flat config minus the React/Storybook plugins.
|
||||
export default defineConfig([
|
||||
globalIgnores(['build', 'coverage']),
|
||||
globalIgnores(["build", "coverage"]),
|
||||
{
|
||||
files: ['**/*.{ts,mts}'],
|
||||
files: ["**/*.{ts,mts}"],
|
||||
extends: [js.configs.recommended, tseslint.configs.recommended],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2022,
|
||||
sourceType: 'module',
|
||||
sourceType: "module",
|
||||
globals: globals.node,
|
||||
},
|
||||
},
|
||||
|
|
|
|||
2
clients/launcher/package-lock.json
generated
2
clients/launcher/package-lock.json
generated
|
|
@ -19,7 +19,7 @@
|
|||
"@vitest/coverage-v8": "^4.1.0",
|
||||
"eslint": "^9.39.4",
|
||||
"globals": "^17.4.0",
|
||||
"prettier": "^3.8.1",
|
||||
"prettier": "3.8.4",
|
||||
"typescript": "~5.9.3",
|
||||
"typescript-eslint": "^8.56.1",
|
||||
"vitest": "^4.1.0"
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@
|
|||
"build": "tsc",
|
||||
"postbuild": "node scripts/make-executable.js",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier --write src __tests__",
|
||||
"format:check": "prettier --check src __tests__",
|
||||
"format": "prettier --write src __tests__ scripts \"*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}\"",
|
||||
"format:check": "prettier --check src __tests__ scripts \"*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}\"",
|
||||
"test": "vitest run",
|
||||
"test:coverage": "vitest run --coverage",
|
||||
"validate": "npm run format:check && npm run lint && npm run build && npm run test"
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
"@vitest/coverage-v8": "^4.1.0",
|
||||
"eslint": "^9.39.4",
|
||||
"globals": "^17.4.0",
|
||||
"prettier": "^3.8.1",
|
||||
"prettier": "3.8.4",
|
||||
"typescript": "~5.9.3",
|
||||
"typescript-eslint": "^8.56.1",
|
||||
"vitest": "^4.1.0"
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import { defineConfig } from 'vitest/config';
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
globals: false,
|
||||
environment: 'node',
|
||||
include: ['__tests__/**/*.test.ts'],
|
||||
environment: "node",
|
||||
include: ["__tests__/**/*.test.ts"],
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
reporter: ['text', 'html', 'json-summary'],
|
||||
include: ['src/**/*.ts'],
|
||||
provider: "v8",
|
||||
reporter: ["text", "html", "json-summary"],
|
||||
include: ["src/**/*.ts"],
|
||||
exclude: [
|
||||
// Binary bootstrap: shebang + commander wiring that dynamically imports
|
||||
// each client's build/index.js and dispatches via process.exit. It only
|
||||
|
|
@ -16,7 +16,7 @@ export default defineConfig({
|
|||
// launcher smokes (smoke:launcher / smoke:cli / smoke:tui / smoke:web).
|
||||
// Mirrors the cli/web `index.ts` exclusion. The pure arg-parsing logic
|
||||
// lives in parse-launcher-argv.ts, which is unit-tested and gated below.
|
||||
'src/index.ts',
|
||||
"src/index.ts",
|
||||
],
|
||||
thresholds: {
|
||||
perFile: true,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import js from '@eslint/js';
|
||||
import globals from 'globals';
|
||||
import reactHooks from 'eslint-plugin-react-hooks';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import { defineConfig, globalIgnores } from 'eslint/config';
|
||||
import js from "@eslint/js";
|
||||
import globals from "globals";
|
||||
import reactHooks from "eslint-plugin-react-hooks";
|
||||
import tseslint from "typescript-eslint";
|
||||
import { defineConfig, globalIgnores } from "eslint/config";
|
||||
|
||||
// The TUI is Node + React (Ink) TypeScript. This mirrors the web client's flat
|
||||
// config minus the browser-only plugins (react-refresh / Storybook).
|
||||
|
|
@ -15,19 +15,19 @@ import { defineConfig, globalIgnores } from 'eslint/config';
|
|||
// component/hook surface that is itself the interim-excluded one tracked in
|
||||
// #1501. Enforcing them would require refactoring code out of scope here.
|
||||
export default defineConfig([
|
||||
globalIgnores(['build', 'coverage']),
|
||||
globalIgnores(["build", "coverage"]),
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
plugins: { 'react-hooks': reactHooks },
|
||||
files: ["**/*.{ts,tsx}"],
|
||||
plugins: { "react-hooks": reactHooks },
|
||||
extends: [js.configs.recommended, tseslint.configs.recommended],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2022,
|
||||
sourceType: 'module',
|
||||
sourceType: "module",
|
||||
globals: globals.node,
|
||||
},
|
||||
rules: {
|
||||
'react-hooks/rules-of-hooks': 'error',
|
||||
'react-hooks/exhaustive-deps': 'warn',
|
||||
"react-hooks/rules-of-hooks": "error",
|
||||
"react-hooks/exhaustive-deps": "warn",
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
|
|
|||
2
clients/tui/package-lock.json
generated
2
clients/tui/package-lock.json
generated
|
|
@ -34,7 +34,7 @@
|
|||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"globals": "^17.4.0",
|
||||
"ink-testing-library": "^4.0.0",
|
||||
"prettier": "^3.8.1",
|
||||
"prettier": "3.8.4",
|
||||
"tsup": "^8.5.0",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "~5.9.3",
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@
|
|||
"test": "vitest run",
|
||||
"test:coverage": "vitest run --coverage",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier --write src __tests__ index.ts tui.tsx dev.ts",
|
||||
"format:check": "prettier --check src __tests__ index.ts tui.tsx dev.ts"
|
||||
"format": "prettier --write src __tests__ \"*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}\"",
|
||||
"format:check": "prettier --check src __tests__ \"*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/client": "2.0.0-beta.5",
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"globals": "^17.4.0",
|
||||
"ink-testing-library": "^4.0.0",
|
||||
"prettier": "^3.8.1",
|
||||
"prettier": "3.8.4",
|
||||
"tsup": "^8.5.0",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "~5.9.3",
|
||||
|
|
|
|||
|
|
@ -1,37 +1,37 @@
|
|||
import { defineConfig } from 'tsup';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { defineConfig } from "tsup";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const repoRoot = path.resolve(dirname, '../..');
|
||||
const repoRoot = path.resolve(dirname, "../..");
|
||||
|
||||
export default defineConfig({
|
||||
entry: ['index.ts'],
|
||||
format: ['esm'],
|
||||
outDir: 'build',
|
||||
entry: ["index.ts"],
|
||||
format: ["esm"],
|
||||
outDir: "build",
|
||||
clean: true,
|
||||
// No source maps in the published bundle — they roughly double the on-disk
|
||||
// size and aren't needed at runtime (debug via `npm run dev` on the source).
|
||||
sourcemap: false,
|
||||
target: 'node22',
|
||||
platform: 'node',
|
||||
target: "node22",
|
||||
platform: "node",
|
||||
noExternal: [/^@inspector\/core/],
|
||||
external: [
|
||||
'react',
|
||||
'ink',
|
||||
'ink-form',
|
||||
'ink-scroll-view',
|
||||
'open',
|
||||
'commander',
|
||||
'pino',
|
||||
'@modelcontextprotocol/client',
|
||||
'@modelcontextprotocol/core',
|
||||
'@napi-rs/keyring',
|
||||
"react",
|
||||
"ink",
|
||||
"ink-form",
|
||||
"ink-scroll-view",
|
||||
"open",
|
||||
"commander",
|
||||
"pino",
|
||||
"@modelcontextprotocol/client",
|
||||
"@modelcontextprotocol/core",
|
||||
"@napi-rs/keyring",
|
||||
],
|
||||
esbuildOptions(options) {
|
||||
options.alias = {
|
||||
'@inspector/core': path.join(repoRoot, 'core'),
|
||||
"@inspector/core": path.join(repoRoot, "core"),
|
||||
};
|
||||
options.jsx = 'automatic';
|
||||
options.jsx = "automatic";
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,18 +1,15 @@
|
|||
import type { StorybookConfig } from '@storybook/react-vite';
|
||||
import type { StorybookConfig } from "@storybook/react-vite";
|
||||
|
||||
const config: StorybookConfig = {
|
||||
"stories": [
|
||||
"../src/**/*.mdx",
|
||||
"../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"
|
||||
],
|
||||
"addons": [
|
||||
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
|
||||
addons: [
|
||||
"@chromatic-com/storybook",
|
||||
"@storybook/addon-vitest",
|
||||
"@storybook/addon-a11y",
|
||||
"@storybook/addon-docs",
|
||||
"@storybook/addon-onboarding"
|
||||
"@storybook/addon-onboarding",
|
||||
],
|
||||
"framework": "@storybook/react-vite",
|
||||
framework: "@storybook/react-vite",
|
||||
previewHead: (head) => `
|
||||
${head}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
|
|
@ -20,4 +17,4 @@ const config: StorybookConfig = {
|
|||
<link href="https://fonts.googleapis.com/css2?family=Fredoka:wght@300..700&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap" rel="stylesheet" />
|
||||
`,
|
||||
};
|
||||
export default config;
|
||||
export default config;
|
||||
|
|
|
|||
|
|
@ -1,64 +1,74 @@
|
|||
import type { Preview } from '@storybook/react-vite'
|
||||
import { MantineProvider, useMantineColorScheme, type CSSVariablesResolver } from '@mantine/core'
|
||||
import { Notifications } from '@mantine/notifications'
|
||||
import '@mantine/core/styles.css'
|
||||
import '@mantine/notifications/styles.css'
|
||||
import '../src/App.css'
|
||||
import { theme } from '../src/theme/theme'
|
||||
import { useEffect } from 'react'
|
||||
import type { Preview } from "@storybook/react-vite";
|
||||
import {
|
||||
MantineProvider,
|
||||
useMantineColorScheme,
|
||||
type CSSVariablesResolver,
|
||||
} from "@mantine/core";
|
||||
import { Notifications } from "@mantine/notifications";
|
||||
import "@mantine/core/styles.css";
|
||||
import "@mantine/notifications/styles.css";
|
||||
import "../src/App.css";
|
||||
import { theme } from "../src/theme/theme";
|
||||
import { useEffect } from "react";
|
||||
|
||||
// eslint-disable-next-line react-refresh/only-export-components
|
||||
function ColorSchemeWrapper({
|
||||
colorScheme,
|
||||
children,
|
||||
}: {
|
||||
colorScheme: 'light' | 'dark'
|
||||
children: React.ReactNode
|
||||
colorScheme: "light" | "dark";
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const { setColorScheme } = useMantineColorScheme()
|
||||
const { setColorScheme } = useMantineColorScheme();
|
||||
|
||||
useEffect(() => {
|
||||
setColorScheme(colorScheme)
|
||||
}, [colorScheme, setColorScheme])
|
||||
setColorScheme(colorScheme);
|
||||
}, [colorScheme, setColorScheme]);
|
||||
|
||||
return <>{children}</>
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
const resolver: CSSVariablesResolver = () => ({
|
||||
variables: {},
|
||||
light: {},
|
||||
dark: {
|
||||
'--mantine-color-body': 'var(--mantine-color-dark-9)',
|
||||
"--mantine-color-body": "var(--mantine-color-dark-9)",
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
const preview: Preview = {
|
||||
globalTypes: {
|
||||
colorScheme: {
|
||||
description: 'Mantine color scheme',
|
||||
description: "Mantine color scheme",
|
||||
toolbar: {
|
||||
title: 'Color Scheme',
|
||||
icon: 'mirror',
|
||||
title: "Color Scheme",
|
||||
icon: "mirror",
|
||||
items: [
|
||||
{ value: 'light', title: 'Light', icon: 'sun' },
|
||||
{ value: 'dark', title: 'Dark', icon: 'moon' },
|
||||
{ value: "light", title: "Light", icon: "sun" },
|
||||
{ value: "dark", title: "Dark", icon: "moon" },
|
||||
],
|
||||
dynamicTitle: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
initialGlobals: {
|
||||
colorScheme: 'light',
|
||||
colorScheme: "light",
|
||||
},
|
||||
decorators: [
|
||||
(Story, context) => {
|
||||
const isFullscreen = context.parameters?.layout === 'fullscreen'
|
||||
const isFullscreen = context.parameters?.layout === "fullscreen";
|
||||
return (
|
||||
<MantineProvider theme={theme} defaultColorScheme="light" cssVariablesResolver={resolver}>
|
||||
<ColorSchemeWrapper colorScheme={context.globals.colorScheme ?? 'light'}>
|
||||
<MantineProvider
|
||||
theme={theme}
|
||||
defaultColorScheme="light"
|
||||
cssVariablesResolver={resolver}
|
||||
>
|
||||
<ColorSchemeWrapper
|
||||
colorScheme={context.globals.colorScheme ?? "light"}
|
||||
>
|
||||
<Notifications position="top-right" />
|
||||
{isFullscreen ? (
|
||||
<div style={{ height: '100vh', overflow: 'hidden' }}>
|
||||
<div style={{ height: "100vh", overflow: "hidden" }}>
|
||||
<Story />
|
||||
</div>
|
||||
) : (
|
||||
|
|
@ -66,7 +76,7 @@ const preview: Preview = {
|
|||
)}
|
||||
</ColorSchemeWrapper>
|
||||
</MantineProvider>
|
||||
)
|
||||
);
|
||||
},
|
||||
],
|
||||
parameters: {
|
||||
|
|
@ -80,7 +90,7 @@ const preview: Preview = {
|
|||
// `'error'` fails the Storybook play-function tests (part of `npm run ci`)
|
||||
// on any axe violation, so the zero-violation state this PR reached is
|
||||
// enforced going forward rather than being a point-in-time result.
|
||||
test: 'error',
|
||||
test: "error",
|
||||
// Stories render presentational components (and whole screens) in
|
||||
// isolation, outside the app's `AppShell` — which is what provides the
|
||||
// page landmarks (`<main>`, nav) in the real app. The `region` rule
|
||||
|
|
@ -90,11 +100,11 @@ const preview: Preview = {
|
|||
// by the components under test. Disable it here so the a11y panel surfaces
|
||||
// only rules the components can actually own.
|
||||
config: {
|
||||
rules: [{ id: 'region', enabled: false }],
|
||||
rules: [{ id: "region", enabled: false }],
|
||||
},
|
||||
},
|
||||
layout: 'centered',
|
||||
layout: "centered",
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
export default preview
|
||||
export default preview;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import * as a11yAddonAnnotations from "@storybook/addon-a11y/preview";
|
||||
import { setProjectAnnotations } from '@storybook/react-vite';
|
||||
import * as projectAnnotations from './preview';
|
||||
import { setProjectAnnotations } from "@storybook/react-vite";
|
||||
import * as projectAnnotations from "./preview";
|
||||
|
||||
// This is an important step to apply the right configuration when testing your stories.
|
||||
// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations
|
||||
setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]);
|
||||
setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]);
|
||||
|
|
|
|||
2
clients/web/package-lock.json
generated
2
clients/web/package-lock.json
generated
|
|
@ -69,7 +69,7 @@
|
|||
"globals": "^17.4.0",
|
||||
"happy-dom": "^20.9.0",
|
||||
"playwright": "^1.58.2",
|
||||
"prettier": "^3.8.4",
|
||||
"prettier": "3.8.4",
|
||||
"storybook": "^10.2.19",
|
||||
"tsup": "^8.5.1",
|
||||
"typescript": "~5.9.3",
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@
|
|||
"test:integration:watch": "npm run test-servers:build && vitest --project=integration",
|
||||
"test-servers:build": "tsc -p ../../test-servers --noCheck",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier --write src server \"*.{ts,js}\"",
|
||||
"format:check": "prettier --check src server \"*.{ts,js}\"",
|
||||
"format": "prettier --write src server .storybook \"*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}\"",
|
||||
"format:check": "prettier --check src server .storybook \"*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}\"",
|
||||
"preview": "vite preview",
|
||||
"storybook": "storybook dev -p 6006"
|
||||
},
|
||||
|
|
@ -91,7 +91,7 @@
|
|||
"globals": "^17.4.0",
|
||||
"happy-dom": "^20.9.0",
|
||||
"playwright": "^1.58.2",
|
||||
"prettier": "^3.8.1",
|
||||
"prettier": "3.8.4",
|
||||
"storybook": "^10.2.19",
|
||||
"tsup": "^8.5.1",
|
||||
"typescript": "~5.9.3",
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue