tg-claude 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +175 -0
- package/bin/cli.js +2 -0
- package/dist/claude/ClaudeProcess.d.ts +77 -0
- package/dist/claude/ClaudeProcess.d.ts.map +1 -0
- package/dist/claude/ClaudeProcess.js +270 -0
- package/dist/claude/ClaudeProcess.js.map +1 -0
- package/dist/claude/EventAdapter.d.ts +44 -0
- package/dist/claude/EventAdapter.d.ts.map +1 -0
- package/dist/claude/EventAdapter.js +129 -0
- package/dist/claude/EventAdapter.js.map +1 -0
- package/dist/claude/index.d.ts +10 -0
- package/dist/claude/index.d.ts.map +1 -0
- package/dist/claude/index.js +9 -0
- package/dist/claude/index.js.map +1 -0
- package/dist/claude/types.d.ts +244 -0
- package/dist/claude/types.d.ts.map +1 -0
- package/dist/claude/types.js +8 -0
- package/dist/claude/types.js.map +1 -0
- package/dist/env.d.ts +21 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +49 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +360 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/AnsiStripper.d.ts +54 -0
- package/dist/parser/AnsiStripper.d.ts.map +1 -0
- package/dist/parser/AnsiStripper.js +115 -0
- package/dist/parser/AnsiStripper.js.map +1 -0
- package/dist/parser/OptionExtractor.d.ts +31 -0
- package/dist/parser/OptionExtractor.d.ts.map +1 -0
- package/dist/parser/OptionExtractor.js +91 -0
- package/dist/parser/OptionExtractor.js.map +1 -0
- package/dist/parser/OutputParser.d.ts +121 -0
- package/dist/parser/OutputParser.d.ts.map +1 -0
- package/dist/parser/OutputParser.js +306 -0
- package/dist/parser/OutputParser.js.map +1 -0
- package/dist/parser/PromptDetector.d.ts +20 -0
- package/dist/parser/PromptDetector.d.ts.map +1 -0
- package/dist/parser/PromptDetector.js +68 -0
- package/dist/parser/PromptDetector.js.map +1 -0
- package/dist/parser/index.d.ts +7 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +5 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/types.d.ts +73 -0
- package/dist/parser/types.d.ts.map +1 -0
- package/dist/parser/types.js +2 -0
- package/dist/parser/types.js.map +1 -0
- package/dist/pty/OutputBuffer.d.ts +39 -0
- package/dist/pty/OutputBuffer.d.ts.map +1 -0
- package/dist/pty/OutputBuffer.js +55 -0
- package/dist/pty/OutputBuffer.js.map +1 -0
- package/dist/pty/PtyProcess.d.ts +47 -0
- package/dist/pty/PtyProcess.d.ts.map +1 -0
- package/dist/pty/PtyProcess.js +94 -0
- package/dist/pty/PtyProcess.js.map +1 -0
- package/dist/pty/PtyService.d.ts +55 -0
- package/dist/pty/PtyService.d.ts.map +1 -0
- package/dist/pty/PtyService.js +115 -0
- package/dist/pty/PtyService.js.map +1 -0
- package/dist/pty/index.d.ts +5 -0
- package/dist/pty/index.d.ts.map +1 -0
- package/dist/pty/index.js +4 -0
- package/dist/pty/index.js.map +1 -0
- package/dist/pty/types.d.ts +36 -0
- package/dist/pty/types.d.ts.map +1 -0
- package/dist/pty/types.js +2 -0
- package/dist/pty/types.js.map +1 -0
- package/dist/router/BoundedQueue.d.ts +57 -0
- package/dist/router/BoundedQueue.d.ts.map +1 -0
- package/dist/router/BoundedQueue.js +86 -0
- package/dist/router/BoundedQueue.js.map +1 -0
- package/dist/router/EventRouter.d.ts +103 -0
- package/dist/router/EventRouter.d.ts.map +1 -0
- package/dist/router/EventRouter.js +169 -0
- package/dist/router/EventRouter.js.map +1 -0
- package/dist/router/index.d.ts +13 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +12 -0
- package/dist/router/index.js.map +1 -0
- package/dist/router/types.d.ts +104 -0
- package/dist/router/types.d.ts.map +1 -0
- package/dist/router/types.js +6 -0
- package/dist/router/types.js.map +1 -0
- package/dist/telegram/TelegramBot.d.ts +151 -0
- package/dist/telegram/TelegramBot.d.ts.map +1 -0
- package/dist/telegram/TelegramBot.js +514 -0
- package/dist/telegram/TelegramBot.js.map +1 -0
- package/dist/telegram/index.d.ts +7 -0
- package/dist/telegram/index.d.ts.map +1 -0
- package/dist/telegram/index.js +6 -0
- package/dist/telegram/index.js.map +1 -0
- package/dist/telegram/types.d.ts +30 -0
- package/dist/telegram/types.d.ts.map +1 -0
- package/dist/telegram/types.js +5 -0
- package/dist/telegram/types.js.map +1 -0
- package/dist/terminal/TerminalInterface.d.ts +61 -0
- package/dist/terminal/TerminalInterface.d.ts.map +1 -0
- package/dist/terminal/TerminalInterface.js +218 -0
- package/dist/terminal/TerminalInterface.js.map +1 -0
- package/dist/terminal/index.d.ts +3 -0
- package/dist/terminal/index.d.ts.map +1 -0
- package/dist/terminal/index.js +2 -0
- package/dist/terminal/index.js.map +1 -0
- package/dist/terminal/types.d.ts +17 -0
- package/dist/terminal/types.d.ts.map +1 -0
- package/dist/terminal/types.js +2 -0
- package/dist/terminal/types.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic bounded queue with configurable overflow behavior.
|
|
3
|
+
* Drops oldest items when capacity exceeded (matches OutputBuffer pattern).
|
|
4
|
+
*/
|
|
5
|
+
export class BoundedQueue {
|
|
6
|
+
items = [];
|
|
7
|
+
maxSize;
|
|
8
|
+
droppedCount = 0;
|
|
9
|
+
/**
|
|
10
|
+
* Create a new BoundedQueue
|
|
11
|
+
* @param maxSize - Maximum number of items the queue can hold (must be >= 1)
|
|
12
|
+
* @throws Error if maxSize is less than 1
|
|
13
|
+
*/
|
|
14
|
+
constructor(maxSize) {
|
|
15
|
+
if (maxSize < 1) {
|
|
16
|
+
throw new Error('maxSize must be at least 1');
|
|
17
|
+
}
|
|
18
|
+
this.maxSize = maxSize;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Add item to queue. If full, drops oldest item.
|
|
22
|
+
* @param item - Item to add to the queue
|
|
23
|
+
* @returns true if item was added without dropping, false if overflow occurred
|
|
24
|
+
*/
|
|
25
|
+
push(item) {
|
|
26
|
+
const overflow = this.items.length >= this.maxSize;
|
|
27
|
+
if (overflow) {
|
|
28
|
+
this.items.shift();
|
|
29
|
+
this.droppedCount++;
|
|
30
|
+
}
|
|
31
|
+
this.items.push(item);
|
|
32
|
+
return !overflow;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Remove and return oldest item, or undefined if empty.
|
|
36
|
+
* @returns The oldest item in the queue, or undefined if queue is empty
|
|
37
|
+
*/
|
|
38
|
+
shift() {
|
|
39
|
+
return this.items.shift();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Peek at oldest item without removing.
|
|
43
|
+
* @returns The oldest item in the queue, or undefined if queue is empty
|
|
44
|
+
*/
|
|
45
|
+
peek() {
|
|
46
|
+
return this.items[0];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Current number of items in queue.
|
|
50
|
+
*/
|
|
51
|
+
get size() {
|
|
52
|
+
return this.items.length;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Whether queue is at capacity.
|
|
56
|
+
*/
|
|
57
|
+
get isFull() {
|
|
58
|
+
return this.items.length >= this.maxSize;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Whether queue is empty.
|
|
62
|
+
*/
|
|
63
|
+
get isEmpty() {
|
|
64
|
+
return this.items.length === 0;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Total items dropped due to overflow since creation.
|
|
68
|
+
*/
|
|
69
|
+
get totalDropped() {
|
|
70
|
+
return this.droppedCount;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Clear all items from queue.
|
|
74
|
+
*/
|
|
75
|
+
clear() {
|
|
76
|
+
this.items = [];
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get all items as array (for debugging).
|
|
80
|
+
* @returns A copy of the internal items array
|
|
81
|
+
*/
|
|
82
|
+
toArray() {
|
|
83
|
+
return [...this.items];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=BoundedQueue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BoundedQueue.js","sourceRoot":"","sources":["../../src/router/BoundedQueue.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,OAAO,YAAY;IACf,KAAK,GAAQ,EAAE,CAAC;IACP,OAAO,CAAS;IACzB,YAAY,GAAG,CAAC,CAAC;IAEzB;;;;OAIG;IACH,YAAY,OAAe;QACzB,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACH,IAAI,CAAC,IAAO;QACV,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC;QACnD,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACnB,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,OAAO,CAAC,QAAQ,CAAC;IACnB,CAAC;IAED;;;OAGG;IACH,KAAK;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC;IAED;;;OAGG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC;IAC3C,CAAC;IAED;;OAEG;IACH,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;IAClB,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { EventRouterEvents, OutboundEvent, InboundEvent } from './types.js';
|
|
2
|
+
export interface EventRouterOptions {
|
|
3
|
+
/** Max outbound events per session (default: 100) */
|
|
4
|
+
outboundQueueSize?: number;
|
|
5
|
+
/** Max inbound events per session (default: 50) */
|
|
6
|
+
inboundQueueSize?: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Central router for bidirectional event flow between PTY/Parser and Telegram layers.
|
|
10
|
+
* Maintains per-session bounded queues for decoupled communication.
|
|
11
|
+
*
|
|
12
|
+
* @emits outbound - When outbound event is published
|
|
13
|
+
* @emits inbound - When inbound event is published
|
|
14
|
+
* @emits sessionCreated - When a new session is registered
|
|
15
|
+
* @emits sessionDestroyed - When a session is unregistered
|
|
16
|
+
* @emits queueOverflow - When a queue drops an event due to size limit
|
|
17
|
+
*/
|
|
18
|
+
export declare class EventRouter {
|
|
19
|
+
private readonly emitter;
|
|
20
|
+
private readonly options;
|
|
21
|
+
private readonly outboundQueues;
|
|
22
|
+
private readonly inboundQueues;
|
|
23
|
+
constructor(options?: EventRouterOptions);
|
|
24
|
+
/**
|
|
25
|
+
* Subscribe to router events.
|
|
26
|
+
*/
|
|
27
|
+
on<K extends keyof EventRouterEvents>(event: K, listener: EventRouterEvents[K]): this;
|
|
28
|
+
/**
|
|
29
|
+
* Subscribe to router events (once).
|
|
30
|
+
*/
|
|
31
|
+
once<K extends keyof EventRouterEvents>(event: K, listener: EventRouterEvents[K]): this;
|
|
32
|
+
/**
|
|
33
|
+
* Unsubscribe from router events.
|
|
34
|
+
*/
|
|
35
|
+
off<K extends keyof EventRouterEvents>(event: K, listener: EventRouterEvents[K]): this;
|
|
36
|
+
/**
|
|
37
|
+
* Remove all listeners for an event.
|
|
38
|
+
*/
|
|
39
|
+
removeAllListeners<K extends keyof EventRouterEvents>(event?: K): this;
|
|
40
|
+
/**
|
|
41
|
+
* Register a new session with dedicated queues.
|
|
42
|
+
* @throws Error if session already registered
|
|
43
|
+
*/
|
|
44
|
+
registerSession(sessionId: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Unregister a session and remove its queues.
|
|
47
|
+
* Safe to call if session doesn't exist.
|
|
48
|
+
*/
|
|
49
|
+
unregisterSession(sessionId: string): void;
|
|
50
|
+
/**
|
|
51
|
+
* Check if a session is registered.
|
|
52
|
+
*/
|
|
53
|
+
hasSession(sessionId: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Get all registered session IDs.
|
|
56
|
+
*/
|
|
57
|
+
getSessions(): string[];
|
|
58
|
+
/**
|
|
59
|
+
* Publish an outbound event (PTY/Parser -> Telegram direction).
|
|
60
|
+
* @returns false if session not found, true otherwise
|
|
61
|
+
*/
|
|
62
|
+
publishOutbound(event: OutboundEvent): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Publish an inbound event (Telegram -> PTY direction).
|
|
65
|
+
* @returns false if session not found, true otherwise
|
|
66
|
+
*/
|
|
67
|
+
publishInbound(event: InboundEvent): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Consume (dequeue) the oldest outbound event for a session.
|
|
70
|
+
* @returns The event or undefined if queue empty or session not found
|
|
71
|
+
*/
|
|
72
|
+
consumeOutbound(sessionId: string): OutboundEvent | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Consume (dequeue) the oldest inbound event for a session.
|
|
75
|
+
* @returns The event or undefined if queue empty or session not found
|
|
76
|
+
*/
|
|
77
|
+
consumeInbound(sessionId: string): InboundEvent | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* Peek at the oldest outbound event without consuming.
|
|
80
|
+
*/
|
|
81
|
+
peekOutbound(sessionId: string): OutboundEvent | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* Peek at the oldest inbound event without consuming.
|
|
84
|
+
*/
|
|
85
|
+
peekInbound(sessionId: string): InboundEvent | undefined;
|
|
86
|
+
/**
|
|
87
|
+
* Get outbound queue size for a session.
|
|
88
|
+
*/
|
|
89
|
+
getOutboundQueueSize(sessionId: string): number;
|
|
90
|
+
/**
|
|
91
|
+
* Get inbound queue size for a session.
|
|
92
|
+
*/
|
|
93
|
+
getInboundQueueSize(sessionId: string): number;
|
|
94
|
+
/**
|
|
95
|
+
* Get total dropped events for outbound queue.
|
|
96
|
+
*/
|
|
97
|
+
getOutboundDropped(sessionId: string): number;
|
|
98
|
+
/**
|
|
99
|
+
* Get total dropped events for inbound queue.
|
|
100
|
+
*/
|
|
101
|
+
getInboundDropped(sessionId: string): number;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=EventRouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventRouter.d.ts","sourceRoot":"","sources":["../../src/router/EventRouter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAGjF,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAWD;;;;;;;;;GASG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;IAC1D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IACvD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAkD;IACjF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAiD;gBAEnE,OAAO,GAAE,kBAAuB;IAQ5C;;OAEG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,IAAI;IAKrF;;OAEG;IACH,IAAI,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,IAAI;IAKvF;;OAEG;IACH,GAAG,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,IAAI;IAKtF;;OAEG;IACH,kBAAkB,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI;IAKtE;;;OAGG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IASxC;;;OAGG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAO1C;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAItC;;OAEG;IACH,WAAW,IAAI,MAAM,EAAE;IAIvB;;;OAGG;IACH,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO;IAY9C;;;OAGG;IACH,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO;IAY5C;;;OAGG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI7D;;;OAGG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAI3D;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI1D;;OAEG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAIxD;;OAEG;IACH,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAI/C;;OAEG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAI9C;;OAEG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAI7C;;OAEG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;CAG7C"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { BoundedQueue } from './BoundedQueue.js';
|
|
3
|
+
/**
|
|
4
|
+
* Central router for bidirectional event flow between PTY/Parser and Telegram layers.
|
|
5
|
+
* Maintains per-session bounded queues for decoupled communication.
|
|
6
|
+
*
|
|
7
|
+
* @emits outbound - When outbound event is published
|
|
8
|
+
* @emits inbound - When inbound event is published
|
|
9
|
+
* @emits sessionCreated - When a new session is registered
|
|
10
|
+
* @emits sessionDestroyed - When a session is unregistered
|
|
11
|
+
* @emits queueOverflow - When a queue drops an event due to size limit
|
|
12
|
+
*/
|
|
13
|
+
export class EventRouter {
|
|
14
|
+
emitter;
|
|
15
|
+
options;
|
|
16
|
+
outboundQueues = new Map();
|
|
17
|
+
inboundQueues = new Map();
|
|
18
|
+
constructor(options = {}) {
|
|
19
|
+
this.emitter = new EventEmitter();
|
|
20
|
+
this.options = {
|
|
21
|
+
outboundQueueSize: options.outboundQueueSize ?? 100,
|
|
22
|
+
inboundQueueSize: options.inboundQueueSize ?? 50,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Subscribe to router events.
|
|
27
|
+
*/
|
|
28
|
+
on(event, listener) {
|
|
29
|
+
this.emitter.on(event, listener);
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Subscribe to router events (once).
|
|
34
|
+
*/
|
|
35
|
+
once(event, listener) {
|
|
36
|
+
this.emitter.once(event, listener);
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Unsubscribe from router events.
|
|
41
|
+
*/
|
|
42
|
+
off(event, listener) {
|
|
43
|
+
this.emitter.off(event, listener);
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Remove all listeners for an event.
|
|
48
|
+
*/
|
|
49
|
+
removeAllListeners(event) {
|
|
50
|
+
this.emitter.removeAllListeners(event);
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Register a new session with dedicated queues.
|
|
55
|
+
* @throws Error if session already registered
|
|
56
|
+
*/
|
|
57
|
+
registerSession(sessionId) {
|
|
58
|
+
if (this.outboundQueues.has(sessionId)) {
|
|
59
|
+
throw new Error(`Session ${sessionId} already registered`);
|
|
60
|
+
}
|
|
61
|
+
this.outboundQueues.set(sessionId, new BoundedQueue(this.options.outboundQueueSize));
|
|
62
|
+
this.inboundQueues.set(sessionId, new BoundedQueue(this.options.inboundQueueSize));
|
|
63
|
+
this.emitter.emit('sessionCreated', sessionId);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Unregister a session and remove its queues.
|
|
67
|
+
* Safe to call if session doesn't exist.
|
|
68
|
+
*/
|
|
69
|
+
unregisterSession(sessionId) {
|
|
70
|
+
if (!this.outboundQueues.has(sessionId))
|
|
71
|
+
return;
|
|
72
|
+
this.outboundQueues.delete(sessionId);
|
|
73
|
+
this.inboundQueues.delete(sessionId);
|
|
74
|
+
this.emitter.emit('sessionDestroyed', sessionId);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Check if a session is registered.
|
|
78
|
+
*/
|
|
79
|
+
hasSession(sessionId) {
|
|
80
|
+
return this.outboundQueues.has(sessionId);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get all registered session IDs.
|
|
84
|
+
*/
|
|
85
|
+
getSessions() {
|
|
86
|
+
return Array.from(this.outboundQueues.keys());
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Publish an outbound event (PTY/Parser -> Telegram direction).
|
|
90
|
+
* @returns false if session not found, true otherwise
|
|
91
|
+
*/
|
|
92
|
+
publishOutbound(event) {
|
|
93
|
+
const queue = this.outboundQueues.get(event.sessionId);
|
|
94
|
+
if (!queue)
|
|
95
|
+
return false;
|
|
96
|
+
const added = queue.push(event);
|
|
97
|
+
if (!added) {
|
|
98
|
+
this.emitter.emit('queueOverflow', event.sessionId, 'outbound');
|
|
99
|
+
}
|
|
100
|
+
this.emitter.emit('outbound', event);
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Publish an inbound event (Telegram -> PTY direction).
|
|
105
|
+
* @returns false if session not found, true otherwise
|
|
106
|
+
*/
|
|
107
|
+
publishInbound(event) {
|
|
108
|
+
const queue = this.inboundQueues.get(event.sessionId);
|
|
109
|
+
if (!queue)
|
|
110
|
+
return false;
|
|
111
|
+
const added = queue.push(event);
|
|
112
|
+
if (!added) {
|
|
113
|
+
this.emitter.emit('queueOverflow', event.sessionId, 'inbound');
|
|
114
|
+
}
|
|
115
|
+
this.emitter.emit('inbound', event);
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Consume (dequeue) the oldest outbound event for a session.
|
|
120
|
+
* @returns The event or undefined if queue empty or session not found
|
|
121
|
+
*/
|
|
122
|
+
consumeOutbound(sessionId) {
|
|
123
|
+
return this.outboundQueues.get(sessionId)?.shift();
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Consume (dequeue) the oldest inbound event for a session.
|
|
127
|
+
* @returns The event or undefined if queue empty or session not found
|
|
128
|
+
*/
|
|
129
|
+
consumeInbound(sessionId) {
|
|
130
|
+
return this.inboundQueues.get(sessionId)?.shift();
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Peek at the oldest outbound event without consuming.
|
|
134
|
+
*/
|
|
135
|
+
peekOutbound(sessionId) {
|
|
136
|
+
return this.outboundQueues.get(sessionId)?.peek();
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Peek at the oldest inbound event without consuming.
|
|
140
|
+
*/
|
|
141
|
+
peekInbound(sessionId) {
|
|
142
|
+
return this.inboundQueues.get(sessionId)?.peek();
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Get outbound queue size for a session.
|
|
146
|
+
*/
|
|
147
|
+
getOutboundQueueSize(sessionId) {
|
|
148
|
+
return this.outboundQueues.get(sessionId)?.size ?? 0;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Get inbound queue size for a session.
|
|
152
|
+
*/
|
|
153
|
+
getInboundQueueSize(sessionId) {
|
|
154
|
+
return this.inboundQueues.get(sessionId)?.size ?? 0;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Get total dropped events for outbound queue.
|
|
158
|
+
*/
|
|
159
|
+
getOutboundDropped(sessionId) {
|
|
160
|
+
return this.outboundQueues.get(sessionId)?.totalDropped ?? 0;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Get total dropped events for inbound queue.
|
|
164
|
+
*/
|
|
165
|
+
getInboundDropped(sessionId) {
|
|
166
|
+
return this.inboundQueues.get(sessionId)?.totalDropped ?? 0;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=EventRouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventRouter.js","sourceRoot":"","sources":["../../src/router/EventRouter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAkBjD;;;;;;;;;GASG;AACH,MAAM,OAAO,WAAW;IACL,OAAO,CAAkC;IACzC,OAAO,CAA+B;IACtC,cAAc,GAAG,IAAI,GAAG,EAAuC,CAAC;IAChE,aAAa,GAAG,IAAI,GAAG,EAAsC,CAAC;IAE/E,YAAY,UAA8B,EAAE;QAC1C,IAAI,CAAC,OAAO,GAAG,IAAI,YAAY,EAAqC,CAAC;QACrE,IAAI,CAAC,OAAO,GAAG;YACb,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,IAAI,GAAG;YACnD,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,IAAI,EAAE;SACjD,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,EAAE,CAAoC,KAAQ,EAAE,QAA8B;QAC5E,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,IAAI,CAAoC,KAAQ,EAAE,QAA8B;QAC9E,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,GAAG,CAAoC,KAAQ,EAAE,QAA8B;QAC7E,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,kBAAkB,CAAoC,KAAS;QAC7D,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,eAAe,CAAC,SAAiB;QAC/B,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CAAC,WAAW,SAAS,qBAAqB,CAAC,CAAC;QAC7D,CAAC;QACD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC;QACrF,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC;QACnF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;IACjD,CAAC;IAED;;;OAGG;IACH,iBAAiB,CAAC,SAAiB;QACjC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,OAAO;QAChD,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACrC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAC,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,SAAiB;QAC1B,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,WAAW;QACT,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;IAED;;;OAGG;IACH,eAAe,CAAC,KAAoB;QAClC,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QAEzB,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QAClE,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,cAAc,CAAC,KAAmB;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACtD,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QAEzB,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACjE,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,eAAe,CAAC,SAAiB;QAC/B,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC;IACrD,CAAC;IAED;;;OAGG;IACH,cAAc,CAAC,SAAiB;QAC9B,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC;IACpD,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,SAAiB;QAC5B,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC;IACpD,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,SAAiB;QAC3B,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,oBAAoB,CAAC,SAAiB;QACpC,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC;IACvD,CAAC;IAED;;OAEG;IACH,mBAAmB,CAAC,SAAiB;QACnC,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC;IACtD,CAAC;IAED;;OAEG;IACH,kBAAkB,CAAC,SAAiB;QAClC,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,YAAY,IAAI,CAAC,CAAC;IAC/D,CAAC;IAED;;OAEG;IACH,iBAAiB,CAAC,SAAiB;QACjC,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,YAAY,IAAI,CAAC,CAAC;IAC9D,CAAC;CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Router module - bidirectional event routing between PTY/Parser and Telegram layers.
|
|
3
|
+
*
|
|
4
|
+
* Exports:
|
|
5
|
+
* - Event types for outbound (PTY->Telegram) and inbound (Telegram->PTY) directions
|
|
6
|
+
* - BoundedQueue utility for memory-safe event buffering
|
|
7
|
+
* - EventRouter class for session-based event routing
|
|
8
|
+
*/
|
|
9
|
+
export * from './types.js';
|
|
10
|
+
export { BoundedQueue } from './BoundedQueue.js';
|
|
11
|
+
export { EventRouter } from './EventRouter.js';
|
|
12
|
+
export type { EventRouterOptions } from './EventRouter.js';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/router/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Router module - bidirectional event routing between PTY/Parser and Telegram layers.
|
|
3
|
+
*
|
|
4
|
+
* Exports:
|
|
5
|
+
* - Event types for outbound (PTY->Telegram) and inbound (Telegram->PTY) directions
|
|
6
|
+
* - BoundedQueue utility for memory-safe event buffering
|
|
7
|
+
* - EventRouter class for session-based event routing
|
|
8
|
+
*/
|
|
9
|
+
export * from './types.js';
|
|
10
|
+
export { BoundedQueue } from './BoundedQueue.js';
|
|
11
|
+
export { EventRouter } from './EventRouter.js';
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/router/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event types for bidirectional routing between PTY/Parser and Telegram layers.
|
|
3
|
+
* Outbound events flow from PTY to Telegram; Inbound events flow from Telegram to PTY.
|
|
4
|
+
*/
|
|
5
|
+
import type { PromptEvent } from '../parser/types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Payload for streaming output chunks
|
|
8
|
+
*/
|
|
9
|
+
export interface OutputPayload {
|
|
10
|
+
/** Cleaned text with ANSI codes stripped */
|
|
11
|
+
text: string;
|
|
12
|
+
/** Original raw output including ANSI codes */
|
|
13
|
+
raw: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Payload for process exit events
|
|
17
|
+
*/
|
|
18
|
+
export interface ExitPayload {
|
|
19
|
+
/** Exit code from the process */
|
|
20
|
+
exitCode: number;
|
|
21
|
+
/** Signal number if terminated by signal */
|
|
22
|
+
signal?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Payload for task completion events
|
|
26
|
+
*/
|
|
27
|
+
export interface CompletionPayload {
|
|
28
|
+
/** Summary of final output */
|
|
29
|
+
summary: string;
|
|
30
|
+
/** Duration from work start to completion (ms) */
|
|
31
|
+
duration?: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Event flowing from PTY/Parser layer to Telegram layer.
|
|
35
|
+
* Discriminated union based on 'type' field.
|
|
36
|
+
*/
|
|
37
|
+
export interface OutboundEvent {
|
|
38
|
+
/** Session identifier for routing */
|
|
39
|
+
sessionId: string;
|
|
40
|
+
/** Event category */
|
|
41
|
+
type: 'prompt' | 'output' | 'exit' | 'completion';
|
|
42
|
+
/** Event payload, discriminated by type */
|
|
43
|
+
payload: PromptEvent | OutputPayload | ExitPayload | CompletionPayload;
|
|
44
|
+
/** Timestamp when event occurred (ms since epoch) */
|
|
45
|
+
timestamp: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Payload for user response to a prompt
|
|
49
|
+
*/
|
|
50
|
+
export interface ResponsePayload {
|
|
51
|
+
/** User's response text */
|
|
52
|
+
text: string;
|
|
53
|
+
/** Index of selected option (if user chose from options) */
|
|
54
|
+
optionIndex?: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Payload for cancellation request
|
|
58
|
+
*/
|
|
59
|
+
export interface CancelPayload {
|
|
60
|
+
/** Optional reason for cancellation */
|
|
61
|
+
reason?: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Payload for terminal resize request
|
|
65
|
+
*/
|
|
66
|
+
export interface ResizePayload {
|
|
67
|
+
/** Number of columns */
|
|
68
|
+
cols: number;
|
|
69
|
+
/** Number of rows */
|
|
70
|
+
rows: number;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Event flowing from Telegram layer to PTY layer.
|
|
74
|
+
* Discriminated union based on 'type' field.
|
|
75
|
+
*/
|
|
76
|
+
export interface InboundEvent {
|
|
77
|
+
/** Session identifier for routing */
|
|
78
|
+
sessionId: string;
|
|
79
|
+
/** Event category */
|
|
80
|
+
type: 'response' | 'cancel' | 'resize';
|
|
81
|
+
/** Event payload, discriminated by type */
|
|
82
|
+
payload: ResponsePayload | CancelPayload | ResizePayload;
|
|
83
|
+
/** Timestamp when event was created (ms since epoch) */
|
|
84
|
+
timestamp: number;
|
|
85
|
+
/** Source interface that generated this event (for echo prevention) */
|
|
86
|
+
source?: 'terminal' | 'telegram';
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Event map for typed EventEmitter.
|
|
90
|
+
* Defines all events the EventRouter can emit.
|
|
91
|
+
*/
|
|
92
|
+
export interface EventRouterEvents {
|
|
93
|
+
/** Emitted when an outbound event is published */
|
|
94
|
+
outbound: (event: OutboundEvent) => void;
|
|
95
|
+
/** Emitted when an inbound event is published */
|
|
96
|
+
inbound: (event: InboundEvent) => void;
|
|
97
|
+
/** Emitted when a new session is registered */
|
|
98
|
+
sessionCreated: (sessionId: string) => void;
|
|
99
|
+
/** Emitted when a session is unregistered */
|
|
100
|
+
sessionDestroyed: (sessionId: string) => void;
|
|
101
|
+
/** Emitted when a queue overflows (drops oldest) */
|
|
102
|
+
queueOverflow: (sessionId: string, direction: 'inbound' | 'outbound') => void;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/router/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAMtD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB;IACrB,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,YAAY,CAAC;IAClD,2CAA2C;IAC3C,OAAO,EAAE,WAAW,GAAG,aAAa,GAAG,WAAW,GAAG,iBAAiB,CAAC;IACvE,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB;IACrB,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACvC,2CAA2C;IAC3C,OAAO,EAAE,eAAe,GAAG,aAAa,GAAG,aAAa,CAAC;IACzD,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,MAAM,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;CAClC;AAMD;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACzC,iDAAiD;IACjD,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACvC,+CAA+C;IAC/C,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,6CAA6C;IAC7C,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,oDAAoD;IACpD,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,UAAU,KAAK,IAAI,CAAC;CAC/E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/router/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TelegramBot class wrapping grammY Bot with composition pattern.
|
|
3
|
+
* Implements AUTH-01 whitelist authentication for single-user access.
|
|
4
|
+
*/
|
|
5
|
+
import type { NotificationPayload } from './types.js';
|
|
6
|
+
import type { TelegramConfig } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Handler for inline button callback responses.
|
|
9
|
+
* @param sessionId - The session that receives the response
|
|
10
|
+
* @param optionIndex - The selected option index (1-based)
|
|
11
|
+
*/
|
|
12
|
+
export type CallbackHandler = (sessionId: string, optionIndex: number) => void;
|
|
13
|
+
/**
|
|
14
|
+
* Handler for freeform text message responses.
|
|
15
|
+
* @param sessionId - The session that receives the response
|
|
16
|
+
* @param text - The user's text input
|
|
17
|
+
*/
|
|
18
|
+
export type TextMessageHandler = (sessionId: string, text: string) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Options for TelegramBot initialization.
|
|
21
|
+
* Extends TelegramConfig to allow future options.
|
|
22
|
+
*/
|
|
23
|
+
export interface TelegramBotOptions extends TelegramConfig {
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* TelegramBot wraps grammY Bot with composition pattern.
|
|
27
|
+
* Provides single-user authentication and graceful lifecycle management.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const bot = new TelegramBot({
|
|
32
|
+
* token: process.env.TELEGRAM_BOT_TOKEN,
|
|
33
|
+
* allowedUserId: Number(process.env.TELEGRAM_USER_ID),
|
|
34
|
+
* });
|
|
35
|
+
* await bot.start();
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare class TelegramBot {
|
|
39
|
+
private readonly bot;
|
|
40
|
+
private readonly allowedUserId;
|
|
41
|
+
private started;
|
|
42
|
+
private readonly sessionChatMap;
|
|
43
|
+
onCallback: CallbackHandler | null;
|
|
44
|
+
onTextMessage: TextMessageHandler | null;
|
|
45
|
+
private awaitingSession;
|
|
46
|
+
private readonly multiSelectState;
|
|
47
|
+
constructor(options: TelegramBotOptions);
|
|
48
|
+
/**
|
|
49
|
+
* Set up bot middleware and command handlers.
|
|
50
|
+
*/
|
|
51
|
+
private setupMiddleware;
|
|
52
|
+
/**
|
|
53
|
+
* Set up error handler for Telegram API and network errors.
|
|
54
|
+
*/
|
|
55
|
+
private setupErrorHandler;
|
|
56
|
+
/**
|
|
57
|
+
* Handle single-select button click (existing behavior, refactored)
|
|
58
|
+
*/
|
|
59
|
+
private handleSingleSelect;
|
|
60
|
+
/**
|
|
61
|
+
* Handle multi-select toggle button click
|
|
62
|
+
*/
|
|
63
|
+
private handleToggle;
|
|
64
|
+
/**
|
|
65
|
+
* Handle multi-select submit button click
|
|
66
|
+
*/
|
|
67
|
+
private handleSubmit;
|
|
68
|
+
/**
|
|
69
|
+
* Build multi-select keyboard with checkmarks for selected options
|
|
70
|
+
*/
|
|
71
|
+
private buildMultiSelectKeyboard;
|
|
72
|
+
/**
|
|
73
|
+
* Start the bot with long polling.
|
|
74
|
+
* Safe to call multiple times (idempotent).
|
|
75
|
+
*/
|
|
76
|
+
start(): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Stop the bot gracefully.
|
|
79
|
+
* Safe to call multiple times (idempotent).
|
|
80
|
+
*/
|
|
81
|
+
stop(): void;
|
|
82
|
+
/**
|
|
83
|
+
* Check if the bot is currently running.
|
|
84
|
+
*/
|
|
85
|
+
get isStarted(): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Get the chat ID for the single whitelisted user.
|
|
88
|
+
* For private chats, chat_id equals user_id.
|
|
89
|
+
*/
|
|
90
|
+
get chatId(): number;
|
|
91
|
+
/**
|
|
92
|
+
* Expose bot.api for proactive messaging.
|
|
93
|
+
* Used by higher layers to send notifications.
|
|
94
|
+
*/
|
|
95
|
+
get api(): import("grammy").Api<import("grammy").RawApi>;
|
|
96
|
+
/**
|
|
97
|
+
* Register a session for notifications.
|
|
98
|
+
* Maps session to the whitelisted user's chat.
|
|
99
|
+
*/
|
|
100
|
+
registerSession(sessionId: string): void;
|
|
101
|
+
/**
|
|
102
|
+
* Unregister a session.
|
|
103
|
+
*/
|
|
104
|
+
unregisterSession(sessionId: string): void;
|
|
105
|
+
/**
|
|
106
|
+
* Check if a session is registered.
|
|
107
|
+
*/
|
|
108
|
+
hasSession(sessionId: string): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Send a prompt notification to Telegram with inline keyboard.
|
|
111
|
+
* @param payload - The notification payload with question and options
|
|
112
|
+
* @returns Message ID if sent, undefined if session not registered
|
|
113
|
+
*/
|
|
114
|
+
sendNotification(payload: NotificationPayload): Promise<number | undefined>;
|
|
115
|
+
/**
|
|
116
|
+
* Truncate button text for Telegram inline keyboards.
|
|
117
|
+
* Extracts label (before " - ") and truncates to max length.
|
|
118
|
+
* Telegram buttons have ~40-50 char visible width.
|
|
119
|
+
*/
|
|
120
|
+
private truncateButtonText;
|
|
121
|
+
/**
|
|
122
|
+
* Escape HTML special characters for Telegram HTML parse mode.
|
|
123
|
+
*/
|
|
124
|
+
private escapeHtml;
|
|
125
|
+
/**
|
|
126
|
+
* Send a completion notification to Telegram.
|
|
127
|
+
* Handles long messages by splitting into multiple messages.
|
|
128
|
+
* @param payload - The completion payload with summary
|
|
129
|
+
* @returns Message ID of last message if sent, undefined if session not registered
|
|
130
|
+
*/
|
|
131
|
+
sendCompletionNotification(payload: {
|
|
132
|
+
sessionId: string;
|
|
133
|
+
summary: string;
|
|
134
|
+
duration?: number;
|
|
135
|
+
}): Promise<number | undefined>;
|
|
136
|
+
/**
|
|
137
|
+
* Split a long message into chunks at natural break points.
|
|
138
|
+
*/
|
|
139
|
+
private splitMessage;
|
|
140
|
+
/**
|
|
141
|
+
* Mark a session as awaiting user input.
|
|
142
|
+
* Called when a prompt notification is sent.
|
|
143
|
+
*/
|
|
144
|
+
setAwaitingInput(sessionId: string): void;
|
|
145
|
+
/**
|
|
146
|
+
* Clear the awaiting input state.
|
|
147
|
+
* Called when response is received or session ends.
|
|
148
|
+
*/
|
|
149
|
+
clearAwaitingInput(): void;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=TelegramBot.d.ts.map
|