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

@weaveintel/collab

v0.1.1

Published

Real-time collaboration + CRDT co-editing — one presence model, a CoeditDoc port with an RGA reference adapter, and the AI-as-editing-peer.

Downloads

238

Readme

@weaveintel/collab

One package for real-time collaboration in AI apps — co-edit a document with other people and the AI agent, see who's here, share and hand off live work. Tiny, zero-dependency, and built so the co-editing engine is swappable.

New to this? "Collaboration" here means more than one person — or a person and an AI — working on the same thing at the same time: seeing each other's cursors in a shared document, a run you both watch live, handing a task to a teammate. This package holds the small, proven building blocks for all of that. It merges what used to be two packages (coedit + collaboration) into one.

Why it exists (the story)

Two people typing into the same paragraph at the same moment is a genuinely hard problem: naïvely, "insert at position 5" means something different on each screen the instant the other person types, so the copies drift apart. The fix is a CRDT (Conflict-free Replicated Data Type) — the maths behind Google Docs and Figma multiplayer — where every copy always rebuilds the identical result with no central lock. Add an AI agent as just another participant, and you have a document a human and a model write together. This package gives you that, plus the surrounding multiplayer plumbing (presence, sharing, live subscriptions, handoff) that a collaborative AI product needs.

When to reach for it (and when not)

  • Reach for it when a document, note, or run is edited or watched by more than one party at once — including the AI — and you need it to converge, show live cursors, or be shared/handed off.
  • Don't reach for it for a single-user draft with one writer and no live sharing — plain storage is simpler. And you do not need it just to call a model; that's @weaveintel/runtime.
  • Already run Yjs? You can keep it — see Swapping the engine below. You do not have to adopt our CRDT to use the presence / sharing / agent-peer parts.

Quick start — co-edit a document

import { createRgaDoc } from '@weaveintel/collab';

// Two replicas — different people, or a person and the AI. Each has a unique site id.
const alice = createRgaDoc('alice');
const bob = createRgaDoc('bob');

const seed = alice.insert(0, 'Hello!'); // Alice types
bob.applyOps(seed);                      // …delivered to Bob

// Now they edit the SAME spot at the SAME time:
const a = alice.insert(5, ' Alice');     // "Hello Alice!"
const b = bob.insert(5, ' Bob');         // "Hello Bob!"

bob.applyOps(a);
alice.applyOps(b);

alice.text() === bob.text();             // ✅ true — both converged, nobody's edit lost

Only a peer is missing part of the history? Send exactly the missing bit — bandwidth-minimal, and the same call whether they were offline for a second or a week:

const missing = alice.opsSince(bob.stateVector()); // precisely what Bob lacks
bob.applyOps(missing);                              // caught up

The AI as a co-editing peer

The differentiator: the agent is just another replica. Its streamed output merges with concurrent human edits automatically — no locking, no "the agent overwrote my paragraph".

import { createRgaDoc, createAgentPeer, agentSiteId } from '@weaveintel/collab';

const doc = createRgaDoc(agentSiteId(runId));  // a reserved agent site id
const agent = createAgentPeer(doc);            // direct co-editor
agent.append('text the model just streamed');  // merges with whatever the human is typing

Research note (mid-2026): a user study found people prefer the agent as a suggester — tracked changes they accept — for large or overlapping edits. Pass { mode: 'suggest' } and you get the ops back without applying them, so your app can gate them behind a human's ✓/✕.

Swapping the engine — the CoeditDoc port

Everything above talks to a small interface, CoeditDoc (insert / delete / applyOps / snapshot / fork / anchor). The built-in RGA (createRgaDoc) is the default, zero-dependency engine — but it is an adapter behind the port, not welded in. If your stack already runs Yjs, or you want a different CRDT/OT engine, you write one small adapter and everything else — the sync loop, the live cursors, the AI peer — keeps working unchanged.

We do not add a Yjs dependency; the adapter lives in your app. To prove a swapped-in engine behaves identically, run the shipped conformance contract against it:

import { describe, it, expect } from 'vitest';
import { coeditDocContract } from '@weaveintel/collab';
import { createYjsDoc } from './my-yjs-adapter.js';

// The exact suite the built-in RGA passes: convergence, idempotent merge,
// snapshot round-trip, state-vector deltas, fork isolation, cursor anchoring.
coeditDocContract(createYjsDoc, { describe, it, expect });

👉 Full worked Yjs adapter + method-by-method map: docs/adapters.md.

What's in the box

Co-editing (the CRDT side)

| Primitive | What it does | |---|---| | CoeditDoc (port) + createRgaDoc / fromRgaDoc | The co-editing seam and its zero-dependency RGA reference adapter. insert/delete return ops to broadcast; applyOps merges; opsSince/stateVector sync; snapshot persists; fork makes a speculative shadow; anchor/resolve pin cursors. | | coeditDocContract | The conformance suite every adapter must pass (RGA today, Yjs tomorrow) — the guarantee behind "the engine is swappable". | | RgaDoc | The raw RGA text CRDT, if you want it directly. Convergent, idempotent, causal-buffered; verified against the Kleppmann/Gomes proof. | | Awareness + cursorFromIndex/indexFromCursor | Ephemeral live cursors anchored to a character (not an integer offset), so they don't jump when others edit. Last-write-wins per peer, TTL-expired (Yjs-convention). | | createAgentPeer | The AI as a co-editing peerdirect or suggest (human-in-the-loop) mode. | | peerColor / AI_PARTICIPANT / sanitizeAwarenessState | Live-presence helpers: a stable, accessible per-peer cursor colour; the synthetic "weaveIntel AI" participant; and a strict sanitiser the server runs over incoming cursor frames (bounded + inert — presence is un-authenticated chatter). | | BlockDoc (+ pmToBlocks, blocksToMarkdown/blocksToHtml, validateClientBlockOps, diffBlocks) | The rich-text / block-document CRDT on the same RGA — co-edit a structured note (headings, lists, to-dos, code) with inline marks, convert to/from Tiptap JSON, and diff-on-save. | | validateClientOps | The trusted-relay op validator — anti-forgery (a peer can't author ops as another site), size/flood caps, shape checks. |

Multiplayer (the session/presence side)

| Primitive | What it does | |---|---| | createInMemoryPresenceManager | Presence — a heartbeat-driven, TTL-expiring "who's here" set (agents are first-class peers). Port + in-memory adapter; your app supplies a SQL adapter. Snapshot-not-delta, ephemeral, server-derived identity. | | createInMemorySessionManager | Shared sessions — turn a single-owner run multi-user with roles (owner / collaborator / viewer); invite links layer on top. | | createInMemorySubscriptionManager | Durable subscriptions — "notify me when this finishes, even if I close the tab." | | createInMemoryCommentManager / AnnotationManager | Run comments (threaded, anchored to a stable part) and annotation scores (the bridge to eval datasets). | | createInMemoryHandoffManager | Unified handoff — one durable, audited lifecycle for passing the baton user↔user, agent↔human (escalation), agent↔agent. | | PresenceStatus / PeerKind / PeerIdentity | The one shared presence vocabulary both the ephemeral (cursor) and durable (session) layers speak. |

Every manager ships as a port + in-memory reference adapter + a shared contract test, so an app's SQL adapter is provably behaviour-identical. That's the same port-is-the-product pattern as CoeditDoc.

The algorithm (RGA), briefly

Chosen after a mid-2026 survey — it's what Automerge ships and the simplest sequence CRDT that is provably convergent (verified against the Kleppmann/Gomes Isabelle proof + Sypytkowski's reference):

  • Element id = (counter, siteId) — globally unique, totally ordered.
  • Insert-after-reference: an insert records the id of the element it follows, never an absolute index.
  • The one convergence rule: among elements sharing a reference, order by descending id. Every replica sorts the same way, so applying the same ops in any order yields byte-identical text.
  • Delete = tombstone (hidden, not erased, so it still anchors others). Causal buffering holds an op until its dependency arrives.

License

MIT.