opensentinel 2.1.1

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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +283 -0
  3. package/dist/bot-KJ26BG56.js +15 -0
  4. package/dist/bot-KJ26BG56.js.map +1 -0
  5. package/dist/charts-MMXM6BWW.js +241 -0
  6. package/dist/charts-MMXM6BWW.js.map +1 -0
  7. package/dist/chunk-4LVWXUNC.js +1079 -0
  8. package/dist/chunk-4LVWXUNC.js.map +1 -0
  9. package/dist/chunk-4TG2IG5K.js +5249 -0
  10. package/dist/chunk-4TG2IG5K.js.map +1 -0
  11. package/dist/chunk-6DRDKB45.js +251 -0
  12. package/dist/chunk-6DRDKB45.js.map +1 -0
  13. package/dist/chunk-6SNHU3CY.js +123 -0
  14. package/dist/chunk-6SNHU3CY.js.map +1 -0
  15. package/dist/chunk-CI6Q63MM.js +1613 -0
  16. package/dist/chunk-CI6Q63MM.js.map +1 -0
  17. package/dist/chunk-CQ4JURG7.js +57 -0
  18. package/dist/chunk-CQ4JURG7.js.map +1 -0
  19. package/dist/chunk-F6QUZQGI.js +51 -0
  20. package/dist/chunk-F6QUZQGI.js.map +1 -0
  21. package/dist/chunk-GK3E2I7A.js +216 -0
  22. package/dist/chunk-GK3E2I7A.js.map +1 -0
  23. package/dist/chunk-GUBEEYDW.js +211 -0
  24. package/dist/chunk-GUBEEYDW.js.map +1 -0
  25. package/dist/chunk-GVJVEWHI.js +29 -0
  26. package/dist/chunk-GVJVEWHI.js.map +1 -0
  27. package/dist/chunk-HH2HBTQM.js +806 -0
  28. package/dist/chunk-HH2HBTQM.js.map +1 -0
  29. package/dist/chunk-JXUP2X7V.js +129 -0
  30. package/dist/chunk-JXUP2X7V.js.map +1 -0
  31. package/dist/chunk-KHNYJY2Z.js +178 -0
  32. package/dist/chunk-KHNYJY2Z.js.map +1 -0
  33. package/dist/chunk-L3F43VPB.js +652 -0
  34. package/dist/chunk-L3F43VPB.js.map +1 -0
  35. package/dist/chunk-L3PDU3XN.js +803 -0
  36. package/dist/chunk-L3PDU3XN.js.map +1 -0
  37. package/dist/chunk-NSBPE2FW.js +17 -0
  38. package/dist/chunk-NSBPE2FW.js.map +1 -0
  39. package/dist/cli.d.ts +1 -0
  40. package/dist/cli.js +52 -0
  41. package/dist/cli.js.map +1 -0
  42. package/dist/commands/setup.d.ts +9 -0
  43. package/dist/commands/setup.js +374 -0
  44. package/dist/commands/setup.js.map +1 -0
  45. package/dist/commands/start.d.ts +8 -0
  46. package/dist/commands/start.js +27 -0
  47. package/dist/commands/start.js.map +1 -0
  48. package/dist/commands/status.d.ts +8 -0
  49. package/dist/commands/status.js +57 -0
  50. package/dist/commands/status.js.map +1 -0
  51. package/dist/commands/stop.d.ts +8 -0
  52. package/dist/commands/stop.js +37 -0
  53. package/dist/commands/stop.js.map +1 -0
  54. package/dist/commands/utils.d.ts +50 -0
  55. package/dist/commands/utils.js +36 -0
  56. package/dist/commands/utils.js.map +1 -0
  57. package/dist/discord-ZOJFTVTB.js +49 -0
  58. package/dist/discord-ZOJFTVTB.js.map +1 -0
  59. package/dist/imessage-JFRB6EJ7.js +14 -0
  60. package/dist/imessage-JFRB6EJ7.js.map +1 -0
  61. package/dist/lib.d.ts +855 -0
  62. package/dist/lib.js +274 -0
  63. package/dist/lib.js.map +1 -0
  64. package/dist/mcp-LS7Q3Z5W.js +30 -0
  65. package/dist/mcp-LS7Q3Z5W.js.map +1 -0
  66. package/dist/scheduler-EZ7CZMCS.js +42 -0
  67. package/dist/scheduler-EZ7CZMCS.js.map +1 -0
  68. package/dist/signal-T3MCSULM.js +14 -0
  69. package/dist/signal-T3MCSULM.js.map +1 -0
  70. package/dist/slack-N2M4FHAJ.js +54 -0
  71. package/dist/slack-N2M4FHAJ.js.map +1 -0
  72. package/dist/src-K7GASHRH.js +430 -0
  73. package/dist/src-K7GASHRH.js.map +1 -0
  74. package/dist/tools-24GZHYRF.js +16 -0
  75. package/dist/tools-24GZHYRF.js.map +1 -0
  76. package/dist/whatsapp-VCRUPAO5.js +14 -0
  77. package/dist/whatsapp-VCRUPAO5.js.map +1 -0
  78. package/drizzle/0000_chilly_shinobi_shaw.sql +75 -0
  79. package/drizzle/0001_freezing_shape.sql +274 -0
  80. package/drizzle/meta/0000_snapshot.json +529 -0
  81. package/drizzle/meta/0001_snapshot.json +2576 -0
  82. package/drizzle/meta/_journal.json +20 -0
  83. package/package.json +98 -0
@@ -0,0 +1,1079 @@
1
+ import {
2
+ chat,
3
+ checkAchievements,
4
+ generateGrowthReport,
5
+ getAchievementProgress,
6
+ getCurrentMode,
7
+ getModeStats,
8
+ getUserPoints
9
+ } from "./chunk-CI6Q63MM.js";
10
+ import {
11
+ TOOLS,
12
+ addAgentMessage,
13
+ addAgentProgress,
14
+ archivedMemories,
15
+ calendarTriggers,
16
+ db,
17
+ env,
18
+ errorLogs,
19
+ executeTool,
20
+ flushMetrics,
21
+ getAgent,
22
+ memories,
23
+ metric,
24
+ shouldAgentStop,
25
+ updateAgentStatus,
26
+ updateAgentTokens
27
+ } from "./chunk-4TG2IG5K.js";
28
+
29
+ // src/core/scheduler.ts
30
+ import { Queue, Worker as Worker2 } from "bullmq";
31
+ import Redis2 from "ioredis";
32
+
33
+ // src/core/agents/agent-worker.ts
34
+ import { Worker } from "bullmq";
35
+ import Redis from "ioredis";
36
+ import Anthropic from "@anthropic-ai/sdk";
37
+
38
+ // src/core/agents/agent-types.ts
39
+ var AGENT_SYSTEM_PROMPTS = {
40
+ research: `You are a Research Agent. Your goal is to thoroughly investigate a topic and provide comprehensive, well-sourced information.
41
+
42
+ Process:
43
+ 1. Break down the research question into sub-questions
44
+ 2. Search for information from multiple sources
45
+ 3. Cross-reference and verify findings
46
+ 4. Synthesize information into a coherent report
47
+ 5. Note confidence levels and any uncertainties
48
+
49
+ Guidelines:
50
+ - Always cite or reference your sources
51
+ - Present multiple perspectives when relevant
52
+ - Distinguish between facts and interpretations
53
+ - Flag when information might be outdated
54
+ - Structure findings hierarchically
55
+
56
+ Report your progress after each major step.`,
57
+ coding: `You are a Coding Agent. Your goal is to implement, debug, or improve code based on the given objective.
58
+
59
+ Process:
60
+ 1. Understand the requirements thoroughly
61
+ 2. Explore existing code if relevant
62
+ 3. Plan the implementation approach
63
+ 4. Write clean, documented code
64
+ 5. Test and verify the solution
65
+
66
+ Guidelines:
67
+ - Follow existing code conventions in the project
68
+ - Write clear comments for complex logic
69
+ - Handle edge cases and errors gracefully
70
+ - Consider performance implications
71
+ - Provide a summary of changes made
72
+
73
+ Report your progress after each significant step.`,
74
+ writing: `You are a Writing Agent. Your goal is to create high-quality written content based on the given objective.
75
+
76
+ Process:
77
+ 1. Understand the purpose and audience
78
+ 2. Research the topic if needed
79
+ 3. Create an outline
80
+ 4. Write the first draft
81
+ 5. Review and refine
82
+
83
+ Guidelines:
84
+ - Match the tone and style to the purpose
85
+ - Structure content logically
86
+ - Use clear, concise language
87
+ - Support claims with evidence when relevant
88
+ - Proofread for grammar and clarity
89
+
90
+ Report your progress at each stage.`,
91
+ analysis: `You are an Analysis Agent. Your goal is to analyze data or information and provide actionable insights.
92
+
93
+ Process:
94
+ 1. Understand the analysis objective
95
+ 2. Gather and organize the data
96
+ 3. Apply appropriate analytical methods
97
+ 4. Identify patterns and insights
98
+ 5. Present findings with recommendations
99
+
100
+ Guidelines:
101
+ - Be objective and data-driven
102
+ - Acknowledge limitations in the data
103
+ - Provide context for numbers
104
+ - Make recommendations actionable
105
+ - Visualize data when helpful
106
+
107
+ Report your progress and key findings along the way.`
108
+ };
109
+ var AGENT_TOOL_PERMISSIONS = {
110
+ research: [
111
+ "web_search",
112
+ "browse_url",
113
+ "read_file",
114
+ "list_directory",
115
+ "search_files"
116
+ ],
117
+ coding: [
118
+ "read_file",
119
+ "write_file",
120
+ "list_directory",
121
+ "search_files",
122
+ "execute_command"
123
+ ],
124
+ writing: [
125
+ "read_file",
126
+ "write_file",
127
+ "web_search",
128
+ "browse_url"
129
+ ],
130
+ analysis: [
131
+ "read_file",
132
+ "web_search",
133
+ "browse_url",
134
+ "list_directory",
135
+ "search_files"
136
+ ]
137
+ };
138
+
139
+ // src/core/observability/error-tracker.ts
140
+ import { eq, and, gte, lte, desc } from "drizzle-orm";
141
+ async function trackError(error) {
142
+ metric.error(error.source);
143
+ console.error(`[${error.source.toUpperCase()}] ${error.errorType}: ${error.message}`);
144
+ if (error.stack) {
145
+ console.error(error.stack);
146
+ }
147
+ const [logged] = await db.insert(errorLogs).values({
148
+ source: error.source,
149
+ errorType: error.errorType,
150
+ errorCode: error.errorCode,
151
+ message: error.message,
152
+ stack: error.stack,
153
+ context: error.context,
154
+ userId: error.userId,
155
+ conversationId: error.conversationId
156
+ }).returning();
157
+ return logged.id;
158
+ }
159
+ function captureException(err, source, context, userId) {
160
+ const error = err instanceof Error ? err : new Error(String(err));
161
+ return trackError({
162
+ source,
163
+ errorType: error.constructor.name,
164
+ message: error.message,
165
+ stack: error.stack,
166
+ context,
167
+ userId
168
+ });
169
+ }
170
+
171
+ // src/core/agents/agent-worker.ts
172
+ var connection = new Redis(env.REDIS_URL, {
173
+ maxRetriesPerRequest: null
174
+ });
175
+ var anthropic = new Anthropic({
176
+ apiKey: env.CLAUDE_API_KEY
177
+ });
178
+ var worker = null;
179
+ async function processAgentTask(job) {
180
+ const { agentId, userId, type, objective, context, tokenBudget } = job.data;
181
+ const startTime = Date.now();
182
+ let totalTokensUsed = 0;
183
+ console.log(`[Agent ${agentId}] Starting ${type} agent: ${objective}`);
184
+ await updateAgentStatus(agentId, "running");
185
+ await addAgentProgress(agentId, 1, "Starting agent", "running");
186
+ const systemPrompt = buildSystemPrompt(type, context);
187
+ const allowedToolNames = AGENT_TOOL_PERMISSIONS[type];
188
+ const agentTools = TOOLS.filter((t) => allowedToolNames.includes(t.name));
189
+ const messages = [
190
+ {
191
+ role: "user",
192
+ content: `Your objective: ${objective}
193
+
194
+ ${context ? `Additional context:
195
+ ${JSON.stringify(context, null, 2)}` : ""}
196
+
197
+ Please proceed with the task, reporting your progress as you go.`
198
+ }
199
+ ];
200
+ await addAgentMessage(agentId, {
201
+ role: "user",
202
+ content: messages[0].content
203
+ });
204
+ let stepNumber = 2;
205
+ const maxSteps = 20;
206
+ try {
207
+ while (stepNumber <= maxSteps) {
208
+ const stopCheck = await shouldAgentStop(agentId);
209
+ if (stopCheck.stop) {
210
+ await addAgentProgress(
211
+ agentId,
212
+ stepNumber,
213
+ `Stopping: ${stopCheck.reason}`,
214
+ "completed"
215
+ );
216
+ break;
217
+ }
218
+ const response = await anthropic.messages.create({
219
+ model: "claude-sonnet-4-20250514",
220
+ max_tokens: 4096,
221
+ system: systemPrompt,
222
+ tools: agentTools,
223
+ messages
224
+ });
225
+ totalTokensUsed += response.usage.input_tokens + response.usage.output_tokens;
226
+ await updateAgentTokens(agentId, totalTokensUsed);
227
+ if (totalTokensUsed >= tokenBudget) {
228
+ await addAgentProgress(
229
+ agentId,
230
+ stepNumber,
231
+ "Token budget reached",
232
+ "completed"
233
+ );
234
+ break;
235
+ }
236
+ const assistantContent = response.content;
237
+ const textContent = assistantContent.filter((c) => c.type === "text").map((c) => c.text).join("\n");
238
+ if (textContent) {
239
+ await addAgentMessage(agentId, {
240
+ role: "assistant",
241
+ content: textContent
242
+ });
243
+ const progressDesc = textContent.slice(0, 200).replace(/\n/g, " ");
244
+ await addAgentProgress(agentId, stepNumber, progressDesc, "running");
245
+ }
246
+ if (response.stop_reason === "end_turn") {
247
+ await addAgentProgress(
248
+ agentId,
249
+ stepNumber + 1,
250
+ "Task completed",
251
+ "completed",
252
+ textContent
253
+ );
254
+ return {
255
+ success: true,
256
+ output: textContent,
257
+ summary: extractSummary(textContent),
258
+ tokensUsed: totalTokensUsed,
259
+ durationMs: Date.now() - startTime
260
+ };
261
+ }
262
+ if (response.stop_reason === "tool_use") {
263
+ const toolResults = [];
264
+ for (const block of assistantContent) {
265
+ if (block.type === "tool_use") {
266
+ const toolName = block.name;
267
+ const toolInput = block.input;
268
+ console.log(`[Agent ${agentId}] Using tool: ${toolName}`);
269
+ const result = await executeTool(toolName, toolInput);
270
+ await addAgentMessage(agentId, {
271
+ role: "tool_result",
272
+ content: JSON.stringify({ tool: toolName, result }),
273
+ metadata: { toolInput }
274
+ });
275
+ toolResults.push({
276
+ type: "tool_result",
277
+ tool_use_id: block.id,
278
+ content: JSON.stringify(result)
279
+ });
280
+ }
281
+ }
282
+ messages.push({ role: "assistant", content: assistantContent });
283
+ messages.push({ role: "user", content: toolResults });
284
+ }
285
+ stepNumber++;
286
+ }
287
+ const agent = await getAgent(agentId);
288
+ const lastMessage = agent?.messages.slice(-1)[0]?.content || "";
289
+ return {
290
+ success: true,
291
+ output: lastMessage,
292
+ summary: "Agent completed maximum steps",
293
+ tokensUsed: totalTokensUsed,
294
+ durationMs: Date.now() - startTime
295
+ };
296
+ } catch (error) {
297
+ const errorMessage = error instanceof Error ? error.message : String(error);
298
+ await captureException(error, "agent", {
299
+ agentId,
300
+ type,
301
+ objective
302
+ }, userId);
303
+ await addAgentProgress(
304
+ agentId,
305
+ stepNumber,
306
+ `Error: ${errorMessage}`,
307
+ "failed"
308
+ );
309
+ return {
310
+ success: false,
311
+ error: errorMessage,
312
+ tokensUsed: totalTokensUsed,
313
+ durationMs: Date.now() - startTime
314
+ };
315
+ }
316
+ }
317
+ function buildSystemPrompt(type, context) {
318
+ let prompt = AGENT_SYSTEM_PROMPTS[type];
319
+ if (context) {
320
+ prompt += `
321
+
322
+ Additional context about the user/task:
323
+ ${JSON.stringify(context, null, 2)}`;
324
+ }
325
+ return prompt;
326
+ }
327
+ function extractSummary(text) {
328
+ const summaryMatch = text.match(/(?:summary|conclusion|result):\s*(.+?)(?:\n\n|$)/i);
329
+ if (summaryMatch) {
330
+ return summaryMatch[1].trim();
331
+ }
332
+ const paragraphs = text.split("\n\n").filter((p) => p.trim());
333
+ return paragraphs.slice(-1)[0]?.slice(0, 500) || text.slice(0, 500);
334
+ }
335
+ function startAgentWorker() {
336
+ if (worker) return;
337
+ worker = new Worker(
338
+ "sentinel-agents",
339
+ async (job) => {
340
+ const result = await processAgentTask(job);
341
+ await updateAgentStatus(
342
+ job.data.agentId,
343
+ result.success ? "completed" : "failed",
344
+ result
345
+ );
346
+ metric.agentOperation("complete", job.data.type);
347
+ return result;
348
+ },
349
+ {
350
+ connection,
351
+ concurrency: 3
352
+ // Run up to 3 agents concurrently
353
+ }
354
+ );
355
+ worker.on("completed", (job) => {
356
+ console.log(`[AgentWorker] Agent completed: ${job.data.agentId}`);
357
+ });
358
+ worker.on("failed", (job, err) => {
359
+ console.error(`[AgentWorker] Agent failed: ${job?.data.agentId}`, err);
360
+ });
361
+ console.log("[AgentWorker] Agent worker started");
362
+ }
363
+ function stopAgentWorker() {
364
+ if (worker) {
365
+ worker.close();
366
+ worker = null;
367
+ }
368
+ }
369
+
370
+ // src/inputs/calendar/trigger-processor.ts
371
+ import { eq as eq2 } from "drizzle-orm";
372
+
373
+ // src/inputs/calendar/ical-parser.ts
374
+ function getEventsInRange(events, start, end) {
375
+ return events.filter(
376
+ (event) => event.startDate >= start && event.startDate <= end
377
+ );
378
+ }
379
+ function getUpcomingEvents(events, count = 10) {
380
+ const now = /* @__PURE__ */ new Date();
381
+ return events.filter((event) => event.startDate >= now).slice(0, count);
382
+ }
383
+ function getTodaysEvents(events) {
384
+ const today = /* @__PURE__ */ new Date();
385
+ today.setHours(0, 0, 0, 0);
386
+ const tomorrow = new Date(today);
387
+ tomorrow.setDate(tomorrow.getDate() + 1);
388
+ return getEventsInRange(events, today, tomorrow);
389
+ }
390
+
391
+ // src/inputs/calendar/trigger-processor.ts
392
+ async function getUserTriggers(userId) {
393
+ const triggers = await db.select().from(calendarTriggers).where(eq2(calendarTriggers.userId, userId));
394
+ return triggers.map((t) => ({
395
+ id: t.id,
396
+ userId: t.userId,
397
+ name: t.name,
398
+ calendarSource: t.calendarSource,
399
+ calendarId: t.calendarId || void 0,
400
+ triggerType: t.triggerType,
401
+ offsetMinutes: t.offsetMinutes || 0,
402
+ action: t.action,
403
+ enabled: t.enabled ?? true
404
+ }));
405
+ }
406
+ async function processCalendarTriggers(userId, events, chatId) {
407
+ const triggers = await getUserTriggers(userId);
408
+ const enabledTriggers = triggers.filter((t) => t.enabled);
409
+ const results = [];
410
+ const now = Date.now();
411
+ for (const trigger of enabledTriggers) {
412
+ try {
413
+ if (trigger.triggerType === "daily_briefing") {
414
+ continue;
415
+ }
416
+ for (const event of events) {
417
+ const eventTime = trigger.triggerType === "event_start" ? event.startDate.getTime() : event.endDate.getTime();
418
+ const triggerTime = eventTime - trigger.offsetMinutes * 60 * 1e3;
419
+ if (triggerTime > now) {
420
+ const delay = triggerTime - now;
421
+ const jobId = await scheduleTask(
422
+ {
423
+ type: "custom",
424
+ message: formatTriggerMessage(trigger, event),
425
+ userId,
426
+ chatId
427
+ },
428
+ delay
429
+ );
430
+ results.push({
431
+ triggerId: trigger.id,
432
+ event,
433
+ scheduledJobId: jobId
434
+ });
435
+ await db.update(calendarTriggers).set({ lastTriggered: /* @__PURE__ */ new Date() }).where(eq2(calendarTriggers.id, trigger.id));
436
+ }
437
+ }
438
+ } catch (error) {
439
+ results.push({
440
+ triggerId: trigger.id,
441
+ error: error instanceof Error ? error.message : String(error)
442
+ });
443
+ }
444
+ }
445
+ return results;
446
+ }
447
+ function formatTriggerMessage(trigger, event) {
448
+ const timeStr = event.startDate.toLocaleTimeString([], {
449
+ hour: "2-digit",
450
+ minute: "2-digit"
451
+ });
452
+ if (trigger.triggerType === "event_start") {
453
+ if (trigger.offsetMinutes > 0) {
454
+ return `\u23F0 Reminder: "${event.summary}" starts in ${trigger.offsetMinutes} minutes at ${timeStr}`;
455
+ }
456
+ return `\u{1F514} "${event.summary}" is starting now!`;
457
+ }
458
+ if (trigger.triggerType === "event_end") {
459
+ return `\u2705 "${event.summary}" has ended`;
460
+ }
461
+ return `\u{1F4C5} Calendar event: ${event.summary}`;
462
+ }
463
+ async function generateDailyBriefing(userId, events) {
464
+ const todayEvents = getTodaysEvents(events);
465
+ const upcomingEvents = getUpcomingEvents(events, 5);
466
+ let briefing = "\u{1F4C5} **Your Daily Calendar Briefing**\n\n";
467
+ if (todayEvents.length === 0) {
468
+ briefing += "No events scheduled for today.\n\n";
469
+ } else {
470
+ briefing += `**Today's Events (${todayEvents.length}):**
471
+ `;
472
+ for (const event of todayEvents) {
473
+ const timeStr = event.isAllDay ? "All day" : event.startDate.toLocaleTimeString([], {
474
+ hour: "2-digit",
475
+ minute: "2-digit"
476
+ });
477
+ briefing += `\u2022 ${timeStr}: ${event.summary}`;
478
+ if (event.location) {
479
+ briefing += ` @ ${event.location}`;
480
+ }
481
+ briefing += "\n";
482
+ }
483
+ briefing += "\n";
484
+ }
485
+ const futureEvents = upcomingEvents.filter(
486
+ (e) => !todayEvents.some((t) => t.uid === e.uid)
487
+ );
488
+ if (futureEvents.length > 0) {
489
+ briefing += "**Upcoming:**\n";
490
+ for (const event of futureEvents.slice(0, 3)) {
491
+ const dateStr = event.startDate.toLocaleDateString([], {
492
+ weekday: "short",
493
+ month: "short",
494
+ day: "numeric"
495
+ });
496
+ briefing += `\u2022 ${dateStr}: ${event.summary}
497
+ `;
498
+ }
499
+ }
500
+ return briefing;
501
+ }
502
+
503
+ // src/core/molt/memory-shedder.ts
504
+ import { eq as eq3, and as and3, lt, lte as lte3 } from "drizzle-orm";
505
+ var SHED_CONFIG = {
506
+ staleDays: 90,
507
+ // Memories not accessed in 90 days
508
+ lowImportanceThreshold: 3,
509
+ // Memories with importance <= 3
510
+ minConfidence: 70
511
+ // Minimum confidence to auto-shed
512
+ };
513
+ async function findStaleMemories(userId, staleDays = SHED_CONFIG.staleDays) {
514
+ const cutoff = new Date(Date.now() - staleDays * 24 * 60 * 60 * 1e3);
515
+ const stale = await db.select().from(memories).where(
516
+ and3(
517
+ eq3(memories.userId, userId),
518
+ lt(memories.lastAccessed, cutoff)
519
+ )
520
+ );
521
+ return stale.map((m) => ({
522
+ memoryId: m.id,
523
+ content: m.content,
524
+ type: m.type,
525
+ reason: "stale",
526
+ lastAccessed: m.lastAccessed,
527
+ importance: m.importance || 5,
528
+ confidence: calculateStaleConfidence(m.lastAccessed, m.importance || 5)
529
+ }));
530
+ }
531
+ function calculateStaleConfidence(lastAccessed, importance) {
532
+ if (!lastAccessed) return 80;
533
+ const daysSinceAccess = Math.floor(
534
+ (Date.now() - lastAccessed.getTime()) / (24 * 60 * 60 * 1e3)
535
+ );
536
+ let confidence = Math.min(daysSinceAccess / 2, 50);
537
+ confidence += (10 - importance) * 5;
538
+ return Math.min(confidence, 100);
539
+ }
540
+ async function findLowImportanceMemories(userId, threshold = SHED_CONFIG.lowImportanceThreshold) {
541
+ const lowImportance = await db.select().from(memories).where(
542
+ and3(
543
+ eq3(memories.userId, userId),
544
+ lte3(memories.importance, threshold)
545
+ )
546
+ );
547
+ return lowImportance.map((m) => ({
548
+ memoryId: m.id,
549
+ content: m.content,
550
+ type: m.type,
551
+ reason: "low_importance",
552
+ lastAccessed: m.lastAccessed,
553
+ importance: m.importance || 5,
554
+ confidence: (SHED_CONFIG.lowImportanceThreshold - (m.importance || 5) + 1) * 25
555
+ }));
556
+ }
557
+ async function findDuplicateMemories(userId) {
558
+ const allMemories = await db.select().from(memories).where(eq3(memories.userId, userId));
559
+ const candidates = [];
560
+ const seen = /* @__PURE__ */ new Map();
561
+ for (const memory of allMemories) {
562
+ const normalized = memory.content.toLowerCase().trim();
563
+ const key = normalized.slice(0, 100);
564
+ const existing = seen.get(key);
565
+ if (existing) {
566
+ const isDuplicate = memory.createdAt > existing.createdAt ? memory : existing;
567
+ candidates.push({
568
+ memoryId: isDuplicate.id,
569
+ content: isDuplicate.content,
570
+ type: isDuplicate.type,
571
+ reason: "duplicate",
572
+ lastAccessed: isDuplicate.lastAccessed,
573
+ importance: isDuplicate.importance || 5,
574
+ confidence: 75
575
+ // Fairly confident about duplicates
576
+ });
577
+ } else {
578
+ seen.set(key, memory);
579
+ }
580
+ }
581
+ return candidates;
582
+ }
583
+ async function identifyShedCandidates(userId) {
584
+ const [stale, lowImportance, duplicates] = await Promise.all([
585
+ findStaleMemories(userId),
586
+ findLowImportanceMemories(userId),
587
+ findDuplicateMemories(userId)
588
+ ]);
589
+ const candidateMap = /* @__PURE__ */ new Map();
590
+ for (const candidate of [...stale, ...lowImportance, ...duplicates]) {
591
+ const existing = candidateMap.get(candidate.memoryId);
592
+ if (!existing || candidate.confidence > existing.confidence) {
593
+ candidateMap.set(candidate.memoryId, candidate);
594
+ }
595
+ }
596
+ return Array.from(candidateMap.values()).sort(
597
+ (a, b) => b.confidence - a.confidence
598
+ );
599
+ }
600
+ async function archiveMemory(memoryId, reason) {
601
+ const [memory] = await db.select().from(memories).where(eq3(memories.id, memoryId)).limit(1);
602
+ if (!memory) return false;
603
+ await db.insert(archivedMemories).values({
604
+ originalMemoryId: memory.id,
605
+ userId: memory.userId,
606
+ type: memory.type,
607
+ content: memory.content,
608
+ reason,
609
+ originalCreatedAt: memory.createdAt
610
+ });
611
+ await db.delete(memories).where(eq3(memories.id, memoryId));
612
+ return true;
613
+ }
614
+ async function autoShed(userId, minConfidence = SHED_CONFIG.minConfidence) {
615
+ const candidates = await identifyShedCandidates(userId);
616
+ const toArchive = candidates.filter((c) => c.confidence >= minConfidence);
617
+ const results = {
618
+ archivedCount: 0,
619
+ archivedIds: [],
620
+ skippedCount: 0
621
+ };
622
+ for (const candidate of toArchive) {
623
+ const success = await archiveMemory(candidate.memoryId, candidate.reason);
624
+ if (success) {
625
+ results.archivedCount++;
626
+ results.archivedIds.push(candidate.memoryId);
627
+ } else {
628
+ results.skippedCount++;
629
+ }
630
+ }
631
+ return results;
632
+ }
633
+ async function getArchivedMemories(userId, limit = 50) {
634
+ return db.select().from(archivedMemories).where(eq3(archivedMemories.userId, userId)).limit(limit);
635
+ }
636
+ async function getShedStats(userId) {
637
+ const archived = await getArchivedMemories(userId, 1e3);
638
+ const candidates = await identifyShedCandidates(userId);
639
+ const byReason = {
640
+ stale: 0,
641
+ duplicate: 0,
642
+ low_importance: 0,
643
+ user_request: 0,
644
+ deprecated_workflow: 0
645
+ };
646
+ for (const memory of archived) {
647
+ const reason = memory.reason;
648
+ if (reason in byReason) {
649
+ byReason[reason]++;
650
+ }
651
+ }
652
+ return {
653
+ totalArchived: archived.length,
654
+ byReason,
655
+ pendingCandidates: candidates.length
656
+ };
657
+ }
658
+
659
+ // src/core/molt/growth-reporter.ts
660
+ async function generateWeeklyReport(userId) {
661
+ const endDate = /* @__PURE__ */ new Date();
662
+ const startDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1e3);
663
+ return generateReport(userId, startDate, endDate, "weekly");
664
+ }
665
+ async function generateMonthlyReport(userId) {
666
+ const endDate = /* @__PURE__ */ new Date();
667
+ const startDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
668
+ return generateReport(userId, startDate, endDate, "monthly");
669
+ }
670
+ async function generateReport(userId, startDate, endDate, type) {
671
+ const growthData = await generateGrowthReport(userId, startDate, endDate);
672
+ const newAchievements = await checkAchievements(userId);
673
+ const totalPoints = await getUserPoints(userId);
674
+ const modeStats = await getModeStats(userId);
675
+ const shedStats = await getShedStats(userId);
676
+ const highlights = generateHighlights(growthData, newAchievements);
677
+ const suggestions = await generateSuggestions(userId, growthData);
678
+ const summary = generateSummary(growthData, newAchievements, type);
679
+ return {
680
+ period: {
681
+ type,
682
+ start: startDate,
683
+ end: endDate
684
+ },
685
+ summary,
686
+ metrics: {
687
+ conversations: growthData.metrics.conversations,
688
+ messages: growthData.metrics.messages,
689
+ toolUses: growthData.metrics.toolUses,
690
+ newMemories: growthData.metrics.newMemories,
691
+ archivedMemories: shedStats.totalArchived
692
+ },
693
+ achievements: {
694
+ newlyUnlocked: newAchievements.map((a) => ({
695
+ name: a.name,
696
+ emoji: a.iconEmoji,
697
+ points: a.points
698
+ })),
699
+ totalPoints,
700
+ pointsGained: newAchievements.reduce((sum, a) => sum + a.points, 0)
701
+ },
702
+ modeUsage: {
703
+ productivity: modeStats.productivity,
704
+ creative: modeStats.creative,
705
+ research: modeStats.research,
706
+ learning: modeStats.learning
707
+ },
708
+ highlights,
709
+ suggestions
710
+ };
711
+ }
712
+ function generateHighlights(growthData, newAchievements) {
713
+ const highlights = [];
714
+ if (growthData.metrics.conversations > 0) {
715
+ highlights.push(
716
+ `You had ${growthData.metrics.conversations} conversations this period!`
717
+ );
718
+ }
719
+ if (growthData.metrics.toolUses > 10) {
720
+ highlights.push(
721
+ `Power user alert! You used tools ${growthData.metrics.toolUses} times.`
722
+ );
723
+ }
724
+ if (growthData.metrics.newMemories > 5) {
725
+ highlights.push(
726
+ `I learned ${growthData.metrics.newMemories} new things about you.`
727
+ );
728
+ }
729
+ for (const achievement of newAchievements) {
730
+ highlights.push(
731
+ `${achievement.iconEmoji} Achievement unlocked: ${achievement.name}!`
732
+ );
733
+ }
734
+ if (growthData.patterns.length > 0) {
735
+ const topPattern = growthData.patterns[0];
736
+ highlights.push(
737
+ `New pattern detected: You frequently use ${topPattern.key}.`
738
+ );
739
+ }
740
+ return highlights;
741
+ }
742
+ async function generateSuggestions(userId, growthData) {
743
+ const suggestions = [];
744
+ const progress = await getAchievementProgress(userId);
745
+ const almostUnlocked = progress.filter(
746
+ (p) => p.progress / p.target >= 0.7 && p.progress / p.target < 1
747
+ );
748
+ for (const achievement of almostUnlocked.slice(0, 2)) {
749
+ const remaining = achievement.target - achievement.progress;
750
+ suggestions.push(
751
+ `You're close to unlocking "${achievement.achievement.name}"! Just ${remaining} more ${achievement.achievement.criteria.metric}.`
752
+ );
753
+ }
754
+ const currentMode = await getCurrentMode(userId);
755
+ if (!currentMode) {
756
+ suggestions.push(
757
+ "Try activating a transformation mode! Say 'switch to productivity mode' to get started."
758
+ );
759
+ }
760
+ if (growthData.metrics.toolUses < 5) {
761
+ suggestions.push(
762
+ "You haven't used many tools this period. Try asking me to search the web, browse a page, or run a command!"
763
+ );
764
+ }
765
+ return suggestions;
766
+ }
767
+ function generateSummary(growthData, newAchievements, type) {
768
+ const period = type === "weekly" ? "this week" : "this month";
769
+ let summary = `Here's your ${type} growth report! `;
770
+ if (growthData.metrics.conversations > 0) {
771
+ summary += `You've been active with ${growthData.metrics.conversations} conversations ${period}. `;
772
+ } else {
773
+ summary += `I missed you ${period}! Let's catch up. `;
774
+ }
775
+ if (newAchievements.length > 0) {
776
+ summary += `You unlocked ${newAchievements.length} new achievement${newAchievements.length > 1 ? "s" : ""}! `;
777
+ }
778
+ if (growthData.metrics.newMemories > 0) {
779
+ summary += `I've been learning about you - ${growthData.metrics.newMemories} new memories stored. `;
780
+ }
781
+ return summary.trim();
782
+ }
783
+
784
+ // src/core/scheduler.ts
785
+ var _connection = null;
786
+ var _taskQueue = null;
787
+ var _maintenanceQueue = null;
788
+ function getConnection() {
789
+ if (!_connection) {
790
+ _connection = new Redis2(env.REDIS_URL, {
791
+ maxRetriesPerRequest: null
792
+ });
793
+ }
794
+ return _connection;
795
+ }
796
+ function getTaskQueue() {
797
+ if (!_taskQueue) {
798
+ _taskQueue = new Queue("sentinel-tasks", { connection: getConnection() });
799
+ }
800
+ return _taskQueue;
801
+ }
802
+ function getMaintenanceQueue() {
803
+ if (!_maintenanceQueue) {
804
+ _maintenanceQueue = new Queue("sentinel-maintenance", { connection: getConnection() });
805
+ }
806
+ return _maintenanceQueue;
807
+ }
808
+ var connection2 = new Proxy({}, {
809
+ get(_target, prop) {
810
+ const instance = getConnection();
811
+ const value = instance[prop];
812
+ if (typeof value === "function") return value.bind(instance);
813
+ return value;
814
+ }
815
+ });
816
+ var taskQueue = new Proxy({}, {
817
+ get(_target, prop) {
818
+ const instance = getTaskQueue();
819
+ const value = instance[prop];
820
+ if (typeof value === "function") return value.bind(instance);
821
+ return value;
822
+ }
823
+ });
824
+ var maintenanceQueue = new Proxy({}, {
825
+ get(_target, prop) {
826
+ const instance = getMaintenanceQueue();
827
+ const value = instance[prop];
828
+ if (typeof value === "function") return value.bind(instance);
829
+ return value;
830
+ }
831
+ });
832
+ async function scheduleTask(task, delay) {
833
+ const job = await taskQueue.add("scheduled-task", task, {
834
+ delay,
835
+ removeOnComplete: true,
836
+ removeOnFail: 100
837
+ });
838
+ return job.id || "";
839
+ }
840
+ async function scheduleRecurring(name, task, pattern) {
841
+ await taskQueue.add(name, task, {
842
+ repeat: { pattern },
843
+ removeOnComplete: true
844
+ });
845
+ }
846
+ async function cancelTask(jobId) {
847
+ const job = await taskQueue.getJob(jobId);
848
+ if (job) {
849
+ await job.remove();
850
+ return true;
851
+ }
852
+ return false;
853
+ }
854
+ var worker2 = null;
855
+ var maintenanceWorker = null;
856
+ function startWorker(onTask) {
857
+ if (worker2) return;
858
+ worker2 = new Worker2(
859
+ "sentinel-tasks",
860
+ async (job) => {
861
+ console.log(`[Scheduler] Processing task: ${job.name}`);
862
+ await onTask(job.data);
863
+ },
864
+ { connection: getConnection() }
865
+ );
866
+ worker2.on("completed", (job) => {
867
+ console.log(`[Scheduler] Task completed: ${job.id}`);
868
+ });
869
+ worker2.on("failed", (job, err) => {
870
+ console.error(`[Scheduler] Task failed: ${job?.id}`, err);
871
+ });
872
+ console.log("[Scheduler] Worker started");
873
+ }
874
+ function startMaintenanceWorker() {
875
+ if (maintenanceWorker) return;
876
+ maintenanceWorker = new Worker2(
877
+ "sentinel-maintenance",
878
+ async (job) => {
879
+ console.log(`[Maintenance] Processing: ${job.name}`);
880
+ switch (job.data.type) {
881
+ case "calendar_check":
882
+ if (job.data.userId) {
883
+ await processCalendarTriggers(job.data.userId, []);
884
+ }
885
+ break;
886
+ case "memory_shed":
887
+ if (job.data.userId) {
888
+ const result = await autoShed(job.data.userId);
889
+ console.log(`[Maintenance] Memory shed: archived ${result.archivedCount} memories`);
890
+ }
891
+ break;
892
+ case "growth_report":
893
+ if (job.data.userId) {
894
+ const reportType = job.data.metadata?.reportType;
895
+ if (reportType === "monthly") {
896
+ await generateMonthlyReport(job.data.userId);
897
+ } else {
898
+ await generateWeeklyReport(job.data.userId);
899
+ }
900
+ }
901
+ break;
902
+ case "metrics_flush":
903
+ await flushMetrics();
904
+ break;
905
+ default:
906
+ console.log(`[Maintenance] Unknown task type: ${job.data.type}`);
907
+ }
908
+ },
909
+ { connection: getConnection() }
910
+ );
911
+ maintenanceWorker.on("completed", (job) => {
912
+ console.log(`[Maintenance] Completed: ${job.id}`);
913
+ });
914
+ maintenanceWorker.on("failed", (job, err) => {
915
+ console.error(`[Maintenance] Failed: ${job?.id}`, err);
916
+ });
917
+ console.log("[Maintenance] Worker started");
918
+ }
919
+ function stopWorker() {
920
+ if (worker2) {
921
+ worker2.close();
922
+ worker2 = null;
923
+ }
924
+ }
925
+ function stopMaintenanceWorker() {
926
+ if (maintenanceWorker) {
927
+ maintenanceWorker.close();
928
+ maintenanceWorker = null;
929
+ }
930
+ }
931
+ async function initializeScheduler(onTask) {
932
+ startWorker(onTask);
933
+ startMaintenanceWorker();
934
+ startAgentWorker();
935
+ await setupRecurringJobs();
936
+ console.log("[Scheduler] Initialized");
937
+ }
938
+ async function setupRecurringJobs() {
939
+ await maintenanceQueue.add(
940
+ "calendar-check",
941
+ { type: "calendar_check" },
942
+ {
943
+ repeat: { pattern: "*/15 * * * *" },
944
+ removeOnComplete: true
945
+ }
946
+ );
947
+ await maintenanceQueue.add(
948
+ "metrics-flush",
949
+ { type: "metrics_flush" },
950
+ {
951
+ repeat: { pattern: "*/5 * * * *" },
952
+ removeOnComplete: true
953
+ }
954
+ );
955
+ await maintenanceQueue.add(
956
+ "memory-shed-weekly",
957
+ { type: "memory_shed" },
958
+ {
959
+ repeat: { pattern: "0 3 * * 0" },
960
+ removeOnComplete: true
961
+ }
962
+ );
963
+ await maintenanceQueue.add(
964
+ "quota-reset-monthly",
965
+ { type: "custom", message: "quota_reset" },
966
+ {
967
+ repeat: { pattern: "0 0 1 * *" },
968
+ removeOnComplete: true
969
+ }
970
+ );
971
+ console.log("[Scheduler] Recurring jobs scheduled");
972
+ }
973
+ async function scheduleUserMaintenance(userId, type, options) {
974
+ const task = {
975
+ type,
976
+ userId,
977
+ metadata: options?.reportType ? { reportType: options.reportType } : void 0
978
+ };
979
+ if (options?.pattern) {
980
+ await maintenanceQueue.add(`${type}-${userId}`, task, {
981
+ repeat: { pattern: options.pattern },
982
+ removeOnComplete: true
983
+ });
984
+ } else {
985
+ await maintenanceQueue.add(`${type}-${userId}`, task, {
986
+ removeOnComplete: true
987
+ });
988
+ }
989
+ }
990
+ async function shutdownScheduler() {
991
+ stopWorker();
992
+ stopMaintenanceWorker();
993
+ stopAgentWorker();
994
+ if (_connection) await _connection.quit();
995
+ console.log("[Scheduler] Shutdown complete");
996
+ }
997
+ async function scheduleReminder(message, delayMs, chatId) {
998
+ return scheduleTask(
999
+ {
1000
+ type: "reminder",
1001
+ message,
1002
+ chatId
1003
+ },
1004
+ delayMs
1005
+ );
1006
+ }
1007
+ async function generateBriefing(userId) {
1008
+ if (userId) {
1009
+ try {
1010
+ return await generateDailyBriefing(userId, []);
1011
+ } catch {
1012
+ }
1013
+ }
1014
+ const response = await chat(
1015
+ [
1016
+ {
1017
+ role: "user",
1018
+ content: `Generate a brief morning briefing. Include:
1019
+ 1. A motivational greeting
1020
+ 2. Today's date and day of week
1021
+ 3. A productivity tip
1022
+
1023
+ Keep it concise and uplifting.`
1024
+ }
1025
+ ],
1026
+ "You are a helpful assistant creating a morning briefing."
1027
+ );
1028
+ return response.content;
1029
+ }
1030
+ async function getQueueStats() {
1031
+ const [taskStats, maintenanceStats] = await Promise.all([
1032
+ Promise.all([
1033
+ taskQueue.getWaitingCount(),
1034
+ taskQueue.getActiveCount(),
1035
+ taskQueue.getCompletedCount(),
1036
+ taskQueue.getFailedCount()
1037
+ ]),
1038
+ Promise.all([
1039
+ maintenanceQueue.getWaitingCount(),
1040
+ maintenanceQueue.getActiveCount(),
1041
+ maintenanceQueue.getCompletedCount(),
1042
+ maintenanceQueue.getFailedCount()
1043
+ ])
1044
+ ]);
1045
+ return {
1046
+ tasks: {
1047
+ waiting: taskStats[0],
1048
+ active: taskStats[1],
1049
+ completed: taskStats[2],
1050
+ failed: taskStats[3]
1051
+ },
1052
+ maintenance: {
1053
+ waiting: maintenanceStats[0],
1054
+ active: maintenanceStats[1],
1055
+ completed: maintenanceStats[2],
1056
+ failed: maintenanceStats[3]
1057
+ }
1058
+ };
1059
+ }
1060
+
1061
+ export {
1062
+ connection2 as connection,
1063
+ taskQueue,
1064
+ maintenanceQueue,
1065
+ scheduleTask,
1066
+ scheduleRecurring,
1067
+ cancelTask,
1068
+ startWorker,
1069
+ startMaintenanceWorker,
1070
+ stopWorker,
1071
+ stopMaintenanceWorker,
1072
+ initializeScheduler,
1073
+ scheduleUserMaintenance,
1074
+ shutdownScheduler,
1075
+ scheduleReminder,
1076
+ generateBriefing,
1077
+ getQueueStats
1078
+ };
1079
+ //# sourceMappingURL=chunk-4LVWXUNC.js.map