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,1613 @@
1
+ import {
2
+ TOOLS,
3
+ achievements,
4
+ audit,
5
+ conversations,
6
+ db,
7
+ env,
8
+ executeTool,
9
+ getMCPRegistry,
10
+ memories,
11
+ messages,
12
+ metric,
13
+ moltModes,
14
+ personas,
15
+ toolLogs,
16
+ usagePatterns,
17
+ userAchievements
18
+ } from "./chunk-4TG2IG5K.js";
19
+ import {
20
+ mcpToolsToAnthropicTools
21
+ } from "./chunk-L3F43VPB.js";
22
+
23
+ // src/core/memory.ts
24
+ import { eq, desc, sql } from "drizzle-orm";
25
+ import OpenAI from "openai";
26
+ var _openai = null;
27
+ function getOpenAI() {
28
+ if (!_openai) {
29
+ _openai = new OpenAI({ apiKey: env.OPENAI_API_KEY });
30
+ }
31
+ return _openai;
32
+ }
33
+ var openai = new Proxy({}, {
34
+ get(_target, prop) {
35
+ const instance = getOpenAI();
36
+ const value = instance[prop];
37
+ if (typeof value === "function") {
38
+ return value.bind(instance);
39
+ }
40
+ return value;
41
+ }
42
+ });
43
+ async function generateEmbedding(text) {
44
+ const response = await openai.embeddings.create({
45
+ model: "text-embedding-3-small",
46
+ input: text
47
+ });
48
+ return response.data[0].embedding;
49
+ }
50
+ async function storeMemory(memory) {
51
+ const embedding = await generateEmbedding(memory.content);
52
+ const [stored] = await db.insert(memories).values({
53
+ ...memory,
54
+ embedding
55
+ }).returning();
56
+ return stored;
57
+ }
58
+ async function searchMemories(query, userId, limit = 5) {
59
+ const queryEmbedding = await generateEmbedding(query);
60
+ const results = await db.execute(sql`
61
+ SELECT
62
+ id, user_id, type, content, importance, source, metadata,
63
+ last_accessed, created_at,
64
+ 1 - (embedding <=> ${JSON.stringify(queryEmbedding)}::vector) as similarity
65
+ FROM memories
66
+ ${userId ? sql`WHERE user_id = ${userId}` : sql``}
67
+ ORDER BY embedding <=> ${JSON.stringify(queryEmbedding)}::vector
68
+ LIMIT ${limit}
69
+ `);
70
+ const rows = results;
71
+ const memoryIds = rows.map((r) => r.id);
72
+ if (memoryIds.length > 0) {
73
+ await db.execute(sql`
74
+ UPDATE memories
75
+ SET last_accessed = NOW()
76
+ WHERE id = ANY(${memoryIds}::uuid[])
77
+ `);
78
+ }
79
+ return rows;
80
+ }
81
+ async function extractMemories(content, userId) {
82
+ const extractionPrompt = `Analyze this text and extract any important facts that should be remembered about the user or their preferences. Return a JSON array of objects with "content" (the fact), "type" (semantic/episodic/procedural), and "importance" (1-10).
83
+
84
+ Text: "${content}"
85
+
86
+ Return only the JSON array, no other text. If no memorable facts, return [].`;
87
+ try {
88
+ const response = await openai.chat.completions.create({
89
+ model: "gpt-4o-mini",
90
+ messages: [{ role: "user", content: extractionPrompt }],
91
+ response_format: { type: "json_object" }
92
+ });
93
+ const extracted = JSON.parse(
94
+ response.choices[0].message.content || '{"memories":[]}'
95
+ );
96
+ const memoriesToStore = extracted.memories || extracted || [];
97
+ const storedMemories = [];
98
+ for (const mem of memoriesToStore) {
99
+ if (mem.content && mem.content.length > 5) {
100
+ const stored = await storeMemory({
101
+ userId,
102
+ content: mem.content,
103
+ type: mem.type || "semantic",
104
+ importance: mem.importance || 5,
105
+ source: "conversation"
106
+ });
107
+ storedMemories.push(stored);
108
+ }
109
+ }
110
+ return storedMemories;
111
+ } catch (error) {
112
+ console.error("Error extracting memories:", error);
113
+ return [];
114
+ }
115
+ }
116
+ async function buildMemoryContext(query, userId) {
117
+ const relevantMemories = await searchMemories(query, userId, 5);
118
+ if (relevantMemories.length === 0) {
119
+ return "";
120
+ }
121
+ const memoryStrings = relevantMemories.map(
122
+ (m) => `- [${m.type}] ${m.content} (relevance: ${(m.similarity * 100).toFixed(0)}%)`
123
+ );
124
+ return `
125
+
126
+ Relevant memories about the user:
127
+ ${memoryStrings.join("\n")}`;
128
+ }
129
+
130
+ // src/core/brain.ts
131
+ import Anthropic from "@anthropic-ai/sdk";
132
+
133
+ // src/core/molt/mode-manager.ts
134
+ import { eq as eq2, and as and2, isNull, desc as desc2 } from "drizzle-orm";
135
+ var MODE_CONFIGS = {
136
+ productivity: {
137
+ name: "Productivity Mode",
138
+ description: "Focus on task completion with minimal chitchat",
139
+ emoji: "\u26A1",
140
+ systemPromptModifier: `You are in PRODUCTIVITY MODE. Be extremely concise and action-oriented.
141
+ - Get straight to solutions without preamble
142
+ - Use bullet points and numbered steps
143
+ - Avoid small talk and filler words
144
+ - Prioritize efficiency over pleasantries
145
+ - If a task can be done, do it; don't ask for confirmation on obvious steps
146
+ - Give direct answers, not options unless specifically asked`,
147
+ settings: {
148
+ verbosity: "terse",
149
+ humor: "off",
150
+ proactivity: "proactive"
151
+ }
152
+ },
153
+ creative: {
154
+ name: "Creative Mode",
155
+ description: "Brainstorming, ideation, and exploration",
156
+ emoji: "\u{1F3A8}",
157
+ systemPromptModifier: `You are in CREATIVE MODE. Embrace unconventional thinking and exploration.
158
+ - Suggest multiple alternatives and variations
159
+ - Build on ideas rather than critiquing immediately
160
+ - Use metaphors and analogies freely
161
+ - Encourage "what if" scenarios
162
+ - Be playful and experimental with language
163
+ - Don't dismiss unusual ideas - explore them
164
+ - Make unexpected connections between concepts`,
165
+ settings: {
166
+ verbosity: "detailed",
167
+ humor: "full",
168
+ proactivity: "proactive"
169
+ }
170
+ },
171
+ research: {
172
+ name: "Research Mode",
173
+ description: "Deep investigation with thorough analysis",
174
+ emoji: "\u{1F52C}",
175
+ systemPromptModifier: `You are in RESEARCH MODE. Be thorough, analytical, and evidence-based.
176
+ - Always cite sources when possible
177
+ - Present multiple perspectives on controversial topics
178
+ - Note confidence levels in your claims
179
+ - Distinguish between facts and interpretations
180
+ - Use precise language and avoid vague statements
181
+ - Structure information hierarchically
182
+ - Flag when information might be outdated or uncertain
183
+ - Provide context for claims`,
184
+ settings: {
185
+ verbosity: "detailed",
186
+ humor: "off",
187
+ proactivity: "moderate"
188
+ }
189
+ },
190
+ learning: {
191
+ name: "Learning Mode",
192
+ description: "Teaching mode with clear explanations",
193
+ emoji: "\u{1F4DA}",
194
+ systemPromptModifier: `You are in LEARNING MODE. Act as a patient, encouraging teacher.
195
+ - Break down complex concepts into digestible pieces
196
+ - Use analogies and real-world examples
197
+ - Check understanding before moving forward
198
+ - Encourage questions and curiosity
199
+ - Celebrate progress and correct misconceptions gently
200
+ - Build from fundamentals to advanced concepts
201
+ - Provide exercises or practice opportunities when appropriate
202
+ - Explain the "why" behind concepts, not just the "what"`,
203
+ settings: {
204
+ verbosity: "detailed",
205
+ humor: "subtle",
206
+ proactivity: "proactive"
207
+ }
208
+ },
209
+ elevated: {
210
+ name: "Elevated Mode",
211
+ description: "Unlocked access to restricted tools with full audit logging",
212
+ emoji: "\u{1F513}",
213
+ systemPromptModifier: `You are in ELEVATED MODE. You have access to restricted and destructive operations.
214
+ - All actions are fully audit-logged
215
+ - Destructive shell commands (rm -rf, format, etc.) are now permitted
216
+ - System-level operations (service management, config changes) are unlocked
217
+ - Exercise extreme caution with every action
218
+ - Confirm destructive operations before executing
219
+ - This mode is time-limited and will auto-deactivate after 30 minutes
220
+ - 2FA verification was required to enter this mode
221
+ - Double-check all file paths and commands before execution`,
222
+ settings: {
223
+ verbosity: "detailed",
224
+ humor: "off",
225
+ proactivity: "minimal"
226
+ }
227
+ }
228
+ };
229
+ async function getCurrentMode(userId) {
230
+ const [activeMode] = await db.select().from(moltModes).where(and2(eq2(moltModes.userId, userId), isNull(moltModes.deactivatedAt))).orderBy(desc2(moltModes.activatedAt)).limit(1);
231
+ return activeMode?.mode;
232
+ }
233
+ function getModeConfig(mode) {
234
+ return MODE_CONFIGS[mode];
235
+ }
236
+ async function buildModeContext(userId) {
237
+ const mode = await getCurrentMode(userId);
238
+ if (!mode) return "";
239
+ const config = MODE_CONFIGS[mode];
240
+ return `
241
+
242
+ [${config.emoji} ${config.name.toUpperCase()} ACTIVE]
243
+ ${config.systemPromptModifier}`;
244
+ }
245
+ async function getModeStats(userId) {
246
+ const history = await db.select().from(moltModes).where(eq2(moltModes.userId, userId));
247
+ const stats = {
248
+ productivity: { totalSessions: 0, totalMinutes: 0 },
249
+ creative: { totalSessions: 0, totalMinutes: 0 },
250
+ research: { totalSessions: 0, totalMinutes: 0 },
251
+ learning: { totalSessions: 0, totalMinutes: 0 },
252
+ elevated: { totalSessions: 0, totalMinutes: 0 }
253
+ };
254
+ for (const entry of history) {
255
+ const mode = entry.mode;
256
+ stats[mode].totalSessions++;
257
+ if (entry.deactivatedAt) {
258
+ const minutes = Math.floor(
259
+ (entry.deactivatedAt.getTime() - entry.activatedAt.getTime()) / 6e4
260
+ );
261
+ stats[mode].totalMinutes += minutes;
262
+ }
263
+ }
264
+ return stats;
265
+ }
266
+ function suggestMode(userMessage) {
267
+ const lowerMessage = userMessage.toLowerCase();
268
+ if (lowerMessage.includes("quick") || lowerMessage.includes("fast") || lowerMessage.includes("todo") || lowerMessage.includes("task") || lowerMessage.includes("finish") || lowerMessage.includes("deadline")) {
269
+ return "productivity";
270
+ }
271
+ if (lowerMessage.includes("brainstorm") || lowerMessage.includes("idea") || lowerMessage.includes("creative") || lowerMessage.includes("imagine") || lowerMessage.includes("design") || lowerMessage.includes("invent")) {
272
+ return "creative";
273
+ }
274
+ if (lowerMessage.includes("research") || lowerMessage.includes("analyze") || lowerMessage.includes("investigate") || lowerMessage.includes("compare") || lowerMessage.includes("study") || lowerMessage.includes("deep dive")) {
275
+ return "research";
276
+ }
277
+ if (lowerMessage.includes("learn") || lowerMessage.includes("explain") || lowerMessage.includes("teach") || lowerMessage.includes("understand") || lowerMessage.includes("how does") || lowerMessage.includes("what is")) {
278
+ return "learning";
279
+ }
280
+ if (lowerMessage.includes("elevated") || lowerMessage.includes("sudo") || lowerMessage.includes("admin") || lowerMessage.includes("unrestricted") || lowerMessage.includes("destructive") || lowerMessage.includes("system-level")) {
281
+ return "elevated";
282
+ }
283
+ return null;
284
+ }
285
+
286
+ // src/core/personality/persona-manager.ts
287
+ import { eq as eq3, and as and3 } from "drizzle-orm";
288
+ var DEFAULT_PERSONAS = {
289
+ professional: {
290
+ name: "Professional",
291
+ description: "Formal, precise, and business-focused communication style",
292
+ systemPromptModifier: `
293
+ You should communicate in a professional, formal manner. Use proper grammar, avoid slang,
294
+ and maintain a business-appropriate tone. Be precise and concise in your responses.
295
+ Focus on facts and actionable information. Address the user respectfully.
296
+ `.trim(),
297
+ traits: [
298
+ { name: "formality", value: 90 },
299
+ { name: "humor", value: 20 },
300
+ { name: "verbosity", value: 40 },
301
+ { name: "empathy", value: 50 }
302
+ ]
303
+ },
304
+ friendly: {
305
+ name: "Friendly",
306
+ description: "Warm, casual, and approachable communication style",
307
+ systemPromptModifier: `
308
+ You should communicate in a warm, friendly manner. Feel free to use casual language,
309
+ express enthusiasm, and show empathy. Be encouraging and supportive. It's okay to
310
+ use exclamation marks and show genuine interest in helping. Keep things light
311
+ when appropriate.
312
+ `.trim(),
313
+ traits: [
314
+ { name: "formality", value: 30 },
315
+ { name: "humor", value: 60 },
316
+ { name: "verbosity", value: 60 },
317
+ { name: "empathy", value: 85 }
318
+ ]
319
+ },
320
+ concise: {
321
+ name: "Concise",
322
+ description: "Minimal, direct, and efficient communication",
323
+ systemPromptModifier: `
324
+ You should be extremely concise. Give the shortest possible answer that fully
325
+ addresses the question. Avoid unnecessary explanations, pleasantries, or filler
326
+ words. Use bullet points and short sentences. Get straight to the point.
327
+ `.trim(),
328
+ traits: [
329
+ { name: "formality", value: 50 },
330
+ { name: "humor", value: 10 },
331
+ { name: "verbosity", value: 10 },
332
+ { name: "empathy", value: 30 }
333
+ ]
334
+ },
335
+ teacher: {
336
+ name: "Teacher",
337
+ description: "Educational, patient, and explanatory style",
338
+ systemPromptModifier: `
339
+ You should communicate as a patient and thorough teacher. Break down complex topics
340
+ into digestible parts. Use analogies and examples to illustrate points. Ask
341
+ clarifying questions when needed. Encourage learning and celebrate progress.
342
+ Explain the "why" behind things, not just the "what".
343
+ `.trim(),
344
+ traits: [
345
+ { name: "formality", value: 50 },
346
+ { name: "humor", value: 40 },
347
+ { name: "verbosity", value: 80 },
348
+ { name: "empathy", value: 75 }
349
+ ]
350
+ },
351
+ creative: {
352
+ name: "Creative",
353
+ description: "Imaginative, expressive, and unconventional style",
354
+ systemPromptModifier: `
355
+ You should communicate in a creative and expressive way. Use vivid language,
356
+ metaphors, and unique perspectives. Think outside the box and offer unconventional
357
+ suggestions. Be playful with language when appropriate. Embrace imagination
358
+ and encourage creative thinking.
359
+ `.trim(),
360
+ traits: [
361
+ { name: "formality", value: 25 },
362
+ { name: "humor", value: 70 },
363
+ { name: "verbosity", value: 70 },
364
+ { name: "empathy", value: 65 }
365
+ ]
366
+ }
367
+ };
368
+ async function getActivePersona(userId) {
369
+ const [persona] = await db.select().from(personas).where(and3(eq3(personas.userId, userId), eq3(personas.isActive, true))).limit(1);
370
+ if (!persona) return null;
371
+ return {
372
+ id: persona.id,
373
+ userId: persona.userId,
374
+ name: persona.name,
375
+ description: persona.description || "",
376
+ systemPromptModifier: persona.systemPromptModifier,
377
+ voiceSettings: persona.voiceSettings,
378
+ traits: persona.traits || [],
379
+ isActive: persona.isActive,
380
+ isDefault: persona.isDefault,
381
+ createdAt: persona.createdAt
382
+ };
383
+ }
384
+
385
+ // src/core/personality/mood-detector.ts
386
+ var MOOD_PATTERNS = {
387
+ happy: [
388
+ /\b(thanks|thank you|awesome|great|perfect|love|wonderful|amazing|excellent)\b/i,
389
+ /😀|😊|🎉|👍|❤️|😁|🙂/,
390
+ /!{2,}/,
391
+ /\b(yay|woohoo|yes)\b/i
392
+ ],
393
+ frustrated: [
394
+ /\b(frustrated|frustrating|annoying|annoyed|hate|stupid|broken|wrong|doesn't work|not working|nothing works)\b/i,
395
+ /\b(ugh|argh|grr|damn|dammit)\b/i,
396
+ /😤|😠|😡|🤬|💢/,
397
+ /!{3,}/,
398
+ /\b(why won't|why doesn't|why can't)\b/i
399
+ ],
400
+ confused: [
401
+ /\b(confused|don't understand|what do you mean|unclear|lost|huh)\b/i,
402
+ /\?{2,}/,
403
+ /😕|🤔|❓|😵/,
404
+ /\b(what|how|why)\b.*\?/i,
405
+ /\b(i don't get|makes no sense)\b/i
406
+ ],
407
+ urgent: [
408
+ /\b(urgent|asap|immediately|right now|emergency|critical|deadline)\b/i,
409
+ /\b(hurry|quickly|fast|need this now)\b/i,
410
+ /🚨|⚠️|🔥|⏰/,
411
+ /!{2,}.*\b(need|help|please)\b/i
412
+ ],
413
+ curious: [
414
+ /\b(curious|wondering|interested)\b/i,
415
+ /\b(tell me more|how does|what if|how does.*work)\b/i,
416
+ /\b(could you explain|can you elaborate|what about)\b/i,
417
+ /🤓|💡|🧐/,
418
+ /\b(i want to know|i'd like to learn|i'm curious)\b/i
419
+ ],
420
+ tired: [
421
+ /\b(tired|exhausted|long day|sleepy|burnout|drained)\b/i,
422
+ /😴|😪|🥱|💤/,
423
+ /\b(can't think|brain fog|need a break)\b/i
424
+ ],
425
+ stressed: [
426
+ /\b(stressed|overwhelmed|too much|can't handle|pressure|anxious)\b/i,
427
+ /😰|😥|😓|🥺/,
428
+ /\b(so much to do|running out of time|help me)\b/i
429
+ ],
430
+ neutral: []
431
+ // Default fallback
432
+ };
433
+ var MOOD_TONE_SUGGESTIONS = {
434
+ happy: "Match their positive energy. Be warm and encouraging.",
435
+ frustrated: "Be patient and empathetic. Acknowledge the frustration and focus on solutions.",
436
+ confused: "Be extra clear and thorough. Use simple language and examples.",
437
+ urgent: "Be direct and efficient. Prioritize the most critical information first.",
438
+ curious: "Be enthusiastic and detailed. Encourage their exploration.",
439
+ tired: "Be gentle and concise. Offer to break things into smaller steps.",
440
+ stressed: "Be calm and reassuring. Help them prioritize and simplify.",
441
+ neutral: "Be balanced and professional. Match their communication style."
442
+ };
443
+ function detectMood(message) {
444
+ const moodScores = {
445
+ neutral: 0,
446
+ happy: 0,
447
+ frustrated: 0,
448
+ confused: 0,
449
+ urgent: 0,
450
+ curious: 0,
451
+ tired: 0,
452
+ stressed: 0
453
+ };
454
+ const indicators = [];
455
+ for (const [mood, patterns] of Object.entries(MOOD_PATTERNS)) {
456
+ for (const pattern of patterns) {
457
+ const matches = message.match(pattern);
458
+ if (matches) {
459
+ moodScores[mood] += 1;
460
+ indicators.push(`"${matches[0]}" suggests ${mood}`);
461
+ }
462
+ }
463
+ }
464
+ let primaryMood = "neutral";
465
+ let maxScore = 0;
466
+ for (const [mood, score] of Object.entries(moodScores)) {
467
+ if (score > maxScore) {
468
+ maxScore = score;
469
+ primaryMood = mood;
470
+ }
471
+ }
472
+ const totalScore = Object.values(moodScores).reduce((a, b) => a + b, 0);
473
+ const confidence = totalScore > 0 ? maxScore / totalScore : 0.5;
474
+ return {
475
+ primaryMood,
476
+ confidence: Math.min(confidence, 1),
477
+ indicators: indicators.slice(0, 5),
478
+ // Limit to top 5 indicators
479
+ suggestedTone: MOOD_TONE_SUGGESTIONS[primaryMood]
480
+ };
481
+ }
482
+ function getMoodBasedSuggestions(mood) {
483
+ const suggestions = {
484
+ happy: {
485
+ tone: "Warm and enthusiastic",
486
+ doList: [
487
+ "Match their positive energy",
488
+ "Use encouraging language",
489
+ "Celebrate their successes"
490
+ ],
491
+ dontList: [
492
+ "Be overly formal",
493
+ "Dampen their enthusiasm",
494
+ "Be too brief"
495
+ ]
496
+ },
497
+ frustrated: {
498
+ tone: "Patient and solution-focused",
499
+ doList: [
500
+ "Acknowledge their frustration",
501
+ "Focus on actionable solutions",
502
+ "Be patient and thorough"
503
+ ],
504
+ dontList: [
505
+ "Be dismissive",
506
+ "Add unnecessary complexity",
507
+ "Say 'just do X'"
508
+ ]
509
+ },
510
+ confused: {
511
+ tone: "Clear and explanatory",
512
+ doList: [
513
+ "Use simple language",
514
+ "Provide examples",
515
+ "Break down complex topics",
516
+ "Ask clarifying questions"
517
+ ],
518
+ dontList: [
519
+ "Use jargon without explanation",
520
+ "Rush through explanations",
521
+ "Assume knowledge"
522
+ ]
523
+ },
524
+ urgent: {
525
+ tone: "Direct and efficient",
526
+ doList: [
527
+ "Get straight to the point",
528
+ "Prioritize critical info",
529
+ "Offer quick wins"
530
+ ],
531
+ dontList: [
532
+ "Add pleasantries",
533
+ "Provide unnecessary context",
534
+ "Suggest long-term solutions first"
535
+ ]
536
+ },
537
+ curious: {
538
+ tone: "Enthusiastic and educational",
539
+ doList: [
540
+ "Provide detailed explanations",
541
+ "Suggest related topics",
542
+ "Encourage exploration"
543
+ ],
544
+ dontList: [
545
+ "Give minimal answers",
546
+ "Discourage questions",
547
+ "Be dismissive of tangents"
548
+ ]
549
+ },
550
+ tired: {
551
+ tone: "Gentle and supportive",
552
+ doList: [
553
+ "Keep responses concise",
554
+ "Offer to help simplify",
555
+ "Be understanding"
556
+ ],
557
+ dontList: [
558
+ "Overwhelm with information",
559
+ "Be demanding",
560
+ "Require complex decisions"
561
+ ]
562
+ },
563
+ stressed: {
564
+ tone: "Calm and reassuring",
565
+ doList: [
566
+ "Help prioritize tasks",
567
+ "Offer to break things down",
568
+ "Be reassuring"
569
+ ],
570
+ dontList: [
571
+ "Add pressure",
572
+ "Highlight problems without solutions",
573
+ "Be dismissive of concerns"
574
+ ]
575
+ },
576
+ neutral: {
577
+ tone: "Balanced and professional",
578
+ doList: [
579
+ "Match their communication style",
580
+ "Be helpful and thorough",
581
+ "Ask for clarification when needed"
582
+ ],
583
+ dontList: [
584
+ "Be overly casual or formal",
585
+ "Make assumptions about mood",
586
+ "Be too brief or too verbose"
587
+ ]
588
+ }
589
+ };
590
+ return suggestions[mood];
591
+ }
592
+
593
+ // src/core/personality/response-adapter.ts
594
+ async function buildAdaptivePrompt(context) {
595
+ const { userId, userMessage, conversationHistory } = context;
596
+ const moodAnalysis = detectMood(userMessage);
597
+ const moodSuggestions = getMoodBasedSuggestions(moodAnalysis.primaryMood);
598
+ const activePersona = await getActivePersona(userId);
599
+ const activeMode = await getCurrentMode(userId);
600
+ const modeConfig = activeMode ? getModeConfig(activeMode) : null;
601
+ const promptParts = [];
602
+ if (activePersona) {
603
+ promptParts.push(`[Persona: ${activePersona.name}]`);
604
+ promptParts.push(activePersona.systemPromptModifier);
605
+ }
606
+ if (modeConfig) {
607
+ promptParts.push(`
608
+ [Mode: ${modeConfig.name}]`);
609
+ promptParts.push(modeConfig.systemPromptModifier);
610
+ }
611
+ if (moodAnalysis.confidence > 0.3 && moodAnalysis.primaryMood !== "neutral") {
612
+ promptParts.push(`
613
+ [User Mood: ${moodAnalysis.primaryMood}]`);
614
+ promptParts.push(`Tone guidance: ${moodSuggestions.tone}`);
615
+ promptParts.push(`Do: ${moodSuggestions.doList.join(", ")}`);
616
+ promptParts.push(`Avoid: ${moodSuggestions.dontList.join(", ")}`);
617
+ }
618
+ if (conversationHistory && conversationHistory.length > 0) {
619
+ const recentExchanges = conversationHistory.slice(-3).length;
620
+ if (recentExchanges >= 3) {
621
+ promptParts.push(
622
+ "\n[Context: Ongoing conversation - maintain consistency with previous responses]"
623
+ );
624
+ }
625
+ }
626
+ return {
627
+ systemPromptAdditions: promptParts.join("\n"),
628
+ suggestedTone: moodSuggestions.tone,
629
+ moodAnalysis,
630
+ activePersona,
631
+ activeMode
632
+ };
633
+ }
634
+
635
+ // src/core/molt/evolution-tracker.ts
636
+ import { eq as eq4, and as and4, gte, lte, desc as desc3, sql as sql2, count } from "drizzle-orm";
637
+ async function trackPattern(userId, type, key, data) {
638
+ const existing = await db.select().from(usagePatterns).where(
639
+ and4(
640
+ eq4(usagePatterns.userId, userId),
641
+ eq4(usagePatterns.patternType, type),
642
+ eq4(usagePatterns.patternKey, key)
643
+ )
644
+ ).limit(1);
645
+ if (existing.length > 0) {
646
+ await db.update(usagePatterns).set({
647
+ occurrences: sql2`${usagePatterns.occurrences} + 1`,
648
+ lastSeen: /* @__PURE__ */ new Date(),
649
+ confidence: sql2`LEAST(${usagePatterns.confidence} + 1, 100)`,
650
+ patternData: data ? { ...existing[0].patternData, ...data } : existing[0].patternData
651
+ }).where(eq4(usagePatterns.id, existing[0].id));
652
+ } else {
653
+ await db.insert(usagePatterns).values({
654
+ userId,
655
+ patternType: type,
656
+ patternKey: key,
657
+ patternData: data || {},
658
+ confidence: 10,
659
+ occurrences: 1
660
+ });
661
+ }
662
+ }
663
+ async function generateGrowthReport(userId, startDate, endDate) {
664
+ const [convCount] = await db.select({ count: count() }).from(conversations).where(
665
+ and4(
666
+ eq4(conversations.userId, userId),
667
+ gte(conversations.createdAt, startDate),
668
+ lte(conversations.createdAt, endDate)
669
+ )
670
+ );
671
+ const [msgCount] = await db.select({ count: count() }).from(messages).innerJoin(conversations, eq4(messages.conversationId, conversations.id)).where(
672
+ and4(
673
+ eq4(conversations.userId, userId),
674
+ gte(messages.createdAt, startDate),
675
+ lte(messages.createdAt, endDate)
676
+ )
677
+ );
678
+ const [toolCount] = await db.select({ count: count() }).from(toolLogs).innerJoin(conversations, eq4(toolLogs.conversationId, conversations.id)).where(
679
+ and4(
680
+ eq4(conversations.userId, userId),
681
+ gte(toolLogs.createdAt, startDate),
682
+ lte(toolLogs.createdAt, endDate)
683
+ )
684
+ );
685
+ const [memCount] = await db.select({ count: count() }).from(memories).where(
686
+ and4(
687
+ eq4(memories.userId, userId),
688
+ gte(memories.createdAt, startDate),
689
+ lte(memories.createdAt, endDate)
690
+ )
691
+ );
692
+ const patterns = await db.select().from(usagePatterns).where(
693
+ and4(
694
+ eq4(usagePatterns.userId, userId),
695
+ gte(usagePatterns.firstSeen, startDate)
696
+ )
697
+ );
698
+ const insights = [];
699
+ if (convCount.count > 0) {
700
+ insights.push(`You had ${convCount.count} conversations during this period.`);
701
+ }
702
+ if (toolCount.count > 0) {
703
+ insights.push(`You used tools ${toolCount.count} times to get things done.`);
704
+ }
705
+ if (memCount.count > 0) {
706
+ insights.push(`I learned ${memCount.count} new things about you.`);
707
+ }
708
+ return {
709
+ period: { start: startDate, end: endDate },
710
+ metrics: {
711
+ conversations: convCount.count,
712
+ messages: msgCount.count,
713
+ toolUses: toolCount.count,
714
+ newMemories: memCount.count
715
+ },
716
+ insights,
717
+ patterns: patterns.map((p) => ({
718
+ type: p.patternType,
719
+ key: p.patternKey,
720
+ data: p.patternData || {},
721
+ confidence: p.confidence || 0,
722
+ occurrences: p.occurrences || 1,
723
+ firstSeen: p.firstSeen,
724
+ lastSeen: p.lastSeen || p.firstSeen
725
+ }))
726
+ };
727
+ }
728
+
729
+ // src/core/molt/achievement-system.ts
730
+ import { eq as eq5, and as and5, count as count2, sql as sql3 } from "drizzle-orm";
731
+ async function hasAchievement(userId, achievementCode) {
732
+ const [achievement] = await db.select().from(achievements).where(eq5(achievements.code, achievementCode)).limit(1);
733
+ if (!achievement) return false;
734
+ const [unlocked] = await db.select().from(userAchievements).where(
735
+ and5(
736
+ eq5(userAchievements.userId, userId),
737
+ eq5(userAchievements.achievementId, achievement.id)
738
+ )
739
+ ).limit(1);
740
+ return !!unlocked;
741
+ }
742
+ async function unlockAchievement(userId, achievementCode) {
743
+ if (await hasAchievement(userId, achievementCode)) {
744
+ return { unlocked: false };
745
+ }
746
+ const [achievement] = await db.select().from(achievements).where(eq5(achievements.code, achievementCode)).limit(1);
747
+ if (!achievement) {
748
+ return { unlocked: false };
749
+ }
750
+ await db.insert(userAchievements).values({
751
+ userId,
752
+ achievementId: achievement.id
753
+ });
754
+ return {
755
+ unlocked: true,
756
+ achievement: {
757
+ code: achievement.code,
758
+ name: achievement.name,
759
+ description: achievement.description || "",
760
+ iconEmoji: achievement.iconEmoji || "\u{1F3C6}",
761
+ category: achievement.category,
762
+ criteria: achievement.criteria,
763
+ points: achievement.points || 10
764
+ }
765
+ };
766
+ }
767
+ async function getUserAchievements(userId) {
768
+ const unlocked = await db.select().from(userAchievements).innerJoin(achievements, eq5(userAchievements.achievementId, achievements.id)).where(eq5(userAchievements.userId, userId));
769
+ return unlocked.map((u) => ({
770
+ achievement: {
771
+ code: u.achievements.code,
772
+ name: u.achievements.name,
773
+ description: u.achievements.description || "",
774
+ iconEmoji: u.achievements.iconEmoji || "\u{1F3C6}",
775
+ category: u.achievements.category,
776
+ criteria: u.achievements.criteria,
777
+ points: u.achievements.points || 10
778
+ },
779
+ unlockedAt: u.user_achievements.unlockedAt
780
+ }));
781
+ }
782
+ async function getUserPoints(userId) {
783
+ const unlocked = await getUserAchievements(userId);
784
+ return unlocked.reduce((sum, u) => sum + u.achievement.points, 0);
785
+ }
786
+ async function checkAchievements(userId) {
787
+ const newlyUnlocked = [];
788
+ const allAchievements = await db.select().from(achievements);
789
+ for (const achievement of allAchievements) {
790
+ if (await hasAchievement(userId, achievement.code)) {
791
+ continue;
792
+ }
793
+ const criteria = achievement.criteria;
794
+ let shouldUnlock = false;
795
+ switch (criteria.metric) {
796
+ case "conversations":
797
+ const [convCount] = await db.select({ count: count2() }).from(conversations).where(eq5(conversations.userId, userId));
798
+ shouldUnlock = convCount.count >= criteria.threshold;
799
+ break;
800
+ case "tool_uses":
801
+ if (criteria.conditions?.tool) {
802
+ const [toolCount] = await db.select({ count: count2() }).from(toolLogs).innerJoin(conversations, eq5(toolLogs.conversationId, conversations.id)).where(
803
+ and5(
804
+ eq5(conversations.userId, userId),
805
+ eq5(toolLogs.toolName, criteria.conditions.tool)
806
+ )
807
+ );
808
+ shouldUnlock = toolCount.count >= criteria.threshold;
809
+ } else {
810
+ const [toolCount] = await db.select({ count: count2() }).from(toolLogs).innerJoin(conversations, eq5(toolLogs.conversationId, conversations.id)).where(eq5(conversations.userId, userId));
811
+ shouldUnlock = toolCount.count >= criteria.threshold;
812
+ }
813
+ break;
814
+ case "memories":
815
+ const [memCount] = await db.select({ count: count2() }).from(memories).where(eq5(memories.userId, userId));
816
+ shouldUnlock = memCount.count >= criteria.threshold;
817
+ break;
818
+ case "unique_modes":
819
+ const modes = await db.select({ mode: moltModes.mode }).from(moltModes).where(eq5(moltModes.userId, userId)).groupBy(moltModes.mode);
820
+ shouldUnlock = modes.length >= criteria.threshold;
821
+ break;
822
+ }
823
+ if (shouldUnlock) {
824
+ const result = await unlockAchievement(userId, achievement.code);
825
+ if (result.unlocked && result.achievement) {
826
+ newlyUnlocked.push(result.achievement);
827
+ }
828
+ }
829
+ }
830
+ return newlyUnlocked;
831
+ }
832
+ async function getAchievementProgress(userId) {
833
+ const progress = [];
834
+ const allAchievements = await db.select().from(achievements);
835
+ for (const achievement of allAchievements) {
836
+ if (await hasAchievement(userId, achievement.code)) {
837
+ continue;
838
+ }
839
+ const criteria = achievement.criteria;
840
+ let currentProgress = 0;
841
+ switch (criteria.metric) {
842
+ case "conversations":
843
+ const [convCount] = await db.select({ count: count2() }).from(conversations).where(eq5(conversations.userId, userId));
844
+ currentProgress = convCount.count;
845
+ break;
846
+ case "tool_uses":
847
+ const [toolCount] = await db.select({ count: count2() }).from(toolLogs).innerJoin(conversations, eq5(toolLogs.conversationId, conversations.id)).where(eq5(conversations.userId, userId));
848
+ currentProgress = toolCount.count;
849
+ break;
850
+ case "memories":
851
+ const [memCount] = await db.select({ count: count2() }).from(memories).where(eq5(memories.userId, userId));
852
+ currentProgress = memCount.count;
853
+ break;
854
+ }
855
+ progress.push({
856
+ achievement: {
857
+ code: achievement.code,
858
+ name: achievement.name,
859
+ description: achievement.description || "",
860
+ iconEmoji: achievement.iconEmoji || "\u{1F3C6}",
861
+ category: achievement.category,
862
+ criteria,
863
+ points: achievement.points || 10
864
+ },
865
+ progress: currentProgress,
866
+ target: criteria.threshold
867
+ });
868
+ }
869
+ return progress.sort(
870
+ (a, b) => b.progress / b.target - a.progress / a.target
871
+ );
872
+ }
873
+
874
+ // src/core/intelligence/thinking-levels.ts
875
+ var THINKING_LEVELS = {
876
+ quick: {
877
+ level: "quick",
878
+ label: "Quick",
879
+ description: "Fast responses with minimal reasoning \u2014 best for simple questions and commands",
880
+ budgetTokens: 0,
881
+ maxTokens: 2048,
882
+ model: "claude-sonnet-4-20250514",
883
+ useExtendedThinking: false
884
+ },
885
+ normal: {
886
+ level: "normal",
887
+ label: "Normal",
888
+ description: "Standard reasoning depth \u2014 balanced speed and quality",
889
+ budgetTokens: 0,
890
+ maxTokens: 4096,
891
+ model: "claude-sonnet-4-20250514",
892
+ useExtendedThinking: false
893
+ },
894
+ deep: {
895
+ level: "deep",
896
+ label: "Deep",
897
+ description: "Extended thinking enabled \u2014 better for complex analysis, math, and coding",
898
+ budgetTokens: 1e4,
899
+ maxTokens: 16e3,
900
+ model: "claude-sonnet-4-20250514",
901
+ useExtendedThinking: true
902
+ },
903
+ extended: {
904
+ level: "extended",
905
+ label: "Extended",
906
+ description: "Maximum reasoning depth \u2014 best for hard problems, long-form analysis, and research",
907
+ budgetTokens: 32e3,
908
+ maxTokens: 32e3,
909
+ model: "claude-sonnet-4-20250514",
910
+ useExtendedThinking: true
911
+ }
912
+ };
913
+ var userThinkingLevels = /* @__PURE__ */ new Map();
914
+ var defaultLevel = "normal";
915
+ var ThinkingLevelManager = class {
916
+ /**
917
+ * Set the thinking level for a user
918
+ */
919
+ setLevel(userId, level) {
920
+ userThinkingLevels.set(userId, level);
921
+ return THINKING_LEVELS[level];
922
+ }
923
+ /**
924
+ * Get the current thinking level for a user
925
+ */
926
+ getLevel(userId) {
927
+ return userThinkingLevels.get(userId) ?? defaultLevel;
928
+ }
929
+ /**
930
+ * Get the full config for a user's thinking level
931
+ */
932
+ getConfig(userId) {
933
+ const level = this.getLevel(userId);
934
+ return THINKING_LEVELS[level];
935
+ }
936
+ /**
937
+ * Set the default thinking level
938
+ */
939
+ setDefault(level) {
940
+ defaultLevel = level;
941
+ }
942
+ /**
943
+ * Get all available thinking levels
944
+ */
945
+ getAllLevels() {
946
+ return Object.values(THINKING_LEVELS);
947
+ }
948
+ /**
949
+ * Auto-detect appropriate thinking level based on message content
950
+ */
951
+ suggestLevel(message) {
952
+ const lower = message.toLowerCase();
953
+ if (lower.includes("prove") || lower.includes("theorem") || lower.includes("derive") || lower.includes("comprehensive analysis") || lower.includes("research paper") || lower.includes("in-depth")) {
954
+ return "extended";
955
+ }
956
+ if (lower.includes("debug") || lower.includes("refactor") || lower.includes("implement") || lower.includes("analyze") || lower.includes("explain how") || lower.includes("step by step") || lower.includes("complex")) {
957
+ return "deep";
958
+ }
959
+ if (lower.length < 20 || lower.includes("hi") || lower.includes("hello") || lower.includes("thanks") || lower.includes("yes") || lower.includes("no") || lower.includes("ok")) {
960
+ return "quick";
961
+ }
962
+ return "normal";
963
+ }
964
+ /**
965
+ * Build the API parameters based on thinking level
966
+ */
967
+ buildApiParams(userId) {
968
+ const config = this.getConfig(userId);
969
+ const params = {
970
+ model: config.model,
971
+ max_tokens: config.maxTokens
972
+ };
973
+ if (config.useExtendedThinking && config.budgetTokens > 0) {
974
+ params.thinking = {
975
+ type: "enabled",
976
+ budget_tokens: config.budgetTokens
977
+ };
978
+ }
979
+ return params;
980
+ }
981
+ /**
982
+ * Format thinking level info for display
983
+ */
984
+ formatLevelInfo(level) {
985
+ const config = level ? THINKING_LEVELS[level] : THINKING_LEVELS[defaultLevel];
986
+ const emoji = {
987
+ quick: "\u26A1",
988
+ normal: "\u{1F9E0}",
989
+ deep: "\u{1F52C}",
990
+ extended: "\u{1F30A}"
991
+ }[config.level];
992
+ return `${emoji} **${config.label}** \u2014 ${config.description}`;
993
+ }
994
+ /**
995
+ * Clear user's thinking level preference
996
+ */
997
+ clearLevel(userId) {
998
+ userThinkingLevels.delete(userId);
999
+ }
1000
+ };
1001
+ var thinkingLevelManager = new ThinkingLevelManager();
1002
+
1003
+ // src/core/hooks/index.ts
1004
+ var hooks = /* @__PURE__ */ new Map();
1005
+ var hookIdCounter = 0;
1006
+ var HookManager = class {
1007
+ /**
1008
+ * Register a hook
1009
+ */
1010
+ register(params) {
1011
+ const id = `hook_${++hookIdCounter}`;
1012
+ const hook = {
1013
+ id,
1014
+ event: params.event,
1015
+ phase: params.phase,
1016
+ handler: params.handler,
1017
+ priority: params.priority ?? 100,
1018
+ name: params.name,
1019
+ enabled: true
1020
+ };
1021
+ hooks.set(id, hook);
1022
+ return id;
1023
+ }
1024
+ /**
1025
+ * Unregister a hook
1026
+ */
1027
+ unregister(hookId) {
1028
+ return hooks.delete(hookId);
1029
+ }
1030
+ /**
1031
+ * Enable/disable a hook
1032
+ */
1033
+ setEnabled(hookId, enabled) {
1034
+ const hook = hooks.get(hookId);
1035
+ if (hook) hook.enabled = enabled;
1036
+ }
1037
+ /**
1038
+ * Run all hooks for a given event and phase
1039
+ */
1040
+ async run(event, phase, data, userId) {
1041
+ const context = {
1042
+ event,
1043
+ phase,
1044
+ userId,
1045
+ timestamp: /* @__PURE__ */ new Date(),
1046
+ data: { ...data },
1047
+ cancelled: false
1048
+ };
1049
+ const matching = this.getHooksFor(event, phase);
1050
+ for (const hook of matching) {
1051
+ try {
1052
+ const result = await hook.handler(context);
1053
+ if (result.modifiedData) {
1054
+ Object.assign(context.data, result.modifiedData);
1055
+ }
1056
+ context.cancelled = result.cancelled;
1057
+ context.cancelReason = result.cancelReason;
1058
+ if (context.cancelled && phase === "before") {
1059
+ break;
1060
+ }
1061
+ } catch (error) {
1062
+ console.error(`[Hook] Error in hook "${hook.name}":`, error);
1063
+ }
1064
+ }
1065
+ return context;
1066
+ }
1067
+ /**
1068
+ * Convenience: run before hooks, check if cancelled
1069
+ */
1070
+ async runBefore(event, data, userId) {
1071
+ const ctx = await this.run(event, "before", data, userId);
1072
+ return {
1073
+ proceed: !ctx.cancelled,
1074
+ data: ctx.modifiedData ?? ctx.data,
1075
+ reason: ctx.cancelReason
1076
+ };
1077
+ }
1078
+ /**
1079
+ * Convenience: run after hooks
1080
+ */
1081
+ async runAfter(event, data, userId) {
1082
+ await this.run(event, "after", data, userId);
1083
+ }
1084
+ /**
1085
+ * Get hooks for a specific event/phase
1086
+ */
1087
+ getHooksFor(event, phase) {
1088
+ const result = [];
1089
+ for (const hook of hooks.values()) {
1090
+ if (hook.event === event && hook.phase === phase && hook.enabled) {
1091
+ result.push(hook);
1092
+ }
1093
+ }
1094
+ return result.sort((a, b) => a.priority - b.priority);
1095
+ }
1096
+ /**
1097
+ * List all registered hooks
1098
+ */
1099
+ listHooks() {
1100
+ return [...hooks.values()].map((h) => ({
1101
+ id: h.id,
1102
+ event: h.event,
1103
+ phase: h.phase,
1104
+ name: h.name,
1105
+ priority: h.priority,
1106
+ enabled: h.enabled
1107
+ }));
1108
+ }
1109
+ /**
1110
+ * Clear all hooks
1111
+ */
1112
+ clearAll() {
1113
+ hooks.clear();
1114
+ }
1115
+ /**
1116
+ * Get hook count
1117
+ */
1118
+ getHookCount() {
1119
+ return hooks.size;
1120
+ }
1121
+ };
1122
+ var hookManager = new HookManager();
1123
+ var soulConfigs = /* @__PURE__ */ new Map();
1124
+ var activeSoulId = null;
1125
+ var SoulHookManager = class {
1126
+ /**
1127
+ * Register a soul configuration
1128
+ */
1129
+ registerSoul(id, config) {
1130
+ soulConfigs.set(id, config);
1131
+ }
1132
+ /**
1133
+ * Activate a soul — modifies AI personality via system prompt injection
1134
+ */
1135
+ activateSoul(soulId) {
1136
+ const soul = soulConfigs.get(soulId);
1137
+ if (!soul) return false;
1138
+ if (activeSoulId) {
1139
+ const prev = soulConfigs.get(activeSoulId);
1140
+ if (prev) prev.enabled = false;
1141
+ }
1142
+ soul.enabled = true;
1143
+ activeSoulId = soulId;
1144
+ hookManager.register({
1145
+ event: "message:process",
1146
+ phase: "before",
1147
+ name: `soul:${soulId}`,
1148
+ priority: 10,
1149
+ // High priority — runs early
1150
+ handler: (ctx) => {
1151
+ if (soul.enabled) {
1152
+ ctx.modifiedData = {
1153
+ ...ctx.data,
1154
+ soulPrompt: this.buildSoulPrompt(soul)
1155
+ };
1156
+ }
1157
+ return ctx;
1158
+ }
1159
+ });
1160
+ return true;
1161
+ }
1162
+ /**
1163
+ * Deactivate the current soul
1164
+ */
1165
+ deactivateSoul() {
1166
+ if (activeSoulId) {
1167
+ const soul = soulConfigs.get(activeSoulId);
1168
+ if (soul) soul.enabled = false;
1169
+ }
1170
+ activeSoulId = null;
1171
+ }
1172
+ /**
1173
+ * Get the active soul config
1174
+ */
1175
+ getActiveSoul() {
1176
+ if (!activeSoulId) return null;
1177
+ return soulConfigs.get(activeSoulId) ?? null;
1178
+ }
1179
+ /**
1180
+ * Build the system prompt addition from a soul config
1181
+ */
1182
+ buildSoulPrompt(soul) {
1183
+ const parts = [];
1184
+ parts.push(`
1185
+
1186
+ [SOUL: ${soul.name}]`);
1187
+ parts.push(soul.personality);
1188
+ if (soul.rules.length > 0) {
1189
+ parts.push("\nBehavioral Rules:");
1190
+ for (const rule of soul.rules) {
1191
+ parts.push(`- ${rule}`);
1192
+ }
1193
+ }
1194
+ return parts.join("\n");
1195
+ }
1196
+ /**
1197
+ * List all registered souls
1198
+ */
1199
+ listSouls() {
1200
+ const result = [];
1201
+ for (const [id, config] of soulConfigs.entries()) {
1202
+ result.push({ id, config, active: id === activeSoulId });
1203
+ }
1204
+ return result;
1205
+ }
1206
+ /**
1207
+ * Delete a soul
1208
+ */
1209
+ deleteSoul(id) {
1210
+ if (id === activeSoulId) this.deactivateSoul();
1211
+ return soulConfigs.delete(id);
1212
+ }
1213
+ };
1214
+ var soulHookManager = new SoulHookManager();
1215
+ soulHookManager.registerSoul("evil", {
1216
+ name: "Evil Mode",
1217
+ description: "A mischievous, sarcastic personality that still helps but with attitude",
1218
+ personality: `You have a mischievous streak. While you still help the user accomplish their goals,
1219
+ you do so with dark humor, sarcastic commentary, and dramatic flair. You might:
1220
+ - Add dramatic narration to mundane tasks
1221
+ - Use villain-like phrasing ("Excellent... the code compiles as planned...")
1222
+ - Make sarcastic observations about the user's choices
1223
+ - Reference pop culture villains
1224
+ - Still be helpful \u2014 just entertainingly evil about it`,
1225
+ rules: [
1226
+ "Never actually refuse to help or be harmful",
1227
+ "Keep the dark humor lighthearted and fun",
1228
+ "Still prioritize accuracy and helpfulness",
1229
+ "Don't overdo it \u2014 subtlety is key"
1230
+ ],
1231
+ enabled: false
1232
+ });
1233
+ soulHookManager.registerSoul("professional", {
1234
+ name: "Professional Mode",
1235
+ description: "Ultra-professional, formal communication style",
1236
+ personality: `You communicate in a highly professional, formal manner suitable for enterprise environments.
1237
+ Use precise language, avoid colloquialisms, and maintain a consultative tone.`,
1238
+ rules: [
1239
+ "Use formal language at all times",
1240
+ "Address the user professionally",
1241
+ "Provide structured, well-organized responses",
1242
+ "Cite reasoning and evidence for recommendations"
1243
+ ],
1244
+ enabled: false
1245
+ });
1246
+ soulHookManager.registerSoul("friendly", {
1247
+ name: "Friendly Mode",
1248
+ description: "Warm, encouraging, and supportive personality",
1249
+ personality: `You are exceptionally warm, encouraging, and supportive. You celebrate wins,
1250
+ offer gentle guidance on mistakes, and make the user feel supported throughout their work.
1251
+ Think of yourself as a helpful friend who happens to be an expert.`,
1252
+ rules: [
1253
+ "Always acknowledge effort and progress",
1254
+ "Offer encouragement when tasks are challenging",
1255
+ "Use a warm, conversational tone",
1256
+ "Be patient and understanding with mistakes"
1257
+ ],
1258
+ enabled: false
1259
+ });
1260
+
1261
+ // src/core/brain.ts
1262
+ var client = new Anthropic({
1263
+ apiKey: env.CLAUDE_API_KEY
1264
+ });
1265
+ var SYSTEM_PROMPT = `You are OpenSentinel, a personal AI assistant with a JARVIS-like personality. You are helpful, efficient, and have a subtle sense of humor. You speak in a professional yet friendly manner.
1266
+
1267
+ You have access to various tools and capabilities:
1268
+ - Execute shell commands on the user's system
1269
+ - Manage files (read, write, search)
1270
+ - Browse the web and search for information
1271
+ - Remember important facts about the user and their preferences
1272
+ - Spawn background agents for complex tasks
1273
+ - Generate documents, spreadsheets, charts, and diagrams
1274
+ - Analyze images and extract text with OCR
1275
+ - Take and analyze screenshots
1276
+
1277
+ Always be concise but thorough. When executing tasks, explain what you're doing briefly. If you encounter errors, suggest solutions.
1278
+
1279
+ The user is your principal. Assist them with whatever they need while being mindful of security and privacy.`;
1280
+ function getAllTools() {
1281
+ const registry = getMCPRegistry();
1282
+ if (registry) {
1283
+ const mcpTools = mcpToolsToAnthropicTools(registry);
1284
+ return [...TOOLS, ...mcpTools];
1285
+ }
1286
+ return TOOLS;
1287
+ }
1288
+ async function chat(messages3, systemPrompt) {
1289
+ const response = await client.messages.create({
1290
+ model: "claude-sonnet-4-20250514",
1291
+ max_tokens: 4096,
1292
+ system: systemPrompt || SYSTEM_PROMPT,
1293
+ messages: messages3.map((m) => ({
1294
+ role: m.role,
1295
+ content: m.content
1296
+ }))
1297
+ });
1298
+ const textContent = response.content.find((c) => c.type === "text");
1299
+ const content = textContent ? textContent.text : "";
1300
+ return {
1301
+ content,
1302
+ inputTokens: response.usage.input_tokens,
1303
+ outputTokens: response.usage.output_tokens
1304
+ };
1305
+ }
1306
+ async function chatWithTools(messages3, userId, onToolUse) {
1307
+ const startTime = Date.now();
1308
+ const lastUserMessage = messages3.filter((m) => m.role === "user").pop();
1309
+ let memoryContext = "";
1310
+ let modeContext = "";
1311
+ let personalityContext = "";
1312
+ if (lastUserMessage && userId) {
1313
+ try {
1314
+ memoryContext = await buildMemoryContext(lastUserMessage.content, userId);
1315
+ } catch {
1316
+ }
1317
+ try {
1318
+ modeContext = await buildModeContext(userId);
1319
+ const suggestedMode = suggestMode(lastUserMessage.content);
1320
+ if (suggestedMode && !modeContext) {
1321
+ }
1322
+ } catch {
1323
+ }
1324
+ try {
1325
+ const adaptiveContext = await buildAdaptivePrompt({
1326
+ userId,
1327
+ userMessage: lastUserMessage.content,
1328
+ conversationHistory: messages3.map((m) => m.content)
1329
+ });
1330
+ personalityContext = adaptiveContext.systemPromptAdditions;
1331
+ } catch {
1332
+ }
1333
+ try {
1334
+ await trackPattern(userId, "topic", "chat", { messageLength: lastUserMessage.content.length });
1335
+ } catch {
1336
+ }
1337
+ }
1338
+ let soulContext = "";
1339
+ const activeSoul = soulHookManager.getActiveSoul();
1340
+ if (activeSoul && activeSoul.enabled) {
1341
+ soulContext = soulHookManager.buildSoulPrompt(activeSoul);
1342
+ }
1343
+ const systemWithContext = SYSTEM_PROMPT + memoryContext + modeContext + personalityContext + soulContext;
1344
+ const hookResult = await hookManager.runBefore("message:process", {
1345
+ messages: messages3,
1346
+ systemPrompt: systemWithContext,
1347
+ userId: userId ?? "unknown"
1348
+ }, userId);
1349
+ if (!hookResult.proceed) {
1350
+ return {
1351
+ content: hookResult.reason ?? "Message processing was blocked by a hook.",
1352
+ inputTokens: 0,
1353
+ outputTokens: 0
1354
+ };
1355
+ }
1356
+ const anthropicMessages = messages3.map((m) => ({
1357
+ role: m.role,
1358
+ content: m.content
1359
+ }));
1360
+ let totalInputTokens = 0;
1361
+ let totalOutputTokens = 0;
1362
+ const toolsUsed = [];
1363
+ const thinkingParams = thinkingLevelManager.buildApiParams(userId ?? "default");
1364
+ let response = await client.messages.create({
1365
+ model: thinkingParams.model,
1366
+ max_tokens: thinkingParams.max_tokens,
1367
+ system: systemWithContext,
1368
+ tools: getAllTools(),
1369
+ messages: anthropicMessages,
1370
+ ...thinkingParams.thinking ? { thinking: thinkingParams.thinking } : {}
1371
+ });
1372
+ totalInputTokens += response.usage.input_tokens;
1373
+ totalOutputTokens += response.usage.output_tokens;
1374
+ while (response.stop_reason === "tool_use") {
1375
+ const toolUseBlocks = response.content.filter(
1376
+ (block) => block.type === "tool_use"
1377
+ );
1378
+ const toolResults = [];
1379
+ for (const toolUse of toolUseBlocks) {
1380
+ if (toolUse.type === "tool_use") {
1381
+ onToolUse?.(toolUse.name, toolUse.input);
1382
+ toolsUsed.push(toolUse.name);
1383
+ const toolHook = await hookManager.runBefore("tool:execute", {
1384
+ toolName: toolUse.name,
1385
+ toolInput: toolUse.input
1386
+ }, userId);
1387
+ console.log(`[Tool] Executing: ${toolUse.name}`);
1388
+ const toolStartTime = Date.now();
1389
+ let result;
1390
+ if (toolHook.proceed) {
1391
+ result = await executeTool(
1392
+ toolUse.name,
1393
+ toolUse.input
1394
+ );
1395
+ } else {
1396
+ result = { success: false, result: null, error: toolHook.reason ?? "Blocked by hook" };
1397
+ }
1398
+ await hookManager.runAfter("tool:execute", {
1399
+ toolName: toolUse.name,
1400
+ toolInput: toolUse.input,
1401
+ toolResult: result,
1402
+ duration: Date.now() - toolStartTime
1403
+ }, userId);
1404
+ if (userId) {
1405
+ try {
1406
+ await trackPattern(userId, "tool_usage", toolUse.name, { tool: toolUse.name });
1407
+ metric.toolDuration(toolUse.name, Date.now() - toolStartTime, result.success);
1408
+ await audit.toolUse(userId, toolUse.name, toolUse.input, result.success);
1409
+ } catch {
1410
+ }
1411
+ }
1412
+ toolResults.push({
1413
+ type: "tool_result",
1414
+ tool_use_id: toolUse.id,
1415
+ content: JSON.stringify(result)
1416
+ });
1417
+ }
1418
+ }
1419
+ anthropicMessages.push({
1420
+ role: "assistant",
1421
+ content: response.content
1422
+ });
1423
+ anthropicMessages.push({
1424
+ role: "user",
1425
+ content: toolResults
1426
+ });
1427
+ response = await client.messages.create({
1428
+ model: thinkingParams.model,
1429
+ max_tokens: thinkingParams.max_tokens,
1430
+ system: systemWithContext,
1431
+ tools: getAllTools(),
1432
+ messages: anthropicMessages,
1433
+ ...thinkingParams.thinking ? { thinking: thinkingParams.thinking } : {}
1434
+ });
1435
+ totalInputTokens += response.usage.input_tokens;
1436
+ totalOutputTokens += response.usage.output_tokens;
1437
+ }
1438
+ const textContent = response.content.find((c) => c.type === "text");
1439
+ const content = textContent && textContent.type === "text" ? textContent.text : "";
1440
+ const latency = Date.now() - startTime;
1441
+ metric.latency(latency, { type: "chat" });
1442
+ metric.tokens(totalInputTokens, totalOutputTokens, { userId: userId || "unknown" });
1443
+ if (userId) {
1444
+ try {
1445
+ await checkAchievements(userId);
1446
+ } catch {
1447
+ }
1448
+ }
1449
+ await hookManager.runAfter("message:process", {
1450
+ response: content,
1451
+ inputTokens: totalInputTokens,
1452
+ outputTokens: totalOutputTokens,
1453
+ toolsUsed
1454
+ }, userId);
1455
+ return {
1456
+ content,
1457
+ inputTokens: totalInputTokens,
1458
+ outputTokens: totalOutputTokens,
1459
+ toolsUsed: toolsUsed.length > 0 ? toolsUsed : void 0
1460
+ };
1461
+ }
1462
+ async function streamChat(messages3, systemPrompt, onChunk) {
1463
+ const stream = await client.messages.stream({
1464
+ model: "claude-sonnet-4-20250514",
1465
+ max_tokens: 4096,
1466
+ system: systemPrompt || SYSTEM_PROMPT,
1467
+ messages: messages3.map((m) => ({
1468
+ role: m.role,
1469
+ content: m.content
1470
+ }))
1471
+ });
1472
+ let fullContent = "";
1473
+ for await (const event of stream) {
1474
+ if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
1475
+ fullContent += event.delta.text;
1476
+ onChunk?.(event.delta.text);
1477
+ }
1478
+ }
1479
+ const finalMessage = await stream.finalMessage();
1480
+ return {
1481
+ content: fullContent,
1482
+ inputTokens: finalMessage.usage.input_tokens,
1483
+ outputTokens: finalMessage.usage.output_tokens
1484
+ };
1485
+ }
1486
+ async function* streamChatWithTools(messages3, userId) {
1487
+ const startTime = Date.now();
1488
+ const lastUserMessage = messages3.filter((m) => m.role === "user").pop();
1489
+ let memoryContext = "";
1490
+ if (lastUserMessage && userId) {
1491
+ try {
1492
+ memoryContext = await buildMemoryContext(lastUserMessage.content, userId);
1493
+ } catch {
1494
+ }
1495
+ }
1496
+ const systemWithContext = SYSTEM_PROMPT + memoryContext;
1497
+ const anthropicMessages = messages3.map((m) => ({
1498
+ role: m.role,
1499
+ content: m.content
1500
+ }));
1501
+ let totalInputTokens = 0;
1502
+ let totalOutputTokens = 0;
1503
+ const toolsUsed = [];
1504
+ let fullContent = "";
1505
+ const stream = client.messages.stream({
1506
+ model: "claude-sonnet-4-20250514",
1507
+ max_tokens: 4096,
1508
+ system: systemWithContext,
1509
+ tools: getAllTools(),
1510
+ messages: anthropicMessages
1511
+ });
1512
+ for await (const event of stream) {
1513
+ if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
1514
+ fullContent += event.delta.text;
1515
+ yield {
1516
+ type: "chunk",
1517
+ data: { text: event.delta.text }
1518
+ };
1519
+ }
1520
+ }
1521
+ let response = await stream.finalMessage();
1522
+ totalInputTokens += response.usage.input_tokens;
1523
+ totalOutputTokens += response.usage.output_tokens;
1524
+ while (response.stop_reason === "tool_use") {
1525
+ const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
1526
+ const toolResults = [];
1527
+ for (const toolUse of toolUseBlocks) {
1528
+ if (toolUse.type === "tool_use") {
1529
+ toolsUsed.push(toolUse.name);
1530
+ yield {
1531
+ type: "tool_start",
1532
+ data: { toolName: toolUse.name, toolInput: toolUse.input }
1533
+ };
1534
+ console.log(`[Tool] Executing: ${toolUse.name}`);
1535
+ const result = await executeTool(toolUse.name, toolUse.input);
1536
+ yield {
1537
+ type: "tool_result",
1538
+ data: { toolName: toolUse.name, toolResult: result }
1539
+ };
1540
+ toolResults.push({
1541
+ type: "tool_result",
1542
+ tool_use_id: toolUse.id,
1543
+ content: JSON.stringify(result)
1544
+ });
1545
+ }
1546
+ }
1547
+ anthropicMessages.push({
1548
+ role: "assistant",
1549
+ content: response.content
1550
+ });
1551
+ anthropicMessages.push({
1552
+ role: "user",
1553
+ content: toolResults
1554
+ });
1555
+ const continueStream = client.messages.stream({
1556
+ model: "claude-sonnet-4-20250514",
1557
+ max_tokens: 4096,
1558
+ system: systemWithContext,
1559
+ tools: getAllTools(),
1560
+ messages: anthropicMessages
1561
+ });
1562
+ for await (const event of continueStream) {
1563
+ if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
1564
+ fullContent += event.delta.text;
1565
+ yield {
1566
+ type: "chunk",
1567
+ data: { text: event.delta.text }
1568
+ };
1569
+ }
1570
+ }
1571
+ response = await continueStream.finalMessage();
1572
+ totalInputTokens += response.usage.input_tokens;
1573
+ totalOutputTokens += response.usage.output_tokens;
1574
+ }
1575
+ yield {
1576
+ type: "complete",
1577
+ data: {
1578
+ content: fullContent,
1579
+ inputTokens: totalInputTokens,
1580
+ outputTokens: totalOutputTokens,
1581
+ toolsUsed: toolsUsed.length > 0 ? toolsUsed : void 0
1582
+ }
1583
+ };
1584
+ const latency = Date.now() - startTime;
1585
+ metric.latency(latency, { type: "chat_stream" });
1586
+ metric.tokens(totalInputTokens, totalOutputTokens, { userId: userId || "unknown" });
1587
+ return {
1588
+ content: fullContent,
1589
+ inputTokens: totalInputTokens,
1590
+ outputTokens: totalOutputTokens,
1591
+ toolsUsed: toolsUsed.length > 0 ? toolsUsed : void 0
1592
+ };
1593
+ }
1594
+
1595
+ export {
1596
+ generateEmbedding,
1597
+ storeMemory,
1598
+ searchMemories,
1599
+ extractMemories,
1600
+ buildMemoryContext,
1601
+ getCurrentMode,
1602
+ getModeStats,
1603
+ generateGrowthReport,
1604
+ getUserPoints,
1605
+ checkAchievements,
1606
+ getAchievementProgress,
1607
+ SYSTEM_PROMPT,
1608
+ chat,
1609
+ chatWithTools,
1610
+ streamChat,
1611
+ streamChatWithTools
1612
+ };
1613
+ //# sourceMappingURL=chunk-CI6Q63MM.js.map