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

@agility/vibe-embed

v0.1.0

Published

Embed the Agility vibe-coding chat in a React app — widget lifecycle, a versioned host↔widget protocol, and a provider/hook pair.

Downloads

84

Readme

@agility/vibe-embed

Embeds the Agility vibe-coding chat into a React app as an Intercom-style widget: an iframe the host controls, a versioned message protocol between them, and a provider/hook pair so any component can open the chat or read what it's doing.

The first host is Agility's own Content Manager app (React 18, Vite), behind a feature flag.

Install

npm install @agility/vibe-embed     # yarn add @agility/vibe-embed

Requires React >= 18 as a peer. Public npm, same scope and registry as @agility/plenum-ui and the rest — no .npmrc entry and no auth token, in the app or in CI.

Why not GitHub Packages: it requires the package be scoped to the repo owner (@agility), and npm maps a registry per scope, not per package. Pointing @agility at GitHub Packages would send plenum-ui, content-fetch, nextjs, management-sdk and the rest there too, and they'd all 404. Using GitHub Packages for this SDK would mean moving the entire scope.

Use

Mount the provider once at the app shell — behind the flag, so flag-off never renders it:

import { AgilityVibeProvider, useAgilityVibe } from "@agility/vibe-embed"

<AgilityVibeProvider
  widgetUrl="https://vibe-coding.agilitycms.com/widget"
  instanceGuid={instance.guid}
  auth={() => getManagementToken()}   // called lazily, and again on iframe reload
  context={{ url: location.pathname, pageID }}
  onNavigate={(e) => router.push(e.url)}
>
  {children}
</AgilityVibeProvider>

Then anywhere below it:

const vibe = useAgilityVibe()
if (!vibe) return null          // null until the provider has mounted — see below
vibe.toggle()
vibe.state.busy                 // true while a turn is running

The things worth knowing before you wire it up

  • useAgilityVibe() returns null on the first render. The widget instance is created in an effect, so the context has no handle until after mount. Guard it. It is typed | null rather than throwing so a launcher can render its own disabled state instead of exploding in a host app that merely rendered early.
  • auth returns the logged-in CMS user's management token, and is called lazily and again whenever the iframe reloads — so a short-lived token is fine, and expected. Identity is re-derived server-side from the token presented; nothing trusts a client-claimed user id.
  • Options are captured at mount, deliberately. widgetUrl or instanceGuid changing means a different widget, not a reconfigured one — remount with a key when the user switches instance.
  • renderLauncher={false} if the host has its own launcher. Read state.busy/state.open and drive it yourself; the plan calls for the launcher to show when a chat is processing.
  • context is pushed on every change — a SPA route change is a setContext, which is how the agent knows what the user is looking at. It's context, not a request: the agent is told never to act on it by itself.

Protocol

Host↔widget messages are versioned and namespaced (PROTOCOL_SOURCE, PROTOCOL_V) and every inbound message is validated by parseWidgetMessage before it reaches state — an iframe on another origin is untrusted input. reduceState is pure and exported, so the host can model widget state without a live iframe (that's what the tests do).

Publishing

pnpm --filter @agility/vibe-embed publish --access public

prepack builds first, files ships dist alone, and publishConfig repoints main/types/exports at diston publish only.

In this monorepo the package stays source-resolved (mainsrc/index.ts), so the dashboard keeps importing TypeScript directly with no build step and no dist in the dev path to go stale. That split is the whole reason publishConfig exists here.

Nothing secret ships: this is browser code that a host serves to its own users. Being on public npm doesn't open the widget to the world either — origin and auth are enforced server-side, and public embedding in customers' apps remains a separate decision (see docs/plans/chat-widget.md).