npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@grafana/design-setup

v0.2.0

Published

npx CLI that wires a consuming app to Agentic Experience Platform (AXP) packages

Downloads

666

Readme

@grafana/design-setup

npx-able CLI that wires a consuming app to the Agentic Experience Platform (AXP) packages published from this monorepo: runtime UI packages, @grafana-design/design-mcp for agents, providers/CSS, AGENTS.md, feedback slash commands, and webpack/vite notes.

Where the packages come from

The AXP runtime packages are published privately to Google Artifact Registry under the @grafana-design scope, not to npmjs.org. This CLI is the exception: it stays public on npmjs as @grafana/design-setup, because npx -y @grafana/design-setup@beta has to work before any registry credential exists — it can't live behind the credential it sets up.

So the CLI authenticates first, then installs. You don't need a token: read access is granted to all Grafana staff through GCP IAM, so there is nothing to request. On each run it will:

  1. Check whether you can already read the registry, and do nothing if so — the normal case in CI, where workload identity has already supplied a credential, and on any machine that authenticated recently.
  2. Otherwise mint a short-lived credential into your user-level ~/.npmrc.
  3. If there's nothing to mint from, run gcloud auth application-default login to open a browser, then mint.

gcloud is therefore only needed the first time on a given machine, and not at all in CI. If it's missing, the CLI stops and tells you how to install it rather than half-wiring your project — a run that stops at a gate names the step it stopped at, and nothing past that step runs, so it's always safe to fix the problem and run again. Pass --skip-auth if you've authenticated some other way and don't want to be prompted.

The scope mapping is committed to your project's .npmrc; the credential is not, and never will be — it lives in your user-level ~/.npmrc, because a token committed to a repo is how registry credentials leak. One case worth knowing: if your project's .npmrc already maps @grafana-design to a different registry, the CLI reports it and stops rather than rewriting the line, on the grounds that a registry URL somebody chose deliberately isn't ours to overwrite silently.

The credential is short-lived. When an install starts failing with a 401, run npx -y google-artifactregistry-auth to mint a fresh one — or wrap that in a mise/direnv hook so entering the directory does it for you. A preinstall hook would be the obvious place, but two of the three known consumer repos set ignore-scripts=true as supply-chain hardening, so it would be silently dead in exactly the repos that need it most.

CI is not covered by this CLI

Everything above is about the machine you run the CLI on. Your CI still has to authenticate for itself, and that is the step people discover when the first PR fails on install.

The CLI cannot do it: the work is a workflow change plus, for most repos, a grafana/deployment_tools PR adding the repository to an allow-list, which needs a terraform apply. Neither is something a setup CLI should write on your behalf.

Read docs/REGISTRY_ACCESS.md and do it before you open the PR that adds the dependencies. In short:

  • Repos calling grafana/plugin-ci-workflows pass npm-registry-auth: true and are done.
  • Everyone else adds id-token: write on the job (at workflow level zizmor flags it), a google-github-actions/auth step impersonating github-cloud-npm-dev-pkgs@, and a npx -y google-artifactregistry-auth step, all before install. A job-level permissions block replaces the inherited set, so repeat any grant that job already relied on.
  • Do not reach for login-to-gar. It authenticates with direct workload identity federation, which has no read binding on this registry for a consumer repo, so the job authenticates to Google and is then refused by the registry.

Yarn 4 consumers need more than the CLI writes, too — Yarn Berry never reads .npmrc. That guide has the .yarnrc.yml shape.

If a CI job is already running and you only need it to stop prompting, --skip-auth makes the CLI assume a credential is in place rather than trying to mint one.

First-time setup (consumer app or Grafana plugin)

Run these from the root of the app or plugin you want to wire up (the folder that owns package.json), or from a workspace root in a monorepo.

1. Run the CLI

Use npx, whatever package manager the project itself uses:

npx -y @grafana/design-setup@beta

-y answers npx's "Ok to proceed?" prompt, so the command doesn't stall in a script or a non-interactive shell.

Run it with npx even in a pnpm, Yarn, or Bun repo. The CLI detects your package manager from the lockfile and runs the right install at the end, so the runner you fetch it with doesn't change what lands in the project. pnpm dlx in particular can hand you a stale CLI: pnpm dlx caches a resolved version for 24 hours by default, and a repo setting minimumReleaseAge quarantines recent publishes, so a fresh beta can silently resolve to an older one. npx has neither behavior.

Useful flags: --dry-run, --target plugin|vite, --cwd <path>, --app <path> (repeatable).

Monorepos

When the CLI finds pnpm-workspace.yaml or a package.json workspaces field, it splits work:

| Root (once) | Per app | | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | | @grafana-design/design-mcp, .mcp.json, AGENTS.md, /axp-* commands, minimumReleaseAgeExclude | Runtime deps, providers on the App root, CSS imports, bundler patch/notes |

An app is a workspace package with src/plugin.json, or a bundler config plus an app-shaped entry (src/module.tsx, src/App.tsx, src/main.tsx, … — not src/index.*, so libraries with Vitest Vite configs are skipped). By default every detected app is wired.

  • --app <path> (repeatable; relative to the workspace root) wires only those packages. Paths need a package.json but do not have to pass the app heuristic — so you can target a package the detector would skip.
  • --cwd apps/plugin (an app member) wires that app only and still places root-scoped artifacts at the workspace root.
  • --cwd apps/lib (a member that is not an app) falls through and wires every detected app under the workspace — same as running from the root. Use --app if you meant a single package.
  • --cwd scratch/vite-app (under the workspace but not listed in workspace globs) wires only that package, with root-scoped artifacts still at the workspace root — it does not wire every member app. Install also runs pnpm install --ignore-workspace in that package so its runtime deps actually link.
  • Install always runs at the workspace root (and in any wired non-member packages as above).

Preview the resolved layout without writing: --dry-run.

Limitation: pnpm negation globs in packages (for example - '!apps/legacy') are ignored by the CLI’s glob expander. Prefer --app when a workspace mixes apps you want wired with packages that match the same positive glob.

2. Confirm install

Run install yourself if you used --skip-install, if install failed/warned, or if node_modules looks incomplete:

pnpm install   # or npm install / yarn install

3. Check the providers on your app root

The CLI wires the providers directly into your App component — src/app/App.tsx, src/components/App/App.tsx or src/App.tsx, whichever it finds. For Grafana plugins that leaves:

import { ColorMode, PortalProvider } from '@grafana-design/theme-providers';
import { getAppEvents, useTheme2 } from '@grafana/runtime';

export default function App(props: AppRootProps) {
  return (
    <PortalProvider defaultRoot="grafana-portal-container">
      <ColorMode getAppEvents={getAppEvents} useTheme2={useTheme2}>
        {/* existing tree */}
      </ColorMode>
    </PortalProvider>
  );
}

ColorMode keeps AXP tokens in sync with the host theme; PortalProvider shares Grafana’s portal root so floating UI stacks with the host. Standalone Vite apps have no Grafana theme bus, so they get PortalProvider + ColorModeProvider defaultColorMode="dark" instead.

The providers are written out individually rather than behind a generated ThemeProviders wrapper, so the app’s own source shows which providers are in play and what they depend on — matching how grafana-assistant-app wires this by hand.

The step is conservative: an app that already establishes color mode is left untouched and reported as such, and an App whose shape the CLI can’t identify is reported so you can wire it yourself. Check the step’s output rather than assuming.

4. Apply webpack notes if the CLI did not patch for you

Recognizable create-plugin webpack configs are patched automatically (CSS sideEffects + font [hash][ext]), and nothing is written for you to do by hand.

docs/axp-webpack-notes.md (or docs/axp-vite-notes.md) appears only when the CLI could not patch for you — an unrecognized config, or a Vite project. If one is there, open it and apply the snippets; without them, token/font CSS can be tree-shaken or font files can 404 at runtime. The next-steps output names the file when there is one.

5. Restart your coding agent

Reload Cursor / Claude Code / your MCP client so it picks up .mcp.json and the feedback commands. Confirm design-mcp tools appear (get_token, list_styling_docs, get_styling_doc, get_migration_recipe, search).

The CLI also adds a marked AXP section to AGENTS.md so agents prefer MCP over inventing UI. If AGENTS.md carries a generated-file banner (hatch, or any generator that says "do not edit" / "auto-generated"), the CLI leaves it alone instead of editing it directly. When a .hatch/ directory is present, it writes the guidance as its own rule at .hatch/_rules/mcp-first-guidance.md — run pnpm hatch:gen after to fold it in. For any other generator, it writes docs/axp-agents-guidance.md instead for you to fold into your own generator source.

6. Send tester feedback

The CLI writes three commands. Two file issues on grafana/design under the feedback label; the third only reports.

| Command | When to use it | | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | /axp-send-feedback | In the moment, for one thing. Interviews you for one of four feedback kinds (worked, didn’t work, course corrections, unexpected builds), pulls chat context, and confirms before creating the issue. | | /axp-summarize-session | At the end of a session. Scans the whole conversation, categorizes every finding, shows you a numbered list to approve or trim, then batch-files up to 10 issues. Skips anything already filed in the moment. | | /axp-diagnostics | Any time, and worth running before you file. Reports a table of how AXP is wired here — MCP server, AGENTS.md block, installed versions and how far behind the tag they are, supply-chain settings, per-app providers/CSS/bundler — plus a fix line per failing row. Saves the report to axp-diagnostics.md so you can share it; changes nothing else. |

The two feedback commands need gh authenticated with permission to open issues on that repo. /axp-diagnostics uses gh only to report the project URL, and degrades gracefully without it.

Supported today: Cursor and Claude Code (files under .cursor/commands/ and .claude/commands/). Copilot and other agents: run the skills from the MCP server directly, or file the issues manually. Re-runs of the CLI refresh these files — don’t edit them in the consumer.

The command files are deliberately thin. They tell the agent to fetch the workflow from the grafana-design MCP server (get_design_skill({ name: "axp-send-feedback" })) rather than carrying it inline, so the questions can be revised during the beta without re-running design-setup. Note the reach narrowed when the server moved to a private registry: .mcp.json now runs the installed server rather than resolving a dist-tag through npx, so a revision arrives on the next dependency bump rather than the next agent restart. The trade-off: every one of them needs that MCP server connected. If it isn’t, they stop and tell you to check .mcp.json rather than inventing an answer.

7. Smoke-check

  • Build and start the plugin/app in light and dark.
  • Open a floating surface (menu, dialog, tooltip) and confirm it portals and styles correctly.
  • Confirm Inter / JetBrains Mono and AXP colors load (no missing font or unstyled chrome).

What “done” looks like

| Artifact | Purpose | | ---------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | App package.json deps | @grafana-design/design-tokens, theme-providers, icons, fonts | | Root devDependencies | @grafana-design/design-mcp | | Root .mcp.json | grafana-design stdio server for agents | | Root AGENTS.md | AXP priority order for coding agents | | Root .cursor/commands/ + .claude/commands/ | /axp-send-feedback, /axp-summarize-session (file issues on grafana/design), /axp-diagnostics | | App App component | Color mode + portal providers wrapped around the root JSX | | App entry CSS imports | tokens.css / fonts.css when an entry file was found | | App webpack/vite notes or patch | Fonts and token CSS survive the bundler |

After that, build UI with @grafana/ui where it covers the need, and from @grafana-design/design-tokens and the styling docs (served by design-mcp) where it does not. The CLI installs no component package: @grafana-design/base-ui, @grafana-design/ai-elements and @grafana-design/components are deprecated. See MIGRATION.md.

What the CLI does (detail)

  1. Adds runtime deps on each app package: @grafana-design/design-tokens, @grafana-design/theme-providers, @grafana-design/icons and @grafana-design/fonts. It adds no component package, and leaves one an app already depends on in place.
  2. Adds @grafana-design/design-mcp as a devDependency on the root package (same --tag as the runtime packages). If an app still lists it from an older workaround, the pin is moved up to the root.
  3. Prepends tokens.css / fonts.css imports to a detected app entry (src/main.tsx, src/module.tsx, …) when present.
  4. Wraps each app's App root JSX with PortalProvider + ColorMode (or ColorModeProvider for standalone hosts) and adds the imports, merging into an existing import from the same module. Apps that already establish color mode, or whose App shape isn't recognized, are reported rather than edited.
  5. Merges root .mcp.json with a grafana-design stdio server, pointing node at the installed node_modules/@grafana-design/design-mcp/dist/index.js. Not npx: .mcp.json has nowhere to inject a registry credential, so an npx entry to a private package only resolves while a short-lived token happens to be valid. An npx entry left by an earlier version of this CLI is replaced; hand-written entries are left alone.
  6. Inserts a marked AXP section into root AGENTS.md — or, if AGENTS.md looks generated, writes .hatch/_rules/mcp-first-guidance.md (when .hatch/ is present) or docs/axp-agents-guidance.md (otherwise) with the same guidance instead of editing it directly.
  7. Writes /axp-send-feedback, /axp-summarize-session, and /axp-diagnostics command files under root .cursor/commands/ and .claude/commands/ (owned by design-setup; refreshed on re-run). Each is a pointer to the same-named MCP-served skill, not a copy of it. Cursor and Claude Code only — see §6 for other agents.
  8. Patches recognizable create-plugin webpack configs in each app. Only when it cannot does it write notes, without clobbering an existing notes file — a successful patch leaves nothing behind to apply.
  9. Adds the AXP package names to root minimumReleaseAgeExclude, only if the repo already sets minimumReleaseAge. See Release-age quarantine.
  10. Runs the detected package manager’s install last at the workspace/project root, so an install failure does not skip file wiring.

Re-runs are idempotent where possible.

Release-age quarantine

pnpm 11 can hold back newly-published versions with minimumReleaseAge, a supply-chain measure that shrinks the window in which a compromised release gets installed. It's a good default, and it interacts badly with a beta: a build published this morning sits inside the quarantine, so @grafana-design/design-tokens@beta resolves to whatever's older than the window instead — or fails with ERR_PNPM_NO_MATURE_MATCHING_VERSION when no version on the tag is old enough. Nothing warns you; you just get last week's packages.

When the CLI sees minimumReleaseAge set (in pnpm-workspace.yaml, or minimum-release-age in .npmrc), it adds the AXP package names to minimumReleaseAgeExclude before running the install, and prints what it wrote.

What it deliberately does not do:

  • It never changes minimumReleaseAge itself. Every dependency outside the AXP set keeps the full quarantine.
  • It never touches a repo that hasn't opted in. No minimumReleaseAge, no edit.
  • It names packages rather than disabling the check. The exemption covers packages the Grafana design team publishes and nothing else.

If your repo keeps this setting under security review, that's a change you may want to make yourself instead — run with --skip-install, add the entries deliberately, then install. The CLI prints the exact list either way.

Options

--cwd <path>         Consumer root or workspace package (default: .)
--app <path>         Wire only this package (repeatable; any dir with package.json;
                     relative to workspace root). Skips app auto-detection.
--dry-run            Print actions only
--skip-install       Update files but skip install
--tag <dist-tag>     npm tag for AXP packages (default: beta; fonts always use latest)
--target plugin|vite|auto
-h, --help

Programmatic API

runSetup(options, layout?) returns { results, layout } (not a bare StepResult[]). Pass an already-resolved layout when the caller printed it first; otherwise the layout is resolved inside runSetup.

Local development (this monorepo)

pnpm --filter @grafana/design-setup build
pnpm --filter @grafana/design-setup test
pnpm design-setup -- --cwd /path/to/app --dry-run

First publish

New packages need a one-time stub publish + OIDC trusted publisher before the release workflow can publish them. See docs/PUBLISHING.md.

License

Apache-2.0