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

@sarchauhan/chat

v0.0.2

Published

Embeddable React chat UI, streaming runtime, and prebuilt agent widgets.

Readme

@sarchauhan/chat

An embeddable React chat package with streaming messages, themes, tool views, and interactive widgets. Bring any backend through ChatAdapter; Next.js is only used by the example apps.

Install

npm install @sarchauhan/chat

React and React DOM (version 18 or later) are peer dependencies and must be installed in your application. The package also depends on the published @sarchauhan/adapter and @sarchauhan/protocol packages; npm installs these automatically.

Quick start

Create a ChatAdapter for your backend, then mount the component and import its stylesheet once:

import { Chat } from "@sarchauhan/chat";
import type { ChatAdapter } from "@sarchauhan/adapter";
import "@sarchauhan/chat/styles.css";

const adapter: ChatAdapter = {
  async *sendMessage() {
    yield { id: "reply-1", role: "assistant", parts: [{ type: "text", text: "Hello!" }] };
  },
};

export function App() {
  return <Chat adapter={adapter} />;
}

See the sections below for built-in widgets, adapter payloads, and artifact/subagent rendering.

import { Chat } from "@sarchauhan/chat";
import "@sarchauhan/chat/styles.css";

<Chat adapter={adapter} />;

Composer and theming

Chat and ChatComposer accept placeholder, inputLabel (the input's accessible name; defaults to the placeholder), and showAttachments (default true; set false for text-only backends). ChatComposer can be mounted on its own inside ChatContextProvider when the host renders the transcript itself.

<ChatContextProvider adapter={adapter} defaultThreadId={threadId}>
  <ChatComposer placeholder="Describe a task…" inputLabel="Task" showAttachments={false} />
</ChatContextProvider>

All chrome reads --chat-* tokens from .chat-root, including widget font weights (--chat-weight-medium, --chat-weight-semibold) and the send button (--chat-primary, --chat-primary-fg). Override them on .chat-root[data-theme="…"] to restyle the package without overriding selectors.

Prebuilt components

import { ReadFileWidget, PatchWidget, SearchWidget, QuestionWidget } from "@sarchauhan/chat/widgets";

<div className="chat-root" data-theme="light">
  <ReadFileWidget path="src/config.ts" content="export const retries = 3;" startLine={12} />
  <PatchWidget path="src/config.ts" before="const retries = 1;\n" after="const retries = 3;\n" />
  <SearchWidget query="retries" results={[{ path: "src/config.ts", line: 12, text: "export const retries = 3;" }]} />
  <QuestionWidget
    prompt="How should messages load?"
    options={[{ label: "Stream", value: "stream", description: "Render responses as they arrive.", recommended: true }, "Wait for completion"]}
    allowCustom
    onSubmit={async ({ values, text }) => { await submitAnswer({ values, text }); }}
  />
</div>;

Import styles.css once. Standalone components inherit theme tokens from .chat-root. Read and patch views collapse when complete; running/error/approval views open automatically. Previews are bounded, with controls to show more. Diff colors indicate additions/deletions; everything else uses the existing neutral theme. Question supports radio/checkbox choices, descriptions, recommended choices, free text, explicit confirmation, disabled/submitted states, and retry after failed submission.

Computed tool views

Chat includes read-file, patch, search, and question in its default widget registry. Backends can send them with createWidgetData(name, props, { id, interactive }) from @sarchauhan/protocol.

Known tool parts are also mapped automatically:

| View | Tool names | Recognized payload | | --- | --- | --- | | Read file | read, read_file, readFile, read-file | Input path/file/filename/file_path; output content; optional startLine/start_line/offset | | Patch | patch, apply_patch, edit, edit_file | Unified/apply-patch text in diff/patch, or before/after, old_string/new_string, oldText/newText | | Search | search, grep, file_search, web_search | query/pattern/search; output array or results/matches; result path/file/url, optional line, text/snippet/content, title | | Question | question, ask_question | Input prompt/question, options, optional description, multiple, allowCustom |

Unsupported payloads retain the generic tool view. Tool state/error are preserved, and completed question tools cannot be submitted again. A custom registry entry for the original tool name takes precedence; custom entries for canonical widget names override builtins too.

Question responses through Chat become user messages containing selected labels and custom text. For structured responses with widget IDs, use WidgetProvider and its respondToWidget callback with MessageContent/WidgetRenderer. Standalone QuestionWidget returns { values: string[], text?: string } directly.

Public helpers: computeToolWidget, computeToolState, computeDiff, computeTextDiff, normalizeSearchResults, and safeResultUrl. Computed text diffs use one replacement hunk with three context lines; they preserve unchanged edges and final-newline markers. Supplied unified diffs retain their original hunks and file headers.

Distribution

npm run build emits ESM, CommonJS, TypeScript declarations, source maps, and CSS assets. Both JS entry points preserve "use client" for React Server Component consumers. React/React DOM are peers; the package does not depend on Next.js or the AI SDK.

Preparing the 0.0.2 release

The chat package is versioned independently of the private workspace root. For this release, @sarchauhan/chat is 0.0.2, its protocol dependency is 0.0.3, and its adapter dependency remains at 0.0.1.

From the repository root, verify the release before publishing:

npm ci
npm test
npm run typecheck
npm pack -w @sarchauhan/chat --dry-run
node packages/chat/test/package-smoke.mjs

Confirm that the package preview includes both JS entry points, TypeScript declarations, CSS assets, the README, and the changelog. The package smoke check installs the protocol and chat tarballs outside the workspace with the published adapter, then checks ESM, CommonJS, rendering, and protocol helpers. Workspace builds alone do not validate this dependency boundary.

Publish protocol before chat: published protocol 0.0.1 and 0.0.2 lack the required helpers. An authenticated maintainer can publish explicitly after the checks pass:

npm publish -w @sarchauhan/protocol --access public
npm view @sarchauhan/[email protected] version
npm publish -w @sarchauhan/chat --access public

Created files and images

Existing protocol file parts now render as artifact cards with image thumbnails, preview, open, and download actions. No changes to existing file event producers are needed.

Use ArtifactWidget for one file and ArtifactsWidget for a list. Text previews are escaped text; HTML and SVG are never embedded as active documents. Relative/signed download URLs remain owned by the backend. Raster images, HTTP(S), and blob URLs are supported; unsafe executable URLs are rejected. Browser cross-origin download behavior depends on the backend's Content-Disposition header.

For creation states and metadata, use the additive data envelope:

import { createArtifactData } from "@sarchauhan/protocol";
writer.write(createArtifactData({
  id: "report-1", filename: "report.md", mediaType: "text/markdown",
  status: "creating",
}));
// Later: same ID, complete snapshot replaces the card in place.
writer.write(createArtifactData({
  id: "report-1", filename: "report.md", mediaType: "text/markdown",
  status: "ready", url: "/files/report.md",
  content: "# Results\n\nThe adapter is ready.", sizeBytes: 1204,
}));

Tool outputs with an explicit { artifact } or { artifacts: [...] } envelope also compute these views for otherwise unrecognized tool names. Local filesystem paths are not assumed to be browser-downloadable URLs. The widget registry includes artifact and artifacts.

Integrated subagents

A subagent appears as a compact activity card in the parent conversation. Its inspection view uses the same accessible dialog on every screen: a centered modal above 640px and a bottom sheet at or below 640px. It supports Escape/backdrop dismissal, focus containment/restoration, reduced motion, safe-area padding, a scrolling activity transcript, nested tool views, and created artifacts. Portal content inherits the host theme and custom chat tokens.

import { createSubagentData } from "@sarchauhan/protocol";
writer.write(createSubagentData({
  id: "session-1:research-1", parentId: "session-1:main",
  title: "Research agent", task: "Compare the storage options",
  state: "running", progress: 0.6,
  messages: [{
    id: "reply-1", role: "assistant",
    parts: [{ type: "text", text: "Checking the adapter contract." }],
  }],
}));
// Another full snapshot with the same ID updates the existing card/dialog.

AgentSubagent is independent of any harness. Map backend states into queued, running, completed, failed, or cancelled. IDs identify runs, not just agent names; namespace them across sessions/harnesses. parentId is optional correlation metadata. Progress is an optional fraction, not a fabricated estimate. Messages and artifacts are optional; include only the activity intended for users. System messages are excluded from the inspection transcript.

The event remains an existing AgentDataEvent (data-subagent); no new top-level event/part union or transport is introduced. Only data-subagent and data-artifact events with IDs replace previous snapshots within a message. Other data events retain append semantics. Each snapshot is complete: omitted fields are cleared rather than implicitly merged. Producers own event ordering and persistence; use one parent message per run or replace the prior parent message snapshot when continuing across turns. A harness that does not provide activity still produces a useful status/task card.

Use SubagentWidget directly for custom layouts, or let Chat/MessageContent render data-subagent through the builtin registry. Multiple run IDs render separate cards. Inspection nesting is bounded to three levels while keeping deeper status cards visible.