@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.
- package/.claude/settings.local.json +11 -0
- package/CLAUDE.md +104 -0
- package/LICENSE +21 -0
- package/README.md +215 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +118 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +68 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +135 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/{lib/mentions.d.ts → message-parser.d.ts} +3 -5
- package/dist/message-parser.d.ts.map +1 -0
- package/dist/message-parser.js +45 -0
- package/dist/message-parser.js.map +1 -0
- 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/server.d.ts +24 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +356 -0
- package/dist/server.js.map +1 -0
- package/dist/session-updates.d.ts +26 -0
- package/dist/session-updates.d.ts.map +1 -0
- package/dist/session-updates.js +68 -0
- package/dist/session-updates.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 +208 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +580 -0
- package/dist/session.js.map +1 -0
- package/dist/state.d.ts +74 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +250 -0
- package/dist/state.js.map +1 -0
- package/dist/terminal.d.ts +47 -0
- package/dist/terminal.d.ts.map +1 -0
- package/dist/terminal.js +137 -0
- package/dist/terminal.js.map +1 -0
- package/dist/types.d.ts +64 -2
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -31
- package/dist/types.js.map +1 -1
- package/dist/ws-adapter.d.ts +39 -0
- package/dist/ws-adapter.d.ts.map +1 -0
- package/dist/ws-adapter.js +198 -0
- package/dist/ws-adapter.js.map +1 -0
- package/package.json +47 -24
- package/src/client.ts +162 -0
- package/src/index.ts +66 -0
- package/src/message-parser.test.ts +207 -0
- package/src/message-parser.ts +54 -0
- package/src/session-updates.test.ts +265 -0
- package/src/session-updates.ts +87 -0
- package/src/session.ts +737 -0
- package/src/state.ts +287 -0
- package/src/terminal.ts +164 -0
- package/src/types.ts +88 -0
- package/src/ws-adapter.ts +245 -0
- package/tsconfig.json +22 -0
- package/vitest.config.ts +7 -0
- package/dist/chunk-5IPYOXBE.js +0 -32
- package/dist/chunk-5IPYOXBE.js.map +0 -1
- package/dist/chunk-C73RKCTS.js +0 -36
- package/dist/chunk-C73RKCTS.js.map +0 -1
- package/dist/chunk-VVXT4HQM.js +0 -779
- package/dist/chunk-VVXT4HQM.js.map +0 -1
- package/dist/lib/logger.d.ts +0 -24
- package/dist/lib/logger.js +0 -17
- package/dist/lib/logger.js.map +0 -1
- package/dist/lib/mentions.js +0 -7
- package/dist/lib/mentions.js.map +0 -1
- package/dist/streams/backends/index.d.ts +0 -88
- package/dist/streams/backends/index.js +0 -13
- package/dist/streams/backends/index.js.map +0 -1
- package/dist/streams/manager.d.ts +0 -55
- package/dist/streams/manager.js +0 -248
- package/dist/streams/manager.js.map +0 -1
- package/dist/types-DCRtrjjj.d.ts +0 -192
- package/scripts/fix-pty.cjs +0 -21
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { WebSocket, WebSocketServer } from 'ws';
|
|
2
|
+
import type { AgentSession, AgentSessionEvents } from './session.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* WebSocket message from client
|
|
6
|
+
*/
|
|
7
|
+
interface WsClientMessage {
|
|
8
|
+
type: string;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Options for the WebSocket adapter
|
|
14
|
+
*/
|
|
15
|
+
export interface WsAdapterOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Send history on connect (default: true)
|
|
18
|
+
*/
|
|
19
|
+
sendHistoryOnConnect?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Create a WebSocket adapter for an AgentSession.
|
|
24
|
+
*
|
|
25
|
+
* Bridges session events to WebSocket clients and handles incoming messages.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* import { AgentSession } from 'amux';
|
|
30
|
+
* import { createWsAdapter } from 'amux/ws';
|
|
31
|
+
* import { WebSocketServer } from 'ws';
|
|
32
|
+
*
|
|
33
|
+
* const session = new AgentSession({ ... });
|
|
34
|
+
* const wss = new WebSocketServer({ server, path: '/ws' });
|
|
35
|
+
*
|
|
36
|
+
* createWsAdapter(session, wss);
|
|
37
|
+
*
|
|
38
|
+
* await session.spawnAgent();
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export function createWsAdapter(
|
|
42
|
+
session: AgentSession,
|
|
43
|
+
wss: WebSocketServer,
|
|
44
|
+
options: WsAdapterOptions = {}
|
|
45
|
+
): {
|
|
46
|
+
/** Get connected client count */
|
|
47
|
+
clientCount: () => number;
|
|
48
|
+
/** Broadcast a custom message to all clients */
|
|
49
|
+
broadcast: (message: unknown) => void;
|
|
50
|
+
/** Close all connections */
|
|
51
|
+
close: () => void;
|
|
52
|
+
} {
|
|
53
|
+
const clients = new Set<WebSocket>();
|
|
54
|
+
const sendHistoryOnConnect = options.sendHistoryOnConnect ?? true;
|
|
55
|
+
|
|
56
|
+
// Helper to broadcast to all clients
|
|
57
|
+
function broadcast(message: unknown): void {
|
|
58
|
+
const data = JSON.stringify(message);
|
|
59
|
+
for (const client of clients) {
|
|
60
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
61
|
+
client.send(data);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Wire up session events to broadcast
|
|
67
|
+
const eventHandlers: { [K in keyof AgentSessionEvents]?: (data: AgentSessionEvents[K]) => void } = {
|
|
68
|
+
ready: (data) => broadcast({ type: 'ready', ...data }),
|
|
69
|
+
connecting: () => broadcast({ type: 'connecting' }),
|
|
70
|
+
update: (data) => broadcast({ type: 'session_update', update: data }),
|
|
71
|
+
turn_start: () => broadcast({ type: 'turn_start' }),
|
|
72
|
+
turn_end: () => broadcast({ type: 'turn_end' }),
|
|
73
|
+
permission_request: (data) => broadcast({ type: 'permission_request', ...data }),
|
|
74
|
+
prompt_complete: (data) => broadcast({ type: 'prompt_complete', ...data }),
|
|
75
|
+
session_created: (data) => broadcast({ type: 'session_created', ...data }),
|
|
76
|
+
session_switched: (data) => broadcast({ type: 'session_switched', ...data }),
|
|
77
|
+
history_replay: (data) => broadcast({ type: 'history_replay', ...data }),
|
|
78
|
+
error: (data) => broadcast({ type: 'error', ...data }),
|
|
79
|
+
agent_exit: (data) => broadcast({ type: 'agent_exit', ...data }),
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// Register all event handlers
|
|
83
|
+
for (const [event, handler] of Object.entries(eventHandlers)) {
|
|
84
|
+
session.on(event as keyof AgentSessionEvents, handler as (data: unknown) => void);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Handle WebSocket connections
|
|
88
|
+
wss.on('connection', (ws: WebSocket) => {
|
|
89
|
+
console.log('[amux-ws] Client connected');
|
|
90
|
+
clients.add(ws);
|
|
91
|
+
|
|
92
|
+
// Send current state to new client
|
|
93
|
+
if (session.isConnected) {
|
|
94
|
+
ws.send(JSON.stringify({
|
|
95
|
+
type: 'ready',
|
|
96
|
+
cwd: session.cwd,
|
|
97
|
+
sessionId: session.sessionId,
|
|
98
|
+
capabilities: session.agentCapabilities,
|
|
99
|
+
agent: session.getAgentInfo(),
|
|
100
|
+
availableAgents: session.getAvailableAgents(),
|
|
101
|
+
}));
|
|
102
|
+
|
|
103
|
+
// Send history to hydrate the chat UI
|
|
104
|
+
if (sendHistoryOnConnect) {
|
|
105
|
+
const history = session.loadHistory();
|
|
106
|
+
if (history.length > 0) {
|
|
107
|
+
ws.send(JSON.stringify({
|
|
108
|
+
type: 'history_replay',
|
|
109
|
+
previousSessionId: session.sessionId,
|
|
110
|
+
events: history,
|
|
111
|
+
eventCount: history.length,
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
ws.send(JSON.stringify({ type: 'connecting' }));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Handle incoming messages
|
|
120
|
+
ws.on('message', async (data: Buffer) => {
|
|
121
|
+
try {
|
|
122
|
+
const msg = JSON.parse(data.toString()) as WsClientMessage;
|
|
123
|
+
await handleMessage(ws, msg, session);
|
|
124
|
+
} catch (err) {
|
|
125
|
+
console.error('[amux-ws] Invalid message:', err);
|
|
126
|
+
ws.send(JSON.stringify({ type: 'error', message: 'Invalid message format' }));
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
ws.on('close', () => {
|
|
131
|
+
console.log('[amux-ws] Client disconnected');
|
|
132
|
+
clients.delete(ws);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
ws.on('error', (err) => {
|
|
136
|
+
console.error('[amux-ws] WebSocket error:', err);
|
|
137
|
+
clients.delete(ws);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
clientCount: () => clients.size,
|
|
143
|
+
broadcast,
|
|
144
|
+
close: () => {
|
|
145
|
+
for (const client of clients) {
|
|
146
|
+
client.close();
|
|
147
|
+
}
|
|
148
|
+
clients.clear();
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Handle incoming WebSocket message
|
|
155
|
+
*/
|
|
156
|
+
async function handleMessage(
|
|
157
|
+
ws: WebSocket,
|
|
158
|
+
msg: WsClientMessage,
|
|
159
|
+
session: AgentSession
|
|
160
|
+
): Promise<void> {
|
|
161
|
+
switch (msg.type) {
|
|
162
|
+
case 'prompt':
|
|
163
|
+
if (!session.isConnected || !session.sessionId) {
|
|
164
|
+
ws.send(JSON.stringify({ type: 'error', message: 'Agent not ready' }));
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
await session.prompt(msg.message as string);
|
|
169
|
+
} catch {
|
|
170
|
+
// Error already emitted by session
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
|
|
174
|
+
case 'cancel':
|
|
175
|
+
await session.cancel();
|
|
176
|
+
break;
|
|
177
|
+
|
|
178
|
+
case 'permission_response':
|
|
179
|
+
session.respondToPermission(msg.requestId as string, msg.optionId as string);
|
|
180
|
+
break;
|
|
181
|
+
|
|
182
|
+
case 'change_cwd':
|
|
183
|
+
try {
|
|
184
|
+
await session.changeCwd(msg.path as string);
|
|
185
|
+
} catch (err) {
|
|
186
|
+
ws.send(JSON.stringify({ type: 'error', message: (err as Error).message }));
|
|
187
|
+
}
|
|
188
|
+
break;
|
|
189
|
+
|
|
190
|
+
case 'new_session':
|
|
191
|
+
try {
|
|
192
|
+
await session.newSession();
|
|
193
|
+
} catch (err) {
|
|
194
|
+
ws.send(JSON.stringify({ type: 'error', message: (err as Error).message }));
|
|
195
|
+
}
|
|
196
|
+
break;
|
|
197
|
+
|
|
198
|
+
case 'set_mode':
|
|
199
|
+
try {
|
|
200
|
+
await session.setMode(msg.modeId as string);
|
|
201
|
+
} catch (err) {
|
|
202
|
+
ws.send(JSON.stringify({ type: 'error', message: (err as Error).message }));
|
|
203
|
+
}
|
|
204
|
+
break;
|
|
205
|
+
|
|
206
|
+
case 'set_model':
|
|
207
|
+
try {
|
|
208
|
+
await session.setModel(msg.modelId as string);
|
|
209
|
+
} catch (err) {
|
|
210
|
+
ws.send(JSON.stringify({ type: 'error', message: (err as Error).message }));
|
|
211
|
+
}
|
|
212
|
+
break;
|
|
213
|
+
|
|
214
|
+
case 'change_agent':
|
|
215
|
+
try {
|
|
216
|
+
await session.changeAgent(msg.agentType as string);
|
|
217
|
+
} catch (err) {
|
|
218
|
+
ws.send(JSON.stringify({ type: 'error', message: (err as Error).message }));
|
|
219
|
+
}
|
|
220
|
+
break;
|
|
221
|
+
|
|
222
|
+
case 'get_history': {
|
|
223
|
+
const history = session.loadHistory();
|
|
224
|
+
ws.send(JSON.stringify({ type: 'history', events: history, sessionId: session.sessionId }));
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
case 'list_sessions': {
|
|
229
|
+
const sessions = session.listSessions();
|
|
230
|
+
ws.send(JSON.stringify({ type: 'sessions', sessions }));
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
case 'switch_session':
|
|
235
|
+
try {
|
|
236
|
+
await session.switchSession(msg.sessionId as string);
|
|
237
|
+
} catch (err) {
|
|
238
|
+
ws.send(JSON.stringify({ type: 'error', message: (err as Error).message }));
|
|
239
|
+
}
|
|
240
|
+
break;
|
|
241
|
+
|
|
242
|
+
default:
|
|
243
|
+
ws.send(JSON.stringify({ type: 'error', message: `Unknown message type: ${msg.type}` }));
|
|
244
|
+
}
|
|
245
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "dist",
|
|
8
|
+
"rootDir": "src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true,
|
|
16
|
+
"noUncheckedIndexedAccess": true,
|
|
17
|
+
"noUnusedLocals": true,
|
|
18
|
+
"noUnusedParameters": true
|
|
19
|
+
},
|
|
20
|
+
"include": ["src/**/*"],
|
|
21
|
+
"exclude": ["node_modules", "dist", "src/**/*.test.ts"]
|
|
22
|
+
}
|
package/vitest.config.ts
ADDED
package/dist/chunk-5IPYOXBE.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
// src/lib/logger.ts
|
|
2
|
-
var verbose = false;
|
|
3
|
-
function setVerbose(v) {
|
|
4
|
-
verbose = v;
|
|
5
|
-
}
|
|
6
|
-
function isVerbose() {
|
|
7
|
-
return verbose;
|
|
8
|
-
}
|
|
9
|
-
function debug(tag, message) {
|
|
10
|
-
if (verbose) {
|
|
11
|
-
console.log(`[${tag}] ${message}`);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
function info(tag, message) {
|
|
15
|
-
console.log(`[${tag}] ${message}`);
|
|
16
|
-
}
|
|
17
|
-
function warn(tag, message) {
|
|
18
|
-
console.warn(`[${tag}] ${message}`);
|
|
19
|
-
}
|
|
20
|
-
function error(tag, message) {
|
|
21
|
-
console.error(`[${tag}] ${message}`);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export {
|
|
25
|
-
setVerbose,
|
|
26
|
-
isVerbose,
|
|
27
|
-
debug,
|
|
28
|
-
info,
|
|
29
|
-
warn,
|
|
30
|
-
error
|
|
31
|
-
};
|
|
32
|
-
//# sourceMappingURL=chunk-5IPYOXBE.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/logger.ts"],"sourcesContent":["/**\n * Simple logger with verbose mode toggle.\n * In production, debug logs are suppressed unless verbose mode is enabled.\n */\n\nlet verbose = false;\n\nexport function setVerbose(v: boolean) {\n verbose = v;\n}\n\nexport function isVerbose(): boolean {\n return verbose;\n}\n\n/**\n * Log a debug message. Only shown when verbose mode is enabled.\n */\nexport function debug(tag: string, message: string) {\n if (verbose) {\n console.log(`[${tag}] ${message}`);\n }\n}\n\n/**\n * Log an info message. Always shown.\n */\nexport function info(tag: string, message: string) {\n console.log(`[${tag}] ${message}`);\n}\n\n/**\n * Log a warning. Always shown.\n */\nexport function warn(tag: string, message: string) {\n console.warn(`[${tag}] ${message}`);\n}\n\n/**\n * Log an error. Always shown.\n */\nexport function error(tag: string, message: string) {\n console.error(`[${tag}] ${message}`);\n}\n"],"mappings":";AAKA,IAAI,UAAU;AAEP,SAAS,WAAW,GAAY;AACrC,YAAU;AACZ;AAEO,SAAS,YAAqB;AACnC,SAAO;AACT;AAKO,SAAS,MAAM,KAAa,SAAiB;AAClD,MAAI,SAAS;AACX,YAAQ,IAAI,IAAI,GAAG,KAAK,OAAO,EAAE;AAAA,EACnC;AACF;AAKO,SAAS,KAAK,KAAa,SAAiB;AACjD,UAAQ,IAAI,IAAI,GAAG,KAAK,OAAO,EAAE;AACnC;AAKO,SAAS,KAAK,KAAa,SAAiB;AACjD,UAAQ,KAAK,IAAI,GAAG,KAAK,OAAO,EAAE;AACpC;AAKO,SAAS,MAAM,KAAa,SAAiB;AAClD,UAAQ,MAAM,IAAI,GAAG,KAAK,OAAO,EAAE;AACrC;","names":[]}
|
package/dist/chunk-C73RKCTS.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
// src/lib/mentions.ts
|
|
2
|
-
import path from "path";
|
|
3
|
-
function parseMessageToContentBlocks(message, workingDir) {
|
|
4
|
-
const blocks = [];
|
|
5
|
-
const mentionRegex = /@(\.{0,2}[\w\/\.\-]+)/g;
|
|
6
|
-
let lastIndex = 0;
|
|
7
|
-
for (const match of message.matchAll(mentionRegex)) {
|
|
8
|
-
if (match.index > lastIndex) {
|
|
9
|
-
const text = message.slice(lastIndex, match.index);
|
|
10
|
-
if (text.trim()) {
|
|
11
|
-
blocks.push({ type: "text", text });
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
const relativePath = match[1];
|
|
15
|
-
const absolutePath = path.resolve(workingDir, relativePath);
|
|
16
|
-
blocks.push({
|
|
17
|
-
type: "resource_link",
|
|
18
|
-
uri: `file://${absolutePath}`,
|
|
19
|
-
name: relativePath
|
|
20
|
-
// Required per ACP spec - use the path the user typed
|
|
21
|
-
});
|
|
22
|
-
lastIndex = match.index + match[0].length;
|
|
23
|
-
}
|
|
24
|
-
if (lastIndex < message.length) {
|
|
25
|
-
const text = message.slice(lastIndex);
|
|
26
|
-
if (text.trim()) {
|
|
27
|
-
blocks.push({ type: "text", text });
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return blocks.length > 0 ? blocks : [{ type: "text", text: message }];
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export {
|
|
34
|
-
parseMessageToContentBlocks
|
|
35
|
-
};
|
|
36
|
-
//# sourceMappingURL=chunk-C73RKCTS.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/mentions.ts"],"sourcesContent":["import type { ContentBlock } from '../types.js';\nimport path from 'path';\n\n/**\n * Parse message text with @mentions into ContentBlock array.\n * @mentions become resource_link blocks, other text becomes text blocks.\n *\n * Examples:\n * - \"hello world\" → [{ type: 'text', text: 'hello world' }]\n * - \"@src/foo.ts\" → [{ type: 'resource_link', uri: 'file://...', name: 'src/foo.ts' }]\n * - \"check @src/foo.ts for bugs\" → text + resource_link + text\n */\nexport function parseMessageToContentBlocks(\n message: string,\n workingDir: string\n): ContentBlock[] {\n const blocks: ContentBlock[] = [];\n // Match @path/to/file.ts, @./local.ts, @../parent/file.ts\n // Allows leading ./ or ../ followed by path characters\n const mentionRegex = /@(\\.{0,2}[\\w\\/\\.\\-]+)/g;\n\n let lastIndex = 0;\n for (const match of message.matchAll(mentionRegex)) {\n // Add text before mention\n if (match.index! > lastIndex) {\n const text = message.slice(lastIndex, match.index);\n if (text.trim()) {\n blocks.push({ type: 'text', text });\n }\n }\n\n // Add resource_link for mention\n const relativePath = match[1];\n const absolutePath = path.resolve(workingDir, relativePath);\n blocks.push({\n type: 'resource_link',\n uri: `file://${absolutePath}`,\n name: relativePath, // Required per ACP spec - use the path the user typed\n });\n\n lastIndex = match.index! + match[0].length;\n }\n\n // Add remaining text\n if (lastIndex < message.length) {\n const text = message.slice(lastIndex);\n if (text.trim()) {\n blocks.push({ type: 'text', text });\n }\n }\n\n // If no mentions found, return single text block\n return blocks.length > 0 ? blocks : [{ type: 'text', text: message }];\n}\n"],"mappings":";AACA,OAAO,UAAU;AAWV,SAAS,4BACd,SACA,YACgB;AAChB,QAAM,SAAyB,CAAC;AAGhC,QAAM,eAAe;AAErB,MAAI,YAAY;AAChB,aAAW,SAAS,QAAQ,SAAS,YAAY,GAAG;AAElD,QAAI,MAAM,QAAS,WAAW;AAC5B,YAAM,OAAO,QAAQ,MAAM,WAAW,MAAM,KAAK;AACjD,UAAI,KAAK,KAAK,GAAG;AACf,eAAO,KAAK,EAAE,MAAM,QAAQ,KAAK,CAAC;AAAA,MACpC;AAAA,IACF;AAGA,UAAM,eAAe,MAAM,CAAC;AAC5B,UAAM,eAAe,KAAK,QAAQ,YAAY,YAAY;AAC1D,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,KAAK,UAAU,YAAY;AAAA,MAC3B,MAAM;AAAA;AAAA,IACR,CAAC;AAED,gBAAY,MAAM,QAAS,MAAM,CAAC,EAAE;AAAA,EACtC;AAGA,MAAI,YAAY,QAAQ,QAAQ;AAC9B,UAAM,OAAO,QAAQ,MAAM,SAAS;AACpC,QAAI,KAAK,KAAK,GAAG;AACf,aAAO,KAAK,EAAE,MAAM,QAAQ,KAAK,CAAC;AAAA,IACpC;AAAA,EACF;AAGA,SAAO,OAAO,SAAS,IAAI,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,CAAC;AACtE;","names":[]}
|