@saccolabs/tars 1.0.7
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 +93 -0
- package/context/GEMINI.md +13 -0
- package/context/config/settings.json-template +36 -0
- package/context/skills/create-extension/SKILL.md +90 -0
- package/context/skills/create-skill/SKILL.md +33 -0
- package/context/skills/manage-extensions/SKILL.md +69 -0
- package/context/skills/tars-ops/SKILL.md +89 -0
- package/dist/cli/commands/discord.d.ts +4 -0
- package/dist/cli/commands/discord.js +48 -0
- package/dist/cli/commands/discord.js.map +1 -0
- package/dist/cli/commands/export.d.ts +3 -0
- package/dist/cli/commands/export.js +39 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/import.d.ts +1 -0
- package/dist/cli/commands/import.js +45 -0
- package/dist/cli/commands/import.js.map +1 -0
- package/dist/cli/commands/logs.d.ts +4 -0
- package/dist/cli/commands/logs.js +23 -0
- package/dist/cli/commands/logs.js.map +1 -0
- package/dist/cli/commands/memory.d.ts +1 -0
- package/dist/cli/commands/memory.js +35 -0
- package/dist/cli/commands/memory.js.map +1 -0
- package/dist/cli/commands/secret.d.ts +6 -0
- package/dist/cli/commands/secret.js +46 -0
- package/dist/cli/commands/secret.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +4 -0
- package/dist/cli/commands/setup.js +329 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/commands/start.d.ts +1 -0
- package/dist/cli/commands/start.js +42 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/status.d.ts +1 -0
- package/dist/cli/commands/status.js +56 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/stop.d.ts +1 -0
- package/dist/cli/commands/stop.js +38 -0
- package/dist/cli/commands/stop.js.map +1 -0
- package/dist/cli/commands/uninstall.d.ts +1 -0
- package/dist/cli/commands/uninstall.js +91 -0
- package/dist/cli/commands/uninstall.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +54 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config/config.d.ts +14 -0
- package/dist/config/config.js +69 -0
- package/dist/config/config.js.map +1 -0
- package/dist/discord/discord-bot.d.ts +32 -0
- package/dist/discord/discord-bot.js +151 -0
- package/dist/discord/discord-bot.js.map +1 -0
- package/dist/discord/message-formatter.d.ts +95 -0
- package/dist/discord/message-formatter.js +448 -0
- package/dist/discord/message-formatter.js.map +1 -0
- package/dist/memory/knowledge-store.d.ts +24 -0
- package/dist/memory/knowledge-store.js +126 -0
- package/dist/memory/knowledge-store.js.map +1 -0
- package/dist/memory/memory-manager.d.ts +24 -0
- package/dist/memory/memory-manager.js +101 -0
- package/dist/memory/memory-manager.js.map +1 -0
- package/dist/scripts/debug-cli.d.ts +1 -0
- package/dist/scripts/debug-cli.js +52 -0
- package/dist/scripts/debug-cli.js.map +1 -0
- package/dist/supervisor/gemini-cli.d.ts +28 -0
- package/dist/supervisor/gemini-cli.js +315 -0
- package/dist/supervisor/gemini-cli.js.map +1 -0
- package/dist/supervisor/heartbeat-service.d.ts +21 -0
- package/dist/supervisor/heartbeat-service.js +143 -0
- package/dist/supervisor/heartbeat-service.js.map +1 -0
- package/dist/supervisor/main.d.ts +1 -0
- package/dist/supervisor/main.js +242 -0
- package/dist/supervisor/main.js.map +1 -0
- package/dist/supervisor/session-manager.d.ts +47 -0
- package/dist/supervisor/session-manager.js +118 -0
- package/dist/supervisor/session-manager.js.map +1 -0
- package/dist/supervisor/supervisor.d.ts +32 -0
- package/dist/supervisor/supervisor.js +98 -0
- package/dist/supervisor/supervisor.js.map +1 -0
- package/dist/types/index.d.ts +42 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/attachment-processor.d.ts +22 -0
- package/dist/utils/attachment-processor.js +79 -0
- package/dist/utils/attachment-processor.js.map +1 -0
- package/dist/utils/logger.d.ts +6 -0
- package/dist/utils/logger.js +15 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/secrets-manager.d.ts +27 -0
- package/dist/utils/secrets-manager.js +79 -0
- package/dist/utils/secrets-manager.js.map +1 -0
- package/dist/utils/version.d.ts +3 -0
- package/dist/utils/version.js +23 -0
- package/dist/utils/version.js.map +1 -0
- package/extensions/tasks/gemini-extension.json +14 -0
- package/extensions/tasks/package-lock.json +1209 -0
- package/extensions/tasks/package.json +19 -0
- package/extensions/tasks/src/server.ts +265 -0
- package/extensions/tasks/src/store.ts +92 -0
- package/extensions/tasks/tsconfig.json +14 -0
- package/package.json +55 -0
- package/src/prompts/system.md +25 -0
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discord Message Formatter
|
|
3
|
+
*
|
|
4
|
+
* Transforms Gemini CLI output (GitHub Flavored Markdown)
|
|
5
|
+
* into Discord-compatible formatting.
|
|
6
|
+
*
|
|
7
|
+
* Discord supports:
|
|
8
|
+
* - Bold: **text**
|
|
9
|
+
* - Italic: *text* or _text_
|
|
10
|
+
* - Underline: __text__
|
|
11
|
+
* - Strikethrough: ~~text~~
|
|
12
|
+
* - Code inline: `text`
|
|
13
|
+
* - Code block: ```lang\ncode\n```
|
|
14
|
+
* - Blockquotes: > text
|
|
15
|
+
* - Headers: # (only #, ##, ###)
|
|
16
|
+
*
|
|
17
|
+
* Discord does NOT support:
|
|
18
|
+
* - Markdown tables (we instruct the LLM to avoid these)
|
|
19
|
+
* - #### or deeper headers
|
|
20
|
+
* - Small text (-#)
|
|
21
|
+
*/
|
|
22
|
+
export class MessageFormatter {
|
|
23
|
+
static MAX_MESSAGE_LENGTH = 1990;
|
|
24
|
+
/**
|
|
25
|
+
* Format text for Discord
|
|
26
|
+
*/
|
|
27
|
+
static format(text) {
|
|
28
|
+
if (!text)
|
|
29
|
+
return text;
|
|
30
|
+
let formatted = text;
|
|
31
|
+
// Step 1: Fix broken asterisks FIRST (creates patterns that need spacing)
|
|
32
|
+
formatted = this.fixAsterisks(formatted);
|
|
33
|
+
// Step 2: CRITICAL - Fix spacing issues (LLM often merges words)
|
|
34
|
+
formatted = this.fixSpacing(formatted);
|
|
35
|
+
// Step 3: Normalize bullets (* item -> • item)
|
|
36
|
+
formatted = this.normalizeBullets(formatted);
|
|
37
|
+
// Step 4: Normalize headers (#### -> ### or bold)
|
|
38
|
+
formatted = this.normalizeHeaders(formatted);
|
|
39
|
+
// Step 5: Fix blockquotes (ensure they render properly)
|
|
40
|
+
formatted = this.fixBlockquotes(formatted);
|
|
41
|
+
// Step 6: Format JSON blocks in code blocks
|
|
42
|
+
formatted = this.formatJsonBlocks(formatted);
|
|
43
|
+
// Step 7: Strip any remaining tables (fallback if LLM still generates them)
|
|
44
|
+
formatted = this.stripTables(formatted);
|
|
45
|
+
// Step 8: Fix small text markers (-#) that Discord doesn't support
|
|
46
|
+
formatted = this.fixSmallText(formatted);
|
|
47
|
+
// Step 9: Clean up excessive whitespace
|
|
48
|
+
formatted = formatted.replace(/\n{3,}/g, '\n\n');
|
|
49
|
+
return formatted.trim();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Fix critical spacing issues from LLM output
|
|
53
|
+
* These are the most common formatting bugs that break Discord rendering
|
|
54
|
+
*/
|
|
55
|
+
static fixSpacing(text) {
|
|
56
|
+
let result = text;
|
|
57
|
+
// 1. Ensure space AFTER closing bold before next word
|
|
58
|
+
result = result.replace(/\*\*([^*]+)\*\*(?=[a-zA-Z0-9])/g, '**$1** ');
|
|
59
|
+
// 2. Ensure space BEFORE opening bold after a word
|
|
60
|
+
result = result.replace(/([a-zA-Z0-9])\*\*([^*]+)\*\*/g, '$1 **$2**');
|
|
61
|
+
// 3. Ensure space after colon before bold
|
|
62
|
+
result = result.replace(/([^*]):\*\*/g, '$1: **');
|
|
63
|
+
// 4. Ensure space around middle dots
|
|
64
|
+
result = result.replace(/([a-zA-Z0-9])·([a-zA-Z0-9])/g, '$1 · $2');
|
|
65
|
+
// 5. Ensure DOUBLE NEWLINE before section emojis
|
|
66
|
+
// This ensures headers like "📊 Signal Check" always start on a new paragraph
|
|
67
|
+
// REMOVED: ✅, ❌, ⚠️, 💡, 🛡️ (often used in lists/inline)
|
|
68
|
+
// KEPT: 🔍, 📊, 🧠, 📈, ⚖️, 🎯, 📋, 🔄, 📅 (Major section headers)
|
|
69
|
+
const sectionEmojis = '🔍|📊|🧠|📈|⚖️|🎯|📋|🔄|📅';
|
|
70
|
+
// Look for [not newline][spaces?][likely emoji] -> replace with [char]\n\n[emoji]
|
|
71
|
+
result = result.replace(new RegExp(`([^\\n])\\s*(${sectionEmojis})`, 'g'), '$1\n\n$2');
|
|
72
|
+
// 6. Ensure space after emojis before bold
|
|
73
|
+
result = result.replace(new RegExp(`(${sectionEmojis})\\*\\*`, 'g'), '$1 **');
|
|
74
|
+
// 7. Fix "set for**time**" pattern
|
|
75
|
+
result = result.replace(/for\*\*/g, 'for **');
|
|
76
|
+
// 8. Fix bullet points that run together
|
|
77
|
+
// "• Item1• Item2" -> "• Item1\n• Item2"
|
|
78
|
+
// Also ensure bullets appearing in middle of text get a newline
|
|
79
|
+
result = result.replace(/([^\n])\s*• /g, '$1\n• ');
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Fix broken asterisks patterns
|
|
84
|
+
* Only fixes obviously broken patterns, avoids aggressive matching
|
|
85
|
+
*/
|
|
86
|
+
static fixAsterisks(text) {
|
|
87
|
+
let result = text;
|
|
88
|
+
// Fix 4+ asterisks down to 2 (****text**** -> **text**)
|
|
89
|
+
result = result.replace(/\*{4,}(.+?)\*{4,}/g, '**$1**');
|
|
90
|
+
// Fix trailing-only ** at end of line (text** -> **text**)
|
|
91
|
+
// Only applies when line starts with a letter/number (no leading **)
|
|
92
|
+
// AND has exactly trailing ** (indicative of broken bold)
|
|
93
|
+
result = result.replace(/^([^*\n][^*]*)(\*\*)$/gm, (match, content, trail) => {
|
|
94
|
+
// Check if content already has opening ** - skip if so
|
|
95
|
+
if (content.includes('**'))
|
|
96
|
+
return match;
|
|
97
|
+
return `**${content.trim()}**`;
|
|
98
|
+
});
|
|
99
|
+
// Fix: Close unclosed bold tags at start of line (**Text -> **Text**)
|
|
100
|
+
result = result.replace(/^(\*\*[^*]+?)(?<!\*\*)(\s*[:.,!?-]?)$/gm, (match, content, punct) => {
|
|
101
|
+
// If already closed, don't touch
|
|
102
|
+
if (content.trim().endsWith('**'))
|
|
103
|
+
return match;
|
|
104
|
+
return `${content.trim()}${punct}**`;
|
|
105
|
+
});
|
|
106
|
+
// Also handle cases specifically ending with punctuation on the line
|
|
107
|
+
result = result.replace(/^(\*\*[^*]+)(?=\s*([:.,!?-]))/gm, (match, content, punct) => {
|
|
108
|
+
if (match.endsWith('**'))
|
|
109
|
+
return match;
|
|
110
|
+
// Regex lookahead logic is tricky here, simplifiying:
|
|
111
|
+
// The previous regex fixes the EOL case.
|
|
112
|
+
// This regex handles mid-line punctuation if we want to support it?
|
|
113
|
+
// Actually, the previous regex handles `punctuation at the end of the line OR content`.
|
|
114
|
+
// If we have `**Header: content`, the first regex won't catch it unless it matches newline?
|
|
115
|
+
// Let's rely on the first regex which is robust for EOL.
|
|
116
|
+
// For mid-line, if there's no closing `**`, it's hard to guess where it ends.
|
|
117
|
+
// So we'll skip this second aggressive block to avoid regressions.
|
|
118
|
+
return match;
|
|
119
|
+
});
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Normalize bullet points for Discord
|
|
124
|
+
*/
|
|
125
|
+
static normalizeBullets(text) {
|
|
126
|
+
return (text
|
|
127
|
+
// Convert "* item" to "• item" (but not inside code blocks)
|
|
128
|
+
.replace(/^(\s*)\* /gm, '$1• ')
|
|
129
|
+
// Convert "- item" that's not a separator line or subtext
|
|
130
|
+
.replace(/^(\s*)- (?![-#]+)/gm, '$1• '));
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Normalize markdown headers to Discord-friendly format
|
|
134
|
+
* Discord supports #, ##, ### natively now.
|
|
135
|
+
*/
|
|
136
|
+
static normalizeHeaders(text) {
|
|
137
|
+
return (text
|
|
138
|
+
// Ensure space after hashes
|
|
139
|
+
.replace(/^(#{1,3})(?=[^#\s])/gm, '$1 ')
|
|
140
|
+
// Convert #### and deeper to bold
|
|
141
|
+
.replace(/^#{4,}\s+(.+)$/gm, '**$1**'));
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Fix blockquote formatting
|
|
145
|
+
*/
|
|
146
|
+
static fixBlockquotes(text) {
|
|
147
|
+
const lines = text.split('\n');
|
|
148
|
+
const result = [];
|
|
149
|
+
let inBlockquote = false;
|
|
150
|
+
for (const line of lines) {
|
|
151
|
+
if (line.startsWith('> ')) {
|
|
152
|
+
inBlockquote = true;
|
|
153
|
+
result.push(line);
|
|
154
|
+
}
|
|
155
|
+
else if (line.startsWith('>') && line.length === 1) {
|
|
156
|
+
// Empty blockquote line - skip it
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
else if (inBlockquote && line.trim() === '') {
|
|
160
|
+
inBlockquote = false;
|
|
161
|
+
result.push(line);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
inBlockquote = false;
|
|
165
|
+
result.push(line);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return result.join('\n');
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Detect and wrap JSON-like content in code blocks
|
|
172
|
+
*/
|
|
173
|
+
static formatJsonBlocks(text) {
|
|
174
|
+
if (text.includes('```json') || text.includes('```\n{')) {
|
|
175
|
+
return text;
|
|
176
|
+
}
|
|
177
|
+
const jsonPattern = /(?:^|\n)([\[{][\s\S]*?[\]}])(?=\n|$)/g;
|
|
178
|
+
return text.replace(jsonPattern, (match, json) => {
|
|
179
|
+
try {
|
|
180
|
+
const trimmed = json.trim();
|
|
181
|
+
if ((trimmed.startsWith('{') || trimmed.startsWith('[')) && trimmed.length > 20) {
|
|
182
|
+
const parsed = JSON.parse(trimmed);
|
|
183
|
+
const pretty = JSON.stringify(parsed, null, 2);
|
|
184
|
+
return '\n```json\n' + pretty + '\n```';
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// Not valid JSON
|
|
189
|
+
}
|
|
190
|
+
return match;
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Strip markdown tables - they don't render well on mobile Discord
|
|
195
|
+
* This is a fallback; the LLM should be instructed not to generate tables
|
|
196
|
+
*/
|
|
197
|
+
static stripTables(text) {
|
|
198
|
+
// Detect table patterns and convert to simple list
|
|
199
|
+
const lines = text.split('\n');
|
|
200
|
+
const result = [];
|
|
201
|
+
let inTable = false;
|
|
202
|
+
let tableRows = [];
|
|
203
|
+
for (const line of lines) {
|
|
204
|
+
// Check if this is a table separator line (|---|---|)
|
|
205
|
+
if (line.match(/^\|?\s*[-:]+[-:\s|]*\|?\s*$/)) {
|
|
206
|
+
inTable = true;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
// Check if this is a table row
|
|
210
|
+
if (line.includes('|') && (line.startsWith('|') || line.match(/\w+\s*\|/))) {
|
|
211
|
+
inTable = true;
|
|
212
|
+
const cells = line
|
|
213
|
+
.split('|')
|
|
214
|
+
.map((c) => c.trim())
|
|
215
|
+
.filter((c) => c.length > 0);
|
|
216
|
+
if (cells.length > 0) {
|
|
217
|
+
tableRows.push(cells);
|
|
218
|
+
}
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
// End of table - convert to list
|
|
222
|
+
if (inTable && tableRows.length > 0) {
|
|
223
|
+
// First row is usually header
|
|
224
|
+
const header = tableRows[0];
|
|
225
|
+
const dataRows = tableRows.slice(1);
|
|
226
|
+
for (const row of dataRows) {
|
|
227
|
+
const parts = [];
|
|
228
|
+
for (let i = 0; i < row.length && i < header.length; i++) {
|
|
229
|
+
if (i === 0) {
|
|
230
|
+
parts.push(`**${row[i]}**`);
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
parts.push(row[i]);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
result.push(`• ${parts.join(' · ')}`);
|
|
237
|
+
}
|
|
238
|
+
tableRows = [];
|
|
239
|
+
inTable = false;
|
|
240
|
+
}
|
|
241
|
+
result.push(line);
|
|
242
|
+
}
|
|
243
|
+
// Handle any remaining table at end of text
|
|
244
|
+
if (tableRows.length > 0) {
|
|
245
|
+
const header = tableRows[0];
|
|
246
|
+
const dataRows = tableRows.slice(1);
|
|
247
|
+
for (const row of dataRows) {
|
|
248
|
+
const parts = [];
|
|
249
|
+
for (let i = 0; i < row.length && i < header.length; i++) {
|
|
250
|
+
if (i === 0) {
|
|
251
|
+
parts.push(`**${row[i]}**`);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
parts.push(row[i]);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
result.push(`• ${parts.join(' · ')}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return result.join('\n');
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Fix small text markers (-#) that Discord doesn't support
|
|
264
|
+
*/
|
|
265
|
+
static fixSmallText(text) {
|
|
266
|
+
// Convert -# prefix to regular text or remove it
|
|
267
|
+
return text.replace(/^-#\s*/gm, '');
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Split long messages into Discord-safe chunks intelligently
|
|
271
|
+
* Respects semantic boundaries: headers, code blocks, paragraphs
|
|
272
|
+
*/
|
|
273
|
+
static split(text, maxLength = this.MAX_MESSAGE_LENGTH) {
|
|
274
|
+
if (text.length <= maxLength)
|
|
275
|
+
return [text];
|
|
276
|
+
const chunks = [];
|
|
277
|
+
let remaining = text;
|
|
278
|
+
while (remaining.length > 0) {
|
|
279
|
+
if (remaining.length <= maxLength) {
|
|
280
|
+
chunks.push(remaining);
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
// Find the best semantic split point
|
|
284
|
+
const splitIndex = this.findSemanticSplitPoint(remaining, maxLength);
|
|
285
|
+
chunks.push(remaining.substring(0, splitIndex).trim());
|
|
286
|
+
remaining = remaining.substring(splitIndex).trim();
|
|
287
|
+
}
|
|
288
|
+
return chunks;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Find the optimal split point respecting semantic boundaries
|
|
292
|
+
* Priority: Header > Code block boundary > Paragraph > Sentence > Hard cut
|
|
293
|
+
*/
|
|
294
|
+
static findSemanticSplitPoint(text, maxLength) {
|
|
295
|
+
// 1. Try to split BEFORE a markdown header (## or ###)
|
|
296
|
+
const headerPattern = /\n(##+ )/g;
|
|
297
|
+
let match;
|
|
298
|
+
let lastHeaderBefore = -1;
|
|
299
|
+
while ((match = headerPattern.exec(text)) !== null) {
|
|
300
|
+
const pos = match.index;
|
|
301
|
+
if (pos > maxLength)
|
|
302
|
+
break;
|
|
303
|
+
if (pos > maxLength / 2) {
|
|
304
|
+
lastHeaderBefore = pos;
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (lastHeaderBefore > maxLength / 2) {
|
|
309
|
+
return lastHeaderBefore;
|
|
310
|
+
}
|
|
311
|
+
// 2. Try to split AFTER a complete code block
|
|
312
|
+
const codeBlockEndPattern = /```\n/g;
|
|
313
|
+
let lastCodeEnd = -1;
|
|
314
|
+
while ((match = codeBlockEndPattern.exec(text)) !== null) {
|
|
315
|
+
const pos = match.index + match[0].length;
|
|
316
|
+
if (pos > maxLength)
|
|
317
|
+
break;
|
|
318
|
+
if (pos > maxLength / 2) {
|
|
319
|
+
lastCodeEnd = pos;
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (lastCodeEnd > maxLength / 2) {
|
|
324
|
+
return lastCodeEnd;
|
|
325
|
+
}
|
|
326
|
+
// 3. Try to split at paragraph boundary (double newline)
|
|
327
|
+
let splitIndex = text.lastIndexOf('\n\n', maxLength);
|
|
328
|
+
if (splitIndex > maxLength / 2) {
|
|
329
|
+
return splitIndex + 2;
|
|
330
|
+
}
|
|
331
|
+
// 4. Try to split at single newline
|
|
332
|
+
splitIndex = text.lastIndexOf('\n', maxLength);
|
|
333
|
+
if (splitIndex > maxLength / 3) {
|
|
334
|
+
return splitIndex + 1;
|
|
335
|
+
}
|
|
336
|
+
// 5. Try to split at sentence boundary (. followed by space)
|
|
337
|
+
splitIndex = text.lastIndexOf('. ', maxLength);
|
|
338
|
+
if (splitIndex > maxLength / 3) {
|
|
339
|
+
return splitIndex + 2;
|
|
340
|
+
}
|
|
341
|
+
// 6. Last resort: hard cut at maxLength
|
|
342
|
+
return maxLength;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Format and split in one operation
|
|
346
|
+
* Ensures summary line (first line with actionable emoji) stays at the top
|
|
347
|
+
*/
|
|
348
|
+
static formatAndSplit(text) {
|
|
349
|
+
const formatted = this.format(text);
|
|
350
|
+
// If text fits in one message, no special handling needed
|
|
351
|
+
if (formatted.length <= this.MAX_MESSAGE_LENGTH) {
|
|
352
|
+
return [formatted];
|
|
353
|
+
}
|
|
354
|
+
// Extract summary line (first line starting with key emoji)
|
|
355
|
+
const { summary, rest } = this.extractSummaryLine(formatted);
|
|
356
|
+
// Split the remaining content
|
|
357
|
+
const chunks = this.split(rest);
|
|
358
|
+
// If we found a summary, prepend it to the first chunk
|
|
359
|
+
if (summary && chunks.length > 0) {
|
|
360
|
+
// Check if adding summary would exceed limit
|
|
361
|
+
const firstChunkWithSummary = `${summary}\n\n${chunks[0]}`;
|
|
362
|
+
if (firstChunkWithSummary.length <= this.MAX_MESSAGE_LENGTH) {
|
|
363
|
+
chunks[0] = firstChunkWithSummary;
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
// Summary + first chunk too long, send summary as its own message
|
|
367
|
+
chunks.unshift(summary);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return chunks;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Extract the summary line from the beginning of formatted text
|
|
374
|
+
* Summary lines start with key actionable emojis: 🎯 ⚖️ 📊 ⚠️ ✅ ❓
|
|
375
|
+
*/
|
|
376
|
+
static extractSummaryLine(text) {
|
|
377
|
+
const lines = text.split('\n');
|
|
378
|
+
const summaryEmojis = ['🎯', '⚖️', '📊', '⚠️', '✅', '❓', '❌'];
|
|
379
|
+
// Check first few lines for summary pattern
|
|
380
|
+
for (let i = 0; i < Math.min(3, lines.length); i++) {
|
|
381
|
+
const line = lines[i].trim();
|
|
382
|
+
// Check if line starts with a summary emoji
|
|
383
|
+
if (summaryEmojis.some((emoji) => line.startsWith(emoji))) {
|
|
384
|
+
// Found summary line - extract it and return rest
|
|
385
|
+
const summary = line;
|
|
386
|
+
const restLines = [...lines.slice(0, i), ...lines.slice(i + 1)];
|
|
387
|
+
const rest = restLines.join('\n').trim();
|
|
388
|
+
return { summary, rest };
|
|
389
|
+
}
|
|
390
|
+
// Also check for bold emoji pattern: **🎯 or similar
|
|
391
|
+
if (line.match(/^\*\*[🎯⚖️📊⚠️✅❓❌]/)) {
|
|
392
|
+
const summary = line;
|
|
393
|
+
const restLines = [...lines.slice(0, i), ...lines.slice(i + 1)];
|
|
394
|
+
const rest = restLines.join('\n').trim();
|
|
395
|
+
return { summary, rest };
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return { summary: null, rest: text };
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Parse markdown into sections based on headers (##)
|
|
402
|
+
*/
|
|
403
|
+
static parseSections(text) {
|
|
404
|
+
const sections = [];
|
|
405
|
+
const lines = text.split('\n');
|
|
406
|
+
let currentTitle = 'Summary';
|
|
407
|
+
let currentContent = [];
|
|
408
|
+
for (const line of lines) {
|
|
409
|
+
const headerMatch = line.match(/^##\s+(.+)$/);
|
|
410
|
+
if (headerMatch) {
|
|
411
|
+
if (currentContent.length > 0 || currentTitle !== 'Summary') {
|
|
412
|
+
sections.push({
|
|
413
|
+
title: currentTitle,
|
|
414
|
+
content: currentContent.join('\n').trim()
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
currentTitle = headerMatch[1];
|
|
418
|
+
currentContent = [];
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
currentContent.push(line);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
if (currentContent.length > 0 || sections.length === 0) {
|
|
425
|
+
sections.push({
|
|
426
|
+
title: currentTitle,
|
|
427
|
+
content: currentContent.join('\n').trim()
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
return sections;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Format a data object as a clean Discord-friendly list
|
|
434
|
+
*/
|
|
435
|
+
static formatDataAsEmbed(title, data) {
|
|
436
|
+
const lines = [`**${title}**`];
|
|
437
|
+
for (const [key, value] of Object.entries(data)) {
|
|
438
|
+
if (typeof value === 'object') {
|
|
439
|
+
lines.push(`• **${key}:** \`${JSON.stringify(value)}\``);
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
lines.push(`• **${key}:** ${value}`);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return lines.join('\n');
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
//# sourceMappingURL=message-formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-formatter.js","sourceRoot":"","sources":["../../src/discord/message-formatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Config } from '../config/config.js';
|
|
2
|
+
export interface MemoryResult {
|
|
3
|
+
path: string;
|
|
4
|
+
content: string;
|
|
5
|
+
score: number;
|
|
6
|
+
startLine: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* KnowledgeStore - Local memory using SQLite FTS5.
|
|
10
|
+
* Uses a classic keyword inverted index approach for high-speed, authless search.
|
|
11
|
+
*/
|
|
12
|
+
export declare class KnowledgeStore {
|
|
13
|
+
private db;
|
|
14
|
+
constructor(config: Config);
|
|
15
|
+
private initialize;
|
|
16
|
+
/**
|
|
17
|
+
* Add or update a file in the knowledge base.
|
|
18
|
+
*/
|
|
19
|
+
indexFile(filePath: string, content: string): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Search for relevant knowledge using keyword match (BM25 ranking).
|
|
22
|
+
*/
|
|
23
|
+
search(query: string, limit?: number): Promise<MemoryResult[]>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import logger from '../utils/logger.js';
|
|
5
|
+
import crypto from 'crypto';
|
|
6
|
+
/**
|
|
7
|
+
* KnowledgeStore - Local memory using SQLite FTS5.
|
|
8
|
+
* Uses a classic keyword inverted index approach for high-speed, authless search.
|
|
9
|
+
*/
|
|
10
|
+
export class KnowledgeStore {
|
|
11
|
+
db;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
const dbPath = path.join(config.homeDir, 'data', 'knowledge.db');
|
|
14
|
+
const dbDir = path.dirname(dbPath);
|
|
15
|
+
if (!fs.existsSync(dbDir)) {
|
|
16
|
+
fs.mkdirSync(dbDir, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
// FTS5 is built-in to modern SQLite, no need for allowExtension
|
|
19
|
+
this.db = new DatabaseSync(dbPath);
|
|
20
|
+
this.initialize();
|
|
21
|
+
}
|
|
22
|
+
initialize() {
|
|
23
|
+
try {
|
|
24
|
+
// Initialize Tables
|
|
25
|
+
this.db.exec(`
|
|
26
|
+
CREATE TABLE IF NOT EXISTS files (
|
|
27
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
28
|
+
path TEXT UNIQUE,
|
|
29
|
+
hash TEXT,
|
|
30
|
+
updated_at INTEGER
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
CREATE TABLE IF NOT EXISTS chunks (
|
|
34
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
35
|
+
file_id INTEGER,
|
|
36
|
+
content TEXT,
|
|
37
|
+
start_line INTEGER,
|
|
38
|
+
end_line INTEGER,
|
|
39
|
+
FOREIGN KEY(file_id) REFERENCES files(id) ON DELETE CASCADE
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
-- Initialize FTS5 Search Table (Internal Storage)
|
|
43
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS chunks_fts USING fts5(
|
|
44
|
+
content
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
-- Triggers to keep FTS in sync with chunks table
|
|
48
|
+
CREATE TRIGGER IF NOT EXISTS chunks_ai AFTER INSERT ON chunks BEGIN
|
|
49
|
+
INSERT INTO chunks_fts(rowid, content) VALUES (new.id, new.content);
|
|
50
|
+
END;
|
|
51
|
+
CREATE TRIGGER IF NOT EXISTS chunks_ad AFTER DELETE ON chunks BEGIN
|
|
52
|
+
DELETE FROM chunks_fts WHERE rowid = old.id;
|
|
53
|
+
END;
|
|
54
|
+
CREATE TRIGGER IF NOT EXISTS chunks_au AFTER UPDATE ON chunks BEGIN
|
|
55
|
+
DELETE FROM chunks_fts WHERE rowid = old.id;
|
|
56
|
+
INSERT INTO chunks_fts(rowid, content) VALUES (new.id, new.content);
|
|
57
|
+
END;
|
|
58
|
+
`);
|
|
59
|
+
logger.info('🧠 KnowledgeStore: Local keyword index initialized');
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
logger.error(`❌ KnowledgeStore init failed: ${error.message}`);
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Add or update a file in the knowledge base.
|
|
68
|
+
*/
|
|
69
|
+
async indexFile(filePath, content) {
|
|
70
|
+
const hash = crypto.createHash('sha256').update(content).digest('hex');
|
|
71
|
+
// 1. Check if file has changed
|
|
72
|
+
const existing = this.db
|
|
73
|
+
.prepare('SELECT id, hash FROM files WHERE path = ?')
|
|
74
|
+
.get(filePath);
|
|
75
|
+
if (existing && existing.hash === hash) {
|
|
76
|
+
return; // No changes
|
|
77
|
+
}
|
|
78
|
+
logger.info(`📝 Indexing: ${filePath}`);
|
|
79
|
+
// 2. Clear old file data (Cascade delete handles chunks and triggers handle FTS)
|
|
80
|
+
if (existing) {
|
|
81
|
+
this.db.prepare('DELETE FROM files WHERE id = ?').run(existing.id);
|
|
82
|
+
}
|
|
83
|
+
// 3. Insert File Record
|
|
84
|
+
const fileResult = this.db
|
|
85
|
+
.prepare('INSERT INTO files (path, hash, updated_at) VALUES (?, ?, ?)')
|
|
86
|
+
.run(filePath, hash, Date.now());
|
|
87
|
+
const fileId = fileResult.lastInsertRowid;
|
|
88
|
+
// 4. Chunk Content (Simple paragraph split)
|
|
89
|
+
const paragraphs = content.split(/\n\s*\n/).filter((p) => p.trim().length > 20);
|
|
90
|
+
// 5. Store Chunks (FTS is updated automatically via triggers)
|
|
91
|
+
for (const p of paragraphs) {
|
|
92
|
+
this.db
|
|
93
|
+
.prepare('INSERT INTO chunks (file_id, content, start_line) VALUES (?, ?, ?)')
|
|
94
|
+
.run(fileId, p, 0);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Search for relevant knowledge using keyword match (BM25 ranking).
|
|
99
|
+
*/
|
|
100
|
+
async search(query, limit = 5) {
|
|
101
|
+
try {
|
|
102
|
+
const results = this.db
|
|
103
|
+
.prepare(`
|
|
104
|
+
SELECT f.path, c.content, c.start_line, rank as score
|
|
105
|
+
FROM chunks_fts fts
|
|
106
|
+
JOIN chunks c ON fts.rowid = c.id
|
|
107
|
+
JOIN files f ON c.file_id = f.id
|
|
108
|
+
WHERE chunks_fts MATCH ?
|
|
109
|
+
ORDER BY rank
|
|
110
|
+
LIMIT ?
|
|
111
|
+
`)
|
|
112
|
+
.all(query, limit);
|
|
113
|
+
return results.map((r) => ({
|
|
114
|
+
path: r.path,
|
|
115
|
+
content: r.content,
|
|
116
|
+
startLine: r.start_line,
|
|
117
|
+
score: 1 / (1 + Math.abs(r.score)) // Normalize FTS rank to 0-1 range
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
logger.warn(`⚠️ Search failed: ${query}`);
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=knowledge-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knowledge-store.js","sourceRoot":"","sources":["../../src/memory/knowledge-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Config } from '../config/config.js';
|
|
2
|
+
/**
|
|
3
|
+
* MemoryManager - High-level interface for Tars' memory systems.
|
|
4
|
+
* Manages the transition from flat GEMINI.md to indexed storage.
|
|
5
|
+
*/
|
|
6
|
+
export declare class MemoryManager {
|
|
7
|
+
private knowledgeStore;
|
|
8
|
+
private config;
|
|
9
|
+
constructor(config: Config);
|
|
10
|
+
/**
|
|
11
|
+
* Initial sync of the "Brain" into the knowledge store.
|
|
12
|
+
* This includes GEMINI.md, skills, and session transcripts.
|
|
13
|
+
*/
|
|
14
|
+
fullSync(): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Finds and indexes past session conversations for episodic memory.
|
|
17
|
+
*/
|
|
18
|
+
private syncSessions;
|
|
19
|
+
private syncDir;
|
|
20
|
+
/**
|
|
21
|
+
* Search memory for relevant snippets.
|
|
22
|
+
*/
|
|
23
|
+
search(query: string, limit?: number): Promise<import("./knowledge-store.js").MemoryResult[]>;
|
|
24
|
+
}
|