@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.
Files changed (58) hide show
  1. package/README.md +273 -0
  2. package/dist/client/connection.d.ts +101 -0
  3. package/dist/client/connection.d.ts.map +1 -0
  4. package/dist/client/connection.js +379 -0
  5. package/dist/client/connection.js.map +1 -0
  6. package/dist/client/event-emitter.d.ts +32 -0
  7. package/dist/client/event-emitter.d.ts.map +1 -0
  8. package/dist/client/event-emitter.js +72 -0
  9. package/dist/client/event-emitter.js.map +1 -0
  10. package/dist/client/index.d.ts +30 -0
  11. package/dist/client/index.d.ts.map +1 -0
  12. package/dist/client/index.js +29 -0
  13. package/dist/client/index.js.map +1 -0
  14. package/dist/client/state-machine.d.ts +61 -0
  15. package/dist/client/state-machine.d.ts.map +1 -0
  16. package/dist/client/state-machine.js +292 -0
  17. package/dist/client/state-machine.js.map +1 -0
  18. package/dist/client/stream-processor.d.ts +46 -0
  19. package/dist/client/stream-processor.d.ts.map +1 -0
  20. package/dist/client/stream-processor.js +173 -0
  21. package/dist/client/stream-processor.js.map +1 -0
  22. package/dist/react/hook.d.ts +55 -0
  23. package/dist/react/hook.d.ts.map +1 -0
  24. package/dist/react/hook.js +132 -0
  25. package/dist/react/hook.js.map +1 -0
  26. package/dist/react/index.d.ts +49 -0
  27. package/dist/react/index.d.ts.map +1 -0
  28. package/dist/react/index.js +48 -0
  29. package/dist/react/index.js.map +1 -0
  30. package/dist/server/claude-spawn.d.ts +52 -0
  31. package/dist/server/claude-spawn.d.ts.map +1 -0
  32. package/dist/server/claude-spawn.js +147 -0
  33. package/dist/server/claude-spawn.js.map +1 -0
  34. package/dist/server/conversation.d.ts +113 -0
  35. package/dist/server/conversation.d.ts.map +1 -0
  36. package/dist/server/conversation.js +520 -0
  37. package/dist/server/conversation.js.map +1 -0
  38. package/dist/server/index.d.ts +35 -0
  39. package/dist/server/index.d.ts.map +1 -0
  40. package/dist/server/index.js +39 -0
  41. package/dist/server/index.js.map +1 -0
  42. package/dist/server/sse-emitter.d.ts +42 -0
  43. package/dist/server/sse-emitter.d.ts.map +1 -0
  44. package/dist/server/sse-emitter.js +56 -0
  45. package/dist/server/sse-emitter.js.map +1 -0
  46. package/dist/shared/index.d.ts +3 -0
  47. package/dist/shared/index.d.ts.map +1 -0
  48. package/dist/shared/index.js +3 -0
  49. package/dist/shared/index.js.map +1 -0
  50. package/dist/shared/tool-utils.d.ts +25 -0
  51. package/dist/shared/tool-utils.d.ts.map +1 -0
  52. package/dist/shared/tool-utils.js +49 -0
  53. package/dist/shared/tool-utils.js.map +1 -0
  54. package/dist/shared/types.d.ts +82 -0
  55. package/dist/shared/types.d.ts.map +1 -0
  56. package/dist/shared/types.js +5 -0
  57. package/dist/shared/types.js.map +1 -0
  58. 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"}