@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
package/README.md ADDED
@@ -0,0 +1,273 @@
1
+ # @anthropic/claude-code-lib
2
+
3
+ A reusable library for integrating Claude Code CLI conversations into applications.
4
+
5
+ ## Features
6
+
7
+ - **Server-side**: Spawn and manage Claude CLI processes, handle conversation lifecycle, stream responses via SSE
8
+ - **Client-side**: Parse SSE streams, manage connection state, handle reconnection with exponential backoff
9
+ - **React**: `useClaudeConversation` hook for easy integration
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm install @anthropic/claude-code-lib
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ### Server (Node.js)
20
+
21
+ ```typescript
22
+ import { ClaudeManager } from '@anthropic/claude-code-lib/server';
23
+
24
+ const manager = new ClaudeManager({
25
+ sessionDir: './data/sessions',
26
+ });
27
+
28
+ // Start a conversation
29
+ const conversation = manager.start('user-123', {
30
+ systemPrompt: 'You are a helpful assistant.',
31
+ cwd: process.cwd(),
32
+ initialMessage: 'Hello!',
33
+ });
34
+
35
+ // Subscribe to SSE events
36
+ conversation.subscribe(res);
37
+
38
+ // Send additional messages
39
+ conversation.send('How does this work?');
40
+
41
+ // Stop generation (SIGINT)
42
+ conversation.stop();
43
+
44
+ // Clear conversation
45
+ manager.clear('user-123');
46
+ ```
47
+
48
+ ### Client (Browser)
49
+
50
+ ```typescript
51
+ import { ClaudeConnection } from '@anthropic/claude-code-lib/client';
52
+
53
+ const connection = new ClaudeConnection({
54
+ baseUrl: '/api/claude',
55
+ conversationId: 'user-123',
56
+ });
57
+
58
+ connection.on('stateChange', () => {
59
+ console.log('Messages:', connection.messages);
60
+ console.log('Streaming:', connection.streamingSegments);
61
+ });
62
+
63
+ connection.on('result', () => {
64
+ console.log('Response complete');
65
+ });
66
+
67
+ // Check status and connect
68
+ await connection.connect();
69
+
70
+ // Start a new conversation
71
+ await connection.start('Hello!');
72
+
73
+ // Send a message
74
+ await connection.send('How does this work?');
75
+
76
+ // Stop generation
77
+ await connection.stop();
78
+
79
+ // Clear session
80
+ await connection.clear();
81
+ ```
82
+
83
+ ### React
84
+
85
+ ```tsx
86
+ import { useClaudeConversation } from '@anthropic/claude-code-lib/react';
87
+
88
+ function Chat({ projectId }) {
89
+ const {
90
+ messages,
91
+ status,
92
+ isStreaming,
93
+ streamingSegments,
94
+ hasPersistedSession,
95
+ start,
96
+ send,
97
+ stop,
98
+ clear,
99
+ resume,
100
+ } = useClaudeConversation({
101
+ baseUrl: '/api/claude',
102
+ conversationId: projectId,
103
+ onResult: () => console.log('Response complete'),
104
+ });
105
+
106
+ return (
107
+ <div>
108
+ {/* Completed messages */}
109
+ {messages.map(msg => (
110
+ <div key={msg.id} className={msg.role}>
111
+ {msg.content}
112
+ </div>
113
+ ))}
114
+
115
+ {/* Streaming content */}
116
+ {streamingSegments.map((seg, i) =>
117
+ seg.type === 'text' ? (
118
+ <div key={i}>{seg.content}</div>
119
+ ) : (
120
+ <div key={i}>Running: {seg.name} {seg.param}</div>
121
+ )
122
+ )}
123
+
124
+ {/* Resume link for persisted sessions */}
125
+ {status === 'disconnected' && hasPersistedSession && (
126
+ <button onClick={resume}>Resume Previous Session</button>
127
+ )}
128
+
129
+ {/* Controls */}
130
+ <input type="text" id="message" />
131
+ <button onClick={() => send(document.getElementById('message').value)}>
132
+ Send
133
+ </button>
134
+ {isStreaming && <button onClick={stop}>Stop</button>}
135
+ </div>
136
+ );
137
+ }
138
+ ```
139
+
140
+ ## API Reference
141
+
142
+ ### Server
143
+
144
+ #### `ClaudeManager`
145
+
146
+ Main class for managing Claude conversations.
147
+
148
+ ```typescript
149
+ interface ClaudeManagerConfig {
150
+ sessionDir: string; // Where to persist sessions
151
+ claudePath?: string; // Path to claude CLI (default: 'claude')
152
+ defaultAllowedTools?: string[]; // Default tools to allow
153
+ autoPrewarm?: boolean; // Auto-prewarm after clear (default: false)
154
+ }
155
+
156
+ interface StartOptions {
157
+ systemPrompt: string | { file: string };
158
+ cwd: string;
159
+ allowedTools?: string[];
160
+ initialMessage?: string;
161
+ }
162
+ ```
163
+
164
+ Methods:
165
+ - `start(id, options)` - Start a new conversation
166
+ - `get(id)` - Get an active conversation
167
+ - `resume(id, options)` - Resume from persisted session
168
+ - `stop(id)` - Stop current response (SIGINT)
169
+ - `clear(id)` - Kill process and delete session
170
+ - `prewarm(id, options)` - Spawn without sending message
171
+ - `getStatus(id)` - Get conversation status
172
+ - `hasPersistedSession(id)` - Check for saved session
173
+
174
+ ### Client
175
+
176
+ #### `ClaudeConnection`
177
+
178
+ Event-emitter based connection manager.
179
+
180
+ ```typescript
181
+ interface ClaudeConnectionConfig {
182
+ baseUrl: string;
183
+ conversationId: string;
184
+ reconnect?: {
185
+ maxRetries?: number; // Default: 10
186
+ baseDelay?: number; // Default: 1000ms
187
+ maxDelay?: number; // Default: 30000ms
188
+ };
189
+ }
190
+ ```
191
+
192
+ Properties (read-only):
193
+ - `status` - 'checking' | 'disconnected' | 'connecting' | 'connected' | 'reconnecting'
194
+ - `messages` - Array of completed messages
195
+ - `isStreaming` - Whether currently streaming
196
+ - `streamingSegments` - Current streaming content (text and tools)
197
+ - `hasPersistedSession` - Whether a saved session exists
198
+ - `lastError` - Most recent error
199
+
200
+ Methods:
201
+ - `connect()` - Check status and connect
202
+ - `disconnect()` - Close connection
203
+ - `start(message?)` - Start new conversation
204
+ - `send(message)` - Send message
205
+ - `stop()` - Stop generation
206
+ - `clear()` - Clear session
207
+ - `resume()` - Resume saved session
208
+ - `prewarm()` - Prewarm for faster response
209
+
210
+ Events:
211
+ - `stateChange` - Any state property changed
212
+ - `message` - New message added
213
+ - `streaming` - Streaming segments updated
214
+ - `tool` - Tool invocation
215
+ - `result` - Response complete
216
+ - `error` - Error occurred
217
+
218
+ ### React
219
+
220
+ #### `useClaudeConversation`
221
+
222
+ ```typescript
223
+ interface UseClaudeConversationOptions {
224
+ baseUrl: string;
225
+ conversationId: string;
226
+ autoConnect?: boolean; // Default: true
227
+ reconnect?: ReconnectConfig;
228
+ onResult?: () => void; // Called when response completes
229
+ }
230
+ ```
231
+
232
+ Returns all ClaudeConnection properties and methods as React state.
233
+
234
+ ## HTTP API
235
+
236
+ The package expects these server endpoints:
237
+
238
+ | Endpoint | Method | Purpose |
239
+ |----------|--------|---------|
240
+ | `/:id/status` | GET | Check conversation status |
241
+ | `/:id/start` | POST | Start new conversation |
242
+ | `/:id/connect` | GET | SSE stream for updates |
243
+ | `/:id/message` | POST | Send message |
244
+ | `/:id/stop` | POST | Stop generation |
245
+ | `/:id/clear` | POST | Clear session |
246
+ | `/:id/resume` | POST | Resume saved session |
247
+ | `/:id/prewarm` | POST | Prewarm conversation |
248
+
249
+ ## Architecture
250
+
251
+ ### Streaming
252
+
253
+ When Claude runs tools, the streaming behavior differs from simple responses:
254
+
255
+ 1. `assistant` events stream the **full** response content
256
+ 2. `result` events may only contain the **final** portion after tool execution
257
+
258
+ The state machine accumulates streaming content correctly. Always use `streamingSegments` for display, not just the `result` event.
259
+
260
+ ### Session Persistence
261
+
262
+ Sessions are saved to disk after each message, enabling:
263
+ - Resume after page reload
264
+ - Resume after server restart
265
+ - Multi-device continuation
266
+
267
+ ### Prewarming
268
+
269
+ Call `prewarm()` before the user is likely to start a conversation. This spawns Claude without sending a message, making the first response faster.
270
+
271
+ ## License
272
+
273
+ MIT
@@ -0,0 +1,101 @@
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 { type ConnectionStatus } from './state-machine.js';
12
+ import type { Message, StreamSegment, ClaudeError, ReconnectConfig } from '../shared/types.js';
13
+ export interface ClaudeConnectionConfig {
14
+ baseUrl: string;
15
+ conversationId: string;
16
+ reconnect?: ReconnectConfig;
17
+ }
18
+ export interface ClaudeConnectionEvents {
19
+ stateChange: () => void;
20
+ message: (message: Message) => void;
21
+ streaming: (segments: StreamSegment[]) => void;
22
+ tool: (tool: {
23
+ name: string;
24
+ param?: string;
25
+ }) => void;
26
+ result: () => void;
27
+ error: (error: ClaudeError) => void;
28
+ }
29
+ /**
30
+ * ClaudeConnection manages the connection to a Claude conversation.
31
+ *
32
+ * @example
33
+ * const connection = new ClaudeConnection({
34
+ * baseUrl: '/api/claude',
35
+ * conversationId: 'user-123',
36
+ * });
37
+ *
38
+ * connection.on('message', (msg) => console.log(msg));
39
+ * connection.on('result', () => console.log('Response complete'));
40
+ * connection.connect();
41
+ *
42
+ * // Later
43
+ * await connection.send('Hello!');
44
+ */
45
+ export declare class ClaudeConnection extends EventEmitter<ClaudeConnectionEvents> {
46
+ private config;
47
+ private reconnectConfig;
48
+ private eventSource;
49
+ private state;
50
+ private needNewTextSegment;
51
+ private reconnectAttempt;
52
+ constructor(config: ClaudeConnectionConfig);
53
+ get status(): ConnectionStatus;
54
+ get messages(): Message[];
55
+ get isStreaming(): boolean;
56
+ get streamingSegments(): StreamSegment[];
57
+ get hasPersistedSession(): boolean;
58
+ get lastError(): ClaudeError | null;
59
+ /**
60
+ * Check status and connect if active.
61
+ * Call this on mount to restore state.
62
+ */
63
+ connect(): Promise<void>;
64
+ /**
65
+ * Disconnect from the conversation.
66
+ */
67
+ disconnect(): void;
68
+ /**
69
+ * Start a new conversation.
70
+ */
71
+ start(initialMessage?: string): Promise<void>;
72
+ /**
73
+ * Send a message in an active conversation.
74
+ */
75
+ send(message: string): Promise<void>;
76
+ /**
77
+ * Stop the current response generation (SIGINT).
78
+ */
79
+ stop(): Promise<void>;
80
+ /**
81
+ * Clear the session history and delete persisted session.
82
+ */
83
+ clear(): Promise<void>;
84
+ /**
85
+ * Resume a persisted session.
86
+ */
87
+ resume(): Promise<void>;
88
+ /**
89
+ * Prewarm the conversation for faster first response.
90
+ */
91
+ prewarm(): Promise<void>;
92
+ private updateState;
93
+ private handleEvent;
94
+ private processResponseStream;
95
+ private connectEventSource;
96
+ private closeEventSource;
97
+ private attemptReconnect;
98
+ private calculateRetryDelay;
99
+ private sleep;
100
+ }
101
+ //# sourceMappingURL=connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/client/connection.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAEL,KAAK,gBAAgB,EAStB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAY,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAQzG,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B;AAED,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,SAAS,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;IAC/C,IAAI,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACvD,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,KAAK,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;CACrC;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,sBAAsB,CAAC;IACxE,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,eAAe,CAA4B;IACnD,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,kBAAkB,CAAQ;IAClC,OAAO,CAAC,gBAAgB,CAAK;gBAEjB,MAAM,EAAE,sBAAsB;IAW1C,IAAI,MAAM,IAAI,gBAAgB,CAE7B;IAED,IAAI,QAAQ,IAAI,OAAO,EAAE,CAExB;IAED,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,IAAI,iBAAiB,IAAI,aAAa,EAAE,CAEvC;IAED,IAAI,mBAAmB,IAAI,OAAO,CAEjC;IAED,IAAI,SAAS,IAAI,WAAW,GAAG,IAAI,CAElC;IAED;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B9B;;OAEG;IACH,UAAU,IAAI,IAAI;IAKlB;;OAEG;IACG,KAAK,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6BnD;;OAEG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6B1C;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAW3B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB5B;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B7B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAY9B,OAAO,CAAC,WAAW;IA8BnB,OAAO,CAAC,WAAW;YAiBL,qBAAqB;IA8BnC,OAAO,CAAC,kBAAkB;IAoC1B,OAAO,CAAC,gBAAgB;YAOV,gBAAgB;IAmD9B,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,KAAK;CAGd"}