@moxxy/cli 0.0.10 → 0.0.12

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,1407 @@
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 {
290
+ return null;
291
+ }
292
+ }
293
+ /**
294
+ * Convert stream event to chat stream chunk
295
+ * Handles both CLI format and API format events
296
+ */
297
+ toChunk(event) {
298
+ switch (event.type) {
299
+ // --- Claude CLI format events ---
300
+ case "assistant": {
301
+ const message = event.message;
302
+ if (!message?.content) return null;
303
+ const textBlocks = message.content.filter((b) => b.type === "text");
304
+ const text = textBlocks.map((b) => b.text || "").join("");
305
+ const thinkingBlocks = message.content.filter((b) => b.type === "thinking");
306
+ const thinking = thinkingBlocks.length > 0 ? thinkingBlocks.map((b) => b.thinking || b.text || "").join("") : void 0;
307
+ if (!text && !thinking) return null;
308
+ return {
309
+ content: text,
310
+ thinking,
311
+ done: false,
312
+ sessionKey: this.sessionKey,
313
+ timestamp: Date.now()
314
+ };
315
+ }
316
+ case "result": {
317
+ const resultText = event.result || "";
318
+ return {
319
+ content: resultText,
320
+ done: true,
321
+ sessionKey: this.sessionKey,
322
+ timestamp: Date.now()
323
+ };
324
+ }
325
+ case "system":
326
+ return null;
327
+ // --- Anthropic API format events (legacy/fallback) ---
328
+ case "content_block_delta": {
329
+ const text = event.delta?.text || "";
330
+ return {
331
+ content: text,
332
+ done: false,
333
+ sessionKey: this.sessionKey,
334
+ timestamp: Date.now()
335
+ };
336
+ }
337
+ case "thinking_block": {
338
+ return {
339
+ content: "",
340
+ thinking: event.content || "",
341
+ done: false,
342
+ sessionKey: this.sessionKey,
343
+ timestamp: Date.now()
344
+ };
345
+ }
346
+ case "message_stop": {
347
+ return {
348
+ content: "",
349
+ done: true,
350
+ sessionKey: this.sessionKey,
351
+ timestamp: Date.now()
352
+ };
353
+ }
354
+ case "content_block_start":
355
+ case "content_block_stop":
356
+ case "session_start":
357
+ case "message_start":
358
+ return null;
359
+ default:
360
+ return null;
361
+ }
362
+ }
363
+ /**
364
+ * Parse stream asynchronously
365
+ */
366
+ async *parseStream(stream) {
367
+ const reader = createInterface({
368
+ input: stream,
369
+ crlfDelay: Number.POSITIVE_INFINITY
370
+ });
371
+ try {
372
+ for await (const line of reader) {
373
+ const event = this.parseLine(line);
374
+ if (event) {
375
+ const chunk = this.toChunk(event);
376
+ if (chunk) {
377
+ yield chunk;
378
+ if (chunk.done) {
379
+ break;
380
+ }
381
+ }
382
+ }
383
+ }
384
+ } catch (error) {
385
+ if (error instanceof Error) {
386
+ throw new StreamParseError("Error parsing stream", "", error);
387
+ }
388
+ throw error;
389
+ } finally {
390
+ reader.close();
391
+ }
392
+ }
393
+ /**
394
+ * Collect full response from stream
395
+ * Returns full text and optional thinking
396
+ */
397
+ async collectFullResponse(stream) {
398
+ let fullContent = "";
399
+ let thinking;
400
+ for await (const chunk of this.parseStream(stream)) {
401
+ if (chunk.content) {
402
+ fullContent += chunk.content;
403
+ }
404
+ if (chunk.thinking) {
405
+ thinking = chunk.thinking;
406
+ }
407
+ }
408
+ return { content: fullContent, thinking };
409
+ }
410
+ };
411
+
412
+ // ../claude/src/modules/chat.ts
413
+ var ChatModule = class extends BaseModule {
414
+ /**
415
+ * Send a message and wait for complete response
416
+ */
417
+ async send(options) {
418
+ return this.request("chat.send", options);
419
+ }
420
+ /**
421
+ * Send a message with streaming response
422
+ */
423
+ async *sendStream(options) {
424
+ const sessionKey = options.sessionKey || `claude-stream-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
425
+ const agentId = options.agentId || "claude";
426
+ const transport = this.transport;
427
+ const sessionManager = transport.getSessionManager();
428
+ const processManager = transport.getProcessManager();
429
+ const session = sessionManager.getOrCreateSession(sessionKey, agentId);
430
+ sessionManager.addMessage(sessionKey, {
431
+ role: "user",
432
+ content: options.message,
433
+ timestamp: Date.now()
434
+ });
435
+ this.events.emit("chat:stream:start", sessionKey, agentId);
436
+ options.onStart?.(sessionKey, agentId);
437
+ const existingProc = processManager.get(sessionKey);
438
+ if (existingProc) {
439
+ processManager.kill(sessionKey);
440
+ }
441
+ const proc = await processManager.spawn({
442
+ sessionKey,
443
+ model: transport.config.model,
444
+ thinking: options.thinking,
445
+ permissionMode: transport.config.permissionMode,
446
+ workingDirectory: transport.config.workingDirectory,
447
+ timeout: options.timeout,
448
+ message: options.message,
449
+ outputFormat: "stream-json"
450
+ });
451
+ processManager.setStatus(sessionKey, "busy");
452
+ let fullResponse = "";
453
+ let thinking;
454
+ try {
455
+ const parser = new ClaudeStreamParser(sessionKey);
456
+ for await (const chunk of parser.parseStream(proc.process.stdout)) {
457
+ if (chunk.content) {
458
+ fullResponse += chunk.content;
459
+ }
460
+ if (chunk.thinking) {
461
+ thinking = chunk.thinking;
462
+ }
463
+ this.events.emit("chat:stream", chunk);
464
+ options.onChunk?.(chunk);
465
+ yield chunk;
466
+ if (chunk.done) {
467
+ break;
468
+ }
469
+ }
470
+ sessionManager.addMessage(sessionKey, {
471
+ role: "assistant",
472
+ content: fullResponse,
473
+ thinking,
474
+ timestamp: Date.now()
475
+ });
476
+ processManager.setStatus(sessionKey, "idle");
477
+ processManager.touch(sessionKey);
478
+ this.events.emit("chat:stream:end", sessionKey, agentId);
479
+ options.onEnd?.(sessionKey, agentId);
480
+ return {
481
+ sessionKey,
482
+ agentId,
483
+ response: fullResponse,
484
+ thinking,
485
+ timestamp: Date.now()
486
+ };
487
+ } catch (error) {
488
+ processManager.setStatus(sessionKey, "error");
489
+ throw error;
490
+ }
491
+ }
492
+ /**
493
+ * Get chat history for a session
494
+ */
495
+ async history(sessionKey, options) {
496
+ return this.request("sessions.history", { sessionKey, ...options });
497
+ }
498
+ };
499
+
500
+ // ../claude/src/modules/sessions.ts
501
+ var SessionsModule = class extends BaseModule {
502
+ /**
503
+ * List sessions with optional filtering
504
+ */
505
+ async list(options) {
506
+ return this.request("sessions.list", options);
507
+ }
508
+ /**
509
+ * Get session details
510
+ */
511
+ async get(sessionKey) {
512
+ return this.request("sessions.get", { sessionKey });
513
+ }
514
+ /**
515
+ * Delete a session
516
+ */
517
+ async delete(sessionKey) {
518
+ await this.request("sessions.delete", { sessionKey });
519
+ }
520
+ /**
521
+ * Get session message history
522
+ */
523
+ async history(sessionKey, options) {
524
+ return this.request("sessions.history", { sessionKey, ...options });
525
+ }
526
+ /**
527
+ * Create a new session (convenience method)
528
+ * Sessions are created automatically on first message, but this can be used to pre-create
529
+ */
530
+ async create(agentId = "claude") {
531
+ const sessionKey = `claude-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
532
+ return { sessionKey };
533
+ }
534
+ };
535
+
536
+ // ../claude/src/modules/system.ts
537
+ var SystemModule = class extends BaseModule {
538
+ /**
539
+ * Get health status
540
+ */
541
+ async health() {
542
+ return this.request("system.health");
543
+ }
544
+ /**
545
+ * Get system status
546
+ */
547
+ async status() {
548
+ return this.request("system.status");
549
+ }
550
+ /**
551
+ * Ping (simple health check)
552
+ */
553
+ async ping() {
554
+ try {
555
+ const health = await this.health();
556
+ return {
557
+ ok: health.healthy,
558
+ timestamp: Date.now()
559
+ };
560
+ } catch {
561
+ return {
562
+ ok: false,
563
+ timestamp: Date.now()
564
+ };
565
+ }
566
+ }
567
+ };
568
+
569
+ // ../claude/src/transport/cli.ts
570
+ import { exec } from "child_process";
571
+ import { promisify } from "util";
572
+
573
+ // ../claude/src/transport/process-manager.ts
574
+ import { spawn } from "child_process";
575
+ var ProcessManager = class {
576
+ constructor(config, events) {
577
+ this.config = config;
578
+ this.events = events;
579
+ }
580
+ processes = /* @__PURE__ */ new Map();
581
+ cleanupInterval = null;
582
+ events;
583
+ /**
584
+ * Spawn a new Claude process
585
+ */
586
+ async spawn(options) {
587
+ if (this.processes.size >= this.config.maxProcesses) {
588
+ throw new ProcessError(
589
+ `Maximum process limit reached (${this.config.maxProcesses})`,
590
+ options.sessionKey
591
+ );
592
+ }
593
+ const args = this.buildArgs(options);
594
+ const proc = spawn(this.config.cliPath, args, {
595
+ cwd: options.workingDirectory || this.config.workingDirectory || process.cwd(),
596
+ env: process.env,
597
+ stdio: ["pipe", "pipe", "pipe"]
598
+ });
599
+ if (options.message) {
600
+ proc.stdin.write(options.message);
601
+ }
602
+ proc.stdin.end();
603
+ const claudeProc = {
604
+ sessionKey: options.sessionKey,
605
+ process: proc,
606
+ status: "idle",
607
+ createdAt: Date.now(),
608
+ lastUsedAt: Date.now()
609
+ };
610
+ this.setupProcessHandlers(claudeProc);
611
+ this.processes.set(options.sessionKey, claudeProc);
612
+ this.events.emit("process:spawn", options.sessionKey, proc.pid ?? 0);
613
+ return claudeProc;
614
+ }
615
+ /**
616
+ * Build CLI arguments
617
+ */
618
+ buildArgs(options) {
619
+ const outputFormat = options.outputFormat || "json";
620
+ const args = [
621
+ "--print",
622
+ "--output-format",
623
+ outputFormat
624
+ ];
625
+ if (outputFormat === "stream-json") {
626
+ args.push("--verbose");
627
+ }
628
+ const model = options.model || this.config.model;
629
+ if (model) {
630
+ args.push("--model", model);
631
+ }
632
+ if (options.thinking && options.thinking !== "none") {
633
+ args.push("--thinking", options.thinking);
634
+ }
635
+ if (this.config.dangerouslySkipPermissions) {
636
+ args.push("--dangerously-skip-permissions");
637
+ } else {
638
+ const permissionMode = options.permissionMode || this.config.permissionMode;
639
+ if (permissionMode) {
640
+ args.push("--permission-mode", permissionMode);
641
+ }
642
+ }
643
+ const workingDir = options.workingDirectory || this.config.workingDirectory;
644
+ if (workingDir) {
645
+ args.push("--add-dir", workingDir);
646
+ }
647
+ return args;
648
+ }
649
+ /**
650
+ * Setup process event handlers
651
+ */
652
+ setupProcessHandlers(proc) {
653
+ proc.process.on("error", (error) => {
654
+ proc.status = "error";
655
+ this.events.emit("process:error", proc.sessionKey, error);
656
+ });
657
+ proc.process.on("exit", (code) => {
658
+ this.processes.delete(proc.sessionKey);
659
+ this.events.emit("process:exit", proc.sessionKey, code);
660
+ });
661
+ proc.process.stderr?.on("data", (data) => {
662
+ const message = data.toString();
663
+ this.events.emit("agent:log", proc.sessionKey, message, "error");
664
+ });
665
+ }
666
+ /**
667
+ * Get existing process by session key
668
+ */
669
+ get(sessionKey) {
670
+ return this.processes.get(sessionKey);
671
+ }
672
+ /**
673
+ * Update process last used time
674
+ */
675
+ touch(sessionKey) {
676
+ const proc = this.processes.get(sessionKey);
677
+ if (proc) {
678
+ proc.lastUsedAt = Date.now();
679
+ }
680
+ }
681
+ /**
682
+ * Set process status
683
+ */
684
+ setStatus(sessionKey, status) {
685
+ const proc = this.processes.get(sessionKey);
686
+ if (proc) {
687
+ proc.status = status;
688
+ }
689
+ }
690
+ /**
691
+ * Kill a specific process
692
+ */
693
+ kill(sessionKey) {
694
+ const proc = this.processes.get(sessionKey);
695
+ if (proc) {
696
+ try {
697
+ proc.process.kill("SIGTERM");
698
+ } catch (error) {
699
+ console.error(`Error killing process ${sessionKey}:`, error);
700
+ }
701
+ this.processes.delete(sessionKey);
702
+ }
703
+ }
704
+ /**
705
+ * Kill all processes
706
+ */
707
+ killAll() {
708
+ for (const sessionKey of Array.from(this.processes.keys())) {
709
+ this.kill(sessionKey);
710
+ }
711
+ }
712
+ /**
713
+ * Start periodic cleanup of idle processes
714
+ */
715
+ startCleanup(intervalMs = 6e4) {
716
+ if (this.cleanupInterval) {
717
+ return;
718
+ }
719
+ this.cleanupInterval = setInterval(() => {
720
+ this.cleanupIdleProcesses();
721
+ }, intervalMs);
722
+ }
723
+ /**
724
+ * Stop cleanup interval
725
+ */
726
+ stopCleanup() {
727
+ if (this.cleanupInterval) {
728
+ clearInterval(this.cleanupInterval);
729
+ this.cleanupInterval = null;
730
+ }
731
+ }
732
+ /**
733
+ * Cleanup idle processes
734
+ */
735
+ cleanupIdleProcesses() {
736
+ const now = Date.now();
737
+ const timeout = this.config.processIdleTimeout;
738
+ for (const [sessionKey, proc] of this.processes.entries()) {
739
+ if (proc.status === "idle" && now - proc.lastUsedAt > timeout) {
740
+ this.kill(sessionKey);
741
+ }
742
+ }
743
+ }
744
+ /**
745
+ * Get process count
746
+ */
747
+ getProcessCount() {
748
+ return this.processes.size;
749
+ }
750
+ /**
751
+ * Get all session keys with active processes
752
+ */
753
+ getActiveSessionKeys() {
754
+ return Array.from(this.processes.keys());
755
+ }
756
+ };
757
+
758
+ // ../claude/src/session/storage.ts
759
+ var InMemorySessionStorage = class {
760
+ sessions = /* @__PURE__ */ new Map();
761
+ get(sessionKey) {
762
+ return this.sessions.get(sessionKey);
763
+ }
764
+ set(sessionKey, session) {
765
+ this.sessions.set(sessionKey, session);
766
+ }
767
+ delete(sessionKey) {
768
+ this.sessions.delete(sessionKey);
769
+ }
770
+ has(sessionKey) {
771
+ return this.sessions.has(sessionKey);
772
+ }
773
+ getAll() {
774
+ return Array.from(this.sessions.values());
775
+ }
776
+ clear() {
777
+ this.sessions.clear();
778
+ }
779
+ count() {
780
+ return this.sessions.size;
781
+ }
782
+ };
783
+
784
+ // ../claude/src/session/manager.ts
785
+ var SessionManager = class {
786
+ storage;
787
+ events;
788
+ constructor(events, storage) {
789
+ this.storage = storage || new InMemorySessionStorage();
790
+ this.events = events;
791
+ }
792
+ /**
793
+ * Get or create a session
794
+ */
795
+ getOrCreateSession(sessionKey, agentId) {
796
+ let session = this.storage.get(sessionKey);
797
+ if (!session) {
798
+ session = {
799
+ sessionKey,
800
+ agentId,
801
+ messages: [],
802
+ createdAt: Date.now(),
803
+ updatedAt: Date.now()
804
+ };
805
+ this.storage.set(sessionKey, session);
806
+ this.events.emit("session:created", sessionKey);
807
+ }
808
+ return session;
809
+ }
810
+ /**
811
+ * Get session by key
812
+ */
813
+ getSession(sessionKey) {
814
+ return this.storage.get(sessionKey);
815
+ }
816
+ /**
817
+ * Add message to session
818
+ */
819
+ addMessage(sessionKey, message) {
820
+ const session = this.storage.get(sessionKey);
821
+ if (!session) {
822
+ throw new NotFoundError("Session", sessionKey);
823
+ }
824
+ session.messages.push(message);
825
+ session.updatedAt = Date.now();
826
+ this.storage.set(sessionKey, session);
827
+ }
828
+ /**
829
+ * Get session history
830
+ */
831
+ getHistory(sessionKey, limit) {
832
+ const session = this.storage.get(sessionKey);
833
+ if (!session) {
834
+ throw new NotFoundError("Session", sessionKey);
835
+ }
836
+ if (limit && limit > 0) {
837
+ return session.messages.slice(-limit);
838
+ }
839
+ return session.messages;
840
+ }
841
+ /**
842
+ * List sessions with optional filtering
843
+ */
844
+ listSessions(options) {
845
+ let sessions = this.storage.getAll();
846
+ if (options?.agentId) {
847
+ sessions = sessions.filter((s) => s.agentId === options.agentId);
848
+ }
849
+ if (options?.activeWithinMinutes) {
850
+ const cutoff = Date.now() - options.activeWithinMinutes * 60 * 1e3;
851
+ sessions = sessions.filter((s) => s.updatedAt >= cutoff);
852
+ }
853
+ sessions.sort((a, b) => b.updatedAt - a.updatedAt);
854
+ if (options?.offset) {
855
+ sessions = sessions.slice(options.offset);
856
+ }
857
+ if (options?.limit) {
858
+ sessions = sessions.slice(0, options.limit);
859
+ }
860
+ return sessions;
861
+ }
862
+ /**
863
+ * Delete session
864
+ */
865
+ deleteSession(sessionKey) {
866
+ if (!this.storage.has(sessionKey)) {
867
+ throw new NotFoundError("Session", sessionKey);
868
+ }
869
+ this.storage.delete(sessionKey);
870
+ this.events.emit("session:deleted", sessionKey);
871
+ }
872
+ /**
873
+ * Update session process ID
874
+ */
875
+ setProcessId(sessionKey, processId) {
876
+ const session = this.storage.get(sessionKey);
877
+ if (!session) {
878
+ throw new NotFoundError("Session", sessionKey);
879
+ }
880
+ session.processId = processId;
881
+ session.updatedAt = Date.now();
882
+ this.storage.set(sessionKey, session);
883
+ }
884
+ /**
885
+ * Clear process ID from session
886
+ */
887
+ clearProcessId(sessionKey) {
888
+ const session = this.storage.get(sessionKey);
889
+ if (session) {
890
+ delete session.processId;
891
+ session.updatedAt = Date.now();
892
+ this.storage.set(sessionKey, session);
893
+ }
894
+ }
895
+ /**
896
+ * Get session count
897
+ */
898
+ getSessionCount() {
899
+ return this.storage.count();
900
+ }
901
+ /**
902
+ * Clear all sessions
903
+ */
904
+ clearAll() {
905
+ this.storage.clear();
906
+ }
907
+ };
908
+
909
+ // ../claude/src/transport/cli.ts
910
+ var execAsync = promisify(exec);
911
+ var CLITransport = class {
912
+ state = "disconnected";
913
+ processManager;
914
+ sessionManager;
915
+ events;
916
+ config;
917
+ constructor(config, events) {
918
+ this.events = events;
919
+ this.config = {
920
+ ...config,
921
+ autoConnect: config.autoConnect ?? true,
922
+ timeout: config.timeout ?? 3e5
923
+ // 5 minutes default
924
+ };
925
+ this.processManager = new ProcessManager(
926
+ {
927
+ cliPath: config.cliPath,
928
+ maxProcesses: config.maxProcesses,
929
+ processIdleTimeout: config.processIdleTimeout,
930
+ model: config.model,
931
+ permissionMode: config.permissionMode,
932
+ dangerouslySkipPermissions: config.dangerouslySkipPermissions,
933
+ workingDirectory: config.workingDirectory
934
+ },
935
+ events
936
+ );
937
+ this.sessionManager = new SessionManager(events);
938
+ }
939
+ /**
940
+ * Connect - verify Claude CLI is available
941
+ */
942
+ async connect() {
943
+ if (this.state === "connected") {
944
+ return;
945
+ }
946
+ this.state = "connecting";
947
+ this.events.emit("connection:state", "connecting");
948
+ try {
949
+ await this.verifyCLI();
950
+ this.processManager.startCleanup();
951
+ this.state = "connected";
952
+ this.events.emit("connection:state", "connected");
953
+ this.events.emit("connection:connected");
954
+ } catch (error) {
955
+ this.state = "error";
956
+ this.events.emit("connection:state", "error");
957
+ this.events.emit("connection:error", error);
958
+ throw new ConnectionError("Failed to connect to Claude CLI", void 0, error);
959
+ }
960
+ }
961
+ /**
962
+ * Verify Claude CLI is available
963
+ */
964
+ async verifyCLI() {
965
+ try {
966
+ const { stdout } = await execAsync(`${this.config.cliPath} --version`);
967
+ console.log(`Claude CLI available: ${stdout.trim()}`);
968
+ } catch (error) {
969
+ throw new CLIError(
970
+ `Claude CLI not found at '${this.config.cliPath}'. Ensure Claude CLI is installed and in PATH.`,
971
+ error.code,
972
+ "",
973
+ error.message
974
+ );
975
+ }
976
+ }
977
+ /**
978
+ * Disconnect and cleanup
979
+ */
980
+ disconnect() {
981
+ if (this.state === "disconnected") {
982
+ return;
983
+ }
984
+ this.processManager.killAll();
985
+ this.processManager.stopCleanup();
986
+ this.state = "disconnected";
987
+ this.events.emit("connection:state", "disconnected");
988
+ this.events.emit("connection:disconnected");
989
+ }
990
+ /**
991
+ * Check if connected
992
+ */
993
+ isConnected() {
994
+ return this.state === "connected";
995
+ }
996
+ /**
997
+ * Get connection state
998
+ */
999
+ getConnectionState() {
1000
+ return this.state;
1001
+ }
1002
+ /**
1003
+ * Make an RPC request
1004
+ */
1005
+ async request(method, params = {}) {
1006
+ if (!this.isConnected()) {
1007
+ throw new ConnectionError("Not connected to Claude CLI");
1008
+ }
1009
+ switch (method) {
1010
+ case "chat.send":
1011
+ return this.handleChatSend(params);
1012
+ case "sessions.list":
1013
+ return this.handleSessionsList(params);
1014
+ case "sessions.get":
1015
+ return this.handleSessionsGet(params.sessionKey);
1016
+ case "sessions.delete":
1017
+ return this.handleSessionsDelete(params.sessionKey);
1018
+ case "sessions.history":
1019
+ return this.handleSessionsHistory(params.sessionKey);
1020
+ case "system.health":
1021
+ return this.handleSystemHealth();
1022
+ case "system.status":
1023
+ return this.handleSystemStatus();
1024
+ case "agents.list":
1025
+ return this.handleAgentsList();
1026
+ case "agents.get":
1027
+ return this.handleAgentsGet(params.agentId);
1028
+ default:
1029
+ throw new Error(`Unknown RPC method: ${method}`);
1030
+ }
1031
+ }
1032
+ /**
1033
+ * Handle chat.send request
1034
+ * Uses --output-format=json for single-shot responses
1035
+ */
1036
+ async handleChatSend(options) {
1037
+ const sessionKey = options.sessionKey || `claude-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
1038
+ const agentId = options.agentId || "claude";
1039
+ const timeout = options.timeout || this.config.timeout;
1040
+ const session = this.sessionManager.getOrCreateSession(sessionKey, agentId);
1041
+ this.sessionManager.addMessage(sessionKey, {
1042
+ role: "user",
1043
+ content: options.message,
1044
+ timestamp: Date.now()
1045
+ });
1046
+ const existingProc = this.processManager.get(sessionKey);
1047
+ if (existingProc) {
1048
+ this.processManager.kill(sessionKey);
1049
+ }
1050
+ const proc = await this.processManager.spawn({
1051
+ sessionKey,
1052
+ model: this.config.model,
1053
+ thinking: options.thinking,
1054
+ permissionMode: this.config.permissionMode,
1055
+ workingDirectory: this.config.workingDirectory,
1056
+ timeout,
1057
+ message: options.message,
1058
+ outputFormat: "json"
1059
+ });
1060
+ this.processManager.setStatus(sessionKey, "busy");
1061
+ try {
1062
+ const output = await Promise.race([
1063
+ this.collectStdout(proc.process),
1064
+ this.createTimeoutPromise(timeout)
1065
+ ]);
1066
+ let content = "";
1067
+ let thinking;
1068
+ try {
1069
+ const parsed = JSON.parse(output);
1070
+ content = parsed.result || "";
1071
+ if (parsed.thinking) {
1072
+ thinking = parsed.thinking;
1073
+ }
1074
+ } catch {
1075
+ content = output.trim();
1076
+ }
1077
+ this.sessionManager.addMessage(sessionKey, {
1078
+ role: "assistant",
1079
+ content,
1080
+ thinking,
1081
+ timestamp: Date.now()
1082
+ });
1083
+ this.processManager.setStatus(sessionKey, "idle");
1084
+ this.processManager.touch(sessionKey);
1085
+ return {
1086
+ sessionKey,
1087
+ agentId,
1088
+ response: content,
1089
+ thinking,
1090
+ timestamp: Date.now()
1091
+ };
1092
+ } catch (error) {
1093
+ this.processManager.setStatus(sessionKey, "error");
1094
+ throw error;
1095
+ }
1096
+ }
1097
+ /**
1098
+ * Collect full stdout from a child process as a string.
1099
+ * Also captures stderr — if the process exits with no stdout, throws with stderr.
1100
+ */
1101
+ collectStdout(proc) {
1102
+ return new Promise((resolve, reject) => {
1103
+ const stdoutChunks = [];
1104
+ const stderrChunks = [];
1105
+ proc.stdout?.on("data", (chunk) => stdoutChunks.push(chunk));
1106
+ proc.stderr?.on("data", (chunk) => stderrChunks.push(chunk));
1107
+ proc.stdout?.on("error", reject);
1108
+ proc.on("error", reject);
1109
+ proc.on("close", (code) => {
1110
+ const stdout = Buffer.concat(stdoutChunks).toString("utf-8").trim();
1111
+ const stderr = Buffer.concat(stderrChunks).toString("utf-8").trim();
1112
+ if (stdout) {
1113
+ resolve(stdout);
1114
+ } else if (code !== 0 || stderr) {
1115
+ reject(new Error(`Claude CLI exited with code ${code}${stderr ? `: ${stderr}` : ""}`));
1116
+ } else {
1117
+ resolve("");
1118
+ }
1119
+ });
1120
+ });
1121
+ }
1122
+ /**
1123
+ * Handle sessions.list request
1124
+ */
1125
+ async handleSessionsList(options) {
1126
+ const sessions = this.sessionManager.listSessions(options);
1127
+ return {
1128
+ sessions: sessions.map((s) => ({
1129
+ sessionKey: s.sessionKey,
1130
+ agentId: s.agentId,
1131
+ messageCount: s.messages.length,
1132
+ createdAt: s.createdAt,
1133
+ updatedAt: s.updatedAt
1134
+ })),
1135
+ total: sessions.length
1136
+ };
1137
+ }
1138
+ /**
1139
+ * Handle sessions.get request
1140
+ */
1141
+ async handleSessionsGet(sessionKey) {
1142
+ const session = this.sessionManager.getSession(sessionKey);
1143
+ if (!session) {
1144
+ throw new NotFoundError("Session", sessionKey);
1145
+ }
1146
+ return {
1147
+ sessionKey: session.sessionKey,
1148
+ agentId: session.agentId,
1149
+ messageCount: session.messages.length,
1150
+ createdAt: session.createdAt,
1151
+ updatedAt: session.updatedAt
1152
+ };
1153
+ }
1154
+ /**
1155
+ * Handle sessions.delete request
1156
+ */
1157
+ async handleSessionsDelete(sessionKey) {
1158
+ this.processManager.kill(sessionKey);
1159
+ this.sessionManager.deleteSession(sessionKey);
1160
+ }
1161
+ /**
1162
+ * Handle sessions.history request
1163
+ */
1164
+ async handleSessionsHistory(sessionKey) {
1165
+ const messages = this.sessionManager.getHistory(sessionKey);
1166
+ return { messages };
1167
+ }
1168
+ /**
1169
+ * Handle system.health request
1170
+ */
1171
+ async handleSystemHealth() {
1172
+ try {
1173
+ await this.verifyCLI();
1174
+ return {
1175
+ healthy: true,
1176
+ cliAvailable: true,
1177
+ activeSessions: this.sessionManager.getSessionCount(),
1178
+ activeProcesses: this.processManager.getProcessCount()
1179
+ };
1180
+ } catch {
1181
+ return {
1182
+ healthy: false,
1183
+ cliAvailable: false,
1184
+ activeSessions: this.sessionManager.getSessionCount(),
1185
+ activeProcesses: this.processManager.getProcessCount()
1186
+ };
1187
+ }
1188
+ }
1189
+ /**
1190
+ * Handle system.status request
1191
+ */
1192
+ async handleSystemStatus() {
1193
+ return {
1194
+ state: this.state,
1195
+ activeSessions: this.sessionManager.getSessionCount(),
1196
+ activeProcesses: this.processManager.getProcessCount(),
1197
+ cliPath: this.config.cliPath
1198
+ };
1199
+ }
1200
+ /**
1201
+ * Handle agents.list request (stub)
1202
+ */
1203
+ async handleAgentsList() {
1204
+ return {
1205
+ agents: [
1206
+ {
1207
+ agentId: "claude",
1208
+ status: "available",
1209
+ workspace: this.config.workingDirectory
1210
+ }
1211
+ ],
1212
+ defaultAgentId: "claude"
1213
+ };
1214
+ }
1215
+ /**
1216
+ * Handle agents.get request (stub)
1217
+ */
1218
+ async handleAgentsGet(agentId) {
1219
+ return {
1220
+ agentId,
1221
+ status: "available",
1222
+ workspace: this.config.workingDirectory
1223
+ };
1224
+ }
1225
+ /**
1226
+ * Create timeout promise
1227
+ */
1228
+ createTimeoutPromise(timeout) {
1229
+ return new Promise((_, reject) => {
1230
+ setTimeout(() => {
1231
+ reject(new TimeoutError("Operation timed out", timeout));
1232
+ }, timeout);
1233
+ });
1234
+ }
1235
+ /**
1236
+ * Subscribe to event
1237
+ */
1238
+ on(event, handler) {
1239
+ this.events.on(event, handler);
1240
+ }
1241
+ /**
1242
+ * Unsubscribe from event
1243
+ */
1244
+ off(event, handler) {
1245
+ this.events.off(event, handler);
1246
+ }
1247
+ /**
1248
+ * Emit event
1249
+ */
1250
+ emit(event, ...args) {
1251
+ this.events.emit(event, ...args);
1252
+ }
1253
+ /**
1254
+ * Get process manager (for internal use)
1255
+ */
1256
+ getProcessManager() {
1257
+ return this.processManager;
1258
+ }
1259
+ /**
1260
+ * Get session manager (for internal use)
1261
+ */
1262
+ getSessionManager() {
1263
+ return this.sessionManager;
1264
+ }
1265
+ };
1266
+
1267
+ // ../claude/src/sdk.ts
1268
+ var DEFAULT_CONFIG = {
1269
+ cliPath: "claude",
1270
+ timeout: 3e5,
1271
+ // 5 minutes
1272
+ maxProcesses: 10,
1273
+ processIdleTimeout: 6e5,
1274
+ // 10 minutes
1275
+ model: "claude-sonnet-4-5",
1276
+ permissionMode: "default",
1277
+ dangerouslySkipPermissions: false,
1278
+ workingDirectory: process.cwd(),
1279
+ autoConnect: true
1280
+ };
1281
+ var ClaudeSDK = class _ClaudeSDK {
1282
+ transport;
1283
+ events;
1284
+ // Domain modules
1285
+ system;
1286
+ agents;
1287
+ sessions;
1288
+ chat;
1289
+ constructor(config) {
1290
+ this.events = createEventEmitter();
1291
+ const transportConfig = {
1292
+ cliPath: config.cliPath,
1293
+ timeout: config.timeout,
1294
+ maxProcesses: config.maxProcesses,
1295
+ processIdleTimeout: config.processIdleTimeout,
1296
+ model: config.model,
1297
+ permissionMode: config.permissionMode,
1298
+ dangerouslySkipPermissions: config.dangerouslySkipPermissions,
1299
+ workingDirectory: config.workingDirectory,
1300
+ autoConnect: false
1301
+ // We'll connect manually after initialization
1302
+ };
1303
+ this.transport = new CLITransport(transportConfig, this.events);
1304
+ this.system = new SystemModule(this.transport, this.events);
1305
+ this.agents = new AgentsModule(this.transport, this.events);
1306
+ this.sessions = new SessionsModule(this.transport, this.events);
1307
+ this.chat = new ChatModule(this.transport, this.events);
1308
+ }
1309
+ /**
1310
+ * Create a new ClaudeSDK instance
1311
+ * Auto-connects by default
1312
+ */
1313
+ static async create(config) {
1314
+ const fullConfig = {
1315
+ ...DEFAULT_CONFIG,
1316
+ ...config
1317
+ };
1318
+ const sdk = new _ClaudeSDK(fullConfig);
1319
+ if (fullConfig.autoConnect) {
1320
+ await sdk.connect();
1321
+ }
1322
+ return sdk;
1323
+ }
1324
+ /**
1325
+ * Create a disconnected SDK instance
1326
+ * Must call connect() manually
1327
+ */
1328
+ static createDisconnected(config) {
1329
+ const fullConfig = {
1330
+ ...DEFAULT_CONFIG,
1331
+ ...config,
1332
+ autoConnect: false
1333
+ };
1334
+ return new _ClaudeSDK(fullConfig);
1335
+ }
1336
+ /**
1337
+ * Connect to Claude CLI
1338
+ */
1339
+ async connect() {
1340
+ await this.transport.connect();
1341
+ }
1342
+ /**
1343
+ * Disconnect and cleanup
1344
+ */
1345
+ disconnect() {
1346
+ this.transport.disconnect();
1347
+ }
1348
+ /**
1349
+ * Check if connected
1350
+ */
1351
+ isConnected() {
1352
+ return this.transport.isConnected();
1353
+ }
1354
+ /**
1355
+ * Get connection state
1356
+ */
1357
+ getConnectionState() {
1358
+ return this.transport.getConnectionState();
1359
+ }
1360
+ /**
1361
+ * Subscribe to an event
1362
+ */
1363
+ on(event, handler) {
1364
+ this.events.on(event, handler);
1365
+ return this;
1366
+ }
1367
+ /**
1368
+ * Subscribe to an event once
1369
+ */
1370
+ once(event, handler) {
1371
+ this.events.once(event, handler);
1372
+ return this;
1373
+ }
1374
+ /**
1375
+ * Unsubscribe from an event
1376
+ */
1377
+ off(event, handler) {
1378
+ this.events.off(event, handler);
1379
+ return this;
1380
+ }
1381
+ /**
1382
+ * Remove all listeners for an event
1383
+ */
1384
+ removeAllListeners(event) {
1385
+ this.events.removeAllListeners(event);
1386
+ return this;
1387
+ }
1388
+ /**
1389
+ * Wait for an event (promisified)
1390
+ */
1391
+ waitFor(event, timeout) {
1392
+ return this.events.waitFor(event, timeout);
1393
+ }
1394
+ };
1395
+ export {
1396
+ CLIError,
1397
+ ClaudeError,
1398
+ ClaudeSDK,
1399
+ ConnectionError,
1400
+ NotConnectedError,
1401
+ NotFoundError,
1402
+ NotImplementedError,
1403
+ ProcessError,
1404
+ StreamParseError,
1405
+ TimeoutError,
1406
+ ValidationError
1407
+ };