@moxxy/cli 0.0.8 → 0.0.10

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