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

@wrongstack/acp

v0.318.0

Published

ACP (Agent Client Protocol) integration for WrongStack — client + agent support

Readme

@wrongstack/acp — ACP v1 SDK

Agent Client Protocol (ACP) v1 implementation for WrongStack. The live client and server use WrongStack's JSON-RPC implementation; the /sdk export provides the official @agentclientprotocol/sdk APIs.

WrongStack implements the ACP v1 client and server session flows, with stdio and WebSocket support plus an HTTP server transport. Some optional protocol surfaces are intentionally unavailable; see COMPLIANCE.md for the tested surface and current limitations.

Public entry points

| Import | Authority | |---|---| | @wrongstack/acp | WrongStack's v1 client/server implementation, integrations, and stable v1 contracts | | @wrongstack/acp/client | Client-only implementation surface | | @wrongstack/acp/agent | Server/agent-only implementation surface | | @wrongstack/acp/v1 | WrongStack-owned stable v1 protocol contracts only | | @wrongstack/acp/sdk | Official @agentclientprotocol/sdk APIs and experimental transport helpers | | @wrongstack/acp/legacy | Deprecated pre-v1 draft envelope types; compatibility only |

New code must not import legacy draft contracts from the package root. Use /v1 for protocol types and /sdk only when intentionally adopting the upstream SDK.

Compliance

The package test suite includes client/server protocol tests and an in-process JSON round-trip loopback test. See COMPLIANCE.md for the method matrix and the distinction between wire handling and functional behavior.

Installation

pnpm add @wrongstack/acp

Quick Start

ACP Client (connect to an external agent)

import { ACPSession, textContent } from '@wrongstack/acp';

// Spawn and initialize an ACP agent
const session = await ACPSession.start({
  command: 'claude',
  projectRoot: process.cwd(),
});

// Run a prompt turn
const result = await session.prompt(
  [textContent('Generate a unit test for this function.')],
  new AbortController().signal,
);

console.log(result.text); // Agent's response
await session.close();

ACP Server (expose WrongStack as an ACP agent)

import { WrongStackACPServer, makeACPServerAgentTurn } from '@wrongstack/acp/agent';

const agentFor = async (sessionId: string) => {
  // Create a WrongStack Agent instance for this session
  return createAgent({ provider: 'anthropic', model: 'claude-3-opus' });
};

const server = new WrongStackACPServer({
  runTurn: makeACPServerAgentTurn({ agentFor }),
  transport: 7788, // HTTP mode on port 7788
});

await server.start();

Using the Official SDK (for advanced use cases)

import {
  AcpServer,
  AgentApp,
  createHttpStream,
  createWebSocketStream,
} from '@wrongstack/acp/sdk';

The /sdk entry point re-exports the official SDK's public high-level APIs, method constants, and experimental HTTP/Node/WebSocket helpers. WrongStack's ACPSession is intentionally available from the package root or /client, not from /sdk.

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                       @wrongstack/acp                            │
│                                                                 │
│   ┌─────────────────┐    ┌─────────────────┐                    │
│   │  Client SDK     │    │  Server SDK     │                    │
│   │  (acp-session)  │    │  (protocol-handler)                   │
│   │                 │    │                  │                    │
│   │  › ACPSession   │    │  › ACPProtocolHandler                │
│   │  › ACPSession-  │    │  › WrongStackACPServer               │
│   │    Error         │    │  › ACPServerAgentTurn                │
│   │  › FileServer   │    │  › ACPSessionStore                   │
│   │  › Terminal-    │    │  › RunTurn                           │
│   │    Server       │    │                                      │
│   └────────┬────────┘    └──────────┬──────────────────────────┘ │
│            │                        │                            │
│   ┌────────┴────────────────────────┴────┐                       │
│   │         Transports                    │                       │
│   │  stdio │ HTTP │ WebSocket │ SSE      │                       │
│   └───────────────────────────────────────┘                       │
│                                                                   │
│   ┌────────────────────────────────────────────┐                  │
│   │  Official SDK Bridge (@agentclientprotocol/ │                  │
│   │  sdk)                                      │                  │
│   │                                            │                  │
│   │  › AcpServer, AgentApp, ClientApp          │                  │
│   │  › ActiveSession, SessionBuilder           │                  │
│   │  › createWebSocketStream                   │                  │
│   │  › Schema types (200+ ACP types)           │                  │
│   └────────────────────────────────────────────┘                  │
└──────────────────────────────────────────────────────────────────┘

Client SDK

ACPSession

An ACPSession connects to an external ACP-supporting agent (Claude Code, Gemini CLI, Codex CLI, etc.) as a subprocess or over a network transport.

Connection

const session = await ACPSession.start({
  command: 'claude',
  args: ['--model', 'anthropic-test-model'],
  env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
  cwd: '/path/to/project',
  projectRoot: '/path/to/project',
  mcpServers: [
    { name: 'filesystem', command: '/usr/bin/mcp-filesystem' },
  ],
});

Authentication

if (session.requiresAuth()) {
  const methods = session.getAuthMethods();
  // methods: [{ id: 'agent-login', name: 'Agent login', ... }]
  await session.authenticate('agent-login');
}

Sessions

// Prompt (creates session automatically if needed)
const result = await session.prompt(
  [textContent('Hello!'), imageContent('image/png', base64Data)],
  signal,
);

// Load existing session
await session.loadSession('sess_abc123');

// Resume without replay
await session.resumeSession('sess_abc123');

// List sessions
const { sessions } = await session.listSessions();

// Delete a session
await session.deleteSession('sess_abc123');

// Graceful close
await session.close();

Accessors

session.getCapabilities();       // AgentCapabilities
session.getAuthMethods();        // AuthMethod[]
session.getAgentInfo();          // { name, title?, version }
session.requiresAuth();          // boolean
session.getSessionId();          // SessionId | null

Content Helpers

import { textContent, imageContent, audioContent } from '@wrongstack/acp';

// Text
textContent('Hello world');

// Image (only if agent's promptCapabilities.image === true)
imageContent('image/png', base64String);

// Audio (only if agent's promptCapabilities.audio === true)
audioContent('audio/wav', base64String);

// Check agent capabilities first
const caps = session.getCapabilities();
if (caps.promptCapabilities?.image) {
  blocks.push(imageContent('image/png', screenshot));
}

File & Terminal Servers

Clients implement fs/* and terminal/* methods that the agent calls:

import { FileServer, TerminalServer } from '@wrongstack/acp/client';

const fileServer = new FileServer({ projectRoot: '/path' });
const { content } = await fileServer.readTextFile({ path: '/path/file.ts' });

const terminalServer = new TerminalServer({ projectRoot: '/path' });
const { terminalId } = terminalServer.create({
  command: 'node',
  args: ['-e', 'console.log("hi")'],
});

Server SDK

WrongStackACPServer

Exposes WrongStack as an ACP-compatible agent:

import {
  WrongStackACPServer,
  makeACPServerAgentTurn,
} from '@wrongstack/acp/agent';

const server = new WrongStackACPServer({
  runTurn: makeACPServerAgentTurn({
    agentFor: async (sessionId, cwd) => {
      return myAgentFactory(sessionId, cwd);
    },
  }),
  agentName: 'my-agent',
  defaultCwd: process.cwd(),
  transport: 7788,            // HTTP mode (omit for stdio)
  host: '127.0.0.1',
});

await server.start();

HTTP Transport

When transport is a number, the server listens as HTTP:

# Client connects via:
curl -X POST http://127.0.0.1:7788 \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":1}}'

Session Persistence

import { ACPSessionStore } from '@wrongstack/acp/agent';

const store = new ACPSessionStore({ dir: './.acp-sessions' });
await store.init();
await store.save(sessionState);
const loaded = await store.load('sess_abc');
const all = await store.list();
await store.delete('sess_abc');

Plan & Usage Updates

The server emits plan and usage_update notifications when the Agent provides them:

// In your agent factory:
const result = await agent.run(prompt, { signal });

// If result.plan is an array, session/update plan notifications fire
// If result.usage is provided, session/update usage_update fires

Supported Methods

Client → Agent (ACPSession methods)

| Method | ACPSession API | Status | |--------|---------------|--------| | initialize | ACPSession.start() | ✅ | | authenticate | session.authenticate(methodId) | ✅ | | logout | session.logout() | ✅ | | session/new | Auto-created on first prompt() | ✅ | | session/load | session.loadSession(id) | ✅ | | session/resume | session.resumeSession(id) | ✅ | | session/close | session.close() | ✅ | | session/delete | session.deleteSession(id) | ✅ | | session/list | session.listSessions() | ✅ | | session/fork | session.forkSession(id) | ✅ | | session/prompt | session.prompt(blocks, signal) | ✅ | | session/cancel | Via AbortSignal | ✅ | | session/set_mode | session.setMode(sessionId, modeId) | ✅ | | session/set_config_option | session.setConfigOption(sessionId, optionId, value) | ✅ | | providers/list | session.listProviders() | ✅ | | providers/set | session.setProvider(providerId, config?) | ✅ | | providers/disable | session.disableProvider() | ✅ | | mcp/message | session.mcpMessage(connectionId, message) | ✅ |

Agent → Client (handled by ACPSession)

| Method | Handler | Status | |--------|---------|--------| | session/update | Stream pump (11 stable discriminators; unknown/unstable updates are tolerated) | ✅ | | session/request_permission | Permission policy callback | ✅ | | fs/read_text_file | FileServer (sandboxed) | ✅ | | fs/write_text_file | FileServer (sandboxed) | ✅ | | terminal/create | TerminalServer | ✅ | | terminal/output | TerminalServer | ✅ | | terminal/wait_for_exit | TerminalServer | ✅ | | terminal/kill | TerminalServer | ✅ | | terminal/release | TerminalServer | ✅ |

Server (Agent) — handled by ACPProtocolHandler

| Method | Handler | Status | |--------|---------|--------| | initialize | handleInitialize | ✅ | | authenticate | handleAuthenticate | ✅ | | logout | handleLogout | ✅ | | session/new | handleSessionNew | ✅ | | session/load | handleSessionLoad | ✅ | | session/resume | handleSessionResume | ✅ | | session/close | handleSessionClose | ✅ | | session/delete | handleSessionDelete | ✅ | | session/fork | handleSessionFork | ✅ | | session/list | handleSessionList | ✅ | | session/prompt | handleSessionPrompt | ✅ | | session/cancel | Notification handler | ✅ | | session/set_mode | handleSetMode | ✅ | | session/set_config_option | handleSetConfigOption | ✅ | | providers/list | Returns an empty provider list; provider configuration stays in wstack auth | Limited | | providers/set | Returns an error directing callers to wstack auth | Unsupported | | providers/disable | Acknowledges without changing CLI provider configuration | Limited | | mcp/message | Returns an unavailable error | Unsupported | | document/* | Standard method-not-found response | Unsupported | | nes/* | Standard method-not-found response | Unsupported | | elicitation/* | Standard method-not-found response | Unsupported | | $/cancel_request | Notification handler | ✅ |

Transport

| Transport | Client | Server | Library | |-----------|--------|--------|---------| | stdio | ✅ ACPSession.start() | ✅ WrongStackACPServer | Built-in | | HTTP | ❌ No ACPSession HTTP client | ✅ transport: <port> | Built-in server | | WebSocket | ✅ ACPSession.connectWebSocket() | ✅ via the CLI --ws bridge | Built-in | | SSE | SDK exports only; no WrongStack command wires it | SDK exports only; no WrongStack command wires it | Official SDK re-export |

Error Handling

import { ACPSession, ACPSessionError } from '@wrongstack/acp';

try {
  const result = await session.prompt(blocks, signal);
} catch (err) {
  if (err instanceof ACPSessionError) {
    switch (err.kind) {
      case 'spawn_failed':      // Child process couldn't start
      case 'init_failed':       // Initialize handshake failed
      case 'auth_failed':       // Authentication rejected
      case 'prompt_failed':     // Prompt turn returned error
      case 'aborted':           // User aborted via signal
      case 'closed':            // Session was closed
      case 'unsupported_capability':  // Agent can't do what we need
      case 'protocol_error':    // Unexpected wire message
    }
  }
}

Related