@herdctl/chat 0.0.1 → 0.2.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/LICENSE +21 -0
- package/dist/__tests__/dm-filter.test.d.ts +5 -0
- package/dist/__tests__/dm-filter.test.d.ts.map +1 -0
- package/dist/__tests__/dm-filter.test.js +136 -0
- package/dist/__tests__/dm-filter.test.js.map +1 -0
- package/dist/__tests__/error-handler.test.d.ts +5 -0
- package/dist/__tests__/error-handler.test.d.ts.map +1 -0
- package/dist/__tests__/error-handler.test.js +235 -0
- package/dist/__tests__/error-handler.test.js.map +1 -0
- package/dist/__tests__/errors.test.d.ts +5 -0
- package/dist/__tests__/errors.test.d.ts.map +1 -0
- package/dist/__tests__/errors.test.js +140 -0
- package/dist/__tests__/errors.test.js.map +1 -0
- package/dist/__tests__/index.test.d.ts +2 -0
- package/dist/__tests__/index.test.d.ts.map +1 -0
- package/dist/__tests__/index.test.js +25 -0
- package/dist/__tests__/index.test.js.map +1 -0
- package/dist/__tests__/message-extraction.test.d.ts +5 -0
- package/dist/__tests__/message-extraction.test.d.ts.map +1 -0
- package/dist/__tests__/message-extraction.test.js +157 -0
- package/dist/__tests__/message-extraction.test.js.map +1 -0
- package/dist/__tests__/message-splitting.test.d.ts +5 -0
- package/dist/__tests__/message-splitting.test.d.ts.map +1 -0
- package/dist/__tests__/message-splitting.test.js +153 -0
- package/dist/__tests__/message-splitting.test.js.map +1 -0
- package/dist/__tests__/session-manager.test.d.ts +2 -0
- package/dist/__tests__/session-manager.test.d.ts.map +1 -0
- package/dist/__tests__/session-manager.test.js +779 -0
- package/dist/__tests__/session-manager.test.js.map +1 -0
- package/dist/__tests__/status-formatting.test.d.ts +5 -0
- package/dist/__tests__/status-formatting.test.d.ts.map +1 -0
- package/dist/__tests__/status-formatting.test.js +160 -0
- package/dist/__tests__/status-formatting.test.js.map +1 -0
- package/dist/__tests__/streaming-responder.test.d.ts +5 -0
- package/dist/__tests__/streaming-responder.test.d.ts.map +1 -0
- package/dist/__tests__/streaming-responder.test.js +154 -0
- package/dist/__tests__/streaming-responder.test.js.map +1 -0
- package/dist/dm-filter.d.ts +121 -0
- package/dist/dm-filter.d.ts.map +1 -0
- package/dist/dm-filter.js +162 -0
- package/dist/dm-filter.js.map +1 -0
- package/dist/error-handler.d.ts +217 -0
- package/dist/error-handler.d.ts.map +1 -0
- package/dist/error-handler.js +313 -0
- package/dist/error-handler.js.map +1 -0
- package/dist/errors.d.ts +118 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +157 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/message-extraction.d.ts +81 -0
- package/dist/message-extraction.d.ts.map +1 -0
- package/dist/message-extraction.js +90 -0
- package/dist/message-extraction.js.map +1 -0
- package/dist/message-splitting.d.ts +133 -0
- package/dist/message-splitting.d.ts.map +1 -0
- package/dist/message-splitting.js +188 -0
- package/dist/message-splitting.js.map +1 -0
- package/dist/session-manager/errors.d.ts +59 -0
- package/dist/session-manager/errors.d.ts.map +1 -0
- package/dist/session-manager/errors.js +71 -0
- package/dist/session-manager/errors.js.map +1 -0
- package/dist/session-manager/index.d.ts +10 -0
- package/dist/session-manager/index.d.ts.map +1 -0
- package/dist/session-manager/index.js +14 -0
- package/dist/session-manager/index.js.map +1 -0
- package/dist/session-manager/session-manager.d.ts +123 -0
- package/dist/session-manager/session-manager.d.ts.map +1 -0
- package/dist/session-manager/session-manager.js +394 -0
- package/dist/session-manager/session-manager.js.map +1 -0
- package/dist/session-manager/types.d.ts +205 -0
- package/dist/session-manager/types.d.ts.map +1 -0
- package/dist/session-manager/types.js +67 -0
- package/dist/session-manager/types.js.map +1 -0
- package/dist/status-formatting.d.ts +147 -0
- package/dist/status-formatting.d.ts.map +1 -0
- package/dist/status-formatting.js +234 -0
- package/dist/status-formatting.js.map +1 -0
- package/dist/streaming-responder.d.ts +130 -0
- package/dist/streaming-responder.d.ts.map +1 -0
- package/dist/streaming-responder.js +178 -0
- package/dist/streaming-responder.js.map +1 -0
- package/dist/types.d.ts +184 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +39 -4
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message splitting utilities for chat platforms
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for:
|
|
5
|
+
* - Splitting long messages to fit platform character limits
|
|
6
|
+
* - Maintaining message coherence when splitting (avoiding mid-sentence breaks)
|
|
7
|
+
* - Preserving code blocks when splitting
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Default delay between sending split messages (in milliseconds)
|
|
11
|
+
*/
|
|
12
|
+
export declare const DEFAULT_MESSAGE_DELAY_MS = 500;
|
|
13
|
+
/**
|
|
14
|
+
* Minimum chunk size when splitting messages
|
|
15
|
+
* Prevents creating very small message fragments
|
|
16
|
+
*/
|
|
17
|
+
export declare const MIN_CHUNK_SIZE = 100;
|
|
18
|
+
/**
|
|
19
|
+
* Options for splitting messages
|
|
20
|
+
*/
|
|
21
|
+
export interface MessageSplitOptions {
|
|
22
|
+
/**
|
|
23
|
+
* Maximum length for each message chunk
|
|
24
|
+
* Required - no default since it varies by platform
|
|
25
|
+
*/
|
|
26
|
+
maxLength: number;
|
|
27
|
+
/**
|
|
28
|
+
* Whether to try to split at natural boundaries like sentences (default: true)
|
|
29
|
+
*/
|
|
30
|
+
preserveBoundaries?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Characters to use as split points, in order of preference
|
|
33
|
+
* Default: ['\n\n', '\n', '. ', '! ', '? ', ', ', ' ']
|
|
34
|
+
*/
|
|
35
|
+
splitPoints?: string[];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Result from splitting a message
|
|
39
|
+
*/
|
|
40
|
+
export interface SplitResult {
|
|
41
|
+
/** Array of message chunks */
|
|
42
|
+
chunks: string[];
|
|
43
|
+
/** Whether the message was split */
|
|
44
|
+
wasSplit: boolean;
|
|
45
|
+
/** Original message length */
|
|
46
|
+
originalLength: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Default split points in order of preference
|
|
50
|
+
*
|
|
51
|
+
* We prefer to split at paragraph breaks, then sentences, then clauses, then words
|
|
52
|
+
*/
|
|
53
|
+
export declare const DEFAULT_SPLIT_POINTS: string[];
|
|
54
|
+
/**
|
|
55
|
+
* Find the best split point within a text chunk
|
|
56
|
+
*
|
|
57
|
+
* @param text - Text to find split point in
|
|
58
|
+
* @param maxLength - Maximum length for the chunk
|
|
59
|
+
* @param splitPoints - Split points to search for, in order of preference
|
|
60
|
+
* @returns Index to split at, or maxLength if no good split point found
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const splitIndex = findSplitPoint(longText, 2000);
|
|
65
|
+
* const firstPart = longText.slice(0, splitIndex);
|
|
66
|
+
* const secondPart = longText.slice(splitIndex);
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare function findSplitPoint(text: string, maxLength: number, splitPoints?: string[]): number;
|
|
70
|
+
/**
|
|
71
|
+
* Split a message into chunks that fit within the specified max length
|
|
72
|
+
*
|
|
73
|
+
* @param content - Message content to split
|
|
74
|
+
* @param options - Split options including maxLength
|
|
75
|
+
* @returns Split result with chunks array
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* const result = splitMessage(longText, { maxLength: 2000 });
|
|
80
|
+
* for (const chunk of result.chunks) {
|
|
81
|
+
* await channel.send(chunk);
|
|
82
|
+
* }
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export declare function splitMessage(content: string, options: MessageSplitOptions): SplitResult;
|
|
86
|
+
/**
|
|
87
|
+
* Check if a message needs to be split
|
|
88
|
+
*
|
|
89
|
+
* @param content - Message content to check
|
|
90
|
+
* @param maxLength - Maximum message length
|
|
91
|
+
* @returns true if the message exceeds the max length
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* if (needsSplit(message, 2000)) {
|
|
96
|
+
* const { chunks } = splitMessage(message, { maxLength: 2000 });
|
|
97
|
+
* // Send each chunk
|
|
98
|
+
* } else {
|
|
99
|
+
* // Send as-is
|
|
100
|
+
* }
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export declare function needsSplit(content: string, maxLength: number): boolean;
|
|
104
|
+
/**
|
|
105
|
+
* Truncate a message to fit within the max length, adding an ellipsis
|
|
106
|
+
*
|
|
107
|
+
* @param content - Message content to truncate
|
|
108
|
+
* @param maxLength - Maximum length
|
|
109
|
+
* @param ellipsis - Ellipsis to append (default: '...')
|
|
110
|
+
* @returns Truncated message
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* const short = truncateMessage(longText, 100);
|
|
115
|
+
* // Returns: "This is a very long text that has been trun..."
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
export declare function truncateMessage(content: string, maxLength: number, ellipsis?: string): string;
|
|
119
|
+
/**
|
|
120
|
+
* Format code as a code block with optional language
|
|
121
|
+
*
|
|
122
|
+
* @param code - Code to format
|
|
123
|
+
* @param language - Optional language for syntax highlighting
|
|
124
|
+
* @returns Formatted code block
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* const formatted = formatCodeBlock('const x = 1;', 'typescript');
|
|
129
|
+
* // Returns: "```typescript\nconst x = 1;\n```"
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export declare function formatCodeBlock(code: string, language?: string): string;
|
|
133
|
+
//# sourceMappingURL=message-splitting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-splitting.d.ts","sourceRoot":"","sources":["../src/message-splitting.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;GAEG;AACH,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAE5C;;;GAGG;AACH,eAAO,MAAM,cAAc,MAAM,CAAC;AAMlC;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,8BAA8B;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;IAEjB,oCAAoC;IACpC,QAAQ,EAAE,OAAO,CAAC;IAElB,8BAA8B;IAC9B,cAAc,EAAE,MAAM,CAAC;CACxB;AAMD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,UAA8C,CAAC;AAMhF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,WAAW,GAAE,MAAM,EAAyB,GAC3C,MAAM,CA4BR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,mBAAmB,GAC3B,WAAW,CAoDb;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAEtE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,GAAE,MAAc,GACvB,MAAM,CAOR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAGvE"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message splitting utilities for chat platforms
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for:
|
|
5
|
+
* - Splitting long messages to fit platform character limits
|
|
6
|
+
* - Maintaining message coherence when splitting (avoiding mid-sentence breaks)
|
|
7
|
+
* - Preserving code blocks when splitting
|
|
8
|
+
*/
|
|
9
|
+
// =============================================================================
|
|
10
|
+
// Constants
|
|
11
|
+
// =============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Default delay between sending split messages (in milliseconds)
|
|
14
|
+
*/
|
|
15
|
+
export const DEFAULT_MESSAGE_DELAY_MS = 500;
|
|
16
|
+
/**
|
|
17
|
+
* Minimum chunk size when splitting messages
|
|
18
|
+
* Prevents creating very small message fragments
|
|
19
|
+
*/
|
|
20
|
+
export const MIN_CHUNK_SIZE = 100;
|
|
21
|
+
// =============================================================================
|
|
22
|
+
// Default Split Points
|
|
23
|
+
// =============================================================================
|
|
24
|
+
/**
|
|
25
|
+
* Default split points in order of preference
|
|
26
|
+
*
|
|
27
|
+
* We prefer to split at paragraph breaks, then sentences, then clauses, then words
|
|
28
|
+
*/
|
|
29
|
+
export const DEFAULT_SPLIT_POINTS = ["\n\n", "\n", ". ", "! ", "? ", ", ", " "];
|
|
30
|
+
// =============================================================================
|
|
31
|
+
// Message Splitting Functions
|
|
32
|
+
// =============================================================================
|
|
33
|
+
/**
|
|
34
|
+
* Find the best split point within a text chunk
|
|
35
|
+
*
|
|
36
|
+
* @param text - Text to find split point in
|
|
37
|
+
* @param maxLength - Maximum length for the chunk
|
|
38
|
+
* @param splitPoints - Split points to search for, in order of preference
|
|
39
|
+
* @returns Index to split at, or maxLength if no good split point found
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const splitIndex = findSplitPoint(longText, 2000);
|
|
44
|
+
* const firstPart = longText.slice(0, splitIndex);
|
|
45
|
+
* const secondPart = longText.slice(splitIndex);
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export function findSplitPoint(text, maxLength, splitPoints = DEFAULT_SPLIT_POINTS) {
|
|
49
|
+
// If text fits, no split needed
|
|
50
|
+
if (text.length <= maxLength) {
|
|
51
|
+
return text.length;
|
|
52
|
+
}
|
|
53
|
+
// Try each split point in order of preference
|
|
54
|
+
for (const splitPoint of splitPoints) {
|
|
55
|
+
// Search backwards from maxLength to find the last occurrence of this split point
|
|
56
|
+
const searchText = text.slice(0, maxLength);
|
|
57
|
+
const lastIndex = searchText.lastIndexOf(splitPoint);
|
|
58
|
+
// If found and results in a reasonable chunk size
|
|
59
|
+
if (lastIndex > MIN_CHUNK_SIZE) {
|
|
60
|
+
// Include the split point in the first chunk (e.g., keep the period with the sentence)
|
|
61
|
+
return lastIndex + splitPoint.length;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// No good split point found - fall back to hard split at maxLength
|
|
65
|
+
// But try to avoid splitting in the middle of a word
|
|
66
|
+
const hardSplitIndex = text.lastIndexOf(" ", maxLength);
|
|
67
|
+
if (hardSplitIndex > MIN_CHUNK_SIZE) {
|
|
68
|
+
return hardSplitIndex + 1; // Include the space in the first chunk
|
|
69
|
+
}
|
|
70
|
+
// Last resort: hard split at maxLength
|
|
71
|
+
return maxLength;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Split a message into chunks that fit within the specified max length
|
|
75
|
+
*
|
|
76
|
+
* @param content - Message content to split
|
|
77
|
+
* @param options - Split options including maxLength
|
|
78
|
+
* @returns Split result with chunks array
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const result = splitMessage(longText, { maxLength: 2000 });
|
|
83
|
+
* for (const chunk of result.chunks) {
|
|
84
|
+
* await channel.send(chunk);
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export function splitMessage(content, options) {
|
|
89
|
+
const { maxLength, preserveBoundaries = true, splitPoints = DEFAULT_SPLIT_POINTS, } = options;
|
|
90
|
+
const originalLength = content.length;
|
|
91
|
+
// If content fits in one message, return as-is
|
|
92
|
+
if (content.length <= maxLength) {
|
|
93
|
+
return {
|
|
94
|
+
chunks: [content],
|
|
95
|
+
wasSplit: false,
|
|
96
|
+
originalLength,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const chunks = [];
|
|
100
|
+
let remaining = content;
|
|
101
|
+
while (remaining.length > 0) {
|
|
102
|
+
if (remaining.length <= maxLength) {
|
|
103
|
+
// Remaining text fits in one message
|
|
104
|
+
chunks.push(remaining.trim());
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
// Find the best split point
|
|
108
|
+
let splitIndex;
|
|
109
|
+
if (preserveBoundaries) {
|
|
110
|
+
splitIndex = findSplitPoint(remaining, maxLength, splitPoints);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
// Simple split at maxLength
|
|
114
|
+
splitIndex = maxLength;
|
|
115
|
+
}
|
|
116
|
+
// Extract the chunk and trim
|
|
117
|
+
const chunk = remaining.slice(0, splitIndex).trim();
|
|
118
|
+
if (chunk.length > 0) {
|
|
119
|
+
chunks.push(chunk);
|
|
120
|
+
}
|
|
121
|
+
// Update remaining text
|
|
122
|
+
remaining = remaining.slice(splitIndex).trim();
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
chunks,
|
|
126
|
+
wasSplit: chunks.length > 1,
|
|
127
|
+
originalLength,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Check if a message needs to be split
|
|
132
|
+
*
|
|
133
|
+
* @param content - Message content to check
|
|
134
|
+
* @param maxLength - Maximum message length
|
|
135
|
+
* @returns true if the message exceeds the max length
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```typescript
|
|
139
|
+
* if (needsSplit(message, 2000)) {
|
|
140
|
+
* const { chunks } = splitMessage(message, { maxLength: 2000 });
|
|
141
|
+
* // Send each chunk
|
|
142
|
+
* } else {
|
|
143
|
+
* // Send as-is
|
|
144
|
+
* }
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
export function needsSplit(content, maxLength) {
|
|
148
|
+
return content.length > maxLength;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Truncate a message to fit within the max length, adding an ellipsis
|
|
152
|
+
*
|
|
153
|
+
* @param content - Message content to truncate
|
|
154
|
+
* @param maxLength - Maximum length
|
|
155
|
+
* @param ellipsis - Ellipsis to append (default: '...')
|
|
156
|
+
* @returns Truncated message
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```typescript
|
|
160
|
+
* const short = truncateMessage(longText, 100);
|
|
161
|
+
* // Returns: "This is a very long text that has been trun..."
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
export function truncateMessage(content, maxLength, ellipsis = "...") {
|
|
165
|
+
if (content.length <= maxLength) {
|
|
166
|
+
return content;
|
|
167
|
+
}
|
|
168
|
+
const truncatedLength = maxLength - ellipsis.length;
|
|
169
|
+
return content.slice(0, truncatedLength) + ellipsis;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Format code as a code block with optional language
|
|
173
|
+
*
|
|
174
|
+
* @param code - Code to format
|
|
175
|
+
* @param language - Optional language for syntax highlighting
|
|
176
|
+
* @returns Formatted code block
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```typescript
|
|
180
|
+
* const formatted = formatCodeBlock('const x = 1;', 'typescript');
|
|
181
|
+
* // Returns: "```typescript\nconst x = 1;\n```"
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
export function formatCodeBlock(code, language) {
|
|
185
|
+
const langTag = language ?? "";
|
|
186
|
+
return `\`\`\`${langTag}\n${code}\n\`\`\``;
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=message-splitting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-splitting.js","sourceRoot":"","sources":["../src/message-splitting.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error classes for chat session management
|
|
3
|
+
*
|
|
4
|
+
* Provides typed errors for session persistence and retrieval failures.
|
|
5
|
+
* These error classes are shared between Discord, Slack, and other chat platforms.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Error codes for session manager operations
|
|
9
|
+
*/
|
|
10
|
+
export declare enum SessionErrorCode {
|
|
11
|
+
STATE_READ_FAILED = "SESSION_STATE_READ_FAILED",
|
|
12
|
+
STATE_WRITE_FAILED = "SESSION_STATE_WRITE_FAILED",
|
|
13
|
+
DIRECTORY_CREATE_FAILED = "SESSION_DIRECTORY_CREATE_FAILED",
|
|
14
|
+
SESSION_NOT_FOUND = "SESSION_NOT_FOUND",
|
|
15
|
+
SESSION_EXPIRED = "SESSION_EXPIRED",
|
|
16
|
+
INVALID_STATE = "SESSION_INVALID_STATE"
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Base error class for session manager operations
|
|
20
|
+
*/
|
|
21
|
+
export declare class SessionManagerError extends Error {
|
|
22
|
+
readonly code: SessionErrorCode;
|
|
23
|
+
readonly agentName: string;
|
|
24
|
+
constructor(message: string, code: SessionErrorCode, agentName: string, options?: {
|
|
25
|
+
cause?: Error;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Error thrown when session state file cannot be read
|
|
30
|
+
*/
|
|
31
|
+
export declare class SessionStateReadError extends SessionManagerError {
|
|
32
|
+
readonly path: string;
|
|
33
|
+
constructor(agentName: string, path: string, options?: {
|
|
34
|
+
cause?: Error;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Error thrown when session state file cannot be written
|
|
39
|
+
*/
|
|
40
|
+
export declare class SessionStateWriteError extends SessionManagerError {
|
|
41
|
+
readonly path: string;
|
|
42
|
+
constructor(agentName: string, path: string, options?: {
|
|
43
|
+
cause?: Error;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Error thrown when session directory cannot be created
|
|
48
|
+
*/
|
|
49
|
+
export declare class SessionDirectoryCreateError extends SessionManagerError {
|
|
50
|
+
readonly path: string;
|
|
51
|
+
constructor(agentName: string, path: string, options?: {
|
|
52
|
+
cause?: Error;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Type guard to check if an error is a SessionManagerError
|
|
57
|
+
*/
|
|
58
|
+
export declare function isSessionManagerError(error: unknown): error is SessionManagerError;
|
|
59
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/session-manager/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,oBAAY,gBAAgB;IAC1B,iBAAiB,8BAA8B;IAC/C,kBAAkB,+BAA+B;IACjD,uBAAuB,oCAAoC;IAC3D,iBAAiB,sBAAsB;IACvC,eAAe,oBAAoB;IACnC,aAAa,0BAA0B;CACxC;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,SAAgB,IAAI,EAAE,gBAAgB,CAAC;IACvC,SAAgB,SAAS,EAAE,MAAM,CAAC;gBAGhC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,gBAAgB,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,KAAK,CAAA;KAAE;CAO9B;AAED;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,mBAAmB;IAC5D,SAAgB,IAAI,EAAE,MAAM,CAAC;gBAG3B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,KAAK,CAAA;KAAE;CAW9B;AAED;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,mBAAmB;IAC7D,SAAgB,IAAI,EAAE,MAAM,CAAC;gBAG3B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,KAAK,CAAA;KAAE;CAW9B;AAED;;GAEG;AACH,qBAAa,2BAA4B,SAAQ,mBAAmB;IAClE,SAAgB,IAAI,EAAE,MAAM,CAAC;gBAG3B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,KAAK,CAAA;KAAE;CAW9B;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,mBAAmB,CAE9B"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error classes for chat session management
|
|
3
|
+
*
|
|
4
|
+
* Provides typed errors for session persistence and retrieval failures.
|
|
5
|
+
* These error classes are shared between Discord, Slack, and other chat platforms.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Error codes for session manager operations
|
|
9
|
+
*/
|
|
10
|
+
export var SessionErrorCode;
|
|
11
|
+
(function (SessionErrorCode) {
|
|
12
|
+
SessionErrorCode["STATE_READ_FAILED"] = "SESSION_STATE_READ_FAILED";
|
|
13
|
+
SessionErrorCode["STATE_WRITE_FAILED"] = "SESSION_STATE_WRITE_FAILED";
|
|
14
|
+
SessionErrorCode["DIRECTORY_CREATE_FAILED"] = "SESSION_DIRECTORY_CREATE_FAILED";
|
|
15
|
+
SessionErrorCode["SESSION_NOT_FOUND"] = "SESSION_NOT_FOUND";
|
|
16
|
+
SessionErrorCode["SESSION_EXPIRED"] = "SESSION_EXPIRED";
|
|
17
|
+
SessionErrorCode["INVALID_STATE"] = "SESSION_INVALID_STATE";
|
|
18
|
+
})(SessionErrorCode || (SessionErrorCode = {}));
|
|
19
|
+
/**
|
|
20
|
+
* Base error class for session manager operations
|
|
21
|
+
*/
|
|
22
|
+
export class SessionManagerError extends Error {
|
|
23
|
+
code;
|
|
24
|
+
agentName;
|
|
25
|
+
constructor(message, code, agentName, options) {
|
|
26
|
+
super(message, options);
|
|
27
|
+
this.name = "SessionManagerError";
|
|
28
|
+
this.code = code;
|
|
29
|
+
this.agentName = agentName;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Error thrown when session state file cannot be read
|
|
34
|
+
*/
|
|
35
|
+
export class SessionStateReadError extends SessionManagerError {
|
|
36
|
+
path;
|
|
37
|
+
constructor(agentName, path, options) {
|
|
38
|
+
super(`Failed to read session state for agent '${agentName}' from '${path}'`, SessionErrorCode.STATE_READ_FAILED, agentName, options);
|
|
39
|
+
this.name = "SessionStateReadError";
|
|
40
|
+
this.path = path;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Error thrown when session state file cannot be written
|
|
45
|
+
*/
|
|
46
|
+
export class SessionStateWriteError extends SessionManagerError {
|
|
47
|
+
path;
|
|
48
|
+
constructor(agentName, path, options) {
|
|
49
|
+
super(`Failed to write session state for agent '${agentName}' to '${path}'`, SessionErrorCode.STATE_WRITE_FAILED, agentName, options);
|
|
50
|
+
this.name = "SessionStateWriteError";
|
|
51
|
+
this.path = path;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Error thrown when session directory cannot be created
|
|
56
|
+
*/
|
|
57
|
+
export class SessionDirectoryCreateError extends SessionManagerError {
|
|
58
|
+
path;
|
|
59
|
+
constructor(agentName, path, options) {
|
|
60
|
+
super(`Failed to create session directory for agent '${agentName}' at '${path}'`, SessionErrorCode.DIRECTORY_CREATE_FAILED, agentName, options);
|
|
61
|
+
this.name = "SessionDirectoryCreateError";
|
|
62
|
+
this.path = path;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Type guard to check if an error is a SessionManagerError
|
|
67
|
+
*/
|
|
68
|
+
export function isSessionManagerError(error) {
|
|
69
|
+
return error instanceof SessionManagerError;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/session-manager/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,CAAN,IAAY,gBAOX;AAPD,WAAY,gBAAgB;IAC1B,mEAA+C,CAAA;IAC/C,qEAAiD,CAAA;IACjD,+EAA2D,CAAA;IAC3D,2DAAuC,CAAA;IACvC,uDAAmC,CAAA;IACnC,2DAAuC,CAAA;AACzC,CAAC,EAPW,gBAAgB,KAAhB,gBAAgB,QAO3B;AAED;;GAEG;AACH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5B,IAAI,CAAmB;IACvB,SAAS,CAAS;IAElC,YACE,OAAe,EACf,IAAsB,EACtB,SAAiB,EACjB,OAA2B;QAE3B,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,qBAAsB,SAAQ,mBAAmB;IAC5C,IAAI,CAAS;IAE7B,YACE,SAAiB,EACjB,IAAY,EACZ,OAA2B;QAE3B,KAAK,CACH,2CAA2C,SAAS,WAAW,IAAI,GAAG,EACtE,gBAAgB,CAAC,iBAAiB,EAClC,SAAS,EACT,OAAO,CACR,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACpC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,sBAAuB,SAAQ,mBAAmB;IAC7C,IAAI,CAAS;IAE7B,YACE,SAAiB,EACjB,IAAY,EACZ,OAA2B;QAE3B,KAAK,CACH,4CAA4C,SAAS,SAAS,IAAI,GAAG,EACrE,gBAAgB,CAAC,kBAAkB,EACnC,SAAS,EACT,OAAO,CACR,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;QACrC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,2BAA4B,SAAQ,mBAAmB;IAClD,IAAI,CAAS;IAE7B,YACE,SAAiB,EACjB,IAAY,EACZ,OAA2B;QAE3B,KAAK,CACH,iDAAiD,SAAS,SAAS,IAAI,GAAG,EAC1E,gBAAgB,CAAC,uBAAuB,EACxC,SAAS,EACT,OAAO,CACR,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,6BAA6B,CAAC;QAC1C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CACnC,KAAc;IAEd,OAAO,KAAK,YAAY,mBAAmB,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session manager module for chat platforms
|
|
3
|
+
*
|
|
4
|
+
* Provides per-channel session management for Claude conversations.
|
|
5
|
+
* This module is shared between Discord, Slack, and other chat platforms.
|
|
6
|
+
*/
|
|
7
|
+
export { ChatSessionManager } from "./session-manager.js";
|
|
8
|
+
export { ChannelSessionSchema, ChatSessionStateSchema, type ChannelSession, type ChatSessionState, type SessionManagerLogger, type ChatSessionManagerOptions, type SessionResult, type IChatSessionManager, createInitialSessionState, createChannelSession, } from "./types.js";
|
|
9
|
+
export { SessionErrorCode, SessionManagerError, SessionStateReadError, SessionStateWriteError, SessionDirectoryCreateError, isSessionManagerError, } from "./errors.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session-manager/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,EAEL,oBAAoB,EACpB,sBAAsB,EAEtB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,aAAa,EAClB,KAAK,mBAAmB,EAExB,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACtB,2BAA2B,EAC3B,qBAAqB,GACtB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session manager module for chat platforms
|
|
3
|
+
*
|
|
4
|
+
* Provides per-channel session management for Claude conversations.
|
|
5
|
+
* This module is shared between Discord, Slack, and other chat platforms.
|
|
6
|
+
*/
|
|
7
|
+
export { ChatSessionManager } from "./session-manager.js";
|
|
8
|
+
export {
|
|
9
|
+
// Schemas
|
|
10
|
+
ChannelSessionSchema, ChatSessionStateSchema,
|
|
11
|
+
// Factory functions
|
|
12
|
+
createInitialSessionState, createChannelSession, } from "./types.js";
|
|
13
|
+
export { SessionErrorCode, SessionManagerError, SessionStateReadError, SessionStateWriteError, SessionDirectoryCreateError, isSessionManagerError, } from "./errors.js";
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/session-manager/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO;AACL,UAAU;AACV,oBAAoB,EACpB,sBAAsB;AAQtB,oBAAoB;AACpB,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACtB,2BAA2B,EAC3B,qBAAqB,GACtB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session manager for chat channel conversations
|
|
3
|
+
*
|
|
4
|
+
* Provides per-channel session management for Claude conversations,
|
|
5
|
+
* enabling conversation context preservation across chat channels.
|
|
6
|
+
*
|
|
7
|
+
* This implementation is shared between Discord, Slack, and other chat platforms.
|
|
8
|
+
* Sessions are stored at .herdctl/<platform>-sessions/<agent-name>.yaml
|
|
9
|
+
*/
|
|
10
|
+
import { type ChatSessionManagerOptions, type IChatSessionManager, type SessionResult, type ChannelSession } from "./types.js";
|
|
11
|
+
/**
|
|
12
|
+
* ChatSessionManager manages per-channel Claude sessions for a chat agent.
|
|
13
|
+
*
|
|
14
|
+
* Each agent has its own ChatSessionManager instance, storing session mappings
|
|
15
|
+
* in a YAML file at .herdctl/<platform>-sessions/<agent-name>.yaml
|
|
16
|
+
*
|
|
17
|
+
* Features:
|
|
18
|
+
* - Create new sessions for channels/DMs
|
|
19
|
+
* - Resume existing sessions when user sends messages
|
|
20
|
+
* - Automatic session expiry based on configurable timeout
|
|
21
|
+
* - Cleanup expired sessions on startup
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const sessionManager = new ChatSessionManager({
|
|
26
|
+
* platform: 'discord',
|
|
27
|
+
* agentName: 'my-agent',
|
|
28
|
+
* stateDir: '.herdctl',
|
|
29
|
+
* sessionExpiryHours: 24,
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Get or create a session for a channel
|
|
33
|
+
* const { sessionId, isNew } = await sessionManager.getOrCreateSession('channel-123');
|
|
34
|
+
*
|
|
35
|
+
* // After sending/receiving a message
|
|
36
|
+
* await sessionManager.touchSession('channel-123');
|
|
37
|
+
*
|
|
38
|
+
* // Cleanup expired sessions on startup
|
|
39
|
+
* const cleanedUp = await sessionManager.cleanupExpiredSessions();
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare class ChatSessionManager implements IChatSessionManager {
|
|
43
|
+
readonly agentName: string;
|
|
44
|
+
readonly platform: string;
|
|
45
|
+
private readonly stateDir;
|
|
46
|
+
private readonly sessionExpiryHours;
|
|
47
|
+
private readonly logger;
|
|
48
|
+
private readonly stateFilePath;
|
|
49
|
+
private state;
|
|
50
|
+
constructor(options: ChatSessionManagerOptions);
|
|
51
|
+
/**
|
|
52
|
+
* Get or create a session for a channel/DM
|
|
53
|
+
*
|
|
54
|
+
* If an active (non-expired) session exists, returns it.
|
|
55
|
+
* Otherwise, creates a new session with a generated session ID.
|
|
56
|
+
*/
|
|
57
|
+
getOrCreateSession(channelId: string): Promise<SessionResult>;
|
|
58
|
+
/**
|
|
59
|
+
* Update the last message timestamp for a session
|
|
60
|
+
*/
|
|
61
|
+
touchSession(channelId: string): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Get an existing session without creating one
|
|
64
|
+
*
|
|
65
|
+
* Returns null if no session exists or if the session is expired.
|
|
66
|
+
*/
|
|
67
|
+
getSession(channelId: string): Promise<ChannelSession | null>;
|
|
68
|
+
/**
|
|
69
|
+
* Store or update the session ID for a channel
|
|
70
|
+
*
|
|
71
|
+
* Called after a job completes to store the SDK-provided session ID.
|
|
72
|
+
*/
|
|
73
|
+
setSession(channelId: string, sessionId: string): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Clear a specific session
|
|
76
|
+
*/
|
|
77
|
+
clearSession(channelId: string): Promise<boolean>;
|
|
78
|
+
/**
|
|
79
|
+
* Clean up all expired sessions
|
|
80
|
+
*
|
|
81
|
+
* Should be called on connector startup and periodically.
|
|
82
|
+
*/
|
|
83
|
+
cleanupExpiredSessions(): Promise<number>;
|
|
84
|
+
/**
|
|
85
|
+
* Get the count of active (non-expired) sessions
|
|
86
|
+
*
|
|
87
|
+
* Useful for logging during shutdown to confirm sessions are preserved.
|
|
88
|
+
*/
|
|
89
|
+
getActiveSessionCount(): Promise<number>;
|
|
90
|
+
/**
|
|
91
|
+
* Generate a unique session ID
|
|
92
|
+
* Format: <platform>-<agentName>-<uuid>
|
|
93
|
+
*/
|
|
94
|
+
private generateSessionId;
|
|
95
|
+
/**
|
|
96
|
+
* Check if a session is expired
|
|
97
|
+
*/
|
|
98
|
+
private isSessionExpired;
|
|
99
|
+
/**
|
|
100
|
+
* Load session state from disk
|
|
101
|
+
*
|
|
102
|
+
* Returns cached state if available, otherwise loads from file.
|
|
103
|
+
* Creates initial state if file doesn't exist.
|
|
104
|
+
*/
|
|
105
|
+
private loadState;
|
|
106
|
+
/**
|
|
107
|
+
* Save session state to disk atomically
|
|
108
|
+
*/
|
|
109
|
+
private saveState;
|
|
110
|
+
/**
|
|
111
|
+
* Ensure the sessions directory exists
|
|
112
|
+
*/
|
|
113
|
+
private ensureDirectoryExists;
|
|
114
|
+
/**
|
|
115
|
+
* Generate a temp file path for atomic writes
|
|
116
|
+
*/
|
|
117
|
+
private generateTempPath;
|
|
118
|
+
/**
|
|
119
|
+
* Rename with retry logic for Windows compatibility
|
|
120
|
+
*/
|
|
121
|
+
private renameWithRetry;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=session-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/session-manager/session-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,OAAO,EACL,KAAK,yBAAyB,EAE9B,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,cAAc,EAIpB,MAAM,YAAY,CAAC;AAsBpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,kBAAmB,YAAW,mBAAmB;IAC5D,SAAgB,SAAS,EAAE,MAAM,CAAC;IAClC,SAAgB,QAAQ,EAAE,MAAM,CAAC;IAEjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IAGvC,OAAO,CAAC,KAAK,CAAiC;gBAElC,OAAO,EAAE,yBAAyB;IAoB9C;;;;;OAKG;IACG,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAkCnE;;OAEG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBpD;;;;OAIG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAsBnE;;;;OAIG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBrE;;OAEG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAevD;;;;OAIG;IACG,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC;IA0B/C;;;;OAIG;IACG,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC;IAkB9C;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAOxB;;;;;OAKG;YACW,SAAS;IAuDvB;;OAEG;YACW,SAAS;IA4BvB;;OAEG;YACW,qBAAqB;IAenC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAOxB;;OAEG;YACW,eAAe;CA+B9B"}
|