@bytespell/amux 0.0.12 → 0.0.15
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/.claude/settings.local.json +7 -1
- package/README.md +24 -10
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/message-parser.test.d.ts +2 -0
- package/dist/message-parser.test.d.ts.map +1 -0
- package/dist/message-parser.test.js +188 -0
- package/dist/message-parser.test.js.map +1 -0
- package/dist/session-updates.test.d.ts +2 -0
- package/dist/session-updates.test.d.ts.map +1 -0
- package/dist/session-updates.test.js +223 -0
- package/dist/session-updates.test.js.map +1 -0
- package/dist/session.d.ts +10 -3
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +87 -14
- package/dist/session.js.map +1 -1
- package/dist/types.d.ts +4 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -3
- package/dist/types.js.map +1 -1
- package/package.json +5 -18
- package/src/index.ts +0 -1
- package/src/message-parser.test.ts +207 -0
- package/src/session-updates.test.ts +265 -0
- package/src/session.ts +94 -15
- package/src/types.ts +10 -7
- package/tsconfig.json +1 -1
- package/vitest.config.ts +7 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
isToolCallUpdate,
|
|
4
|
+
isToolCallUpdateMessage,
|
|
5
|
+
normalizeSessionUpdate,
|
|
6
|
+
} from './session-updates.js';
|
|
7
|
+
import type * as acp from '@agentclientprotocol/sdk';
|
|
8
|
+
|
|
9
|
+
describe('isToolCallUpdate', () => {
|
|
10
|
+
it('returns true for tool_call updates', () => {
|
|
11
|
+
const update = {
|
|
12
|
+
sessionUpdate: 'tool_call',
|
|
13
|
+
id: 'test',
|
|
14
|
+
title: 'Test',
|
|
15
|
+
status: 'pending',
|
|
16
|
+
} as acp.SessionUpdate;
|
|
17
|
+
expect(isToolCallUpdate(update)).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('returns false for other update types', () => {
|
|
21
|
+
const update = {
|
|
22
|
+
sessionUpdate: 'agent_message_chunk',
|
|
23
|
+
content: { type: 'text', text: 'hello' },
|
|
24
|
+
} as acp.SessionUpdate;
|
|
25
|
+
expect(isToolCallUpdate(update)).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('isToolCallUpdateMessage', () => {
|
|
30
|
+
it('returns true for tool_call_update updates', () => {
|
|
31
|
+
const update = {
|
|
32
|
+
sessionUpdate: 'tool_call_update',
|
|
33
|
+
id: 'test',
|
|
34
|
+
} as acp.SessionUpdate;
|
|
35
|
+
expect(isToolCallUpdateMessage(update)).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('returns false for other update types', () => {
|
|
39
|
+
const update = {
|
|
40
|
+
sessionUpdate: 'tool_call',
|
|
41
|
+
id: 'test',
|
|
42
|
+
title: 'Test',
|
|
43
|
+
status: 'pending',
|
|
44
|
+
} as acp.SessionUpdate;
|
|
45
|
+
expect(isToolCallUpdateMessage(update)).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('normalizeSessionUpdate', () => {
|
|
50
|
+
it('passes through non-tool updates unchanged', () => {
|
|
51
|
+
const update: acp.SessionUpdate = {
|
|
52
|
+
sessionUpdate: 'agent_message_chunk',
|
|
53
|
+
content: { type: 'text', text: 'hello' },
|
|
54
|
+
};
|
|
55
|
+
const result = normalizeSessionUpdate(update);
|
|
56
|
+
expect(result).toEqual(update);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('passes through turn_start unchanged', () => {
|
|
60
|
+
const update: acp.SessionUpdate = {
|
|
61
|
+
sessionUpdate: 'turn_start',
|
|
62
|
+
};
|
|
63
|
+
const result = normalizeSessionUpdate(update);
|
|
64
|
+
expect(result).toEqual(update);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('passes through turn_end unchanged', () => {
|
|
68
|
+
const update: acp.SessionUpdate = {
|
|
69
|
+
sessionUpdate: 'turn_end',
|
|
70
|
+
};
|
|
71
|
+
const result = normalizeSessionUpdate(update);
|
|
72
|
+
expect(result).toEqual(update);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('passes through tool_call without content unchanged', () => {
|
|
76
|
+
const update = {
|
|
77
|
+
sessionUpdate: 'tool_call',
|
|
78
|
+
id: 'test',
|
|
79
|
+
title: 'Test Tool',
|
|
80
|
+
status: 'pending',
|
|
81
|
+
} as acp.SessionUpdate;
|
|
82
|
+
const result = normalizeSessionUpdate(update);
|
|
83
|
+
expect(result).toEqual(update);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('passes through tool_call with non-diff content unchanged', () => {
|
|
87
|
+
const update = {
|
|
88
|
+
sessionUpdate: 'tool_call',
|
|
89
|
+
id: 'test',
|
|
90
|
+
title: 'Test Tool',
|
|
91
|
+
status: 'pending',
|
|
92
|
+
content: [{ type: 'text', text: 'some output' }],
|
|
93
|
+
} as acp.SessionUpdate;
|
|
94
|
+
const result = normalizeSessionUpdate(update);
|
|
95
|
+
expect(result).toEqual(update);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('normalizes tool_call with diff content', () => {
|
|
99
|
+
const update = {
|
|
100
|
+
sessionUpdate: 'tool_call',
|
|
101
|
+
id: 'test',
|
|
102
|
+
title: 'Edit File',
|
|
103
|
+
status: 'completed',
|
|
104
|
+
content: [
|
|
105
|
+
{
|
|
106
|
+
type: 'diff',
|
|
107
|
+
oldText: 'old content',
|
|
108
|
+
newText: 'new content',
|
|
109
|
+
path: '/path/to/file.ts',
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
} as acp.SessionUpdate;
|
|
113
|
+
|
|
114
|
+
const result = normalizeSessionUpdate(update);
|
|
115
|
+
|
|
116
|
+
// Should have same structure but with normalized diff
|
|
117
|
+
expect(result.sessionUpdate).toBe('tool_call');
|
|
118
|
+
expect((result as { content?: acp.ToolCallContent[] }).content).toHaveLength(1);
|
|
119
|
+
|
|
120
|
+
const diffContent = (result as { content: acp.ToolCallContent[] }).content[0];
|
|
121
|
+
expect(diffContent.type).toBe('diff');
|
|
122
|
+
|
|
123
|
+
// The newText should now contain unified diff format
|
|
124
|
+
const normalizedDiff = diffContent as { newText: string; oldText: string; path: string };
|
|
125
|
+
expect(normalizedDiff.newText).toContain('Index: /path/to/file.ts');
|
|
126
|
+
expect(normalizedDiff.newText).toContain('---');
|
|
127
|
+
expect(normalizedDiff.newText).toContain('+++');
|
|
128
|
+
expect(normalizedDiff.newText).toContain('-old content');
|
|
129
|
+
expect(normalizedDiff.newText).toContain('+new content');
|
|
130
|
+
expect(normalizedDiff.oldText).toBe('');
|
|
131
|
+
expect(normalizedDiff.path).toBe('/path/to/file.ts');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('normalizes tool_call_update with diff content', () => {
|
|
135
|
+
const update = {
|
|
136
|
+
sessionUpdate: 'tool_call_update',
|
|
137
|
+
id: 'test',
|
|
138
|
+
content: [
|
|
139
|
+
{
|
|
140
|
+
type: 'diff',
|
|
141
|
+
oldText: 'line1\nline2',
|
|
142
|
+
newText: 'line1\nmodified',
|
|
143
|
+
path: 'test.ts',
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
} as acp.SessionUpdate;
|
|
147
|
+
|
|
148
|
+
const result = normalizeSessionUpdate(update);
|
|
149
|
+
const diffContent = (result as { content: acp.ToolCallContent[] }).content[0] as {
|
|
150
|
+
newText: string;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
expect(diffContent.newText).toContain('-line1');
|
|
154
|
+
expect(diffContent.newText).toContain('-line2');
|
|
155
|
+
expect(diffContent.newText).toContain('+line1');
|
|
156
|
+
expect(diffContent.newText).toContain('+modified');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('handles empty oldText (new file creation)', () => {
|
|
160
|
+
const update = {
|
|
161
|
+
sessionUpdate: 'tool_call',
|
|
162
|
+
id: 'test',
|
|
163
|
+
title: 'Write File',
|
|
164
|
+
status: 'completed',
|
|
165
|
+
content: [
|
|
166
|
+
{
|
|
167
|
+
type: 'diff',
|
|
168
|
+
oldText: '',
|
|
169
|
+
newText: 'new file content',
|
|
170
|
+
path: 'new-file.ts',
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
} as acp.SessionUpdate;
|
|
174
|
+
|
|
175
|
+
const result = normalizeSessionUpdate(update);
|
|
176
|
+
const diffContent = (result as { content: acp.ToolCallContent[] }).content[0] as {
|
|
177
|
+
newText: string;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
expect(diffContent.newText).toContain('@@ -0,0 +1,1 @@');
|
|
181
|
+
expect(diffContent.newText).toContain('+new file content');
|
|
182
|
+
// No removed lines in the diff body (lines starting with - followed by content, not headers)
|
|
183
|
+
const lines = diffContent.newText.split('\n');
|
|
184
|
+
const removedLines = lines.filter(l => l.startsWith('-') && !l.startsWith('---'));
|
|
185
|
+
expect(removedLines).toHaveLength(0);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('handles multi-line diffs', () => {
|
|
189
|
+
const update = {
|
|
190
|
+
sessionUpdate: 'tool_call',
|
|
191
|
+
id: 'test',
|
|
192
|
+
title: 'Edit File',
|
|
193
|
+
status: 'completed',
|
|
194
|
+
content: [
|
|
195
|
+
{
|
|
196
|
+
type: 'diff',
|
|
197
|
+
oldText: 'line1\nline2\nline3',
|
|
198
|
+
newText: 'line1\nmodified\nline3\nline4',
|
|
199
|
+
path: 'file.ts',
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
} as acp.SessionUpdate;
|
|
203
|
+
|
|
204
|
+
const result = normalizeSessionUpdate(update);
|
|
205
|
+
const diffContent = (result as { content: acp.ToolCallContent[] }).content[0] as {
|
|
206
|
+
newText: string;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// Should have correct line counts in header
|
|
210
|
+
expect(diffContent.newText).toContain('@@ -1,3 +1,4 @@');
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('uses "file" as default path when path is missing', () => {
|
|
214
|
+
const update = {
|
|
215
|
+
sessionUpdate: 'tool_call',
|
|
216
|
+
id: 'test',
|
|
217
|
+
title: 'Edit',
|
|
218
|
+
status: 'completed',
|
|
219
|
+
content: [
|
|
220
|
+
{
|
|
221
|
+
type: 'diff',
|
|
222
|
+
oldText: 'old',
|
|
223
|
+
newText: 'new',
|
|
224
|
+
// path intentionally omitted
|
|
225
|
+
},
|
|
226
|
+
],
|
|
227
|
+
} as acp.SessionUpdate;
|
|
228
|
+
|
|
229
|
+
const result = normalizeSessionUpdate(update);
|
|
230
|
+
const diffContent = (result as { content: acp.ToolCallContent[] }).content[0] as {
|
|
231
|
+
newText: string;
|
|
232
|
+
path: string;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
expect(diffContent.newText).toContain('Index: file');
|
|
236
|
+
expect(diffContent.path).toBe('file');
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('preserves mixed content types in tool_call', () => {
|
|
240
|
+
const update = {
|
|
241
|
+
sessionUpdate: 'tool_call',
|
|
242
|
+
id: 'test',
|
|
243
|
+
title: 'Complex Tool',
|
|
244
|
+
status: 'completed',
|
|
245
|
+
content: [
|
|
246
|
+
{ type: 'text', text: 'Before diff' },
|
|
247
|
+
{
|
|
248
|
+
type: 'diff',
|
|
249
|
+
oldText: 'old',
|
|
250
|
+
newText: 'new',
|
|
251
|
+
path: 'file.ts',
|
|
252
|
+
},
|
|
253
|
+
{ type: 'text', text: 'After diff' },
|
|
254
|
+
],
|
|
255
|
+
} as acp.SessionUpdate;
|
|
256
|
+
|
|
257
|
+
const result = normalizeSessionUpdate(update);
|
|
258
|
+
const content = (result as { content: acp.ToolCallContent[] }).content;
|
|
259
|
+
|
|
260
|
+
expect(content).toHaveLength(3);
|
|
261
|
+
expect(content[0]).toEqual({ type: 'text', text: 'Before diff' });
|
|
262
|
+
expect(content[1]?.type).toBe('diff');
|
|
263
|
+
expect(content[2]).toEqual({ type: 'text', text: 'After diff' });
|
|
264
|
+
});
|
|
265
|
+
});
|
package/src/session.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import { spawn, type ChildProcess } from 'child_process';
|
|
1
|
+
import { spawn, execSync, type ChildProcess } from 'child_process';
|
|
2
2
|
import { EventEmitter } from 'events';
|
|
3
3
|
import os from 'os';
|
|
4
4
|
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
5
6
|
import { Writable, Readable } from 'stream';
|
|
6
7
|
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
|
|
11
|
+
/** Path to amux's own node_modules/.bin where ACP wrappers are installed */
|
|
12
|
+
const AMUX_BIN_DIR = path.join(__dirname, '..', 'node_modules', '.bin');
|
|
13
|
+
|
|
7
14
|
import * as acp from '@agentclientprotocol/sdk';
|
|
8
15
|
|
|
9
16
|
import { AmuxClient } from './client.js';
|
|
@@ -20,6 +27,32 @@ import { AGENTS as DEFAULT_AGENTS } from './types.js';
|
|
|
20
27
|
|
|
21
28
|
const INIT_TIMEOUT_MS = 90000;
|
|
22
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Check if a binary is available on PATH
|
|
32
|
+
*/
|
|
33
|
+
function isOnPath(bin: string): boolean {
|
|
34
|
+
try {
|
|
35
|
+
const cmd = process.platform === 'win32' ? 'where' : 'which';
|
|
36
|
+
execSync(`${cmd} ${bin}`, { stdio: 'ignore' });
|
|
37
|
+
return true;
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Check if an ACP wrapper binary exists in amux's node_modules
|
|
45
|
+
*/
|
|
46
|
+
function hasAcpWrapper(acpBin: string): boolean {
|
|
47
|
+
const binPath = path.join(AMUX_BIN_DIR, acpBin);
|
|
48
|
+
try {
|
|
49
|
+
execSync(`test -x "${binPath}"`, { stdio: 'ignore' });
|
|
50
|
+
return true;
|
|
51
|
+
} catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
23
56
|
/**
|
|
24
57
|
* Events emitted by AgentSession
|
|
25
58
|
*/
|
|
@@ -75,7 +108,6 @@ function withTimeout<T>(promise: Promise<T>, ms: number, operation: string): Pro
|
|
|
75
108
|
* ```typescript
|
|
76
109
|
* const session = new AgentSession({
|
|
77
110
|
* instanceId: 'my-instance',
|
|
78
|
-
* basePath: __dirname,
|
|
79
111
|
* });
|
|
80
112
|
*
|
|
81
113
|
* session.on('ready', (data) => console.log('Ready:', data));
|
|
@@ -96,6 +128,7 @@ export class AgentSession extends EventEmitter {
|
|
|
96
128
|
private agentProcess: ChildProcess | null = null;
|
|
97
129
|
private acpConnection: acp.ClientSideConnection | null = null;
|
|
98
130
|
private _agentCapabilities: acp.AgentCapabilities | null = null;
|
|
131
|
+
private _changingCwd = false;
|
|
99
132
|
|
|
100
133
|
// Components
|
|
101
134
|
private terminalManager: TerminalManager;
|
|
@@ -104,7 +137,6 @@ export class AgentSession extends EventEmitter {
|
|
|
104
137
|
|
|
105
138
|
// Config
|
|
106
139
|
private instanceId: string;
|
|
107
|
-
private basePath: string;
|
|
108
140
|
private fixedCwd?: string;
|
|
109
141
|
private agents: Record<string, AgentConfig>;
|
|
110
142
|
|
|
@@ -112,7 +144,6 @@ export class AgentSession extends EventEmitter {
|
|
|
112
144
|
super();
|
|
113
145
|
|
|
114
146
|
this.instanceId = config.instanceId;
|
|
115
|
-
this.basePath = config.basePath;
|
|
116
147
|
this.fixedCwd = config.fixedCwd;
|
|
117
148
|
this._systemContext = config.systemContext;
|
|
118
149
|
this.agents = DEFAULT_AGENTS;
|
|
@@ -187,10 +218,23 @@ export class AgentSession extends EventEmitter {
|
|
|
187
218
|
}
|
|
188
219
|
|
|
189
220
|
/**
|
|
190
|
-
* Get available agents list
|
|
221
|
+
* Get available agents list (checks if base CLI is on PATH and ACP wrapper is bundled)
|
|
222
|
+
*/
|
|
223
|
+
getAvailableAgents(): Array<{ id: string; name: string; installed: boolean }> {
|
|
224
|
+
return Object.entries(this.agents).map(([id, a]) => ({
|
|
225
|
+
id,
|
|
226
|
+
name: a.name,
|
|
227
|
+
installed: isOnPath(a.cli) && hasAcpWrapper(a.acpBin),
|
|
228
|
+
}));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Get only installed agents
|
|
191
233
|
*/
|
|
192
|
-
|
|
193
|
-
return
|
|
234
|
+
getInstalledAgents(): Array<{ id: string; name: string }> {
|
|
235
|
+
return this.getAvailableAgents()
|
|
236
|
+
.filter((a) => a.installed)
|
|
237
|
+
.map(({ id, name }) => ({ id, name }));
|
|
194
238
|
}
|
|
195
239
|
|
|
196
240
|
/**
|
|
@@ -243,11 +287,29 @@ export class AgentSession extends EventEmitter {
|
|
|
243
287
|
return;
|
|
244
288
|
}
|
|
245
289
|
|
|
290
|
+
// Check if base CLI is installed
|
|
291
|
+
if (!isOnPath(agent.cli)) {
|
|
292
|
+
console.error(`[amux] Agent CLI not found on PATH: ${agent.cli}`);
|
|
293
|
+
this.emit('error', {
|
|
294
|
+
message: `Agent "${agent.cli}" not found. Install it globally or add it to your PATH.`,
|
|
295
|
+
});
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Check if ACP wrapper is bundled
|
|
300
|
+
const acpBinPath = path.join(AMUX_BIN_DIR, agent.acpBin);
|
|
301
|
+
if (!hasAcpWrapper(agent.acpBin)) {
|
|
302
|
+
console.error(`[amux] ACP wrapper not found: ${acpBinPath}`);
|
|
303
|
+
this.emit('error', {
|
|
304
|
+
message: `ACP wrapper "${agent.acpBin}" not bundled. This is an amux installation issue.`,
|
|
305
|
+
});
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
|
|
246
309
|
console.log(`[amux] Spawning ${agent.name} agent in cwd:`, this._cwd);
|
|
247
310
|
this.emit('connecting', {});
|
|
248
311
|
|
|
249
|
-
const
|
|
250
|
-
const newProcess = spawn(agentBin, [], {
|
|
312
|
+
const newProcess = spawn(acpBinPath, [], {
|
|
251
313
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
252
314
|
env: { ...process.env },
|
|
253
315
|
cwd: this._cwd,
|
|
@@ -323,7 +385,7 @@ export class AgentSession extends EventEmitter {
|
|
|
323
385
|
sessionRestore,
|
|
324
386
|
capabilities: this._agentCapabilities,
|
|
325
387
|
agent: this.getAgentInfo(),
|
|
326
|
-
availableAgents: this.
|
|
388
|
+
availableAgents: this.getInstalledAgents(),
|
|
327
389
|
});
|
|
328
390
|
|
|
329
391
|
} catch (err) {
|
|
@@ -617,12 +679,29 @@ export class AgentSession extends EventEmitter {
|
|
|
617
679
|
throw new Error('Working directory is fixed for this session');
|
|
618
680
|
}
|
|
619
681
|
|
|
620
|
-
|
|
621
|
-
this.
|
|
622
|
-
|
|
682
|
+
// Prevent concurrent cwd changes
|
|
683
|
+
if (this._changingCwd) {
|
|
684
|
+
console.log('[amux] changeCwd already in progress, ignoring');
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
623
687
|
|
|
624
|
-
|
|
625
|
-
|
|
688
|
+
// Same path, nothing to do
|
|
689
|
+
if (newPath === this._cwd) {
|
|
690
|
+
console.log('[amux] changeCwd same path, ignoring');
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
this._changingCwd = true;
|
|
695
|
+
try {
|
|
696
|
+
this._cwd = newPath;
|
|
697
|
+
this._sessionId = null;
|
|
698
|
+
this.saveState();
|
|
699
|
+
|
|
700
|
+
await this.killAgent();
|
|
701
|
+
await this.spawnAgent();
|
|
702
|
+
} finally {
|
|
703
|
+
this._changingCwd = false;
|
|
704
|
+
}
|
|
626
705
|
}
|
|
627
706
|
|
|
628
707
|
/**
|
package/src/types.ts
CHANGED
|
@@ -5,7 +5,10 @@ import type * as acp from '@agentclientprotocol/sdk';
|
|
|
5
5
|
*/
|
|
6
6
|
export interface AgentConfig {
|
|
7
7
|
name: string;
|
|
8
|
-
|
|
8
|
+
/** The base CLI binary name (for checking if installed) */
|
|
9
|
+
cli: string;
|
|
10
|
+
/** The ACP wrapper binary name (bundled with amux) */
|
|
11
|
+
acpBin: string;
|
|
9
12
|
}
|
|
10
13
|
|
|
11
14
|
/**
|
|
@@ -14,15 +17,18 @@ export interface AgentConfig {
|
|
|
14
17
|
export const AGENTS: Record<string, AgentConfig> = {
|
|
15
18
|
'claude-code': {
|
|
16
19
|
name: 'Claude Code',
|
|
17
|
-
|
|
20
|
+
cli: 'claude',
|
|
21
|
+
acpBin: 'claude-code-acp',
|
|
18
22
|
},
|
|
19
23
|
'codex': {
|
|
20
24
|
name: 'Codex',
|
|
21
|
-
|
|
25
|
+
cli: 'codex',
|
|
26
|
+
acpBin: 'codex-acp',
|
|
22
27
|
},
|
|
23
28
|
'pi': {
|
|
24
29
|
name: 'Pi',
|
|
25
|
-
|
|
30
|
+
cli: 'pi',
|
|
31
|
+
acpBin: 'pi-acp',
|
|
26
32
|
},
|
|
27
33
|
};
|
|
28
34
|
|
|
@@ -71,9 +77,6 @@ export interface AgentSessionConfig {
|
|
|
71
77
|
/** Unique identifier for this session instance */
|
|
72
78
|
instanceId: string;
|
|
73
79
|
|
|
74
|
-
/** Base path for resolving agent binaries (node_modules/.bin) */
|
|
75
|
-
basePath: string;
|
|
76
|
-
|
|
77
80
|
/** Optional system context to inject (e.g., from a markdown file) */
|
|
78
81
|
systemContext?: string;
|
|
79
82
|
|
package/tsconfig.json
CHANGED