@fronx/use-claude-code 0.1.0
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 +273 -0
- package/dist/client/connection.d.ts +101 -0
- package/dist/client/connection.d.ts.map +1 -0
- package/dist/client/connection.js +379 -0
- package/dist/client/connection.js.map +1 -0
- package/dist/client/event-emitter.d.ts +32 -0
- package/dist/client/event-emitter.d.ts.map +1 -0
- package/dist/client/event-emitter.js +72 -0
- package/dist/client/event-emitter.js.map +1 -0
- package/dist/client/index.d.ts +30 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +29 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/state-machine.d.ts +61 -0
- package/dist/client/state-machine.d.ts.map +1 -0
- package/dist/client/state-machine.js +292 -0
- package/dist/client/state-machine.js.map +1 -0
- package/dist/client/stream-processor.d.ts +46 -0
- package/dist/client/stream-processor.d.ts.map +1 -0
- package/dist/client/stream-processor.js +173 -0
- package/dist/client/stream-processor.js.map +1 -0
- package/dist/react/hook.d.ts +55 -0
- package/dist/react/hook.d.ts.map +1 -0
- package/dist/react/hook.js +132 -0
- package/dist/react/hook.js.map +1 -0
- package/dist/react/index.d.ts +49 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +48 -0
- package/dist/react/index.js.map +1 -0
- package/dist/server/claude-spawn.d.ts +52 -0
- package/dist/server/claude-spawn.d.ts.map +1 -0
- package/dist/server/claude-spawn.js +147 -0
- package/dist/server/claude-spawn.js.map +1 -0
- package/dist/server/conversation.d.ts +113 -0
- package/dist/server/conversation.d.ts.map +1 -0
- package/dist/server/conversation.js +520 -0
- package/dist/server/conversation.js.map +1 -0
- package/dist/server/index.d.ts +35 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +39 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/sse-emitter.d.ts +42 -0
- package/dist/server/sse-emitter.d.ts.map +1 -0
- package/dist/server/sse-emitter.js +56 -0
- package/dist/server/sse-emitter.js.map +1 -0
- package/dist/shared/index.d.ts +3 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +3 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/tool-utils.d.ts +25 -0
- package/dist/shared/tool-utils.d.ts.map +1 -0
- package/dist/shared/tool-utils.js +49 -0
- package/dist/shared/tool-utils.js.map +1 -0
- package/dist/shared/types.d.ts +82 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +5 -0
- package/dist/shared/types.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClaudeConnection - Framework-agnostic core for Claude Code integration.
|
|
3
|
+
*
|
|
4
|
+
* Handles:
|
|
5
|
+
* - Dual-connection pattern: POST+SSE for start/resume, then EventSource for ongoing
|
|
6
|
+
* - Reconnection with exponential backoff
|
|
7
|
+
* - Session ID filtering to ignore stale events after clear
|
|
8
|
+
* - Streaming segments accumulation (text interleaved with tools)
|
|
9
|
+
*/
|
|
10
|
+
import { EventEmitter } from './event-emitter.js';
|
|
11
|
+
import { StreamProcessor } from './stream-processor.js';
|
|
12
|
+
import { createInitialState, createStartingState, processEvent, addUserMessage, setStatus, setHasPersistedSession, clearSessionId, resetState, } from './state-machine.js';
|
|
13
|
+
const DEFAULT_RECONNECT_CONFIG = {
|
|
14
|
+
maxRetries: 10,
|
|
15
|
+
baseDelay: 1000,
|
|
16
|
+
maxDelay: 30000,
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* ClaudeConnection manages the connection to a Claude conversation.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* const connection = new ClaudeConnection({
|
|
23
|
+
* baseUrl: '/api/claude',
|
|
24
|
+
* conversationId: 'user-123',
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* connection.on('message', (msg) => console.log(msg));
|
|
28
|
+
* connection.on('result', () => console.log('Response complete'));
|
|
29
|
+
* connection.connect();
|
|
30
|
+
*
|
|
31
|
+
* // Later
|
|
32
|
+
* await connection.send('Hello!');
|
|
33
|
+
*/
|
|
34
|
+
export class ClaudeConnection extends EventEmitter {
|
|
35
|
+
config;
|
|
36
|
+
reconnectConfig;
|
|
37
|
+
eventSource = null;
|
|
38
|
+
state;
|
|
39
|
+
needNewTextSegment = true;
|
|
40
|
+
reconnectAttempt = 0;
|
|
41
|
+
constructor(config) {
|
|
42
|
+
super();
|
|
43
|
+
this.config = config;
|
|
44
|
+
this.reconnectConfig = {
|
|
45
|
+
...DEFAULT_RECONNECT_CONFIG,
|
|
46
|
+
...config.reconnect,
|
|
47
|
+
};
|
|
48
|
+
this.state = createInitialState();
|
|
49
|
+
}
|
|
50
|
+
// Read-only state accessors
|
|
51
|
+
get status() {
|
|
52
|
+
return this.state.status;
|
|
53
|
+
}
|
|
54
|
+
get messages() {
|
|
55
|
+
return this.state.messages;
|
|
56
|
+
}
|
|
57
|
+
get isStreaming() {
|
|
58
|
+
return this.state.isStreaming;
|
|
59
|
+
}
|
|
60
|
+
get streamingSegments() {
|
|
61
|
+
return this.state.streamingSegments;
|
|
62
|
+
}
|
|
63
|
+
get hasPersistedSession() {
|
|
64
|
+
return this.state.hasPersistedSession;
|
|
65
|
+
}
|
|
66
|
+
get lastError() {
|
|
67
|
+
return this.state.lastError;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Check status and connect if active.
|
|
71
|
+
* Call this on mount to restore state.
|
|
72
|
+
*/
|
|
73
|
+
async connect() {
|
|
74
|
+
this.updateState(setStatus(this.state, 'checking'));
|
|
75
|
+
try {
|
|
76
|
+
const res = await fetch(`${this.config.baseUrl}/${this.config.conversationId}/status`);
|
|
77
|
+
const data = await res.json();
|
|
78
|
+
this.updateState(setHasPersistedSession(this.state, data.hasPersistedSession || false));
|
|
79
|
+
if (data.active) {
|
|
80
|
+
this.updateState(setStatus(this.state, 'connected'));
|
|
81
|
+
this.connectEventSource();
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
this.updateState(setStatus(this.state, 'disconnected'));
|
|
85
|
+
// Only prewarm if no persisted session (user will likely want to resume)
|
|
86
|
+
if (!data.hasPersistedSession) {
|
|
87
|
+
this.prewarm().catch(() => {
|
|
88
|
+
// Prewarm failure is not critical
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
this.updateState(setStatus(this.state, 'disconnected'));
|
|
95
|
+
this.updateState(setHasPersistedSession(this.state, false));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Disconnect from the conversation.
|
|
100
|
+
*/
|
|
101
|
+
disconnect() {
|
|
102
|
+
this.closeEventSource();
|
|
103
|
+
this.updateState(setStatus(this.state, 'disconnected'));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Start a new conversation.
|
|
107
|
+
*/
|
|
108
|
+
async start(initialMessage) {
|
|
109
|
+
this.closeEventSource();
|
|
110
|
+
this.updateState(createStartingState(this.state, initialMessage));
|
|
111
|
+
try {
|
|
112
|
+
const response = await fetch(`${this.config.baseUrl}/${this.config.conversationId}/start`, {
|
|
113
|
+
method: 'POST',
|
|
114
|
+
headers: { 'Content-Type': 'application/json' },
|
|
115
|
+
body: JSON.stringify({ initialMessage: initialMessage || undefined }),
|
|
116
|
+
});
|
|
117
|
+
if (!response.ok) {
|
|
118
|
+
this.updateState(setStatus(this.state, 'disconnected'));
|
|
119
|
+
this.updateState({ ...this.state, isStreaming: false });
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
// Process SSE stream from start endpoint
|
|
123
|
+
await this.processResponseStream(response);
|
|
124
|
+
// After stream ends, connect for future updates
|
|
125
|
+
this.connectEventSource();
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
console.error('Failed to start conversation:', err);
|
|
129
|
+
this.updateState(setStatus(this.state, 'disconnected'));
|
|
130
|
+
this.updateState({ ...this.state, isStreaming: false });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Send a message in an active conversation.
|
|
135
|
+
*/
|
|
136
|
+
async send(message) {
|
|
137
|
+
if (!message.trim())
|
|
138
|
+
return;
|
|
139
|
+
// Optimistically add user message
|
|
140
|
+
this.updateState(addUserMessage(this.state, message));
|
|
141
|
+
this.updateState({ ...this.state, isStreaming: true });
|
|
142
|
+
try {
|
|
143
|
+
const response = await fetch(`${this.config.baseUrl}/${this.config.conversationId}/message`, {
|
|
144
|
+
method: 'POST',
|
|
145
|
+
headers: { 'Content-Type': 'application/json' },
|
|
146
|
+
body: JSON.stringify({ message }),
|
|
147
|
+
});
|
|
148
|
+
if (!response.ok) {
|
|
149
|
+
if (response.status === 404) {
|
|
150
|
+
// Agent no longer exists - session expired
|
|
151
|
+
this.updateState(setStatus(this.state, 'disconnected'));
|
|
152
|
+
}
|
|
153
|
+
console.error('Failed to send message:', response.status);
|
|
154
|
+
this.updateState({ ...this.state, isStreaming: false });
|
|
155
|
+
}
|
|
156
|
+
// Response comes via SSE, not from this endpoint
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
console.error('Failed to send message:', err);
|
|
160
|
+
this.updateState({ ...this.state, isStreaming: false });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Stop the current response generation (SIGINT).
|
|
165
|
+
*/
|
|
166
|
+
async stop() {
|
|
167
|
+
try {
|
|
168
|
+
await fetch(`${this.config.baseUrl}/${this.config.conversationId}/stop`, {
|
|
169
|
+
method: 'POST',
|
|
170
|
+
});
|
|
171
|
+
// The 'stopped' event will handle UI updates
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
console.error('Failed to stop response:', err);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Clear the session history and delete persisted session.
|
|
179
|
+
*/
|
|
180
|
+
async clear() {
|
|
181
|
+
// Immediately clear session ID to reject any in-flight events
|
|
182
|
+
this.updateState(clearSessionId(this.state));
|
|
183
|
+
this.closeEventSource();
|
|
184
|
+
try {
|
|
185
|
+
await fetch(`${this.config.baseUrl}/${this.config.conversationId}/clear`, {
|
|
186
|
+
method: 'POST',
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
console.error('Failed to clear session:', err);
|
|
191
|
+
}
|
|
192
|
+
this.updateState(resetState());
|
|
193
|
+
this.updateState(setHasPersistedSession(this.state, false));
|
|
194
|
+
this.needNewTextSegment = true;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Resume a persisted session.
|
|
198
|
+
*/
|
|
199
|
+
async resume() {
|
|
200
|
+
this.closeEventSource();
|
|
201
|
+
this.updateState(setStatus(this.state, 'connecting'));
|
|
202
|
+
try {
|
|
203
|
+
const response = await fetch(`${this.config.baseUrl}/${this.config.conversationId}/resume`, {
|
|
204
|
+
method: 'POST',
|
|
205
|
+
headers: { 'Content-Type': 'application/json' },
|
|
206
|
+
});
|
|
207
|
+
if (!response.ok) {
|
|
208
|
+
console.error('Failed to resume session:', response.status);
|
|
209
|
+
this.updateState(setStatus(this.state, 'disconnected'));
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
// Process SSE stream from resume endpoint
|
|
213
|
+
await this.processResponseStream(response);
|
|
214
|
+
// After stream ends, connect for future updates
|
|
215
|
+
this.connectEventSource();
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
console.error('Failed to resume session:', err);
|
|
219
|
+
this.updateState(setStatus(this.state, 'disconnected'));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Prewarm the conversation for faster first response.
|
|
224
|
+
*/
|
|
225
|
+
async prewarm() {
|
|
226
|
+
try {
|
|
227
|
+
await fetch(`${this.config.baseUrl}/${this.config.conversationId}/prewarm`, {
|
|
228
|
+
method: 'POST',
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
// Prewarm failure is not critical
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// Private methods
|
|
236
|
+
updateState(newState) {
|
|
237
|
+
const prevMessages = this.state.messages;
|
|
238
|
+
const prevSegments = this.state.streamingSegments;
|
|
239
|
+
const prevStreaming = this.state.isStreaming;
|
|
240
|
+
this.state = newState;
|
|
241
|
+
this.emit('stateChange');
|
|
242
|
+
// Emit specific events
|
|
243
|
+
if (newState.messages !== prevMessages && newState.messages.length > prevMessages.length) {
|
|
244
|
+
const newMessage = newState.messages[newState.messages.length - 1];
|
|
245
|
+
this.emit('message', newMessage);
|
|
246
|
+
}
|
|
247
|
+
if (newState.streamingSegments !== prevSegments) {
|
|
248
|
+
this.emit('streaming', newState.streamingSegments);
|
|
249
|
+
}
|
|
250
|
+
if (prevStreaming && !newState.isStreaming && newState.messages.length > 0) {
|
|
251
|
+
const lastMessage = newState.messages[newState.messages.length - 1];
|
|
252
|
+
if (lastMessage.role === 'assistant' && !lastMessage.content.endsWith('*(stopped)*')) {
|
|
253
|
+
this.emit('result');
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (newState.lastError && newState.lastError !== this.state.lastError) {
|
|
257
|
+
this.emit('error', newState.lastError);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
handleEvent(event) {
|
|
261
|
+
console.log('[ClaudeConnection] Received SSE event:', event.type, event);
|
|
262
|
+
const [newState, newNeedNewTextSegment] = processEvent(this.state, event, this.needNewTextSegment);
|
|
263
|
+
this.needNewTextSegment = newNeedNewTextSegment;
|
|
264
|
+
// Emit tool events
|
|
265
|
+
if (event.type === 'tool') {
|
|
266
|
+
this.emit('tool', { name: event.name, param: event.param });
|
|
267
|
+
}
|
|
268
|
+
this.updateState(newState);
|
|
269
|
+
}
|
|
270
|
+
async processResponseStream(response) {
|
|
271
|
+
console.log('[ClaudeConnection] Processing response stream, status:', response.status);
|
|
272
|
+
const reader = response.body?.getReader();
|
|
273
|
+
if (!reader) {
|
|
274
|
+
console.warn('[ClaudeConnection] No response body reader available');
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const decoder = new TextDecoder();
|
|
278
|
+
const processor = new StreamProcessor((event) => this.handleEvent(event));
|
|
279
|
+
try {
|
|
280
|
+
while (true) {
|
|
281
|
+
const { done, value } = await reader.read();
|
|
282
|
+
if (done) {
|
|
283
|
+
console.log('[ClaudeConnection] Response stream ended');
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
287
|
+
console.log('[ClaudeConnection] Received chunk:', chunk.slice(0, 200));
|
|
288
|
+
processor.processChunk(chunk);
|
|
289
|
+
}
|
|
290
|
+
processor.flush();
|
|
291
|
+
}
|
|
292
|
+
finally {
|
|
293
|
+
await reader.cancel();
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
connectEventSource() {
|
|
297
|
+
this.closeEventSource();
|
|
298
|
+
const eventSource = new EventSource(`${this.config.baseUrl}/${this.config.conversationId}/connect`);
|
|
299
|
+
this.eventSource = eventSource;
|
|
300
|
+
const processor = new StreamProcessor((event) => this.handleEvent(event));
|
|
301
|
+
// Handle named events
|
|
302
|
+
const eventTypes = [
|
|
303
|
+
'init',
|
|
304
|
+
'history',
|
|
305
|
+
'assistant',
|
|
306
|
+
'tool',
|
|
307
|
+
'result',
|
|
308
|
+
'user',
|
|
309
|
+
'error',
|
|
310
|
+
'closed',
|
|
311
|
+
'cleared',
|
|
312
|
+
'stopped',
|
|
313
|
+
];
|
|
314
|
+
for (const type of eventTypes) {
|
|
315
|
+
eventSource.addEventListener(type, (e) => {
|
|
316
|
+
processor.processMessageEvent(e, type);
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
eventSource.onerror = () => {
|
|
320
|
+
this.closeEventSource();
|
|
321
|
+
this.attemptReconnect();
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
closeEventSource() {
|
|
325
|
+
if (this.eventSource) {
|
|
326
|
+
this.eventSource.close();
|
|
327
|
+
this.eventSource = null;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
async attemptReconnect() {
|
|
331
|
+
this.updateState(setStatus(this.state, 'reconnecting'));
|
|
332
|
+
for (let attempt = 0; attempt <= this.reconnectConfig.maxRetries; attempt++) {
|
|
333
|
+
this.reconnectAttempt = attempt;
|
|
334
|
+
try {
|
|
335
|
+
const res = await fetch(`${this.config.baseUrl}/${this.config.conversationId}/status`);
|
|
336
|
+
if (!res.ok) {
|
|
337
|
+
// Network error - retry
|
|
338
|
+
if (attempt < this.reconnectConfig.maxRetries) {
|
|
339
|
+
const delay = this.calculateRetryDelay(attempt);
|
|
340
|
+
await this.sleep(delay);
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
const data = await res.json();
|
|
345
|
+
if (data.active) {
|
|
346
|
+
// Agent is still running - reconnect
|
|
347
|
+
this.reconnectAttempt = 0;
|
|
348
|
+
this.connectEventSource();
|
|
349
|
+
this.updateState(setStatus(this.state, 'connected'));
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
// Agent is not active - give up
|
|
353
|
+
this.updateState(setStatus(this.state, 'disconnected'));
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
catch {
|
|
357
|
+
// Network error - retry
|
|
358
|
+
if (attempt < this.reconnectConfig.maxRetries) {
|
|
359
|
+
const delay = this.calculateRetryDelay(attempt);
|
|
360
|
+
await this.sleep(delay);
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
// Exhausted retries
|
|
366
|
+
this.updateState(setStatus(this.state, 'disconnected'));
|
|
367
|
+
}
|
|
368
|
+
calculateRetryDelay(attempt) {
|
|
369
|
+
const exponentialDelay = this.reconnectConfig.baseDelay * Math.pow(2, attempt);
|
|
370
|
+
const cappedDelay = Math.min(exponentialDelay, this.reconnectConfig.maxDelay);
|
|
371
|
+
// Add jitter (0-25% of delay) to prevent thundering herd
|
|
372
|
+
const jitter = cappedDelay * Math.random() * 0.25;
|
|
373
|
+
return cappedDelay + jitter;
|
|
374
|
+
}
|
|
375
|
+
sleep(ms) {
|
|
376
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
//# sourceMappingURL=connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/client/connection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal typed EventEmitter for browser environments.
|
|
3
|
+
*
|
|
4
|
+
* Type-safe alternative to Node's EventEmitter that works in browsers
|
|
5
|
+
* without any dependencies.
|
|
6
|
+
*/
|
|
7
|
+
export declare class EventEmitter<Events extends {
|
|
8
|
+
[K in keyof Events]: (...args: any[]) => void;
|
|
9
|
+
}> {
|
|
10
|
+
private listeners;
|
|
11
|
+
/**
|
|
12
|
+
* Register an event listener.
|
|
13
|
+
*/
|
|
14
|
+
on<K extends keyof Events>(eventName: K, fn: Events[K]): this;
|
|
15
|
+
/**
|
|
16
|
+
* Remove an event listener.
|
|
17
|
+
*/
|
|
18
|
+
off<K extends keyof Events>(eventName: K, fn: Events[K]): this;
|
|
19
|
+
/**
|
|
20
|
+
* Register a one-time event listener.
|
|
21
|
+
*/
|
|
22
|
+
once<K extends keyof Events>(eventName: K, fn: Events[K]): this;
|
|
23
|
+
/**
|
|
24
|
+
* Emit an event to all registered listeners.
|
|
25
|
+
*/
|
|
26
|
+
protected emit<K extends keyof Events>(eventName: K, ...args: Events[K] extends (...args: infer P) => void ? P : never): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Remove all listeners for an event, or all listeners if no event specified.
|
|
29
|
+
*/
|
|
30
|
+
removeAllListeners<K extends keyof Events>(eventName?: K): this;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=event-emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-emitter.d.ts","sourceRoot":"","sources":["../../src/client/event-emitter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,qBAAa,YAAY,CACvB,MAAM,SAAS;KAAG,CAAC,IAAI,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI;CAAE;IAEhE,OAAO,CAAC,SAAS,CAA6C;IAE9D;;OAEG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI;IAU7D;;OAEG;IACH,GAAG,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI;IAW9D;;OAEG;IACH,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI;IAQ/D;;OAEG;IACH,SAAS,CAAC,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,EACnC,SAAS,EAAE,CAAC,EACZ,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,IAAI,GAAG,CAAC,GAAG,KAAK,GAChE,OAAO;IAWV;;OAEG;IACH,kBAAkB,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC,GAAG,IAAI;CAQhE"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal typed EventEmitter for browser environments.
|
|
3
|
+
*
|
|
4
|
+
* Type-safe alternative to Node's EventEmitter that works in browsers
|
|
5
|
+
* without any dependencies.
|
|
6
|
+
*/
|
|
7
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
8
|
+
export class EventEmitter {
|
|
9
|
+
listeners = {};
|
|
10
|
+
/**
|
|
11
|
+
* Register an event listener.
|
|
12
|
+
*/
|
|
13
|
+
on(eventName, fn) {
|
|
14
|
+
const listeners = this.listeners[eventName];
|
|
15
|
+
if (!listeners) {
|
|
16
|
+
this.listeners[eventName] = [fn];
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
listeners.push(fn);
|
|
20
|
+
}
|
|
21
|
+
return this;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Remove an event listener.
|
|
25
|
+
*/
|
|
26
|
+
off(eventName, fn) {
|
|
27
|
+
const arr = this.listeners[eventName];
|
|
28
|
+
if (arr) {
|
|
29
|
+
const index = arr.indexOf(fn);
|
|
30
|
+
if (index !== -1) {
|
|
31
|
+
arr.splice(index, 1);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Register a one-time event listener.
|
|
38
|
+
*/
|
|
39
|
+
once(eventName, fn) {
|
|
40
|
+
const onceHandler = ((...args) => {
|
|
41
|
+
this.off(eventName, onceHandler);
|
|
42
|
+
fn(...args);
|
|
43
|
+
});
|
|
44
|
+
return this.on(eventName, onceHandler);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Emit an event to all registered listeners.
|
|
48
|
+
*/
|
|
49
|
+
emit(eventName, ...args) {
|
|
50
|
+
const arr = this.listeners[eventName];
|
|
51
|
+
if (!arr || arr.length === 0) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
for (const fn of arr) {
|
|
55
|
+
fn(...args);
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Remove all listeners for an event, or all listeners if no event specified.
|
|
61
|
+
*/
|
|
62
|
+
removeAllListeners(eventName) {
|
|
63
|
+
if (eventName) {
|
|
64
|
+
delete this.listeners[eventName];
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
this.listeners = {};
|
|
68
|
+
}
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=event-emitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-emitter.js","sourceRoot":"","sources":["../../src/client/event-emitter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,uDAAuD;AAEvD,MAAM,OAAO,YAAY;IAGf,SAAS,GAA0C,EAAE,CAAC;IAE9D;;OAEG;IACH,EAAE,CAAyB,SAAY,EAAE,EAAa;QACpD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,GAAG,CAAyB,SAAY,EAAE,EAAa;QACrD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,GAAG,EAAE,CAAC;YACR,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC9B,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;gBACjB,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,IAAI,CAAyB,SAAY,EAAE,EAAa;QACtD,MAAM,WAAW,GAAG,CAAC,CAAC,GAAG,IAAW,EAAE,EAAE;YACtC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,WAAwB,CAAC,CAAC;YAC7C,EAA+B,CAAC,GAAG,IAAI,CAAC,CAAC;QAC5C,CAAC,CAAc,CAAC;QAChB,OAAO,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IACzC,CAAC;IAED;;OAEG;IACO,IAAI,CACZ,SAAY,EACZ,GAAG,IAA8D;QAEjE,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,KAAK,CAAC;QACf,CAAC;QACD,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;YACpB,EAA+B,CAAC,GAAG,IAAI,CAAC,CAAC;QAC5C,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,kBAAkB,CAAyB,SAAa;QACtD,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;QACtB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side Claude Code integration
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* import { ClaudeConnection } from '@anthropic/claude-code-lib/client';
|
|
6
|
+
*
|
|
7
|
+
* const connection = new ClaudeConnection({
|
|
8
|
+
* baseUrl: '/api/claude',
|
|
9
|
+
* conversationId: 'user-123',
|
|
10
|
+
* });
|
|
11
|
+
*
|
|
12
|
+
* connection.on('message', (msg) => console.log(msg));
|
|
13
|
+
* connection.on('result', () => console.log('Response complete'));
|
|
14
|
+
* connection.connect();
|
|
15
|
+
*
|
|
16
|
+
* // Later: start a new conversation
|
|
17
|
+
* await connection.start('Hello!');
|
|
18
|
+
*
|
|
19
|
+
* // Or send a message in an active conversation
|
|
20
|
+
* await connection.send('How does this work?');
|
|
21
|
+
*/
|
|
22
|
+
export * from '../shared/index.js';
|
|
23
|
+
export { ClaudeConnection } from './connection.js';
|
|
24
|
+
export type { ClaudeConnectionConfig, ClaudeConnectionEvents } from './connection.js';
|
|
25
|
+
export { StreamProcessor } from './stream-processor.js';
|
|
26
|
+
export type { StreamEventHandler } from './stream-processor.js';
|
|
27
|
+
export { EventEmitter } from './event-emitter.js';
|
|
28
|
+
export type { ConnectionStatus, ChatState } from './state-machine.js';
|
|
29
|
+
export { createInitialState, createStartingState, processEvent, addUserMessage, setStatus, setHasPersistedSession, clearSessionId, resetState, } from './state-machine.js';
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,cAAc,oBAAoB,CAAC;AAGnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACtF,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,cAAc,EACd,SAAS,EACT,sBAAsB,EACtB,cAAc,EACd,UAAU,GACX,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side Claude Code integration
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* import { ClaudeConnection } from '@anthropic/claude-code-lib/client';
|
|
6
|
+
*
|
|
7
|
+
* const connection = new ClaudeConnection({
|
|
8
|
+
* baseUrl: '/api/claude',
|
|
9
|
+
* conversationId: 'user-123',
|
|
10
|
+
* });
|
|
11
|
+
*
|
|
12
|
+
* connection.on('message', (msg) => console.log(msg));
|
|
13
|
+
* connection.on('result', () => console.log('Response complete'));
|
|
14
|
+
* connection.connect();
|
|
15
|
+
*
|
|
16
|
+
* // Later: start a new conversation
|
|
17
|
+
* await connection.start('Hello!');
|
|
18
|
+
*
|
|
19
|
+
* // Or send a message in an active conversation
|
|
20
|
+
* await connection.send('How does this work?');
|
|
21
|
+
*/
|
|
22
|
+
// Re-export shared types and utilities
|
|
23
|
+
export * from '../shared/index.js';
|
|
24
|
+
// Client-specific exports
|
|
25
|
+
export { ClaudeConnection } from './connection.js';
|
|
26
|
+
export { StreamProcessor } from './stream-processor.js';
|
|
27
|
+
export { EventEmitter } from './event-emitter.js';
|
|
28
|
+
export { createInitialState, createStartingState, processEvent, addUserMessage, setStatus, setHasPersistedSession, clearSessionId, resetState, } from './state-machine.js';
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,uCAAuC;AACvC,cAAc,oBAAoB,CAAC;AAEnC,0BAA0B;AAC1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,cAAc,EACd,SAAS,EACT,sBAAsB,EACtB,cAAc,EACd,UAAU,GACX,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat state machine - handles message accumulation and streaming state correctly.
|
|
3
|
+
*
|
|
4
|
+
* Key insight: when Claude runs tools, the `result` event only contains
|
|
5
|
+
* the FINAL portion of the response. But `assistant` events stream the
|
|
6
|
+
* FULL content. We must use the accumulated streaming content, not the
|
|
7
|
+
* result payload.
|
|
8
|
+
*
|
|
9
|
+
* This module is pure - no React, no DOM, no side effects.
|
|
10
|
+
*/
|
|
11
|
+
import type { Message, StreamSegment, ClaudeError, SSEEvent } from '../shared/types.js';
|
|
12
|
+
export type ConnectionStatus = 'checking' | 'disconnected' | 'connecting' | 'connected' | 'reconnecting';
|
|
13
|
+
export interface ChatState {
|
|
14
|
+
messages: Message[];
|
|
15
|
+
status: ConnectionStatus;
|
|
16
|
+
isStreaming: boolean;
|
|
17
|
+
streamingSegments: StreamSegment[];
|
|
18
|
+
hasPersistedSession: boolean;
|
|
19
|
+
lastError: ClaudeError | null;
|
|
20
|
+
currentSessionId: string | null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create the initial state for a new connection.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createInitialState(): ChatState;
|
|
26
|
+
/**
|
|
27
|
+
* Create state for when starting a new conversation.
|
|
28
|
+
* Optionally includes a user message if provided.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createStartingState(state: ChatState, userMessage?: string): ChatState;
|
|
31
|
+
/**
|
|
32
|
+
* Process an SSE event and return the new state.
|
|
33
|
+
* Pure function - no side effects.
|
|
34
|
+
*
|
|
35
|
+
* @param state - Current state
|
|
36
|
+
* @param event - SSE event to process
|
|
37
|
+
* @param needNewTextSegment - Whether next text should start a new segment (after tool use)
|
|
38
|
+
* @returns Tuple of [newState, needNewTextSegment]
|
|
39
|
+
*/
|
|
40
|
+
export declare function processEvent(state: ChatState, event: SSEEvent, needNewTextSegment: boolean): [ChatState, boolean];
|
|
41
|
+
/**
|
|
42
|
+
* Add a user message to the state (for optimistic updates).
|
|
43
|
+
*/
|
|
44
|
+
export declare function addUserMessage(state: ChatState, content: string): ChatState;
|
|
45
|
+
/**
|
|
46
|
+
* Update status.
|
|
47
|
+
*/
|
|
48
|
+
export declare function setStatus(state: ChatState, status: ConnectionStatus): ChatState;
|
|
49
|
+
/**
|
|
50
|
+
* Set persisted session flag.
|
|
51
|
+
*/
|
|
52
|
+
export declare function setHasPersistedSession(state: ChatState, hasPersistedSession: boolean): ChatState;
|
|
53
|
+
/**
|
|
54
|
+
* Clear session ID (used before clear() to reject stale events).
|
|
55
|
+
*/
|
|
56
|
+
export declare function clearSessionId(state: ChatState): ChatState;
|
|
57
|
+
/**
|
|
58
|
+
* Full state reset for clear operations.
|
|
59
|
+
*/
|
|
60
|
+
export declare function resetState(): ChatState;
|
|
61
|
+
//# sourceMappingURL=state-machine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-machine.d.ts","sourceRoot":"","sources":["../../src/client/state-machine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAExF,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,CAAC;AAEzG,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,MAAM,EAAE,gBAAgB,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,iBAAiB,EAAE,aAAa,EAAE,CAAC;IACnC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAQD;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,SAAS,CAU9C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CA2BrF;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,QAAQ,EACf,kBAAkB,EAAE,OAAO,GAC1B,CAAC,SAAS,EAAE,OAAO,CAAC,CAyMtB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAa3E;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAG,SAAS,CAE/E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,OAAO,GAAG,SAAS,CAEhG;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAE1D;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,SAAS,CAKtC"}
|