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

@aistrike-dev/ui

v5.0.1

Published

Octopus UI - AiStrike design system (Atomic Design over MUI).

Readme

Octopus UI

Storybook

@aistrike-dev/ui is the AiStrike design system: a dark-first component library built as a theme layer over MUI and organized with Atomic Design. Design tokens are sourced from the AiStrike Complete Design System in Figma.

Built with React 19, TypeScript, Vite, Storybook 10, and Emotion. Published to the public npm registry; interactive docs are hosted on GitHub Pages.

Table of contents

Features

  • Dark-first themingdarkTheme is the default; lightTheme is available for completeness.
  • Design tokens — colors, typography, spacing, radius, shadows, z-index, and attack-path semantics as a single source of truth.
  • Atomic Design — atoms → molecules → organisms → templates → pages.
  • MUI-native — themed re-exports, overrides, and thin wrappers where product behavior is needed.
  • Storybook docs — autodocs, controls, accessibility checks, and dark/light theme switching.
  • Machine-readable registryComponentMeta per component for LLM and generative-UI tooling.
  • Agent guidance kitnpx aistrike-ui init-agent installs design-system rules into your repo, so AI agents pick the right component instead of hand-rolling one.

Install

@aistrike-dev/ui is published to the public npm registry - no registry login or scoped .npmrc required:

npm install @aistrike-dev/ui

Peer dependencies

Install these in your consuming app:

| Package | Version | | --- | --- | | react / react-dom | ^19.2.6 | | @mui/material | ^9.1.1 | | @mui/icons-material | ^9.1.1 | | @mui/x-date-pickers | ^9.6.0 | | @emotion/react / @emotion/styled | ^11.14.x | | material-react-table | ^3.2.1 | | date-fns | ^4.4.0 |

Runtime dependencies installed with the package: dayjs and rsuite (used by DateRangePicker). When using DateRangePicker, also import rsuite's stylesheet once at the app root:

import 'rsuite/dist/rsuite-no-reset.min.css';

Quick start

Wrap your app with the Octopus theme and import components from the package entry:

import { ThemeProvider, CssBaseline, darkTheme, Button } from '@aistrike-dev/ui';

export function App() {
  return (
    <ThemeProvider theme={darkTheme}>
      <CssBaseline />
      <Button variant="primary">Investigate</Button>
    </ThemeProvider>
  );
}

Octopus UI uses system-native sans-serif and monospace font stacks, so consuming applications do not need to load external fonts.

Develop

Prerequisites

  • Node.js 20+ (LTS recommended)
  • npm 10+

Setup

git clone git@github-aistrike:aistrike-dev/octopus-ui.git
cd octopus-ui
npm ci
npm run storybook   # http://localhost:6006

npm run dev starts a minimal Vite landing page; the component library and documentation live in Storybook.

Quality checks

Before opening a pull request, run:

npm run typecheck
npm run lint
npm run build
npm run build-storybook

If any *.meta.ts files changed, also run npm run build:registry.

Scripts

| Script | Description | | --- | --- | | npm run storybook | Run Storybook locally | | npm run build-storybook | Build static Storybook to storybook-static/ | | npm run build | Build the publishable library (dist/ ESM + CJS + types + agent kit) | | npm run build:registry | Regenerate the LLM/generative-UI registry JSON | | npm run build:agent-kit | Regenerate dist/agent/ (also runs as part of build) | | npm run lint | ESLint | | npm run test | Vitest (unit guards + Storybook interaction tests) | | npm run release:dry | Preview the next version and release notes (read-only) | | npm run release | semantic-release (CI only; blocked locally for agents) |

Architecture

src/
  tokens/      colors, typography, spacing, radius, shadows, zIndex, attackPath
  theme/       palette, typography, component overrides, variants → darkTheme / lightTheme
  atoms/       Button, Checkbox, TextField, Chip, Icon, …
  molecules/   Search, FormField, Tabs, Alert, DatePicker, …
  organisms/   Card, Dialog, Drawer, Table, LeftNavigation, AttackPathLegend, …
  templates/   DashboardLayout, TablePageLayout, SettingsLayout, …
  pages/       DashboardExample, TableExample, …
  docs/        MDX documentation and token stories
  registry/    ComponentMeta types and generated JSON
  index.ts     public library entry (published surface)
.storybook/    Storybook config, ThemeProvider, theme switcher, a11y, dayjs

Component pattern

Every component folder follows a consistent 4-file pattern:

Name/
  Name.tsx          implementation (themed re-export, override, wrapper, or custom)
  Name.stories.tsx  autodocs, controls, and real states
  Name.meta.ts      machine-readable ComponentMeta
  index.ts          barrel export

Classification

| Type | Description | | --- | --- | | themed-mui | Pure MUI component, styled only via the theme | | mui-overrides | MUI with theme-level styleOverrides or variants | | mui-wrapper | Thin wrapper adding product-specific behavior | | custom | Fully custom, domain-specific implementation | | third-party-wrapper | Wraps a heavy third-party dependency declared as a peer |

Component catalog

| Layer | Count | Examples | | --- | ---: | --- | | Atoms | 19 | Button, Chip, TextField, Select, Icon, Tooltip | | Molecules | 15 | Search, FormField, Tabs, Alert, DatePicker, Pagination | | Organisms | 17 | Card, Dialog, Drawer, Table, FilterPanel, LeftNavigation | | Templates | 6 | DashboardLayout, TablePageLayout, InvestigationLayout | | Pages | 8 | DashboardExample, ThreatsExample, InventoryExample |

Browse the full catalog with live examples at octopus-ui.aistrike.dev.

Code editor (Monaco)

The Monaco editor ships at a separate, ESM-only entry so consumers that never mount an editor never pay for it, and so the root . entry stays dual ESM/CJS:

import { CodeEditor } from '@aistrike-dev/ui/monaco';

Install the peer — it is optional, but pinned:

npm install monaco-editor@^0.56.0

The version is pinned to ^0.56.0 because the design system ships a pre-built worker, and Monaco's main-thread/worker RPC protocol is internal and changes between minors. A mismatch does not error cleanly; it silently degrades (suggestions, diff computation and link detection stop working).

Because @aistrike-dev/ui/monaco needs import.meta.url to resolve its worker, it is published ESM-only — there is no require() entry. If your project is still CommonJS, import it from an ESM context (a dynamic import(), an ESM-only bundler pipeline, or an .mjs/"type": "module" boundary).

Choosing what loads

<CodeEditor
  value={sql}
  onChange={setSql}
  language="sql"
  features={['suggest', 'hover']}   // replaces the default set
  ariaLabel="SQL query"
/>

Built-in languages: sql, python, javascript, shell, markdown, yaml. json, css, html and typescript are not available — they are language services that need their own dedicated workers, which this design deliberately does not ship.

languages and features are mount-only. Both are read once, when the editor is created, and are not re-applied if the prop changes on a later render — there is no live "add a language" or "add a feature" to an editor that already exists. If your instance needs a different languages/features set, remount the component (e.g. by changing its React key). value, readOnly, ariaLabel and options are not mount-only; they stay in sync on every render.

Loading state and failures

<CodeEditor
  value={sql}
  onChange={setSql}
  language="sql"
  ariaLabel="SQL query"
  loadingFallback={<Skeleton variant="rectangular" height={260} />}
  onLoadError={(error) => reportToErrorTracker(error)}
/>

loadingFallback renders in place of the editor until Monaco has finished loading (loadingFallback = null by default, so nothing is shown). onLoadError fires if that load — the dynamic monaco-editor import, a requested language's loader, or an external language's register() — rejects.

Wire onLoadError. If loadMonaco rejects and it is not provided, the component has no way to surface the failure: ready never flips to true, so with the default loadingFallback = null the consumer is left looking at a permanently blank box with nothing in the console pointing at why. Passing onLoadError (to a toast, an error tracker, a fallback UI) is how you find out a load failed at all, let alone why.

Adding a language from another package

The design system never needs to know your package exists. Export register:

// @acme/my-language
import type { MonacoApi } from '@aistrike-dev/ui/monaco';

export function register(monaco: MonacoApi) {
  monaco.languages.register({ id: 'mylang' });
  monaco.languages.setMonarchTokensProvider('mylang', {
    tokenizer: { root: [[/\b(select|from)\b/, 'keyword']] },
  });
}
<CodeEditor
  language="mylang"
  languages={[{ id: 'mylang', load: () => import('@acme/my-language') }]}
  value={code}
  ariaLabel="My language"
/>

Emit token names, never colours. The design system maps names to design tokens for both light and dark. Names follow Monaco's convention (keyword, string, number, comment, operator, type, identifier, delimiter, variable, invalid); dotted sub-names such as operator.pipe inherit their parent's colour.

Accessibility

ariaLabel is a required prop — Monaco renders a bare textarea to assistive technology, so an unlabelled editor is unusable with a screen reader.

Tab inserts a tab character rather than moving focus, which would otherwise be a keyboard trap (WCAG 2.1.2). The escape is Monaco's tab-focus mode: toggleTabFocusMode is part of DEFAULT_FEATURES, so Ctrl+M (Windows and Linux) or Ctrl+Shift+M (macOS) always works out of the box — it toggles Tab between inserting a tab character and moving focus to the next element.

That keystroke is undiscoverable, so CodeEditor can advertise it in the corner while the editor has focus. Pass showTabFocusHint to switch that on; it is off by default, because the hint is chrome that every user sees in order to serve the keyboard-only ones, and which surfaces are worth that trade is a product decision. The prop controls the hint only — Tab behaviour and the escape keystroke are identical either way.

Note the macOS keystroke is Ctrl+Shift+M, not Cmd+M: Monaco binds WinCtrl|Shift|KeyM there, and Cmd+M is the OS minimise-window shortcut.

Theme

The editor follows your MUI theme's palette.mode. Monaco's theme is page-global, so all editors on a page share it — there is deliberately no per-instance theme prop.

Content Security Policy

worker-src 'self' blob:;
style-src  'self' 'unsafe-inline';   /* Monaco injects <style> at runtime */

Server rendering

The component is client-only ('use client'). Monaco touches window and document and cannot render on the server.

Pre-warming the worker

CodeEditor registers Monaco's web worker automatically on mount, so this is optional. If your app knows an editor is coming soon (e.g. it's one route away), call configureMonacoWorker() earlier — at app bootstrap, or on a route transition — to avoid a cold-start delay on the first mount:

import { configureMonacoWorker } from '@aistrike-dev/ui/monaco';

configureMonacoWorker();

It is idempotent — safe to call more than once, or in addition to the automatic registration CodeEditor already performs.

Troubleshooting

The worker resolves from a normally installed monaco-editor package with no extra bundler configuration in both dev and production Vite builds. If your setup still fails to resolve the worker (an unusual bundler config, a monorepo with hoisting quirks), excluding it from dependency pre-bundling is a fallback worth trying:

// vite.config.ts
export default {
  optimizeDeps: { exclude: ['monaco-editor'] },
};

Theming

darkTheme is the default export and the primary, Figma-accurate theme. Custom additions include:

  • <Button variant="primary" /> — emphasis ladder of primary / secondary / ghost / destructive variants (fully typed via theme augmentation)
  • <Chip variant="severity" color="critical" /> — security severity scale (fully typed via theme augmentation)

Import tokens directly when you need values outside of MUI's theme object:

import { tokens, darkTheme } from '@aistrike-dev/ui';

Migrating to 2.0

2.0.0 renames the Button variants to an emphasis ladder and changes the default variant. Update any variant props:

| Before (1.x) | After (2.0) | | --- | --- | | variant="contained" | variant="primary" | | variant="outlined" | variant="secondary" | | variant="text" | variant="ghost" | | variant="attack" | variant="destructive" |

The default variant is now secondary (previously contained), and secondary renders on the #182724 dark-green surface. Reserve primary for the single most important action per view, and always pair destructive with a confirmation step. See Guidelines → Agent Guide in Storybook and the Button stories for the full guidance.

Agent guidance kit

If AI agents write UI in your repository, install the agent kit once. It teaches them which component to reach for, which variant, and what never to hand-roll:

npm i @aistrike-dev/ui
npx --package=@aistrike-dev/ui aistrike-ui init-agent

That writes three things, all safe to commit:

| Installed | What it is | | --- | --- | | AGENTS.md | A managed stanza between <!-- octopus-ui:begin --> markers: the hard rules (imports, no hand-rolling, tokens, llmSafe, ask when unsure) plus an instruction to invoke the octopus-ui skill | | .claude/skills/octopus-ui | A symlink to node_modules/@aistrike-dev/ui/dist/agent — where Claude Code looks for project skills | | .cursor/skills/octopus-ui | The same symlink, where Cursor looks |

The skill directories are links, not copies. Nothing is cached in your repo, so npm update upgrades the guidance with nothing to re-run — that is the whole design. The links are relative and committed, so a teammate who clones and runs npm install gets working guidance immediately.

In a monorepo, run it in the workspace package that uses the design system: the link then points at wherever the dependency actually is, which for a hoisted install is the monorepo root — a link that escapes the package directory (../../../../node_modules/…). It resolves for anyone working in the monorepo, but tooling that takes that one package on its own — npm pack, a Docker COPY of the package directory — may refuse to follow a symlink pointing outside it, or dereference it into a copy; if that matters, exclude the skills directories from those builds.

AGENTS.md names the skill by name, never by path: Claude Code and Cursor look in different directories, and Codex reads AGENTS.md with no skill mechanism at all. The stanza therefore carries the hard rules itself and routes to the skill for the detail. It carries no version number, so a new release of this package does not make your AGENTS.md stale.

aistrike-ui init-agent --check verifies both links resolve and the stanza is current, and exits non-zero if not — a one-line CI guard. It writes nothing.

There is deliberately no .cursor/rules/*.mdc. Cursor treats a root AGENTS.md as a rule and injects it at the start of context on every agent turn — the same reach alwaysApply: true has — and the Cursor CLI and Cloud Agents read it too. A rule file would therefore be a second always-on copy of the same stanza, one that Claude Code, Codex and everything else reading AGENTS.md would never see.

This package ships no install script, and cannot usefully do so: npm ≥ 11.6 blocks dependency lifecycle scripts by default, and approvals written by npm install-scripts approve are pinned to a version, so they stop applying on the next upgrade. Your own root postinstall is never blocked, so if you want the links repaired automatically after every install, add this to your package.json:

"scripts": { "postinstall": "aistrike-ui init-agent --quiet" }

That is optional. A committed symlink re-resolves on its own as soon as npm install recreates node_modules, so most repos need nothing.

If your repo gitignores .claude/ or .cursor/, un-ignore at least the skills directory — an ignored link reaches nobody else. init-agent warns when it spots this.

Where symlinks are unavailable (Windows without Developer Mode), init-agent writes a small pointer SKILL.md instead and says so. Yarn Plug'n'Play is not supported: with no node_modules, there is nothing to link to.

The references the kit points at are all generated from the design system itself:

| Reference | Generated from | | --- | --- | | core-rules.md | src/agent/guidelines/core-rules.md — the global contract | | components.md | every component's *.meta.ts (rules, antiPatterns, accessibility, llmSafe) | | choosing.md | src/agent/guidelines/choosing/*.md — deciding between similar-looking components | | tokens.md | src/tokens — surface and severity tokens, so no hex can drift |

Everything also renders for humans in Storybook under Guidelines → Agent Guide and on each component's docs page.

LLM / generative-UI registry

npm run build:registry aggregates each component's ComponentMeta into:

| File | Purpose | | --- | --- | | src/registry/component-registry.json | Full entries (props, states, tokens, a11y, anti-patterns, llmSafe) | | src/registry/mui-mapping.json | Octopus UI → MUI mapping | | src/registry/a2ui-mapping.json | Octopus UI → A2UI / generative-UI mapping | | src/registry/llm-components.json | Compact LLM index (rules, antiPatterns, accessibility; reference example pages excluded) |

The same JSON ships in the package for runtime use:

import registry from '@aistrike-dev/ui/registry';

A unit test fails if the committed JSON is stale, so run npm run build:registry and commit the result whenever you touch a *.meta.ts.

Contributing

  1. Branch from main using a descriptive name (feat/..., fix/..., chore/..., docs/...).
  2. Follow the 4-file component pattern and Atomic Design structure.
  3. Write commits in Conventional Commits format. Note that every commit type currently publishes a patch and feat: does not yet bump the minor — see RELEASING.md.
  4. Open a pull request into main with a clear summary of user-facing impact.
  5. Keep React, MUI, Emotion, and material-react-table as peerDependencies; runtime dependencies are dayjs and rsuite.

One logical change per PR. Never push directly to main.

Releases

Releases are agent-prepared, PR-gated, and CI-published:

  1. Changes land on a feature branch with Conventional Commits and open a PR into main.
  2. A reviewer approves and merges the PR (branch protection is the release gate).
  3. GitHub Actions runs semantic-release: publishes @aistrike-dev/ui to the public npm registry, tags the commit, creates a GitHub Release with the notes, and notifies Slack. (npm provenance is disabled while the repo is internal.)

See RELEASING.md for the full runbook, required secrets, and DevOps prerequisites.

Related docs

| Document | Audience | | --- | --- | | RELEASING.md | CI/CD pipelines, npm trusted publishing, required secrets | | AGENTS.md | Cursor Cloud agent guide and project map | | docs/foundation-ui-design-system-brief.md | Planning brief and migration context |

License

Proprietary — UNLICENSED. Internal use within AiStrike only.