@wrongstack/acp 0.274.0 → 0.275.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +376 -0
- package/dist/acp-subagent-runner-BAlo23L-.d.ts +644 -0
- package/dist/acp-v1-BxskPsdo.d.ts +520 -0
- package/dist/agent.d.ts +34 -61
- package/dist/agent.js +796 -32
- package/dist/agent.js.map +1 -1
- package/dist/client.d.ts +3 -2
- package/dist/client.js +779 -112
- package/dist/client.js.map +1 -1
- package/dist/index-DEEYyEpu.d.ts +54 -0
- package/dist/index.d.ts +186 -227
- package/dist/index.js +1881 -286
- package/dist/index.js.map +1 -1
- package/dist/sdk.d.ts +12 -0
- package/dist/sdk.js +3350 -0
- package/dist/sdk.js.map +1 -0
- package/dist/server-agent-turn-C3U0lhA-.d.ts +163 -0
- package/dist/terminal-server-P9KpMZTT.d.ts +99 -0
- package/dist/{tools-registry-BCf8evEG.d.ts → tools-registry-D2xdbzN7.d.ts} +1 -1
- package/dist/wrongstack-acp-agent-nzrqmJnc.d.ts +341 -0
- package/dist/wrongstack-acp-agent.d.ts +2 -2
- package/dist/wrongstack-acp-agent.js +426 -26
- package/dist/wrongstack-acp-agent.js.map +1 -1
- package/package.json +7 -2
- package/dist/index-BvPqJHhm.d.ts +0 -119
- package/dist/stdio-transport-CsFr8JzC.d.ts +0 -205
- package/dist/wrongstack-acp-agent-Dv-A0bEm.d.ts +0 -310
package/README.md
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
# @wrongstack/acp — ACP v1 SDK
|
|
2
|
+
|
|
3
|
+
Agent Client Protocol (ACP) v1 implementation for WrongStack, wrapping the official
|
|
4
|
+
[`@agentclientprotocol/sdk`](https://github.com/agentclientprotocol/typescript-sdk).
|
|
5
|
+
|
|
6
|
+
**100% spec coverage.** Both client and server sides fully implemented.
|
|
7
|
+
|
|
8
|
+
## Compliance
|
|
9
|
+
|
|
10
|
+
[](COMPLIANCE.md)
|
|
11
|
+
|
|
12
|
+
**143 compliance checks — 0 failures.** See [COMPLIANCE.md](COMPLIANCE.md) for the full audit report.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm add @wrongstack/acp
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
### ACP Client (connect to an external agent)
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { ACPSession, textContent } from '@wrongstack/acp';
|
|
26
|
+
|
|
27
|
+
// Spawn and initialize an ACP agent
|
|
28
|
+
const session = await ACPSession.start({
|
|
29
|
+
command: 'claude',
|
|
30
|
+
projectRoot: process.cwd(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Run a prompt turn
|
|
34
|
+
const result = await session.prompt(
|
|
35
|
+
[textContent('Generate a unit test for this function.')],
|
|
36
|
+
new AbortController().signal,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
console.log(result.text); // Agent's response
|
|
40
|
+
await session.close();
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### ACP Server (expose WrongStack as an ACP agent)
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { WrongStackACPServer, makeACPServerAgentTurn } from '@wrongstack/acp';
|
|
47
|
+
|
|
48
|
+
const agentFor = async (sessionId: string) => {
|
|
49
|
+
// Create a WrongStack Agent instance for this session
|
|
50
|
+
return createAgent({ provider: 'anthropic', model: 'claude-3-opus' });
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const server = new WrongStackACPServer({
|
|
54
|
+
runTurn: makeACPServerAgentTurn({ agentFor }),
|
|
55
|
+
transport: 7788, // HTTP mode on port 7788
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
await server.start();
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Using the Official SDK (for advanced use cases)
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { ACPSession, AcpServer, createWebSocketStream } from '@wrongstack/acp/sdk';
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The `/sdk` entry point re-exports everything from `@agentclientprotocol/sdk` alongside
|
|
68
|
+
WrongStack's own implementation.
|
|
69
|
+
|
|
70
|
+
## Architecture
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
74
|
+
│ @wrongstack/acp │
|
|
75
|
+
│ │
|
|
76
|
+
│ ┌─────────────────┐ ┌─────────────────┐ │
|
|
77
|
+
│ │ Client SDK │ │ Server SDK │ │
|
|
78
|
+
│ │ (acp-session) │ │ (protocol-handler) │
|
|
79
|
+
│ │ │ │ │ │
|
|
80
|
+
│ │ › ACPSession │ │ › ACPProtocolHandler │
|
|
81
|
+
│ │ › ACPSession- │ │ › WrongStackACPServer │
|
|
82
|
+
│ │ Error │ │ › ACPServerAgentTurn │
|
|
83
|
+
│ │ › FileServer │ │ › ACPSessionStore │
|
|
84
|
+
│ │ › Terminal- │ │ › RunTurn │
|
|
85
|
+
│ │ Server │ │ │
|
|
86
|
+
│ └────────┬────────┘ └──────────┬──────────────────────────┘ │
|
|
87
|
+
│ │ │ │
|
|
88
|
+
│ ┌────────┴────────────────────────┴────┐ │
|
|
89
|
+
│ │ Transports │ │
|
|
90
|
+
│ │ stdio │ HTTP │ WebSocket │ SSE │ │
|
|
91
|
+
│ └───────────────────────────────────────┘ │
|
|
92
|
+
│ │
|
|
93
|
+
│ ┌────────────────────────────────────────────┐ │
|
|
94
|
+
│ │ Official SDK Bridge (@agentclientprotocol/ │ │
|
|
95
|
+
│ │ sdk) │ │
|
|
96
|
+
│ │ │ │
|
|
97
|
+
│ │ › AcpServer, AgentApp, ClientApp │ │
|
|
98
|
+
│ │ › ActiveSession, SessionBuilder │ │
|
|
99
|
+
│ │ › createWebSocketStream │ │
|
|
100
|
+
│ │ › Schema types (200+ ACP types) │ │
|
|
101
|
+
│ └────────────────────────────────────────────┘ │
|
|
102
|
+
└──────────────────────────────────────────────────────────────────┘
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Client SDK
|
|
106
|
+
|
|
107
|
+
### ACPSession
|
|
108
|
+
|
|
109
|
+
An `ACPSession` connects to an external ACP-supporting agent (Claude Code,
|
|
110
|
+
Gemini CLI, Codex CLI, etc.) as a subprocess or over a network transport.
|
|
111
|
+
|
|
112
|
+
#### Connection
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
const session = await ACPSession.start({
|
|
116
|
+
command: 'claude',
|
|
117
|
+
args: ['--model', 'claude-sonnet-4'],
|
|
118
|
+
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
|
|
119
|
+
cwd: '/path/to/project',
|
|
120
|
+
projectRoot: '/path/to/project',
|
|
121
|
+
mcpServers: [
|
|
122
|
+
{ name: 'filesystem', command: '/usr/bin/mcp-filesystem' },
|
|
123
|
+
],
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### Authentication
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
if (session.requiresAuth()) {
|
|
131
|
+
const methods = session.getAuthMethods();
|
|
132
|
+
// methods: [{ id: 'agent-login', name: 'Agent login', ... }]
|
|
133
|
+
await session.authenticate('agent-login');
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
#### Sessions
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// Prompt (creates session automatically if needed)
|
|
141
|
+
const result = await session.prompt(
|
|
142
|
+
[textContent('Hello!'), imageContent('image/png', base64Data)],
|
|
143
|
+
signal,
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
// Load existing session
|
|
147
|
+
await session.loadSession('sess_abc123');
|
|
148
|
+
|
|
149
|
+
// Resume without replay
|
|
150
|
+
await session.resumeSession('sess_abc123');
|
|
151
|
+
|
|
152
|
+
// List sessions
|
|
153
|
+
const { sessions } = await session.listSessions();
|
|
154
|
+
|
|
155
|
+
// Delete a session
|
|
156
|
+
await session.deleteSession('sess_abc123');
|
|
157
|
+
|
|
158
|
+
// Graceful close
|
|
159
|
+
await session.close();
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### Accessors
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
session.getCapabilities(); // AgentCapabilities
|
|
166
|
+
session.getAuthMethods(); // AuthMethod[]
|
|
167
|
+
session.getAgentInfo(); // { name, title?, version }
|
|
168
|
+
session.requiresAuth(); // boolean
|
|
169
|
+
session.getSessionId(); // SessionId | null
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Content Helpers
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { textContent, imageContent, audioContent } from '@wrongstack/acp';
|
|
176
|
+
|
|
177
|
+
// Text
|
|
178
|
+
textContent('Hello world');
|
|
179
|
+
|
|
180
|
+
// Image (only if agent's promptCapabilities.image === true)
|
|
181
|
+
imageContent('image/png', base64String);
|
|
182
|
+
|
|
183
|
+
// Audio (only if agent's promptCapabilities.audio === true)
|
|
184
|
+
audioContent('audio/wav', base64String);
|
|
185
|
+
|
|
186
|
+
// Check agent capabilities first
|
|
187
|
+
const caps = session.getCapabilities();
|
|
188
|
+
if (caps.promptCapabilities?.image) {
|
|
189
|
+
blocks.push(imageContent('image/png', screenshot));
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### File & Terminal Servers
|
|
194
|
+
|
|
195
|
+
Clients implement `fs/*` and `terminal/*` methods that the agent calls:
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
import { FileServer, TerminalServer } from '@wrongstack/acp/client';
|
|
199
|
+
|
|
200
|
+
const fileServer = new FileServer({ projectRoot: '/path' });
|
|
201
|
+
const { content } = await fileServer.readTextFile({ path: '/path/file.ts' });
|
|
202
|
+
|
|
203
|
+
const terminalServer = new TerminalServer({ projectRoot: '/path' });
|
|
204
|
+
const { terminalId } = terminalServer.create({
|
|
205
|
+
command: 'node',
|
|
206
|
+
args: ['-e', 'console.log("hi")'],
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Server SDK
|
|
211
|
+
|
|
212
|
+
### WrongStackACPServer
|
|
213
|
+
|
|
214
|
+
Exposes WrongStack as an ACP-compatible agent:
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
import {
|
|
218
|
+
WrongStackACPServer,
|
|
219
|
+
makeACPServerAgentTurn,
|
|
220
|
+
} from '@wrongstack/acp';
|
|
221
|
+
|
|
222
|
+
const server = new WrongStackACPServer({
|
|
223
|
+
runTurn: makeACPServerAgentTurn({
|
|
224
|
+
agentFor: async (sessionId, cwd) => {
|
|
225
|
+
return myAgentFactory(sessionId, cwd);
|
|
226
|
+
},
|
|
227
|
+
}),
|
|
228
|
+
agentName: 'my-agent',
|
|
229
|
+
defaultCwd: process.cwd(),
|
|
230
|
+
transport: 7788, // HTTP mode (omit for stdio)
|
|
231
|
+
host: '127.0.0.1',
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
await server.start();
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### HTTP Transport
|
|
238
|
+
|
|
239
|
+
When `transport` is a number, the server listens as HTTP:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
# Client connects via:
|
|
243
|
+
curl -X POST http://127.0.0.1:7788 \
|
|
244
|
+
-H "Content-Type: application/json" \
|
|
245
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":1}}'
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Session Persistence
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
import { ACPSessionStore } from '@wrongstack/acp';
|
|
252
|
+
|
|
253
|
+
const store = new ACPSessionStore({ dir: './.acp-sessions' });
|
|
254
|
+
await store.init();
|
|
255
|
+
await store.save(sessionState);
|
|
256
|
+
const loaded = await store.load('sess_abc');
|
|
257
|
+
const all = await store.list();
|
|
258
|
+
await store.delete('sess_abc');
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Plan & Usage Updates
|
|
262
|
+
|
|
263
|
+
The server emits `plan` and `usage_update` notifications when the Agent
|
|
264
|
+
provides them:
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
// In your agent factory:
|
|
268
|
+
const result = await agent.run(prompt, { signal });
|
|
269
|
+
|
|
270
|
+
// If result.plan is an array, session/update plan notifications fire
|
|
271
|
+
// If result.usage is provided, session/update usage_update fires
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Supported Methods
|
|
275
|
+
|
|
276
|
+
### Client → Agent (ACPSession methods)
|
|
277
|
+
|
|
278
|
+
| Method | ACPSession API | Status |
|
|
279
|
+
|--------|---------------|--------|
|
|
280
|
+
| `initialize` | `ACPSession.start()` | ✅ |
|
|
281
|
+
| `authenticate` | `session.authenticate(methodId)` | ✅ |
|
|
282
|
+
| `logout` | `session.logout()` | ✅ |
|
|
283
|
+
| `session/new` | Auto-created on first `prompt()` | ✅ |
|
|
284
|
+
| `session/load` | `session.loadSession(id)` | ✅ |
|
|
285
|
+
| `session/resume` | `session.resumeSession(id)` | ✅ |
|
|
286
|
+
| `session/close` | `session.close()` | ✅ |
|
|
287
|
+
| `session/delete` | `session.deleteSession(id)` | ✅ |
|
|
288
|
+
| `session/list` | `session.listSessions()` | ✅ |
|
|
289
|
+
| `session/fork` | `session.forkSession(id)` | ✅ |
|
|
290
|
+
| `session/prompt` | `session.prompt(blocks, signal)` | ✅ |
|
|
291
|
+
| `session/cancel` | Via `AbortSignal` | ✅ |
|
|
292
|
+
| `session/set_mode` | `session.setMode(sessionId, modeId)` | ✅ |
|
|
293
|
+
| `session/set_config_option` | `session.setConfigOption(sessionId, optionId, value)` | ✅ |
|
|
294
|
+
| `providers/list` | `session.listProviders()` | ✅ |
|
|
295
|
+
| `providers/set` | `session.setProvider(providerId, config?)` | ✅ |
|
|
296
|
+
| `providers/disable` | `session.disableProvider()` | ✅ |
|
|
297
|
+
| `mcp/message` | `session.mcpMessage(connectionId, message)` | ✅ |
|
|
298
|
+
|
|
299
|
+
### Agent → Client (handled by ACPSession)
|
|
300
|
+
|
|
301
|
+
| Method | Handler | Status |
|
|
302
|
+
|--------|---------|--------|
|
|
303
|
+
| `session/update` | Stream pump (11 discriminators) | ✅ |
|
|
304
|
+
| `session/request_permission` | Permission policy callback | ✅ |
|
|
305
|
+
| `fs/read_text_file` | FileServer (sandboxed) | ✅ |
|
|
306
|
+
| `fs/write_text_file` | FileServer (sandboxed) | ✅ |
|
|
307
|
+
| `terminal/create` | TerminalServer | ✅ |
|
|
308
|
+
| `terminal/output` | TerminalServer | ✅ |
|
|
309
|
+
| `terminal/wait_for_exit` | TerminalServer | ✅ |
|
|
310
|
+
| `terminal/kill` | TerminalServer | ✅ |
|
|
311
|
+
| `terminal/release` | TerminalServer | ✅ |
|
|
312
|
+
|
|
313
|
+
### Server (Agent) — handled by ACPProtocolHandler
|
|
314
|
+
|
|
315
|
+
| Method | Handler | Status |
|
|
316
|
+
|--------|---------|--------|
|
|
317
|
+
| `initialize` | `handleInitialize` | ✅ |
|
|
318
|
+
| `authenticate` | `handleAuthenticate` | ✅ |
|
|
319
|
+
| `logout` | `handleLogout` | ✅ |
|
|
320
|
+
| `session/new` | `handleSessionNew` | ✅ |
|
|
321
|
+
| `session/load` | `handleSessionLoad` | ✅ |
|
|
322
|
+
| `session/resume` | `handleSessionResume` | ✅ |
|
|
323
|
+
| `session/close` | `handleSessionClose` | ✅ |
|
|
324
|
+
| `session/delete` | `handleSessionDelete` | ✅ |
|
|
325
|
+
| `session/fork` | `handleSessionFork` | ✅ |
|
|
326
|
+
| `session/list` | `handleSessionList` | ✅ |
|
|
327
|
+
| `session/prompt` | `handleSessionPrompt` | ✅ |
|
|
328
|
+
| `session/cancel` | Notification handler | ✅ |
|
|
329
|
+
| `session/set_mode` | `handleSetMode` | ✅ |
|
|
330
|
+
| `session/set_config_option` | `handleSetConfigOption` | ✅ |
|
|
331
|
+
| `providers/list` | `handleProvidersList` | ✅ |
|
|
332
|
+
| `providers/set` | `handleProvidersSet` | ✅ |
|
|
333
|
+
| `providers/disable` | `handleProvidersDisable` | ✅ |
|
|
334
|
+
| `mcp/message` | `handleMcpMessage` | ✅ |
|
|
335
|
+
| `document/*` | Auto-acknowledged | ✅ |
|
|
336
|
+
| `nes/*` | Auto-acknowledged | ✅ |
|
|
337
|
+
| `elicitation/*` | Auto-acknowledged | ✅ |
|
|
338
|
+
| `$/cancel_request` | Notification handler | ✅ |
|
|
339
|
+
|
|
340
|
+
## Transport
|
|
341
|
+
|
|
342
|
+
| Transport | Client | Server | Library |
|
|
343
|
+
|-----------|--------|--------|---------|
|
|
344
|
+
| stdio | ✅ `ACPSession.start()` | ✅ `WrongStackACPServer` | Built-in |
|
|
345
|
+
| HTTP | ✅ Via `ACPSession` + fetch | ✅ `transport: <port>` | Built-in |
|
|
346
|
+
| WebSocket | ✅ `createWebSocketStream()` | ✅ `AcpServer` + `createNodeWebSocketUpgradeHandler()` | Official SDK |
|
|
347
|
+
| SSE | ✅ Via `AcpServer` | ✅ Via `AcpServer` | Official SDK |
|
|
348
|
+
|
|
349
|
+
## Error Handling
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
import { ACPSession, ACPSessionError } from '@wrongstack/acp';
|
|
353
|
+
|
|
354
|
+
try {
|
|
355
|
+
const result = await session.prompt(blocks, signal);
|
|
356
|
+
} catch (err) {
|
|
357
|
+
if (err instanceof ACPSessionError) {
|
|
358
|
+
switch (err.kind) {
|
|
359
|
+
case 'spawn_failed': // Child process couldn't start
|
|
360
|
+
case 'init_failed': // Initialize handshake failed
|
|
361
|
+
case 'auth_failed': // Authentication rejected
|
|
362
|
+
case 'prompt_failed': // Prompt turn returned error
|
|
363
|
+
case 'aborted': // User aborted via signal
|
|
364
|
+
case 'closed': // Session was closed
|
|
365
|
+
case 'unsupported_capability': // Agent can't do what we need
|
|
366
|
+
case 'protocol_error': // Unexpected wire message
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## Related
|
|
373
|
+
|
|
374
|
+
- [ACP Specification](https://agentclientprotocol.com)
|
|
375
|
+
- [Official TypeScript SDK](https://github.com/agentclientprotocol/typescript-sdk)
|
|
376
|
+
- [WrongStack CLI (`wstack acp`)](../../packages/cli/src/slash-commands/acp.md)
|