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

@bump-sh/agent-widget

v0.1.0

Published

Embeddable, themeable chat widget for Bump.sh agents — a Web Component you drop in with 3 lines.

Readme

@bump-sh/agent-widget

Embeddable, themeable chat widget for Bump.sh agents. A Web Component you drop in with 3 lines — fully isolated (Shadow DOM), fully customizable.

  • 3-line pathnew Widget({ endpoint }) and you have a chat box.
  • 3 display modesmodal (default), sidebar, inline.
  • Isolated — Shadow DOM: the host page's CSS can't leak in, and vice versa.
  • Customizable — CSS tokens, ::part(), slots, and options.
  • BYO conversation — pass your own @bump-sh/agent-conversation Conversation.

Install

npm install @bump-sh/agent-widget

Requires a modern browser with Web Components and native <dialog> support (all evergreen browsers). The only dependency is @bump-sh/agent-conversation.

Quickstart

import { Widget } from "@bump-sh/agent-widget"

new Widget({ endpoint: "https://your-host/demo/weather/agent" })

That mounts a floating launcher + modal. Or declaratively:

<agent-widget endpoint="https://…/agent" mode="sidebar"></agent-widget>
<script type="module" src="https://unpkg.com/@bump-sh/agent-widget"></script>

Importing the package auto-registers the <agent-widget> element.

Playground

Explore every option interactively — live preview plus the code to copy — with the playground:

npm run playground              # from the repo root

Options

const widget = new Widget({
  endpoint,                         // OR conversation: myConversation  (bring your own)
  token,                            // auth: string | () => string | Promise<string>
  config,                           // agent config → Config-<Key> headers (map or per-request callback)
  headers,                          // extra request headers (map or per-request callback)
  mode: "modal",                    // "modal" | "sidebar" | "inline"
  launcher: true,                   // floating launcher button (modal/sidebar); false to open it yourself
  target: "#app",                   // inline container (selector or element); modal/sidebar → <body>
  open: false,                      // start opened (inline is always open)
  theme: { accent: "#0a0a0a" },     // → CSS custom properties, see Theming
  title: "Assistant",
  subtitle: "AI Agent",             // small line under the title
  placeholder: "Ask anything…",
  greeting: "Hi! How can I help?",  // optional first assistant message (visual only, not sent to the agent)
  suggestions: ["What can you do?"], // clickable example prompts, shown until the first message
                                    // (clicking one sends it)
  avatar: "https://…/logo.png",     // image URL or inline emoji/HTML
  launcherIcon: "✨",               // launcher button icon: image URL or inline emoji/HTML
                                    // (defaults to an AI sparkle)
  disclaimer: "AI can make mistakes…", // footer under the composer ("" to hide)
  labels: { send: "Send", close: "Close", launch: "Open chat", today: "Today" },
                                    // a11y labels + the date divider — override to localize
  renderMarkdown: (text) => "…",    // replace the built-in safe renderer
})

The instance is the handle:

widget.open(); widget.close(); widget.toggle()
widget.destroy()      // remove the element from the page
widget.conversation   // the underlying Conversation (history, events, reset)
widget.element        // the <agent-widget> DOM element

HTML attributes

For declarative use, these attributes are observed and reactive — change one and the widget updates:

| attribute | maps to | notes | | ------------- | -------------- | ---------------------------------------------- | | endpoint | endpoint | Changing it resets the built-in conversation. | | mode | mode | modal | sidebar | inline. | | open | open()/close() | Present = open. Toggle it to drive the panel. | | title | title | | | subtitle | subtitle | | | placeholder | placeholder | Also the empty-state hint. |

Everything else (token, config, theme, callbacks…) is JS-only: pass it to new Widget(options), or call element.configure(options) before attaching a hand-created element.

Authentication

Pass a token — it's sent to the endpoint as Authorization: Bearer <token>. Use a callback for short-lived tokens; it's re-evaluated on every request, so the token refreshes without remounting the widget:

new Widget({
  endpoint,
  token: async () => (await fetch("/agent-token")).text(),
})

The token lives in the browser, so mint a user-scoped, short-lived token server-side — where the page already knows who the logged-in user is — and never expose a raw or tenant-wide API key. In your workflow file, the token is available as $current_user.token.

Agent configuration & custom headers

config keys are sent as Config-<Key> request headers and are available in your workflow file as $config.<key> (config: { locale: "fr" }$config.locale); headers adds any other header. Key matching is case-insensitive and treats - and _ as equivalent — prefer dash-separated keys. Both accept a map, or a callback re-evaluated on every request:

new Widget({
  endpoint,
  config: { locale: "fr" },
  headers: () => ({ "X-Request-Id": crypto.randomUUID() }),
})

Markdown rendering

The built-in renderer is intentionally tiny and dependency-free: it escapes all HTML first, then re-introduces a fixed, safe subset — bold, italic, inline code, code blocks, headings, lists, blockquotes, tables, horizontal rules, and links restricted to http(s)/mailto/relative schemes. It keeps the bundle small — no javascript:/data: links, no raw HTML passthrough.

Need full CommonMark/GFM? Swap in a specialized renderer via renderMarkdown. Always pair the parser with a sanitizer — do not trust model output:

import { marked } from "marked"
import DOMPurify from "dompurify"

new Widget({
  endpoint,
  renderMarkdown: (text) => DOMPurify.sanitize(marked.parse(text) as string),
})

Bring your own conversation

Build the Conversation yourself when you need direct access to it — history, on() events, reset() — or to share it with other parts of your app:

import { Conversation } from "@bump-sh/agent-conversation"
import { Widget } from "@bump-sh/agent-widget"

const conversation = new Conversation({ endpoint: "https://…/agent", token: "…" })
new Widget({ conversation })

Anything with a send(content): AsyncIterable<AgentEvent> works (ConversationLike), so you can also wrap or mock it.

Theming

Set CSS custom properties — they pierce the Shadow DOM:

agent-widget {
  --agent-accent: #e11d48;
  --agent-font: "Inter", sans-serif;
  --agent-radius: 12px;
  --agent-width: 360px; /* sidebar */
}

| token | default | what it styles | | --------------------- | ----------------------- | --------------------------------------- | | --agent-accent | #0a0a0a | Accents: links, and buttons by default | | --agent-button-bg | var(--agent-accent) | Launcher & send button — override to decouple them from the accent | | --agent-button-fg | #fff | Launcher & send button icon | | --agent-bg | #ffffff | Panel background | | --agent-text | #0d0d0d | Text | | --agent-muted | #8a8a8f | Secondary text (subtitle, status…) | | --agent-user-bg | #f4f4f5 | User message bubble | | --agent-input-bg | #f7f7f8 | Composer input | | --agent-border | #ececee | Borders | | --agent-code-bg | #f4f4f6 | Code blocks & table headers | | --agent-avatar-bg | var(--agent-user-bg) | Avatar background | | --agent-avatar-size | 28px | Avatar box | | --agent-font | system sans stack | Font family | | --agent-mono | system mono stack | Code font family | | --agent-radius | 20px | Corner radius (user bubble, composer, modal panel) | | --agent-width | 26vw | Sidebar width | | --agent-gutter | 18px | Horizontal padding | | --agent-column | 760px | Max conversation width (inline) | | --agent-z | 2147483000 | Stacking order |

The theme option is a JS shortcut for the most common ones — accent, buttonBg, buttonFg, bg, text, muted, userBg, inputBg, border, codeBg, font, radius, width, z — set the rest directly in CSS as above.

Style internal structure with ::part():

agent-widget::part(send) { border-radius: 6px; }
agent-widget::part(message-user) { background: #eef; }

Parts: launcher, panel, header, title, subtitle, close, thread, message, message-user, message-assistant, avatar, composer, input, send, status, disclaimer.

Replace whole regions with slots: title, empty (empty-thread state), composer-actions (left of the send button).

<agent-widget endpoint="https://…/agent">
  <span slot="title">Ask our docs</span>
</agent-widget>

Interaction & accessibility

  • Enter sends, Shift+Enter inserts a newline.
  • Modal and sidebar are native <dialog>s shown top-layer: Escape closes, focus is trapped, and clicking the backdrop dismisses.
  • Launcher, close, and send buttons carry aria-labels — localize them via labels.
  • While a reply streams, sending is disabled and a status line shows the tools the agent is running.

Exports

  • Widget — the one-line façade (create, mount, handle).
  • AgentWidget — the custom element class, for hand-rolled setups.
  • defineAgentWidget(tag?) — register the element, optionally under a custom tag name (idempotent; called automatically on import).
  • renderMarkdown — the built-in safe renderer, reusable on its own.
  • Types: WidgetOptions, ConversationLike, Labels, Mode, Theme.

License

MIT