@moxxy/cli 0.0.7 → 0.0.9

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,1327 @@
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
+ const existingProc = processManager.get(sessionKey);
408
+ if (existingProc) {
409
+ processManager.kill(sessionKey);
410
+ }
411
+ const proc = await processManager.spawn({
412
+ sessionKey,
413
+ model: transport.config.model,
414
+ thinking: options.thinking,
415
+ permissionMode: transport.config.permissionMode,
416
+ workingDirectory: transport.config.workingDirectory,
417
+ timeout: options.timeout,
418
+ message: options.message
419
+ });
420
+ processManager.setStatus(sessionKey, "busy");
421
+ let fullResponse = "";
422
+ let thinking;
423
+ try {
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",
587
+ "stream-json"
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
+ if (options.message) {
605
+ args.push(options.message);
606
+ }
607
+ return args;
608
+ }
609
+ /**
610
+ * Setup process event handlers
611
+ */
612
+ setupProcessHandlers(proc) {
613
+ proc.process.on("error", (error) => {
614
+ proc.status = "error";
615
+ this.events.emit("process:error", proc.sessionKey, error);
616
+ });
617
+ proc.process.on("exit", (code) => {
618
+ this.processes.delete(proc.sessionKey);
619
+ this.events.emit("process:exit", proc.sessionKey, code);
620
+ });
621
+ proc.process.stderr?.on("data", (data) => {
622
+ const message = data.toString();
623
+ this.events.emit("agent:log", proc.sessionKey, message, "error");
624
+ });
625
+ }
626
+ /**
627
+ * Get existing process by session key
628
+ */
629
+ get(sessionKey) {
630
+ return this.processes.get(sessionKey);
631
+ }
632
+ /**
633
+ * Update process last used time
634
+ */
635
+ touch(sessionKey) {
636
+ const proc = this.processes.get(sessionKey);
637
+ if (proc) {
638
+ proc.lastUsedAt = Date.now();
639
+ }
640
+ }
641
+ /**
642
+ * Set process status
643
+ */
644
+ setStatus(sessionKey, status) {
645
+ const proc = this.processes.get(sessionKey);
646
+ if (proc) {
647
+ proc.status = status;
648
+ }
649
+ }
650
+ /**
651
+ * Kill a specific process
652
+ */
653
+ kill(sessionKey) {
654
+ const proc = this.processes.get(sessionKey);
655
+ if (proc) {
656
+ try {
657
+ proc.process.kill("SIGTERM");
658
+ } catch (error) {
659
+ console.error(`Error killing process ${sessionKey}:`, error);
660
+ }
661
+ this.processes.delete(sessionKey);
662
+ }
663
+ }
664
+ /**
665
+ * Kill all processes
666
+ */
667
+ killAll() {
668
+ for (const sessionKey of Array.from(this.processes.keys())) {
669
+ this.kill(sessionKey);
670
+ }
671
+ }
672
+ /**
673
+ * Start periodic cleanup of idle processes
674
+ */
675
+ startCleanup(intervalMs = 6e4) {
676
+ if (this.cleanupInterval) {
677
+ return;
678
+ }
679
+ this.cleanupInterval = setInterval(() => {
680
+ this.cleanupIdleProcesses();
681
+ }, intervalMs);
682
+ }
683
+ /**
684
+ * Stop cleanup interval
685
+ */
686
+ stopCleanup() {
687
+ if (this.cleanupInterval) {
688
+ clearInterval(this.cleanupInterval);
689
+ this.cleanupInterval = null;
690
+ }
691
+ }
692
+ /**
693
+ * Cleanup idle processes
694
+ */
695
+ cleanupIdleProcesses() {
696
+ const now = Date.now();
697
+ const timeout = this.config.processIdleTimeout;
698
+ for (const [sessionKey, proc] of this.processes.entries()) {
699
+ if (proc.status === "idle" && now - proc.lastUsedAt > timeout) {
700
+ this.kill(sessionKey);
701
+ }
702
+ }
703
+ }
704
+ /**
705
+ * Get process count
706
+ */
707
+ getProcessCount() {
708
+ return this.processes.size;
709
+ }
710
+ /**
711
+ * Get all session keys with active processes
712
+ */
713
+ getActiveSessionKeys() {
714
+ return Array.from(this.processes.keys());
715
+ }
716
+ };
717
+
718
+ // ../claude/src/session/storage.ts
719
+ var InMemorySessionStorage = class {
720
+ sessions = /* @__PURE__ */ new Map();
721
+ get(sessionKey) {
722
+ return this.sessions.get(sessionKey);
723
+ }
724
+ set(sessionKey, session) {
725
+ this.sessions.set(sessionKey, session);
726
+ }
727
+ delete(sessionKey) {
728
+ this.sessions.delete(sessionKey);
729
+ }
730
+ has(sessionKey) {
731
+ return this.sessions.has(sessionKey);
732
+ }
733
+ getAll() {
734
+ return Array.from(this.sessions.values());
735
+ }
736
+ clear() {
737
+ this.sessions.clear();
738
+ }
739
+ count() {
740
+ return this.sessions.size;
741
+ }
742
+ };
743
+
744
+ // ../claude/src/session/manager.ts
745
+ var SessionManager = class {
746
+ storage;
747
+ events;
748
+ constructor(events, storage) {
749
+ this.storage = storage || new InMemorySessionStorage();
750
+ this.events = events;
751
+ }
752
+ /**
753
+ * Get or create a session
754
+ */
755
+ getOrCreateSession(sessionKey, agentId) {
756
+ let session = this.storage.get(sessionKey);
757
+ if (!session) {
758
+ session = {
759
+ sessionKey,
760
+ agentId,
761
+ messages: [],
762
+ createdAt: Date.now(),
763
+ updatedAt: Date.now()
764
+ };
765
+ this.storage.set(sessionKey, session);
766
+ this.events.emit("session:created", sessionKey);
767
+ }
768
+ return session;
769
+ }
770
+ /**
771
+ * Get session by key
772
+ */
773
+ getSession(sessionKey) {
774
+ return this.storage.get(sessionKey);
775
+ }
776
+ /**
777
+ * Add message to session
778
+ */
779
+ addMessage(sessionKey, message) {
780
+ const session = this.storage.get(sessionKey);
781
+ if (!session) {
782
+ throw new NotFoundError("Session", sessionKey);
783
+ }
784
+ session.messages.push(message);
785
+ session.updatedAt = Date.now();
786
+ this.storage.set(sessionKey, session);
787
+ }
788
+ /**
789
+ * Get session history
790
+ */
791
+ getHistory(sessionKey, limit) {
792
+ const session = this.storage.get(sessionKey);
793
+ if (!session) {
794
+ throw new NotFoundError("Session", sessionKey);
795
+ }
796
+ if (limit && limit > 0) {
797
+ return session.messages.slice(-limit);
798
+ }
799
+ return session.messages;
800
+ }
801
+ /**
802
+ * List sessions with optional filtering
803
+ */
804
+ listSessions(options) {
805
+ let sessions = this.storage.getAll();
806
+ if (options?.agentId) {
807
+ sessions = sessions.filter((s) => s.agentId === options.agentId);
808
+ }
809
+ if (options?.activeWithinMinutes) {
810
+ const cutoff = Date.now() - options.activeWithinMinutes * 60 * 1e3;
811
+ sessions = sessions.filter((s) => s.updatedAt >= cutoff);
812
+ }
813
+ sessions.sort((a, b) => b.updatedAt - a.updatedAt);
814
+ if (options?.offset) {
815
+ sessions = sessions.slice(options.offset);
816
+ }
817
+ if (options?.limit) {
818
+ sessions = sessions.slice(0, options.limit);
819
+ }
820
+ return sessions;
821
+ }
822
+ /**
823
+ * Delete session
824
+ */
825
+ deleteSession(sessionKey) {
826
+ if (!this.storage.has(sessionKey)) {
827
+ throw new NotFoundError("Session", sessionKey);
828
+ }
829
+ this.storage.delete(sessionKey);
830
+ this.events.emit("session:deleted", sessionKey);
831
+ }
832
+ /**
833
+ * Update session process ID
834
+ */
835
+ setProcessId(sessionKey, processId) {
836
+ const session = this.storage.get(sessionKey);
837
+ if (!session) {
838
+ throw new NotFoundError("Session", sessionKey);
839
+ }
840
+ session.processId = processId;
841
+ session.updatedAt = Date.now();
842
+ this.storage.set(sessionKey, session);
843
+ }
844
+ /**
845
+ * Clear process ID from session
846
+ */
847
+ clearProcessId(sessionKey) {
848
+ const session = this.storage.get(sessionKey);
849
+ if (session) {
850
+ delete session.processId;
851
+ session.updatedAt = Date.now();
852
+ this.storage.set(sessionKey, session);
853
+ }
854
+ }
855
+ /**
856
+ * Get session count
857
+ */
858
+ getSessionCount() {
859
+ return this.storage.count();
860
+ }
861
+ /**
862
+ * Clear all sessions
863
+ */
864
+ clearAll() {
865
+ this.storage.clear();
866
+ }
867
+ };
868
+
869
+ // ../claude/src/transport/cli.ts
870
+ var execAsync = promisify(exec);
871
+ var CLITransport = class {
872
+ state = "disconnected";
873
+ processManager;
874
+ sessionManager;
875
+ events;
876
+ config;
877
+ constructor(config, events) {
878
+ this.events = events;
879
+ this.config = {
880
+ ...config,
881
+ autoConnect: config.autoConnect ?? true,
882
+ timeout: config.timeout ?? 3e5
883
+ // 5 minutes default
884
+ };
885
+ this.processManager = new ProcessManager(
886
+ {
887
+ cliPath: config.cliPath,
888
+ maxProcesses: config.maxProcesses,
889
+ processIdleTimeout: config.processIdleTimeout,
890
+ model: config.model,
891
+ permissionMode: config.permissionMode,
892
+ workingDirectory: config.workingDirectory
893
+ },
894
+ events
895
+ );
896
+ this.sessionManager = new SessionManager(events);
897
+ }
898
+ /**
899
+ * Connect - verify Claude CLI is available
900
+ */
901
+ async connect() {
902
+ if (this.state === "connected") {
903
+ return;
904
+ }
905
+ this.state = "connecting";
906
+ this.events.emit("connection:state", "connecting");
907
+ try {
908
+ await this.verifyCLI();
909
+ this.processManager.startCleanup();
910
+ this.state = "connected";
911
+ this.events.emit("connection:state", "connected");
912
+ this.events.emit("connection:connected");
913
+ } catch (error) {
914
+ this.state = "error";
915
+ this.events.emit("connection:state", "error");
916
+ this.events.emit("connection:error", error);
917
+ throw new ConnectionError("Failed to connect to Claude CLI", void 0, error);
918
+ }
919
+ }
920
+ /**
921
+ * Verify Claude CLI is available
922
+ */
923
+ async verifyCLI() {
924
+ try {
925
+ const { stdout } = await execAsync(`${this.config.cliPath} --version`);
926
+ console.log(`Claude CLI available: ${stdout.trim()}`);
927
+ } catch (error) {
928
+ throw new CLIError(
929
+ `Claude CLI not found at '${this.config.cliPath}'. Ensure Claude CLI is installed and in PATH.`,
930
+ error.code,
931
+ "",
932
+ error.message
933
+ );
934
+ }
935
+ }
936
+ /**
937
+ * Disconnect and cleanup
938
+ */
939
+ disconnect() {
940
+ if (this.state === "disconnected") {
941
+ return;
942
+ }
943
+ this.processManager.killAll();
944
+ this.processManager.stopCleanup();
945
+ this.state = "disconnected";
946
+ this.events.emit("connection:state", "disconnected");
947
+ this.events.emit("connection:disconnected");
948
+ }
949
+ /**
950
+ * Check if connected
951
+ */
952
+ isConnected() {
953
+ return this.state === "connected";
954
+ }
955
+ /**
956
+ * Get connection state
957
+ */
958
+ getConnectionState() {
959
+ return this.state;
960
+ }
961
+ /**
962
+ * Make an RPC request
963
+ */
964
+ async request(method, params = {}) {
965
+ if (!this.isConnected()) {
966
+ throw new ConnectionError("Not connected to Claude CLI");
967
+ }
968
+ switch (method) {
969
+ case "chat.send":
970
+ return this.handleChatSend(params);
971
+ case "sessions.list":
972
+ return this.handleSessionsList(params);
973
+ case "sessions.get":
974
+ return this.handleSessionsGet(params.sessionKey);
975
+ case "sessions.delete":
976
+ return this.handleSessionsDelete(params.sessionKey);
977
+ case "sessions.history":
978
+ return this.handleSessionsHistory(params.sessionKey);
979
+ case "system.health":
980
+ return this.handleSystemHealth();
981
+ case "system.status":
982
+ return this.handleSystemStatus();
983
+ case "agents.list":
984
+ return this.handleAgentsList();
985
+ case "agents.get":
986
+ return this.handleAgentsGet(params.agentId);
987
+ default:
988
+ throw new Error(`Unknown RPC method: ${method}`);
989
+ }
990
+ }
991
+ /**
992
+ * Handle chat.send request
993
+ */
994
+ async handleChatSend(options) {
995
+ const sessionKey = options.sessionKey || `claude-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
996
+ const agentId = options.agentId || "claude";
997
+ const timeout = options.timeout || this.config.timeout;
998
+ const session = this.sessionManager.getOrCreateSession(sessionKey, agentId);
999
+ this.sessionManager.addMessage(sessionKey, {
1000
+ role: "user",
1001
+ content: options.message,
1002
+ timestamp: Date.now()
1003
+ });
1004
+ const existingProc = this.processManager.get(sessionKey);
1005
+ if (existingProc) {
1006
+ this.processManager.kill(sessionKey);
1007
+ }
1008
+ const proc = await this.processManager.spawn({
1009
+ sessionKey,
1010
+ model: this.config.model,
1011
+ thinking: options.thinking,
1012
+ permissionMode: this.config.permissionMode,
1013
+ workingDirectory: this.config.workingDirectory,
1014
+ timeout,
1015
+ message: options.message
1016
+ });
1017
+ this.processManager.setStatus(sessionKey, "busy");
1018
+ try {
1019
+ const parser = new ClaudeStreamParser(sessionKey);
1020
+ const { content, thinking } = await Promise.race([
1021
+ parser.collectFullResponse(proc.process.stdout),
1022
+ this.createTimeoutPromise(timeout)
1023
+ ]);
1024
+ this.sessionManager.addMessage(sessionKey, {
1025
+ role: "assistant",
1026
+ content,
1027
+ thinking,
1028
+ timestamp: Date.now()
1029
+ });
1030
+ this.processManager.setStatus(sessionKey, "idle");
1031
+ this.processManager.touch(sessionKey);
1032
+ return {
1033
+ sessionKey,
1034
+ agentId,
1035
+ response: content,
1036
+ thinking,
1037
+ timestamp: Date.now()
1038
+ };
1039
+ } catch (error) {
1040
+ this.processManager.setStatus(sessionKey, "error");
1041
+ throw error;
1042
+ }
1043
+ }
1044
+ /**
1045
+ * Handle sessions.list request
1046
+ */
1047
+ async handleSessionsList(options) {
1048
+ const sessions = this.sessionManager.listSessions(options);
1049
+ return {
1050
+ sessions: sessions.map((s) => ({
1051
+ sessionKey: s.sessionKey,
1052
+ agentId: s.agentId,
1053
+ messageCount: s.messages.length,
1054
+ createdAt: s.createdAt,
1055
+ updatedAt: s.updatedAt
1056
+ })),
1057
+ total: sessions.length
1058
+ };
1059
+ }
1060
+ /**
1061
+ * Handle sessions.get request
1062
+ */
1063
+ async handleSessionsGet(sessionKey) {
1064
+ const session = this.sessionManager.getSession(sessionKey);
1065
+ if (!session) {
1066
+ throw new NotFoundError("Session", sessionKey);
1067
+ }
1068
+ return {
1069
+ sessionKey: session.sessionKey,
1070
+ agentId: session.agentId,
1071
+ messageCount: session.messages.length,
1072
+ createdAt: session.createdAt,
1073
+ updatedAt: session.updatedAt
1074
+ };
1075
+ }
1076
+ /**
1077
+ * Handle sessions.delete request
1078
+ */
1079
+ async handleSessionsDelete(sessionKey) {
1080
+ this.processManager.kill(sessionKey);
1081
+ this.sessionManager.deleteSession(sessionKey);
1082
+ }
1083
+ /**
1084
+ * Handle sessions.history request
1085
+ */
1086
+ async handleSessionsHistory(sessionKey) {
1087
+ const messages = this.sessionManager.getHistory(sessionKey);
1088
+ return { messages };
1089
+ }
1090
+ /**
1091
+ * Handle system.health request
1092
+ */
1093
+ async handleSystemHealth() {
1094
+ try {
1095
+ await this.verifyCLI();
1096
+ return {
1097
+ healthy: true,
1098
+ cliAvailable: true,
1099
+ activeSessions: this.sessionManager.getSessionCount(),
1100
+ activeProcesses: this.processManager.getProcessCount()
1101
+ };
1102
+ } catch {
1103
+ return {
1104
+ healthy: false,
1105
+ cliAvailable: false,
1106
+ activeSessions: this.sessionManager.getSessionCount(),
1107
+ activeProcesses: this.processManager.getProcessCount()
1108
+ };
1109
+ }
1110
+ }
1111
+ /**
1112
+ * Handle system.status request
1113
+ */
1114
+ async handleSystemStatus() {
1115
+ return {
1116
+ state: this.state,
1117
+ activeSessions: this.sessionManager.getSessionCount(),
1118
+ activeProcesses: this.processManager.getProcessCount(),
1119
+ cliPath: this.config.cliPath
1120
+ };
1121
+ }
1122
+ /**
1123
+ * Handle agents.list request (stub)
1124
+ */
1125
+ async handleAgentsList() {
1126
+ return {
1127
+ agents: [
1128
+ {
1129
+ agentId: "claude",
1130
+ status: "available",
1131
+ workspace: this.config.workingDirectory
1132
+ }
1133
+ ],
1134
+ defaultAgentId: "claude"
1135
+ };
1136
+ }
1137
+ /**
1138
+ * Handle agents.get request (stub)
1139
+ */
1140
+ async handleAgentsGet(agentId) {
1141
+ return {
1142
+ agentId,
1143
+ status: "available",
1144
+ workspace: this.config.workingDirectory
1145
+ };
1146
+ }
1147
+ /**
1148
+ * Create timeout promise
1149
+ */
1150
+ createTimeoutPromise(timeout) {
1151
+ return new Promise((_, reject) => {
1152
+ setTimeout(() => {
1153
+ reject(new TimeoutError("Operation timed out", timeout));
1154
+ }, timeout);
1155
+ });
1156
+ }
1157
+ /**
1158
+ * Subscribe to event
1159
+ */
1160
+ on(event, handler) {
1161
+ this.events.on(event, handler);
1162
+ }
1163
+ /**
1164
+ * Unsubscribe from event
1165
+ */
1166
+ off(event, handler) {
1167
+ this.events.off(event, handler);
1168
+ }
1169
+ /**
1170
+ * Emit event
1171
+ */
1172
+ emit(event, ...args) {
1173
+ this.events.emit(event, ...args);
1174
+ }
1175
+ /**
1176
+ * Get process manager (for internal use)
1177
+ */
1178
+ getProcessManager() {
1179
+ return this.processManager;
1180
+ }
1181
+ /**
1182
+ * Get session manager (for internal use)
1183
+ */
1184
+ getSessionManager() {
1185
+ return this.sessionManager;
1186
+ }
1187
+ };
1188
+
1189
+ // ../claude/src/sdk.ts
1190
+ var DEFAULT_CONFIG = {
1191
+ cliPath: "claude",
1192
+ timeout: 3e5,
1193
+ // 5 minutes
1194
+ maxProcesses: 10,
1195
+ processIdleTimeout: 6e5,
1196
+ // 10 minutes
1197
+ model: "claude-sonnet-4-5",
1198
+ permissionMode: "default",
1199
+ workingDirectory: process.cwd(),
1200
+ autoConnect: true
1201
+ };
1202
+ var ClaudeSDK = class _ClaudeSDK {
1203
+ transport;
1204
+ events;
1205
+ // Domain modules
1206
+ system;
1207
+ agents;
1208
+ sessions;
1209
+ chat;
1210
+ constructor(config) {
1211
+ this.events = createEventEmitter();
1212
+ const transportConfig = {
1213
+ cliPath: config.cliPath,
1214
+ timeout: config.timeout,
1215
+ maxProcesses: config.maxProcesses,
1216
+ processIdleTimeout: config.processIdleTimeout,
1217
+ model: config.model,
1218
+ permissionMode: config.permissionMode,
1219
+ workingDirectory: config.workingDirectory,
1220
+ autoConnect: false
1221
+ // We'll connect manually after initialization
1222
+ };
1223
+ this.transport = new CLITransport(transportConfig, this.events);
1224
+ this.system = new SystemModule(this.transport, this.events);
1225
+ this.agents = new AgentsModule(this.transport, this.events);
1226
+ this.sessions = new SessionsModule(this.transport, this.events);
1227
+ this.chat = new ChatModule(this.transport, this.events);
1228
+ }
1229
+ /**
1230
+ * Create a new ClaudeSDK instance
1231
+ * Auto-connects by default
1232
+ */
1233
+ static async create(config) {
1234
+ const fullConfig = {
1235
+ ...DEFAULT_CONFIG,
1236
+ ...config
1237
+ };
1238
+ const sdk = new _ClaudeSDK(fullConfig);
1239
+ if (fullConfig.autoConnect) {
1240
+ await sdk.connect();
1241
+ }
1242
+ return sdk;
1243
+ }
1244
+ /**
1245
+ * Create a disconnected SDK instance
1246
+ * Must call connect() manually
1247
+ */
1248
+ static createDisconnected(config) {
1249
+ const fullConfig = {
1250
+ ...DEFAULT_CONFIG,
1251
+ ...config,
1252
+ autoConnect: false
1253
+ };
1254
+ return new _ClaudeSDK(fullConfig);
1255
+ }
1256
+ /**
1257
+ * Connect to Claude CLI
1258
+ */
1259
+ async connect() {
1260
+ await this.transport.connect();
1261
+ }
1262
+ /**
1263
+ * Disconnect and cleanup
1264
+ */
1265
+ disconnect() {
1266
+ this.transport.disconnect();
1267
+ }
1268
+ /**
1269
+ * Check if connected
1270
+ */
1271
+ isConnected() {
1272
+ return this.transport.isConnected();
1273
+ }
1274
+ /**
1275
+ * Get connection state
1276
+ */
1277
+ getConnectionState() {
1278
+ return this.transport.getConnectionState();
1279
+ }
1280
+ /**
1281
+ * Subscribe to an event
1282
+ */
1283
+ on(event, handler) {
1284
+ this.events.on(event, handler);
1285
+ return this;
1286
+ }
1287
+ /**
1288
+ * Subscribe to an event once
1289
+ */
1290
+ once(event, handler) {
1291
+ this.events.once(event, handler);
1292
+ return this;
1293
+ }
1294
+ /**
1295
+ * Unsubscribe from an event
1296
+ */
1297
+ off(event, handler) {
1298
+ this.events.off(event, handler);
1299
+ return this;
1300
+ }
1301
+ /**
1302
+ * Remove all listeners for an event
1303
+ */
1304
+ removeAllListeners(event) {
1305
+ this.events.removeAllListeners(event);
1306
+ return this;
1307
+ }
1308
+ /**
1309
+ * Wait for an event (promisified)
1310
+ */
1311
+ waitFor(event, timeout) {
1312
+ return this.events.waitFor(event, timeout);
1313
+ }
1314
+ };
1315
+ export {
1316
+ CLIError,
1317
+ ClaudeError,
1318
+ ClaudeSDK,
1319
+ ConnectionError,
1320
+ NotConnectedError,
1321
+ NotFoundError,
1322
+ NotImplementedError,
1323
+ ProcessError,
1324
+ StreamParseError,
1325
+ TimeoutError,
1326
+ ValidationError
1327
+ };