@bytespell/amux 0.0.11 → 0.0.13

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.
Files changed (89) hide show
  1. package/.claude/settings.local.json +11 -0
  2. package/CLAUDE.md +104 -0
  3. package/LICENSE +21 -0
  4. package/README.md +215 -0
  5. package/dist/cli.d.ts +14 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +118 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/client.d.ts +68 -0
  10. package/dist/client.d.ts.map +1 -0
  11. package/dist/client.js +135 -0
  12. package/dist/client.js.map +1 -0
  13. package/dist/index.d.ts +41 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +44 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/{lib/mentions.d.ts → message-parser.d.ts} +3 -5
  18. package/dist/message-parser.d.ts.map +1 -0
  19. package/dist/message-parser.js +45 -0
  20. package/dist/message-parser.js.map +1 -0
  21. package/dist/message-parser.test.d.ts +2 -0
  22. package/dist/message-parser.test.d.ts.map +1 -0
  23. package/dist/message-parser.test.js +188 -0
  24. package/dist/message-parser.test.js.map +1 -0
  25. package/dist/server.d.ts +24 -0
  26. package/dist/server.d.ts.map +1 -0
  27. package/dist/server.js +356 -0
  28. package/dist/server.js.map +1 -0
  29. package/dist/session-updates.d.ts +26 -0
  30. package/dist/session-updates.d.ts.map +1 -0
  31. package/dist/session-updates.js +68 -0
  32. package/dist/session-updates.js.map +1 -0
  33. package/dist/session-updates.test.d.ts +2 -0
  34. package/dist/session-updates.test.d.ts.map +1 -0
  35. package/dist/session-updates.test.js +223 -0
  36. package/dist/session-updates.test.js.map +1 -0
  37. package/dist/session.d.ts +208 -0
  38. package/dist/session.d.ts.map +1 -0
  39. package/dist/session.js +580 -0
  40. package/dist/session.js.map +1 -0
  41. package/dist/state.d.ts +74 -0
  42. package/dist/state.d.ts.map +1 -0
  43. package/dist/state.js +250 -0
  44. package/dist/state.js.map +1 -0
  45. package/dist/terminal.d.ts +47 -0
  46. package/dist/terminal.d.ts.map +1 -0
  47. package/dist/terminal.js +137 -0
  48. package/dist/terminal.js.map +1 -0
  49. package/dist/types.d.ts +64 -2
  50. package/dist/types.d.ts.map +1 -0
  51. package/dist/types.js +16 -31
  52. package/dist/types.js.map +1 -1
  53. package/dist/ws-adapter.d.ts +39 -0
  54. package/dist/ws-adapter.d.ts.map +1 -0
  55. package/dist/ws-adapter.js +198 -0
  56. package/dist/ws-adapter.js.map +1 -0
  57. package/package.json +47 -24
  58. package/src/client.ts +162 -0
  59. package/src/index.ts +66 -0
  60. package/src/message-parser.test.ts +207 -0
  61. package/src/message-parser.ts +54 -0
  62. package/src/session-updates.test.ts +265 -0
  63. package/src/session-updates.ts +87 -0
  64. package/src/session.ts +737 -0
  65. package/src/state.ts +287 -0
  66. package/src/terminal.ts +164 -0
  67. package/src/types.ts +88 -0
  68. package/src/ws-adapter.ts +245 -0
  69. package/tsconfig.json +22 -0
  70. package/vitest.config.ts +7 -0
  71. package/dist/chunk-5IPYOXBE.js +0 -32
  72. package/dist/chunk-5IPYOXBE.js.map +0 -1
  73. package/dist/chunk-C73RKCTS.js +0 -36
  74. package/dist/chunk-C73RKCTS.js.map +0 -1
  75. package/dist/chunk-VVXT4HQM.js +0 -779
  76. package/dist/chunk-VVXT4HQM.js.map +0 -1
  77. package/dist/lib/logger.d.ts +0 -24
  78. package/dist/lib/logger.js +0 -17
  79. package/dist/lib/logger.js.map +0 -1
  80. package/dist/lib/mentions.js +0 -7
  81. package/dist/lib/mentions.js.map +0 -1
  82. package/dist/streams/backends/index.d.ts +0 -88
  83. package/dist/streams/backends/index.js +0 -13
  84. package/dist/streams/backends/index.js.map +0 -1
  85. package/dist/streams/manager.d.ts +0 -55
  86. package/dist/streams/manager.js +0 -248
  87. package/dist/streams/manager.js.map +0 -1
  88. package/dist/types-DCRtrjjj.d.ts +0 -192
  89. package/scripts/fix-pty.cjs +0 -21
@@ -0,0 +1,198 @@
1
+ import { WebSocket } from 'ws';
2
+ /**
3
+ * Create a WebSocket adapter for an AgentSession.
4
+ *
5
+ * Bridges session events to WebSocket clients and handles incoming messages.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { AgentSession } from 'amux';
10
+ * import { createWsAdapter } from 'amux/ws';
11
+ * import { WebSocketServer } from 'ws';
12
+ *
13
+ * const session = new AgentSession({ ... });
14
+ * const wss = new WebSocketServer({ server, path: '/ws' });
15
+ *
16
+ * createWsAdapter(session, wss);
17
+ *
18
+ * await session.spawnAgent();
19
+ * ```
20
+ */
21
+ export function createWsAdapter(session, wss, options = {}) {
22
+ const clients = new Set();
23
+ const sendHistoryOnConnect = options.sendHistoryOnConnect ?? true;
24
+ // Helper to broadcast to all clients
25
+ function broadcast(message) {
26
+ const data = JSON.stringify(message);
27
+ for (const client of clients) {
28
+ if (client.readyState === WebSocket.OPEN) {
29
+ client.send(data);
30
+ }
31
+ }
32
+ }
33
+ // Wire up session events to broadcast
34
+ const eventHandlers = {
35
+ ready: (data) => broadcast({ type: 'ready', ...data }),
36
+ connecting: () => broadcast({ type: 'connecting' }),
37
+ update: (data) => broadcast({ type: 'session_update', update: data }),
38
+ turn_start: () => broadcast({ type: 'turn_start' }),
39
+ turn_end: () => broadcast({ type: 'turn_end' }),
40
+ permission_request: (data) => broadcast({ type: 'permission_request', ...data }),
41
+ prompt_complete: (data) => broadcast({ type: 'prompt_complete', ...data }),
42
+ session_created: (data) => broadcast({ type: 'session_created', ...data }),
43
+ session_switched: (data) => broadcast({ type: 'session_switched', ...data }),
44
+ history_replay: (data) => broadcast({ type: 'history_replay', ...data }),
45
+ error: (data) => broadcast({ type: 'error', ...data }),
46
+ agent_exit: (data) => broadcast({ type: 'agent_exit', ...data }),
47
+ };
48
+ // Register all event handlers
49
+ for (const [event, handler] of Object.entries(eventHandlers)) {
50
+ session.on(event, handler);
51
+ }
52
+ // Handle WebSocket connections
53
+ wss.on('connection', (ws) => {
54
+ console.log('[amux-ws] Client connected');
55
+ clients.add(ws);
56
+ // Send current state to new client
57
+ if (session.isConnected) {
58
+ ws.send(JSON.stringify({
59
+ type: 'ready',
60
+ cwd: session.cwd,
61
+ sessionId: session.sessionId,
62
+ capabilities: session.agentCapabilities,
63
+ agent: session.getAgentInfo(),
64
+ availableAgents: session.getAvailableAgents(),
65
+ }));
66
+ // Send history to hydrate the chat UI
67
+ if (sendHistoryOnConnect) {
68
+ const history = session.loadHistory();
69
+ if (history.length > 0) {
70
+ ws.send(JSON.stringify({
71
+ type: 'history_replay',
72
+ previousSessionId: session.sessionId,
73
+ events: history,
74
+ eventCount: history.length,
75
+ }));
76
+ }
77
+ }
78
+ }
79
+ else {
80
+ ws.send(JSON.stringify({ type: 'connecting' }));
81
+ }
82
+ // Handle incoming messages
83
+ ws.on('message', async (data) => {
84
+ try {
85
+ const msg = JSON.parse(data.toString());
86
+ await handleMessage(ws, msg, session);
87
+ }
88
+ catch (err) {
89
+ console.error('[amux-ws] Invalid message:', err);
90
+ ws.send(JSON.stringify({ type: 'error', message: 'Invalid message format' }));
91
+ }
92
+ });
93
+ ws.on('close', () => {
94
+ console.log('[amux-ws] Client disconnected');
95
+ clients.delete(ws);
96
+ });
97
+ ws.on('error', (err) => {
98
+ console.error('[amux-ws] WebSocket error:', err);
99
+ clients.delete(ws);
100
+ });
101
+ });
102
+ return {
103
+ clientCount: () => clients.size,
104
+ broadcast,
105
+ close: () => {
106
+ for (const client of clients) {
107
+ client.close();
108
+ }
109
+ clients.clear();
110
+ },
111
+ };
112
+ }
113
+ /**
114
+ * Handle incoming WebSocket message
115
+ */
116
+ async function handleMessage(ws, msg, session) {
117
+ switch (msg.type) {
118
+ case 'prompt':
119
+ if (!session.isConnected || !session.sessionId) {
120
+ ws.send(JSON.stringify({ type: 'error', message: 'Agent not ready' }));
121
+ return;
122
+ }
123
+ try {
124
+ await session.prompt(msg.message);
125
+ }
126
+ catch {
127
+ // Error already emitted by session
128
+ }
129
+ break;
130
+ case 'cancel':
131
+ await session.cancel();
132
+ break;
133
+ case 'permission_response':
134
+ session.respondToPermission(msg.requestId, msg.optionId);
135
+ break;
136
+ case 'change_cwd':
137
+ try {
138
+ await session.changeCwd(msg.path);
139
+ }
140
+ catch (err) {
141
+ ws.send(JSON.stringify({ type: 'error', message: err.message }));
142
+ }
143
+ break;
144
+ case 'new_session':
145
+ try {
146
+ await session.newSession();
147
+ }
148
+ catch (err) {
149
+ ws.send(JSON.stringify({ type: 'error', message: err.message }));
150
+ }
151
+ break;
152
+ case 'set_mode':
153
+ try {
154
+ await session.setMode(msg.modeId);
155
+ }
156
+ catch (err) {
157
+ ws.send(JSON.stringify({ type: 'error', message: err.message }));
158
+ }
159
+ break;
160
+ case 'set_model':
161
+ try {
162
+ await session.setModel(msg.modelId);
163
+ }
164
+ catch (err) {
165
+ ws.send(JSON.stringify({ type: 'error', message: err.message }));
166
+ }
167
+ break;
168
+ case 'change_agent':
169
+ try {
170
+ await session.changeAgent(msg.agentType);
171
+ }
172
+ catch (err) {
173
+ ws.send(JSON.stringify({ type: 'error', message: err.message }));
174
+ }
175
+ break;
176
+ case 'get_history': {
177
+ const history = session.loadHistory();
178
+ ws.send(JSON.stringify({ type: 'history', events: history, sessionId: session.sessionId }));
179
+ break;
180
+ }
181
+ case 'list_sessions': {
182
+ const sessions = session.listSessions();
183
+ ws.send(JSON.stringify({ type: 'sessions', sessions }));
184
+ break;
185
+ }
186
+ case 'switch_session':
187
+ try {
188
+ await session.switchSession(msg.sessionId);
189
+ }
190
+ catch (err) {
191
+ ws.send(JSON.stringify({ type: 'error', message: err.message }));
192
+ }
193
+ break;
194
+ default:
195
+ ws.send(JSON.stringify({ type: 'error', message: `Unknown message type: ${msg.type}` }));
196
+ }
197
+ }
198
+ //# sourceMappingURL=ws-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws-adapter.js","sourceRoot":"","sources":["../src/ws-adapter.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,36 +1,59 @@
1
1
  {
2
2
  "name": "@bytespell/amux",
3
- "version": "0.0.11",
4
- "description": "Agent Multiplexer - library for managing agent/terminal processes",
5
- "repository": {
6
- "type": "git",
7
- "url": "https://github.com/bytespell-oss/shella"
8
- },
3
+ "version": "0.0.13",
4
+ "description": "ACP Multiplexer - the session layer for ACP agents",
9
5
  "type": "module",
10
- "files": [
11
- "dist/",
12
- "scripts/"
13
- ],
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
14
8
  "exports": {
15
- ".": "./dist/types.js",
16
- "./types": "./dist/types.js",
17
- "./streams/manager": "./dist/streams/manager.js",
18
- "./streams/backends": "./dist/streams/backends/index.js",
19
- "./lib/logger": "./dist/lib/logger.js",
20
- "./lib/mentions": "./dist/lib/mentions.js"
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
21
13
  },
22
14
  "scripts": {
23
- "postinstall": "node scripts/fix-pty.cjs 2>/dev/null || true",
24
- "build": "tsup",
25
- "dev": "tsup --watch"
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest",
19
+ "typecheck": "tsc --noEmit",
20
+ "lint": "eslint src",
21
+ "prepublishOnly": "npm run build"
26
22
  },
23
+ "keywords": [
24
+ "acp",
25
+ "agent",
26
+ "claude",
27
+ "multiplexer",
28
+ "ai",
29
+ "websocket"
30
+ ],
31
+ "author": "",
32
+ "license": "MIT",
27
33
  "dependencies": {
28
- "@agentclientprotocol/sdk": "^0.12.0",
29
- "execa": "^9.6.1",
30
- "node-pty": "^1.2.0-beta.2",
31
- "tree-kill": "^1.2.2"
34
+ "@agentclientprotocol/sdk": "^0.13.0",
35
+ "ws": "^8.19.0"
32
36
  },
33
37
  "devDependencies": {
34
- "@types/node": "^24.10.1"
38
+ "@types/node": "^22.10.0",
39
+ "@types/ws": "^8.18.1",
40
+ "typescript": "~5.7.0",
41
+ "vitest": "^3.1.3"
42
+ },
43
+ "peerDependencies": {
44
+ "@zed-industries/claude-code-acp": ">=0.13.0",
45
+ "@zed-industries/codex-acp": ">=0.9.0",
46
+ "pi-acp": ">=0.0.14"
47
+ },
48
+ "peerDependenciesMeta": {
49
+ "@zed-industries/claude-code-acp": {
50
+ "optional": true
51
+ },
52
+ "@zed-industries/codex-acp": {
53
+ "optional": true
54
+ },
55
+ "pi-acp": {
56
+ "optional": true
57
+ }
35
58
  }
36
59
  }
package/src/client.ts ADDED
@@ -0,0 +1,162 @@
1
+ import fs from 'fs';
2
+ import crypto from 'crypto';
3
+ import type * as acp from '@agentclientprotocol/sdk';
4
+
5
+ import { isToolCallUpdate, normalizeSessionUpdate } from './session-updates.js';
6
+ import type { TerminalManager } from './terminal.js';
7
+ import type { StoredEvent } from './types.js';
8
+
9
+ /**
10
+ * Callback for routing events
11
+ */
12
+ type EventCallback = (event: StoredEvent) => void;
13
+
14
+ /**
15
+ * Pending permission request tracking
16
+ */
17
+ interface PendingPermission {
18
+ resolve: (value: acp.RequestPermissionResponse) => void;
19
+ reject: (reason: Error) => void;
20
+ timeout: ReturnType<typeof setTimeout>;
21
+ }
22
+
23
+ /**
24
+ * ACP Client implementation.
25
+ * Bridges agent notifications to WebSocket clients and handles
26
+ * file operations and terminal management.
27
+ */
28
+ export class AmuxClient implements acp.Client {
29
+ pendingPermissions = new Map<string, PendingPermission>();
30
+
31
+ constructor(
32
+ private terminalManager: TerminalManager,
33
+ private onEvent: EventCallback
34
+ ) {}
35
+
36
+ /**
37
+ * Handle permission request from agent
38
+ */
39
+ async requestPermission(params: acp.RequestPermissionRequest): Promise<acp.RequestPermissionResponse> {
40
+ console.log('[amux] Permission request:', params.toolCall?.title);
41
+
42
+ // Send permission request
43
+ const requestId = crypto.randomUUID();
44
+ this.onEvent({
45
+ type: 'permission_request',
46
+ requestId,
47
+ toolCall: params.toolCall,
48
+ options: params.options,
49
+ });
50
+
51
+ // Wait for response from client (with timeout)
52
+ return new Promise((resolve, reject) => {
53
+ const timeout = setTimeout(() => {
54
+ this.pendingPermissions.delete(requestId);
55
+ resolve({ outcome: { outcome: 'cancelled' } });
56
+ }, 300000); // 5 minute timeout
57
+
58
+ this.pendingPermissions.set(requestId, { resolve, reject, timeout });
59
+ });
60
+ }
61
+
62
+ /**
63
+ * Handle permission response from UI
64
+ */
65
+ handlePermissionResponse(requestId: string, optionId: string): void {
66
+ const pending = this.pendingPermissions.get(requestId);
67
+ if (pending) {
68
+ clearTimeout(pending.timeout);
69
+ this.pendingPermissions.delete(requestId);
70
+ pending.resolve({
71
+ outcome: { outcome: 'selected', optionId },
72
+ });
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Handle session update from agent
78
+ */
79
+ async sessionUpdate(params: acp.SessionNotification): Promise<void> {
80
+ const update = params.update;
81
+
82
+ // Normalize the update (convert Claude-style diffs to unified format)
83
+ const normalized = normalizeSessionUpdate(update);
84
+
85
+ // Route to session
86
+ this.onEvent({ type: 'session_update', update: normalized });
87
+
88
+ // Log updates for debugging
89
+ if (update.sessionUpdate === 'agent_message_chunk') {
90
+ // Don't log every chunk
91
+ } else if (isToolCallUpdate(update)) {
92
+ console.log(`[amux] Tool call: ${update.title} (${update.status}) id=${(update as { toolCallId?: string }).toolCallId}`);
93
+ } else if (update.sessionUpdate === 'tool_call_update') {
94
+ // Don't log every update
95
+ } else if (update.sessionUpdate === 'current_mode_update') {
96
+ console.log(`[amux] Mode update: ${update.currentModeId}`);
97
+ } else {
98
+ console.log(`[amux] Session update: ${update.sessionUpdate}`);
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Write text file (ACP fs capability)
104
+ */
105
+ async writeTextFile(params: acp.WriteTextFileRequest): Promise<acp.WriteTextFileResponse> {
106
+ console.log('[amux] Write text file:', params.path);
107
+ try {
108
+ fs.writeFileSync(params.path, params.content);
109
+ return {};
110
+ } catch (err) {
111
+ throw new Error(`Failed to write file: ${(err as Error).message}`);
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Read text file (ACP fs capability)
117
+ */
118
+ async readTextFile(params: acp.ReadTextFileRequest): Promise<acp.ReadTextFileResponse> {
119
+ console.log('[amux] Read text file:', params.path);
120
+ try {
121
+ const content = fs.readFileSync(params.path, 'utf-8');
122
+ return { content };
123
+ } catch (err) {
124
+ throw new Error(`Failed to read file: ${(err as Error).message}`);
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Create terminal (ACP terminal capability)
130
+ */
131
+ async createTerminal(params: acp.CreateTerminalRequest): Promise<acp.CreateTerminalResponse> {
132
+ return this.terminalManager.create(params);
133
+ }
134
+
135
+ /**
136
+ * Get terminal output (ACP terminal capability)
137
+ */
138
+ async terminalOutput(params: acp.TerminalOutputRequest): Promise<acp.TerminalOutputResponse> {
139
+ return this.terminalManager.getOutput(params.terminalId);
140
+ }
141
+
142
+ /**
143
+ * Wait for terminal exit (ACP terminal capability)
144
+ */
145
+ async waitForTerminalExit(params: acp.WaitForTerminalExitRequest): Promise<acp.WaitForTerminalExitResponse> {
146
+ return this.terminalManager.waitForExit(params.terminalId);
147
+ }
148
+
149
+ /**
150
+ * Kill terminal (ACP terminal capability)
151
+ */
152
+ async killTerminal(params: acp.KillTerminalCommandRequest): Promise<acp.KillTerminalCommandResponse> {
153
+ return this.terminalManager.kill(params.terminalId);
154
+ }
155
+
156
+ /**
157
+ * Release terminal (ACP terminal capability)
158
+ */
159
+ async releaseTerminal(params: acp.ReleaseTerminalRequest): Promise<acp.ReleaseTerminalResponse> {
160
+ return this.terminalManager.release(params.terminalId);
161
+ }
162
+ }
package/src/index.ts ADDED
@@ -0,0 +1,66 @@
1
+ /**
2
+ * amux - Agent Multiplexer
3
+ *
4
+ * A library for managing ACP agent sessions with an EventEmitter interface.
5
+ * Transport-agnostic - wire up to WebSocket, HTTP, IPC, or anything else.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { AgentSession, createWsAdapter } from '@bytespell/amux';
10
+ * import { WebSocketServer } from 'ws';
11
+ *
12
+ * const session = new AgentSession({
13
+ * instanceId: 'my-instance',
14
+ * basePath: __dirname,
15
+ * systemContext: 'You are a helpful assistant...',
16
+ * });
17
+ *
18
+ * // Option 1: Use the WebSocket adapter
19
+ * const wss = new WebSocketServer({ port: 3000 });
20
+ * createWsAdapter(session, wss);
21
+ *
22
+ * // Option 2: Handle events yourself
23
+ * session.on('ready', (data) => console.log('Ready:', data));
24
+ * session.on('update', (data) => myTransport.send(data));
25
+ *
26
+ * await session.spawnAgent();
27
+ * await session.prompt('Hello!');
28
+ * ```
29
+ */
30
+
31
+ // Core session management
32
+ export { AgentSession } from './session.js';
33
+ export type { AgentSessionEvents } from './session.js';
34
+
35
+ // WebSocket adapter
36
+ export { createWsAdapter } from './ws-adapter.js';
37
+ export type { WsAdapterOptions } from './ws-adapter.js';
38
+
39
+ // Supporting components (for advanced usage)
40
+ export { AmuxClient } from './client.js';
41
+ export { TerminalManager } from './terminal.js';
42
+ export { StateManager } from './state.js';
43
+
44
+ // Session update utilities
45
+ export {
46
+ isToolCallUpdate,
47
+ isToolCallUpdateMessage,
48
+ isDiffContent,
49
+ normalizeSessionUpdate,
50
+ } from './session-updates.js';
51
+
52
+ // Message parsing utilities
53
+ export { parseMessageToContentBlocks } from './message-parser.js';
54
+
55
+ // Types
56
+ export type {
57
+ AgentSessionConfig,
58
+ AgentConfig,
59
+ SessionMetadata,
60
+ SessionState,
61
+ SessionRestoreInfo,
62
+ StoredEvent,
63
+ } from './types.js';
64
+
65
+ // Built-in agents registry
66
+ export { AGENTS } from './types.js';