@moxxy/cli 0.0.2 → 0.0.3

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.
@@ -0,0 +1,1324 @@
1
+ import "./chunk-6DZX6EAA.mjs";
2
+
3
+ // ../claude/src/events/emitter.ts
4
+ var TypedEventEmitter = class {
5
+ handlers = /* @__PURE__ */ new Map();
6
+ /**
7
+ * Subscribe to an event with type-safe handler
8
+ */
9
+ on(event, handler) {
10
+ if (!this.handlers.has(event)) {
11
+ this.handlers.set(event, /* @__PURE__ */ new Set());
12
+ }
13
+ this.handlers.get(event).add(handler);
14
+ return this;
15
+ }
16
+ /**
17
+ * Subscribe to an event once
18
+ */
19
+ once(event, handler) {
20
+ const onceHandler = ((...args) => {
21
+ this.off(event, onceHandler);
22
+ handler(...args);
23
+ });
24
+ return this.on(event, onceHandler);
25
+ }
26
+ /**
27
+ * Unsubscribe from an event
28
+ */
29
+ off(event, handler) {
30
+ const eventHandlers = this.handlers.get(event);
31
+ if (eventHandlers) {
32
+ eventHandlers.delete(handler);
33
+ if (eventHandlers.size === 0) {
34
+ this.handlers.delete(event);
35
+ }
36
+ }
37
+ return this;
38
+ }
39
+ /**
40
+ * Emit an event with type-safe arguments
41
+ */
42
+ emit(event, ...args) {
43
+ const eventHandlers = this.handlers.get(event);
44
+ if (!eventHandlers || eventHandlers.size === 0) {
45
+ return false;
46
+ }
47
+ eventHandlers.forEach((handler) => {
48
+ try {
49
+ handler(...args);
50
+ } catch (error) {
51
+ console.error(`Error in event handler for '${event}':`, error);
52
+ }
53
+ });
54
+ return true;
55
+ }
56
+ /**
57
+ * Remove all handlers for an event or all events
58
+ */
59
+ removeAllListeners(event) {
60
+ if (event) {
61
+ this.handlers.delete(event);
62
+ } else {
63
+ this.handlers.clear();
64
+ }
65
+ return this;
66
+ }
67
+ /**
68
+ * Get the number of listeners for an event
69
+ */
70
+ listenerCount(event) {
71
+ return this.handlers.get(event)?.size ?? 0;
72
+ }
73
+ /**
74
+ * Get all registered event names
75
+ */
76
+ eventNames() {
77
+ return Array.from(this.handlers.keys());
78
+ }
79
+ /**
80
+ * Wait for an event to occur (promisified)
81
+ */
82
+ waitFor(event, timeout) {
83
+ return new Promise((resolve, reject) => {
84
+ let timeoutId;
85
+ const handler = ((...args) => {
86
+ if (timeoutId) {
87
+ clearTimeout(timeoutId);
88
+ }
89
+ resolve(args);
90
+ });
91
+ this.once(event, handler);
92
+ if (timeout) {
93
+ timeoutId = setTimeout(() => {
94
+ this.off(event, handler);
95
+ reject(new Error(`Timeout waiting for event '${event}'`));
96
+ }, timeout);
97
+ }
98
+ });
99
+ }
100
+ };
101
+ function createEventEmitter() {
102
+ return new TypedEventEmitter();
103
+ }
104
+
105
+ // ../claude/src/modules/base.ts
106
+ var BaseModule = class {
107
+ constructor(transport, events) {
108
+ this.transport = transport;
109
+ this.events = events;
110
+ }
111
+ /**
112
+ * Make a request through the transport
113
+ */
114
+ async request(method, params) {
115
+ return this.transport.request(method, params);
116
+ }
117
+ };
118
+
119
+ // ../claude/src/errors/errors.ts
120
+ var ClaudeError = class extends Error {
121
+ code;
122
+ details;
123
+ cause;
124
+ constructor(message, code, details, cause) {
125
+ super(message);
126
+ this.name = this.constructor.name;
127
+ this.code = code;
128
+ this.details = details;
129
+ this.cause = cause;
130
+ if (Error.captureStackTrace) {
131
+ Error.captureStackTrace(this, this.constructor);
132
+ }
133
+ }
134
+ toJSON() {
135
+ return {
136
+ name: this.name,
137
+ message: this.message,
138
+ code: this.code,
139
+ details: this.details,
140
+ cause: this.cause ? {
141
+ name: this.cause.name,
142
+ message: this.cause.message
143
+ } : void 0
144
+ };
145
+ }
146
+ };
147
+ var CLIError = class extends ClaudeError {
148
+ exitCode;
149
+ stdout;
150
+ stderr;
151
+ constructor(message, exitCode, stdout, stderr, cause) {
152
+ super(message, "CLI_ERROR", { exitCode, stdout, stderr }, cause);
153
+ this.exitCode = exitCode;
154
+ this.stdout = stdout;
155
+ this.stderr = stderr;
156
+ }
157
+ };
158
+ var ProcessError = class extends ClaudeError {
159
+ processId;
160
+ constructor(message, processId, details, cause) {
161
+ super(
162
+ message,
163
+ "PROCESS_ERROR",
164
+ { processId, ...details && typeof details === "object" ? details : {} },
165
+ cause
166
+ );
167
+ this.processId = processId;
168
+ }
169
+ };
170
+ var StreamParseError = class extends ClaudeError {
171
+ line;
172
+ constructor(message, line, cause) {
173
+ super(message, "STREAM_PARSE_ERROR", { line }, cause);
174
+ this.line = line;
175
+ }
176
+ };
177
+ var ConnectionError = class extends ClaudeError {
178
+ constructor(message, details, cause) {
179
+ super(message, "CONNECTION_ERROR", details, cause);
180
+ }
181
+ };
182
+ var TimeoutError = class extends ClaudeError {
183
+ timeout;
184
+ constructor(message, timeout) {
185
+ super(message, "TIMEOUT_ERROR", { timeout });
186
+ this.timeout = timeout;
187
+ }
188
+ };
189
+ var ValidationError = class extends ClaudeError {
190
+ field;
191
+ constructor(message, field, details) {
192
+ super(
193
+ message,
194
+ "VALIDATION_ERROR",
195
+ { field, ...details && typeof details === "object" ? details : {} }
196
+ );
197
+ this.field = field;
198
+ }
199
+ };
200
+ var NotFoundError = class extends ClaudeError {
201
+ resource;
202
+ identifier;
203
+ constructor(resource, identifier) {
204
+ super(`${resource} not found: ${identifier}`, "NOT_FOUND", { resource, identifier });
205
+ this.resource = resource;
206
+ this.identifier = identifier;
207
+ }
208
+ };
209
+ var NotConnectedError = class extends ClaudeError {
210
+ constructor(message = "SDK not connected") {
211
+ super(message, "NOT_CONNECTED");
212
+ }
213
+ };
214
+ var NotImplementedError = class extends ClaudeError {
215
+ constructor(feature) {
216
+ super(`Feature not implemented: ${feature}`, "NOT_IMPLEMENTED", { feature });
217
+ }
218
+ };
219
+
220
+ // ../claude/src/modules/agents.ts
221
+ var AgentsModule = class extends BaseModule {
222
+ /**
223
+ * List agents
224
+ * Returns a single stub agent since Claude CLI doesn't have multiple agents
225
+ */
226
+ async list() {
227
+ return this.request("agents.list");
228
+ }
229
+ /**
230
+ * Get agent by ID
231
+ * Returns stub agent data
232
+ */
233
+ async get(agentId) {
234
+ return this.request("agents.get", { agentId });
235
+ }
236
+ /**
237
+ * Create agent
238
+ * Not supported - Claude CLI agents are not managed this way
239
+ */
240
+ async create() {
241
+ throw new NotImplementedError("Agent creation not supported with Claude CLI");
242
+ }
243
+ /**
244
+ * Update agent
245
+ * Not supported - Claude CLI agents are not managed this way
246
+ */
247
+ async update() {
248
+ throw new NotImplementedError("Agent updates not supported with Claude CLI");
249
+ }
250
+ /**
251
+ * Delete agent
252
+ * Not supported - Claude CLI agents are not managed this way
253
+ */
254
+ async delete() {
255
+ throw new NotImplementedError("Agent deletion not supported with Claude CLI");
256
+ }
257
+ /**
258
+ * Set agent identity
259
+ * Not supported - Claude CLI manages identity
260
+ */
261
+ async setIdentity() {
262
+ throw new NotImplementedError("Agent identity changes not supported with Claude CLI");
263
+ }
264
+ /**
265
+ * Set agent model
266
+ * Not supported - Model is set per-session in Claude CLI
267
+ */
268
+ async setModel() {
269
+ throw new NotImplementedError("Agent model changes not supported with Claude CLI. Use SDK config instead.");
270
+ }
271
+ };
272
+
273
+ // ../claude/src/parsers/stream-parser.ts
274
+ import { createInterface } from "readline";
275
+ var ClaudeStreamParser = class {
276
+ sessionKey;
277
+ constructor(sessionKey) {
278
+ this.sessionKey = sessionKey;
279
+ }
280
+ /**
281
+ * Parse a single line of JSON stream output
282
+ */
283
+ parseLine(line) {
284
+ if (!line.trim()) {
285
+ return null;
286
+ }
287
+ try {
288
+ return JSON.parse(line);
289
+ } catch (error) {
290
+ return null;
291
+ }
292
+ }
293
+ /**
294
+ * Convert stream event to chat stream chunk
295
+ */
296
+ toChunk(event) {
297
+ switch (event.type) {
298
+ case "content_block_delta": {
299
+ const text = event.delta?.text || "";
300
+ return {
301
+ content: text,
302
+ done: false,
303
+ sessionKey: this.sessionKey,
304
+ timestamp: Date.now()
305
+ };
306
+ }
307
+ case "thinking_block": {
308
+ return {
309
+ content: "",
310
+ thinking: event.content || "",
311
+ done: false,
312
+ sessionKey: this.sessionKey,
313
+ timestamp: Date.now()
314
+ };
315
+ }
316
+ case "message_stop": {
317
+ return {
318
+ content: "",
319
+ done: true,
320
+ sessionKey: this.sessionKey,
321
+ timestamp: Date.now()
322
+ };
323
+ }
324
+ case "content_block_start":
325
+ case "content_block_stop":
326
+ case "session_start":
327
+ case "message_start":
328
+ return null;
329
+ default:
330
+ return null;
331
+ }
332
+ }
333
+ /**
334
+ * Parse stream asynchronously
335
+ */
336
+ async *parseStream(stream) {
337
+ const reader = createInterface({
338
+ input: stream,
339
+ crlfDelay: Number.POSITIVE_INFINITY
340
+ });
341
+ try {
342
+ for await (const line of reader) {
343
+ const event = this.parseLine(line);
344
+ if (event) {
345
+ const chunk = this.toChunk(event);
346
+ if (chunk) {
347
+ yield chunk;
348
+ if (chunk.done) {
349
+ break;
350
+ }
351
+ }
352
+ }
353
+ }
354
+ } catch (error) {
355
+ if (error instanceof Error) {
356
+ throw new StreamParseError("Error parsing stream", "", error);
357
+ }
358
+ throw error;
359
+ } finally {
360
+ reader.close();
361
+ }
362
+ }
363
+ /**
364
+ * Collect full response from stream
365
+ * Returns full text and optional thinking
366
+ */
367
+ async collectFullResponse(stream) {
368
+ let fullContent = "";
369
+ let thinking;
370
+ for await (const chunk of this.parseStream(stream)) {
371
+ if (chunk.content) {
372
+ fullContent += chunk.content;
373
+ }
374
+ if (chunk.thinking) {
375
+ thinking = chunk.thinking;
376
+ }
377
+ }
378
+ return { content: fullContent, thinking };
379
+ }
380
+ };
381
+
382
+ // ../claude/src/modules/chat.ts
383
+ var ChatModule = class extends BaseModule {
384
+ /**
385
+ * Send a message and wait for complete response
386
+ */
387
+ async send(options) {
388
+ return this.request("chat.send", options);
389
+ }
390
+ /**
391
+ * Send a message with streaming response
392
+ */
393
+ async *sendStream(options) {
394
+ const sessionKey = options.sessionKey || `claude-stream-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
395
+ const agentId = options.agentId || "claude";
396
+ const transport = this.transport;
397
+ const sessionManager = transport.getSessionManager();
398
+ const processManager = transport.getProcessManager();
399
+ const session = sessionManager.getOrCreateSession(sessionKey, agentId);
400
+ sessionManager.addMessage(sessionKey, {
401
+ role: "user",
402
+ content: options.message,
403
+ timestamp: Date.now()
404
+ });
405
+ this.events.emit("chat:stream:start", sessionKey, agentId);
406
+ options.onStart?.(sessionKey, agentId);
407
+ let proc = processManager.get(sessionKey);
408
+ if (!proc) {
409
+ proc = await processManager.spawn({
410
+ sessionKey,
411
+ model: transport.config.model,
412
+ thinking: options.thinking,
413
+ permissionMode: transport.config.permissionMode,
414
+ workingDirectory: transport.config.workingDirectory,
415
+ timeout: options.timeout
416
+ });
417
+ }
418
+ processManager.setStatus(sessionKey, "busy");
419
+ let fullResponse = "";
420
+ let thinking;
421
+ try {
422
+ proc.process.stdin?.write(options.message + "\n");
423
+ proc.process.stdin?.end();
424
+ const parser = new ClaudeStreamParser(sessionKey);
425
+ for await (const chunk of parser.parseStream(proc.process.stdout)) {
426
+ if (chunk.content) {
427
+ fullResponse += chunk.content;
428
+ }
429
+ if (chunk.thinking) {
430
+ thinking = chunk.thinking;
431
+ }
432
+ this.events.emit("chat:stream", chunk);
433
+ options.onChunk?.(chunk);
434
+ yield chunk;
435
+ if (chunk.done) {
436
+ break;
437
+ }
438
+ }
439
+ sessionManager.addMessage(sessionKey, {
440
+ role: "assistant",
441
+ content: fullResponse,
442
+ thinking,
443
+ timestamp: Date.now()
444
+ });
445
+ processManager.setStatus(sessionKey, "idle");
446
+ processManager.touch(sessionKey);
447
+ this.events.emit("chat:stream:end", sessionKey, agentId);
448
+ options.onEnd?.(sessionKey, agentId);
449
+ return {
450
+ sessionKey,
451
+ agentId,
452
+ response: fullResponse,
453
+ thinking,
454
+ timestamp: Date.now()
455
+ };
456
+ } catch (error) {
457
+ processManager.setStatus(sessionKey, "error");
458
+ throw error;
459
+ }
460
+ }
461
+ /**
462
+ * Get chat history for a session
463
+ */
464
+ async history(sessionKey, options) {
465
+ return this.request("sessions.history", { sessionKey, ...options });
466
+ }
467
+ };
468
+
469
+ // ../claude/src/modules/sessions.ts
470
+ var SessionsModule = class extends BaseModule {
471
+ /**
472
+ * List sessions with optional filtering
473
+ */
474
+ async list(options) {
475
+ return this.request("sessions.list", options);
476
+ }
477
+ /**
478
+ * Get session details
479
+ */
480
+ async get(sessionKey) {
481
+ return this.request("sessions.get", { sessionKey });
482
+ }
483
+ /**
484
+ * Delete a session
485
+ */
486
+ async delete(sessionKey) {
487
+ await this.request("sessions.delete", { sessionKey });
488
+ }
489
+ /**
490
+ * Get session message history
491
+ */
492
+ async history(sessionKey, options) {
493
+ return this.request("sessions.history", { sessionKey, ...options });
494
+ }
495
+ /**
496
+ * Create a new session (convenience method)
497
+ * Sessions are created automatically on first message, but this can be used to pre-create
498
+ */
499
+ async create(agentId = "claude") {
500
+ const sessionKey = `claude-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
501
+ return { sessionKey };
502
+ }
503
+ };
504
+
505
+ // ../claude/src/modules/system.ts
506
+ var SystemModule = class extends BaseModule {
507
+ /**
508
+ * Get health status
509
+ */
510
+ async health() {
511
+ return this.request("system.health");
512
+ }
513
+ /**
514
+ * Get system status
515
+ */
516
+ async status() {
517
+ return this.request("system.status");
518
+ }
519
+ /**
520
+ * Ping (simple health check)
521
+ */
522
+ async ping() {
523
+ try {
524
+ const health = await this.health();
525
+ return {
526
+ ok: health.healthy,
527
+ timestamp: Date.now()
528
+ };
529
+ } catch {
530
+ return {
531
+ ok: false,
532
+ timestamp: Date.now()
533
+ };
534
+ }
535
+ }
536
+ };
537
+
538
+ // ../claude/src/transport/cli.ts
539
+ import { exec } from "child_process";
540
+ import { promisify } from "util";
541
+
542
+ // ../claude/src/transport/process-manager.ts
543
+ import { spawn } from "child_process";
544
+ var ProcessManager = class {
545
+ constructor(config, events) {
546
+ this.config = config;
547
+ this.events = events;
548
+ }
549
+ processes = /* @__PURE__ */ new Map();
550
+ cleanupInterval = null;
551
+ events;
552
+ /**
553
+ * Spawn a new Claude process
554
+ */
555
+ async spawn(options) {
556
+ if (this.processes.size >= this.config.maxProcesses) {
557
+ throw new ProcessError(
558
+ `Maximum process limit reached (${this.config.maxProcesses})`,
559
+ options.sessionKey
560
+ );
561
+ }
562
+ const args = this.buildArgs(options);
563
+ const proc = spawn(this.config.cliPath, args, {
564
+ cwd: options.workingDirectory || this.config.workingDirectory || process.cwd(),
565
+ env: process.env,
566
+ stdio: ["pipe", "pipe", "pipe"]
567
+ });
568
+ const claudeProc = {
569
+ sessionKey: options.sessionKey,
570
+ process: proc,
571
+ status: "idle",
572
+ createdAt: Date.now(),
573
+ lastUsedAt: Date.now()
574
+ };
575
+ this.setupProcessHandlers(claudeProc);
576
+ this.processes.set(options.sessionKey, claudeProc);
577
+ this.events.emit("process:spawn", options.sessionKey, proc.pid ?? 0);
578
+ return claudeProc;
579
+ }
580
+ /**
581
+ * Build CLI arguments
582
+ */
583
+ buildArgs(options) {
584
+ const args = [
585
+ "--print",
586
+ "--output-format=stream-json",
587
+ `--session-id=${options.sessionKey}`
588
+ ];
589
+ const model = options.model || this.config.model;
590
+ if (model) {
591
+ args.push(`--model=${model}`);
592
+ }
593
+ if (options.thinking && options.thinking !== "none") {
594
+ args.push(`--thinking=${options.thinking}`);
595
+ }
596
+ const permissionMode = options.permissionMode || this.config.permissionMode;
597
+ if (permissionMode) {
598
+ args.push(`--permission-mode=${permissionMode}`);
599
+ }
600
+ const workingDir = options.workingDirectory || this.config.workingDirectory;
601
+ if (workingDir) {
602
+ args.push(`--add-dir=${workingDir}`);
603
+ }
604
+ return args;
605
+ }
606
+ /**
607
+ * Setup process event handlers
608
+ */
609
+ setupProcessHandlers(proc) {
610
+ proc.process.on("error", (error) => {
611
+ proc.status = "error";
612
+ this.events.emit("process:error", proc.sessionKey, error);
613
+ });
614
+ proc.process.on("exit", (code) => {
615
+ this.processes.delete(proc.sessionKey);
616
+ this.events.emit("process:exit", proc.sessionKey, code);
617
+ });
618
+ proc.process.stderr?.on("data", (data) => {
619
+ const message = data.toString();
620
+ this.events.emit("agent:log", proc.sessionKey, message, "error");
621
+ });
622
+ }
623
+ /**
624
+ * Get existing process by session key
625
+ */
626
+ get(sessionKey) {
627
+ return this.processes.get(sessionKey);
628
+ }
629
+ /**
630
+ * Update process last used time
631
+ */
632
+ touch(sessionKey) {
633
+ const proc = this.processes.get(sessionKey);
634
+ if (proc) {
635
+ proc.lastUsedAt = Date.now();
636
+ }
637
+ }
638
+ /**
639
+ * Set process status
640
+ */
641
+ setStatus(sessionKey, status) {
642
+ const proc = this.processes.get(sessionKey);
643
+ if (proc) {
644
+ proc.status = status;
645
+ }
646
+ }
647
+ /**
648
+ * Kill a specific process
649
+ */
650
+ kill(sessionKey) {
651
+ const proc = this.processes.get(sessionKey);
652
+ if (proc) {
653
+ try {
654
+ proc.process.kill("SIGTERM");
655
+ } catch (error) {
656
+ console.error(`Error killing process ${sessionKey}:`, error);
657
+ }
658
+ this.processes.delete(sessionKey);
659
+ }
660
+ }
661
+ /**
662
+ * Kill all processes
663
+ */
664
+ killAll() {
665
+ for (const sessionKey of Array.from(this.processes.keys())) {
666
+ this.kill(sessionKey);
667
+ }
668
+ }
669
+ /**
670
+ * Start periodic cleanup of idle processes
671
+ */
672
+ startCleanup(intervalMs = 6e4) {
673
+ if (this.cleanupInterval) {
674
+ return;
675
+ }
676
+ this.cleanupInterval = setInterval(() => {
677
+ this.cleanupIdleProcesses();
678
+ }, intervalMs);
679
+ }
680
+ /**
681
+ * Stop cleanup interval
682
+ */
683
+ stopCleanup() {
684
+ if (this.cleanupInterval) {
685
+ clearInterval(this.cleanupInterval);
686
+ this.cleanupInterval = null;
687
+ }
688
+ }
689
+ /**
690
+ * Cleanup idle processes
691
+ */
692
+ cleanupIdleProcesses() {
693
+ const now = Date.now();
694
+ const timeout = this.config.processIdleTimeout;
695
+ for (const [sessionKey, proc] of this.processes.entries()) {
696
+ if (proc.status === "idle" && now - proc.lastUsedAt > timeout) {
697
+ this.kill(sessionKey);
698
+ }
699
+ }
700
+ }
701
+ /**
702
+ * Get process count
703
+ */
704
+ getProcessCount() {
705
+ return this.processes.size;
706
+ }
707
+ /**
708
+ * Get all session keys with active processes
709
+ */
710
+ getActiveSessionKeys() {
711
+ return Array.from(this.processes.keys());
712
+ }
713
+ };
714
+
715
+ // ../claude/src/session/storage.ts
716
+ var InMemorySessionStorage = class {
717
+ sessions = /* @__PURE__ */ new Map();
718
+ get(sessionKey) {
719
+ return this.sessions.get(sessionKey);
720
+ }
721
+ set(sessionKey, session) {
722
+ this.sessions.set(sessionKey, session);
723
+ }
724
+ delete(sessionKey) {
725
+ this.sessions.delete(sessionKey);
726
+ }
727
+ has(sessionKey) {
728
+ return this.sessions.has(sessionKey);
729
+ }
730
+ getAll() {
731
+ return Array.from(this.sessions.values());
732
+ }
733
+ clear() {
734
+ this.sessions.clear();
735
+ }
736
+ count() {
737
+ return this.sessions.size;
738
+ }
739
+ };
740
+
741
+ // ../claude/src/session/manager.ts
742
+ var SessionManager = class {
743
+ storage;
744
+ events;
745
+ constructor(events, storage) {
746
+ this.storage = storage || new InMemorySessionStorage();
747
+ this.events = events;
748
+ }
749
+ /**
750
+ * Get or create a session
751
+ */
752
+ getOrCreateSession(sessionKey, agentId) {
753
+ let session = this.storage.get(sessionKey);
754
+ if (!session) {
755
+ session = {
756
+ sessionKey,
757
+ agentId,
758
+ messages: [],
759
+ createdAt: Date.now(),
760
+ updatedAt: Date.now()
761
+ };
762
+ this.storage.set(sessionKey, session);
763
+ this.events.emit("session:created", sessionKey);
764
+ }
765
+ return session;
766
+ }
767
+ /**
768
+ * Get session by key
769
+ */
770
+ getSession(sessionKey) {
771
+ return this.storage.get(sessionKey);
772
+ }
773
+ /**
774
+ * Add message to session
775
+ */
776
+ addMessage(sessionKey, message) {
777
+ const session = this.storage.get(sessionKey);
778
+ if (!session) {
779
+ throw new NotFoundError("Session", sessionKey);
780
+ }
781
+ session.messages.push(message);
782
+ session.updatedAt = Date.now();
783
+ this.storage.set(sessionKey, session);
784
+ }
785
+ /**
786
+ * Get session history
787
+ */
788
+ getHistory(sessionKey, limit) {
789
+ const session = this.storage.get(sessionKey);
790
+ if (!session) {
791
+ throw new NotFoundError("Session", sessionKey);
792
+ }
793
+ if (limit && limit > 0) {
794
+ return session.messages.slice(-limit);
795
+ }
796
+ return session.messages;
797
+ }
798
+ /**
799
+ * List sessions with optional filtering
800
+ */
801
+ listSessions(options) {
802
+ let sessions = this.storage.getAll();
803
+ if (options?.agentId) {
804
+ sessions = sessions.filter((s) => s.agentId === options.agentId);
805
+ }
806
+ if (options?.activeWithinMinutes) {
807
+ const cutoff = Date.now() - options.activeWithinMinutes * 60 * 1e3;
808
+ sessions = sessions.filter((s) => s.updatedAt >= cutoff);
809
+ }
810
+ sessions.sort((a, b) => b.updatedAt - a.updatedAt);
811
+ if (options?.offset) {
812
+ sessions = sessions.slice(options.offset);
813
+ }
814
+ if (options?.limit) {
815
+ sessions = sessions.slice(0, options.limit);
816
+ }
817
+ return sessions;
818
+ }
819
+ /**
820
+ * Delete session
821
+ */
822
+ deleteSession(sessionKey) {
823
+ if (!this.storage.has(sessionKey)) {
824
+ throw new NotFoundError("Session", sessionKey);
825
+ }
826
+ this.storage.delete(sessionKey);
827
+ this.events.emit("session:deleted", sessionKey);
828
+ }
829
+ /**
830
+ * Update session process ID
831
+ */
832
+ setProcessId(sessionKey, processId) {
833
+ const session = this.storage.get(sessionKey);
834
+ if (!session) {
835
+ throw new NotFoundError("Session", sessionKey);
836
+ }
837
+ session.processId = processId;
838
+ session.updatedAt = Date.now();
839
+ this.storage.set(sessionKey, session);
840
+ }
841
+ /**
842
+ * Clear process ID from session
843
+ */
844
+ clearProcessId(sessionKey) {
845
+ const session = this.storage.get(sessionKey);
846
+ if (session) {
847
+ delete session.processId;
848
+ session.updatedAt = Date.now();
849
+ this.storage.set(sessionKey, session);
850
+ }
851
+ }
852
+ /**
853
+ * Get session count
854
+ */
855
+ getSessionCount() {
856
+ return this.storage.count();
857
+ }
858
+ /**
859
+ * Clear all sessions
860
+ */
861
+ clearAll() {
862
+ this.storage.clear();
863
+ }
864
+ };
865
+
866
+ // ../claude/src/transport/cli.ts
867
+ var execAsync = promisify(exec);
868
+ var CLITransport = class {
869
+ state = "disconnected";
870
+ processManager;
871
+ sessionManager;
872
+ events;
873
+ config;
874
+ constructor(config, events) {
875
+ this.events = events;
876
+ this.config = {
877
+ ...config,
878
+ autoConnect: config.autoConnect ?? true,
879
+ timeout: config.timeout ?? 3e5
880
+ // 5 minutes default
881
+ };
882
+ this.processManager = new ProcessManager(
883
+ {
884
+ cliPath: config.cliPath,
885
+ maxProcesses: config.maxProcesses,
886
+ processIdleTimeout: config.processIdleTimeout,
887
+ model: config.model,
888
+ permissionMode: config.permissionMode,
889
+ workingDirectory: config.workingDirectory
890
+ },
891
+ events
892
+ );
893
+ this.sessionManager = new SessionManager(events);
894
+ }
895
+ /**
896
+ * Connect - verify Claude CLI is available
897
+ */
898
+ async connect() {
899
+ if (this.state === "connected") {
900
+ return;
901
+ }
902
+ this.state = "connecting";
903
+ this.events.emit("connection:state", "connecting");
904
+ try {
905
+ await this.verifyCLI();
906
+ this.processManager.startCleanup();
907
+ this.state = "connected";
908
+ this.events.emit("connection:state", "connected");
909
+ this.events.emit("connection:connected");
910
+ } catch (error) {
911
+ this.state = "error";
912
+ this.events.emit("connection:state", "error");
913
+ this.events.emit("connection:error", error);
914
+ throw new ConnectionError("Failed to connect to Claude CLI", void 0, error);
915
+ }
916
+ }
917
+ /**
918
+ * Verify Claude CLI is available
919
+ */
920
+ async verifyCLI() {
921
+ try {
922
+ const { stdout } = await execAsync(`${this.config.cliPath} --version`);
923
+ console.log(`Claude CLI available: ${stdout.trim()}`);
924
+ } catch (error) {
925
+ throw new CLIError(
926
+ `Claude CLI not found at '${this.config.cliPath}'. Ensure Claude CLI is installed and in PATH.`,
927
+ error.code,
928
+ "",
929
+ error.message
930
+ );
931
+ }
932
+ }
933
+ /**
934
+ * Disconnect and cleanup
935
+ */
936
+ disconnect() {
937
+ if (this.state === "disconnected") {
938
+ return;
939
+ }
940
+ this.processManager.killAll();
941
+ this.processManager.stopCleanup();
942
+ this.state = "disconnected";
943
+ this.events.emit("connection:state", "disconnected");
944
+ this.events.emit("connection:disconnected");
945
+ }
946
+ /**
947
+ * Check if connected
948
+ */
949
+ isConnected() {
950
+ return this.state === "connected";
951
+ }
952
+ /**
953
+ * Get connection state
954
+ */
955
+ getConnectionState() {
956
+ return this.state;
957
+ }
958
+ /**
959
+ * Make an RPC request
960
+ */
961
+ async request(method, params = {}) {
962
+ if (!this.isConnected()) {
963
+ throw new ConnectionError("Not connected to Claude CLI");
964
+ }
965
+ switch (method) {
966
+ case "chat.send":
967
+ return this.handleChatSend(params);
968
+ case "sessions.list":
969
+ return this.handleSessionsList(params);
970
+ case "sessions.get":
971
+ return this.handleSessionsGet(params.sessionKey);
972
+ case "sessions.delete":
973
+ return this.handleSessionsDelete(params.sessionKey);
974
+ case "sessions.history":
975
+ return this.handleSessionsHistory(params.sessionKey);
976
+ case "system.health":
977
+ return this.handleSystemHealth();
978
+ case "system.status":
979
+ return this.handleSystemStatus();
980
+ case "agents.list":
981
+ return this.handleAgentsList();
982
+ case "agents.get":
983
+ return this.handleAgentsGet(params.agentId);
984
+ default:
985
+ throw new Error(`Unknown RPC method: ${method}`);
986
+ }
987
+ }
988
+ /**
989
+ * Handle chat.send request
990
+ */
991
+ async handleChatSend(options) {
992
+ const sessionKey = options.sessionKey || `claude-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
993
+ const agentId = options.agentId || "claude";
994
+ const timeout = options.timeout || this.config.timeout;
995
+ const session = this.sessionManager.getOrCreateSession(sessionKey, agentId);
996
+ this.sessionManager.addMessage(sessionKey, {
997
+ role: "user",
998
+ content: options.message,
999
+ timestamp: Date.now()
1000
+ });
1001
+ let proc = this.processManager.get(sessionKey);
1002
+ if (!proc) {
1003
+ proc = await this.processManager.spawn({
1004
+ sessionKey,
1005
+ model: this.config.model,
1006
+ thinking: options.thinking,
1007
+ permissionMode: this.config.permissionMode,
1008
+ workingDirectory: this.config.workingDirectory,
1009
+ timeout
1010
+ });
1011
+ }
1012
+ this.processManager.setStatus(sessionKey, "busy");
1013
+ try {
1014
+ proc.process.stdin?.write(options.message + "\n");
1015
+ proc.process.stdin?.end();
1016
+ const parser = new ClaudeStreamParser(sessionKey);
1017
+ const { content, thinking } = await Promise.race([
1018
+ parser.collectFullResponse(proc.process.stdout),
1019
+ this.createTimeoutPromise(timeout)
1020
+ ]);
1021
+ this.sessionManager.addMessage(sessionKey, {
1022
+ role: "assistant",
1023
+ content,
1024
+ thinking,
1025
+ timestamp: Date.now()
1026
+ });
1027
+ this.processManager.setStatus(sessionKey, "idle");
1028
+ this.processManager.touch(sessionKey);
1029
+ return {
1030
+ sessionKey,
1031
+ agentId,
1032
+ response: content,
1033
+ thinking,
1034
+ timestamp: Date.now()
1035
+ };
1036
+ } catch (error) {
1037
+ this.processManager.setStatus(sessionKey, "error");
1038
+ throw error;
1039
+ }
1040
+ }
1041
+ /**
1042
+ * Handle sessions.list request
1043
+ */
1044
+ async handleSessionsList(options) {
1045
+ const sessions = this.sessionManager.listSessions(options);
1046
+ return {
1047
+ sessions: sessions.map((s) => ({
1048
+ sessionKey: s.sessionKey,
1049
+ agentId: s.agentId,
1050
+ messageCount: s.messages.length,
1051
+ createdAt: s.createdAt,
1052
+ updatedAt: s.updatedAt
1053
+ })),
1054
+ total: sessions.length
1055
+ };
1056
+ }
1057
+ /**
1058
+ * Handle sessions.get request
1059
+ */
1060
+ async handleSessionsGet(sessionKey) {
1061
+ const session = this.sessionManager.getSession(sessionKey);
1062
+ if (!session) {
1063
+ throw new NotFoundError("Session", sessionKey);
1064
+ }
1065
+ return {
1066
+ sessionKey: session.sessionKey,
1067
+ agentId: session.agentId,
1068
+ messageCount: session.messages.length,
1069
+ createdAt: session.createdAt,
1070
+ updatedAt: session.updatedAt
1071
+ };
1072
+ }
1073
+ /**
1074
+ * Handle sessions.delete request
1075
+ */
1076
+ async handleSessionsDelete(sessionKey) {
1077
+ this.processManager.kill(sessionKey);
1078
+ this.sessionManager.deleteSession(sessionKey);
1079
+ }
1080
+ /**
1081
+ * Handle sessions.history request
1082
+ */
1083
+ async handleSessionsHistory(sessionKey) {
1084
+ const messages = this.sessionManager.getHistory(sessionKey);
1085
+ return { messages };
1086
+ }
1087
+ /**
1088
+ * Handle system.health request
1089
+ */
1090
+ async handleSystemHealth() {
1091
+ try {
1092
+ await this.verifyCLI();
1093
+ return {
1094
+ healthy: true,
1095
+ cliAvailable: true,
1096
+ activeSessions: this.sessionManager.getSessionCount(),
1097
+ activeProcesses: this.processManager.getProcessCount()
1098
+ };
1099
+ } catch {
1100
+ return {
1101
+ healthy: false,
1102
+ cliAvailable: false,
1103
+ activeSessions: this.sessionManager.getSessionCount(),
1104
+ activeProcesses: this.processManager.getProcessCount()
1105
+ };
1106
+ }
1107
+ }
1108
+ /**
1109
+ * Handle system.status request
1110
+ */
1111
+ async handleSystemStatus() {
1112
+ return {
1113
+ state: this.state,
1114
+ activeSessions: this.sessionManager.getSessionCount(),
1115
+ activeProcesses: this.processManager.getProcessCount(),
1116
+ cliPath: this.config.cliPath
1117
+ };
1118
+ }
1119
+ /**
1120
+ * Handle agents.list request (stub)
1121
+ */
1122
+ async handleAgentsList() {
1123
+ return {
1124
+ agents: [
1125
+ {
1126
+ agentId: "claude",
1127
+ status: "available",
1128
+ workspace: this.config.workingDirectory
1129
+ }
1130
+ ],
1131
+ defaultAgentId: "claude"
1132
+ };
1133
+ }
1134
+ /**
1135
+ * Handle agents.get request (stub)
1136
+ */
1137
+ async handleAgentsGet(agentId) {
1138
+ return {
1139
+ agentId,
1140
+ status: "available",
1141
+ workspace: this.config.workingDirectory
1142
+ };
1143
+ }
1144
+ /**
1145
+ * Create timeout promise
1146
+ */
1147
+ createTimeoutPromise(timeout) {
1148
+ return new Promise((_, reject) => {
1149
+ setTimeout(() => {
1150
+ reject(new TimeoutError("Operation timed out", timeout));
1151
+ }, timeout);
1152
+ });
1153
+ }
1154
+ /**
1155
+ * Subscribe to event
1156
+ */
1157
+ on(event, handler) {
1158
+ this.events.on(event, handler);
1159
+ }
1160
+ /**
1161
+ * Unsubscribe from event
1162
+ */
1163
+ off(event, handler) {
1164
+ this.events.off(event, handler);
1165
+ }
1166
+ /**
1167
+ * Emit event
1168
+ */
1169
+ emit(event, ...args) {
1170
+ this.events.emit(event, ...args);
1171
+ }
1172
+ /**
1173
+ * Get process manager (for internal use)
1174
+ */
1175
+ getProcessManager() {
1176
+ return this.processManager;
1177
+ }
1178
+ /**
1179
+ * Get session manager (for internal use)
1180
+ */
1181
+ getSessionManager() {
1182
+ return this.sessionManager;
1183
+ }
1184
+ };
1185
+
1186
+ // ../claude/src/sdk.ts
1187
+ var DEFAULT_CONFIG = {
1188
+ cliPath: "claude",
1189
+ timeout: 3e5,
1190
+ // 5 minutes
1191
+ maxProcesses: 10,
1192
+ processIdleTimeout: 6e5,
1193
+ // 10 minutes
1194
+ model: "claude-sonnet-4-5",
1195
+ permissionMode: "default",
1196
+ workingDirectory: process.cwd(),
1197
+ autoConnect: true
1198
+ };
1199
+ var ClaudeSDK = class _ClaudeSDK {
1200
+ transport;
1201
+ events;
1202
+ // Domain modules
1203
+ system;
1204
+ agents;
1205
+ sessions;
1206
+ chat;
1207
+ constructor(config) {
1208
+ this.events = createEventEmitter();
1209
+ const transportConfig = {
1210
+ cliPath: config.cliPath,
1211
+ timeout: config.timeout,
1212
+ maxProcesses: config.maxProcesses,
1213
+ processIdleTimeout: config.processIdleTimeout,
1214
+ model: config.model,
1215
+ permissionMode: config.permissionMode,
1216
+ workingDirectory: config.workingDirectory,
1217
+ autoConnect: false
1218
+ // We'll connect manually after initialization
1219
+ };
1220
+ this.transport = new CLITransport(transportConfig, this.events);
1221
+ this.system = new SystemModule(this.transport, this.events);
1222
+ this.agents = new AgentsModule(this.transport, this.events);
1223
+ this.sessions = new SessionsModule(this.transport, this.events);
1224
+ this.chat = new ChatModule(this.transport, this.events);
1225
+ }
1226
+ /**
1227
+ * Create a new ClaudeSDK instance
1228
+ * Auto-connects by default
1229
+ */
1230
+ static async create(config) {
1231
+ const fullConfig = {
1232
+ ...DEFAULT_CONFIG,
1233
+ ...config
1234
+ };
1235
+ const sdk = new _ClaudeSDK(fullConfig);
1236
+ if (fullConfig.autoConnect) {
1237
+ await sdk.connect();
1238
+ }
1239
+ return sdk;
1240
+ }
1241
+ /**
1242
+ * Create a disconnected SDK instance
1243
+ * Must call connect() manually
1244
+ */
1245
+ static createDisconnected(config) {
1246
+ const fullConfig = {
1247
+ ...DEFAULT_CONFIG,
1248
+ ...config,
1249
+ autoConnect: false
1250
+ };
1251
+ return new _ClaudeSDK(fullConfig);
1252
+ }
1253
+ /**
1254
+ * Connect to Claude CLI
1255
+ */
1256
+ async connect() {
1257
+ await this.transport.connect();
1258
+ }
1259
+ /**
1260
+ * Disconnect and cleanup
1261
+ */
1262
+ disconnect() {
1263
+ this.transport.disconnect();
1264
+ }
1265
+ /**
1266
+ * Check if connected
1267
+ */
1268
+ isConnected() {
1269
+ return this.transport.isConnected();
1270
+ }
1271
+ /**
1272
+ * Get connection state
1273
+ */
1274
+ getConnectionState() {
1275
+ return this.transport.getConnectionState();
1276
+ }
1277
+ /**
1278
+ * Subscribe to an event
1279
+ */
1280
+ on(event, handler) {
1281
+ this.events.on(event, handler);
1282
+ return this;
1283
+ }
1284
+ /**
1285
+ * Subscribe to an event once
1286
+ */
1287
+ once(event, handler) {
1288
+ this.events.once(event, handler);
1289
+ return this;
1290
+ }
1291
+ /**
1292
+ * Unsubscribe from an event
1293
+ */
1294
+ off(event, handler) {
1295
+ this.events.off(event, handler);
1296
+ return this;
1297
+ }
1298
+ /**
1299
+ * Remove all listeners for an event
1300
+ */
1301
+ removeAllListeners(event) {
1302
+ this.events.removeAllListeners(event);
1303
+ return this;
1304
+ }
1305
+ /**
1306
+ * Wait for an event (promisified)
1307
+ */
1308
+ waitFor(event, timeout) {
1309
+ return this.events.waitFor(event, timeout);
1310
+ }
1311
+ };
1312
+ export {
1313
+ CLIError,
1314
+ ClaudeError,
1315
+ ClaudeSDK,
1316
+ ConnectionError,
1317
+ NotConnectedError,
1318
+ NotFoundError,
1319
+ NotImplementedError,
1320
+ ProcessError,
1321
+ StreamParseError,
1322
+ TimeoutError,
1323
+ ValidationError
1324
+ };