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

@xenosystem/agent-host-client

v0.1.0

Published

The dependency-free client for the ONE per-user XENO Agent host: find the lease, refuse a stale one, handshake, and drive conversations, provider lanes and the runtime event stream.

Readme

@xenosystem/agent-host-client

Reach the one per-user XENO Agent host from any Node process, with no dependencies.

Apps do not each embed an agent (XENO AGENT PANEL - SPEC.md §3 D1). One host runs per user and every other process attaches to it as a client — which is what buys three lanes (cloud / local / acp), one session store, one permission engine, one audit log, and the possibility of an agent that can see several apps at once.

import { attachToAgentHost, listProviders, openConversation } from '@xenosystem/agent-host-client'

const { status, connection } = await attachToAgentHost({
  clientId: 'xeno-apps',
  clientVersion: '0.1.0',
  // 🔴 Subscribe HERE, not on the returned connection: the host starts streaming on its first
  // authenticated request and the handshake IS that request.
  onEvent: (envelope) => forwardToRenderer(envelope),
})

if (status.state === 'attached') {
  const catalog = await listProviders(connection!)          // → the panel's `catalog` port
  const conversation = await openConversation(connection!)  // → its lanes, and its id
}

Four things that are easy to get wrong

  • A lease is a claim, not a fact. ~/.xeno/agent-host-v1/agent-host.lock survives a hard kill, pids get recycled, and ports get reused. assessLeaseFreshness refuses a dead one; the handshake is the only step that is evidence.
  • state: 'no-host' is the NORMAL case. Most launches happen with no agent host at all. A consumer must work completely without one.
  • Refusals arrive by two different routes. The transport answers ok:false and destroys the socket; conversation.* and provider.lanes.* answer success:false in the payload. Both are turned into throws here so a caller cannot mistake the second for success.
  • There is no lane state before a conversation exists. provider.lanes.list takes a conversationId — conversation.open returns the lanes itself.

Running a REAL host to test against

🔴 Do this before trusting any adapter written against this client. A producer written from a panel's side and a host's actual output are two different things — measured 2026-09-06, the panel package's reference adapter understood zero of a real turn's 13 events, and every unit test in that package was green.

The host composes from its own building blocks; nothing here needs credentials, because the FIXTURE is the agent and everything else is shipped code:

// packages/host/dist and packages/test-kit/dist of xeno-agent-interface
const { startLocalAgentHostAuthority } = await import('.../packages/host/dist/localHostAuthority.js')
const { AgentHostCoordinator }          = await import('.../packages/host/dist/index.js')
const { RuntimeEventStore }             = await import('.../packages/host/dist/runtime/RuntimeEventStore.js')
const { RuntimeEventStoreRepositoryAdapter } = await import('.../packages/host/dist/runtime/RuntimeEventStoreRepositoryAdapter.js')
const { AcpAgentRegistryService, createFixtureAcpAgentConfig } =
  await import('.../packages/host/dist/acp/AcpAgentRegistryService.js')
const { AcpAgentTurnExecutionAdapter, createAcpRuntimeProviderDescriptors } =
  await import('.../packages/host/dist/acp/AcpAgentTurnExecutionAdapter.js')

const registry = new AcpAgentRegistryService({ rootDir: work, registryPath: join(work, 'acp-agents.json') })
registry.saveAgent({ ...createFixtureAcpAgentConfig(work, 'normal', 'fixture-turn'),
                     env: { XENO_ACP_FIXTURE_MODE: 'normal' } })
const runtimeStore = new RuntimeEventStore(join(work, 'runtime-events'))
const providers = await createAcpRuntimeProviderDescriptors(registry)

await startLocalAgentHostAuthority({
  rootDirectory: root,                       // pass this same root to attachToAgentHost
  instanceId: `probe-${process.pid}`,
  createHostTransport: async () => new AgentHostCoordinator({
    hostVersion: '0.0.0-probe', hostInstanceId: `probe-${process.pid}`,
    processBoundary: 'per-user-service', storageSchemaVersion: 2, eventSchemaVersion: 1,
    providers,
    runtimeEventRepository: new RuntimeEventStoreRepositoryAdapter(runtimeStore),
    turnExecutionAdapters: [new AcpAgentTurnExecutionAdapter({ registryService: registry, runtimeStore })],
  }),
})

Then attach with root, call listProviders, and startTurn. Record onEvent to capture the frames.

⚠️ Two things that will look like client defects and are not:

  • conversation.open is REFUSED by a host built this way — "Host-owned provider lane services are unavailable" — because it has no ProviderLaneService. turn.start works anyway: the two are less coupled than they look.
  • The two refusals arrive by DIFFERENT routes. conversation.open fails as a transport ok:false frame; turn.start fails in band with success:false. This client turns both into throws, which is why a caller cannot mistake the second for success.

Status

⚠️ Not published, and one consumer cannot use it yet. xeno-canvas carries its own copy of this protocol in src/main/agentHost.ts — this package was derived from it — because Canvas declares zero file: dependencies and that is the only reason its CI can install. The exit is the same unexecuted clause that strands @xeno/account: published for all consumers. The duplication is recorded rather than hidden, and AGENT_HOST_PROTOCOL_VERSION is asserted on every frame so a drift between the two copies is loud instead of subtle.