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.
- package/LICENSE +21 -0
- package/README.md +283 -0
- package/dist/bot-KJ26BG56.js +15 -0
- package/dist/bot-KJ26BG56.js.map +1 -0
- package/dist/charts-MMXM6BWW.js +241 -0
- package/dist/charts-MMXM6BWW.js.map +1 -0
- package/dist/chunk-4LVWXUNC.js +1079 -0
- package/dist/chunk-4LVWXUNC.js.map +1 -0
- package/dist/chunk-4TG2IG5K.js +5249 -0
- package/dist/chunk-4TG2IG5K.js.map +1 -0
- package/dist/chunk-6DRDKB45.js +251 -0
- package/dist/chunk-6DRDKB45.js.map +1 -0
- package/dist/chunk-6SNHU3CY.js +123 -0
- package/dist/chunk-6SNHU3CY.js.map +1 -0
- package/dist/chunk-CI6Q63MM.js +1613 -0
- package/dist/chunk-CI6Q63MM.js.map +1 -0
- package/dist/chunk-CQ4JURG7.js +57 -0
- package/dist/chunk-CQ4JURG7.js.map +1 -0
- package/dist/chunk-F6QUZQGI.js +51 -0
- package/dist/chunk-F6QUZQGI.js.map +1 -0
- package/dist/chunk-GK3E2I7A.js +216 -0
- package/dist/chunk-GK3E2I7A.js.map +1 -0
- package/dist/chunk-GUBEEYDW.js +211 -0
- package/dist/chunk-GUBEEYDW.js.map +1 -0
- package/dist/chunk-GVJVEWHI.js +29 -0
- package/dist/chunk-GVJVEWHI.js.map +1 -0
- package/dist/chunk-HH2HBTQM.js +806 -0
- package/dist/chunk-HH2HBTQM.js.map +1 -0
- package/dist/chunk-JXUP2X7V.js +129 -0
- package/dist/chunk-JXUP2X7V.js.map +1 -0
- package/dist/chunk-KHNYJY2Z.js +178 -0
- package/dist/chunk-KHNYJY2Z.js.map +1 -0
- package/dist/chunk-L3F43VPB.js +652 -0
- package/dist/chunk-L3F43VPB.js.map +1 -0
- package/dist/chunk-L3PDU3XN.js +803 -0
- package/dist/chunk-L3PDU3XN.js.map +1 -0
- package/dist/chunk-NSBPE2FW.js +17 -0
- package/dist/chunk-NSBPE2FW.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +52 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/setup.d.ts +9 -0
- package/dist/commands/setup.js +374 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/start.d.ts +8 -0
- package/dist/commands/start.js +27 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +8 -0
- package/dist/commands/status.js +57 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.d.ts +8 -0
- package/dist/commands/stop.js +37 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/utils.d.ts +50 -0
- package/dist/commands/utils.js +36 -0
- package/dist/commands/utils.js.map +1 -0
- package/dist/discord-ZOJFTVTB.js +49 -0
- package/dist/discord-ZOJFTVTB.js.map +1 -0
- package/dist/imessage-JFRB6EJ7.js +14 -0
- package/dist/imessage-JFRB6EJ7.js.map +1 -0
- package/dist/lib.d.ts +855 -0
- package/dist/lib.js +274 -0
- package/dist/lib.js.map +1 -0
- package/dist/mcp-LS7Q3Z5W.js +30 -0
- package/dist/mcp-LS7Q3Z5W.js.map +1 -0
- package/dist/scheduler-EZ7CZMCS.js +42 -0
- package/dist/scheduler-EZ7CZMCS.js.map +1 -0
- package/dist/signal-T3MCSULM.js +14 -0
- package/dist/signal-T3MCSULM.js.map +1 -0
- package/dist/slack-N2M4FHAJ.js +54 -0
- package/dist/slack-N2M4FHAJ.js.map +1 -0
- package/dist/src-K7GASHRH.js +430 -0
- package/dist/src-K7GASHRH.js.map +1 -0
- package/dist/tools-24GZHYRF.js +16 -0
- package/dist/tools-24GZHYRF.js.map +1 -0
- package/dist/whatsapp-VCRUPAO5.js +14 -0
- package/dist/whatsapp-VCRUPAO5.js.map +1 -0
- package/drizzle/0000_chilly_shinobi_shaw.sql +75 -0
- package/drizzle/0001_freezing_shape.sql +274 -0
- package/drizzle/meta/0000_snapshot.json +529 -0
- package/drizzle/meta/0001_snapshot.json +2576 -0
- package/drizzle/meta/_journal.json +20 -0
- package/package.json +98 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/memory.ts","../src/core/brain.ts","../src/core/molt/mode-manager.ts","../src/core/personality/persona-manager.ts","../src/core/personality/mood-detector.ts","../src/core/personality/response-adapter.ts","../src/core/molt/evolution-tracker.ts","../src/core/molt/achievement-system.ts","../src/core/intelligence/thinking-levels.ts","../src/core/hooks/index.ts"],"sourcesContent":["import { db, memories, type NewMemory, type Memory } from \"../db\";\nimport { eq, desc, sql, and } from \"drizzle-orm\";\nimport OpenAI from \"openai\";\nimport { env } from \"../config/env\";\n\n// Lazy OpenAI client — created on first use\nlet _openai: OpenAI | null = null;\nfunction getOpenAI(): OpenAI {\n if (!_openai) {\n _openai = new OpenAI({ apiKey: env.OPENAI_API_KEY });\n }\n return _openai;\n}\nconst openai = new Proxy({} as OpenAI, {\n get(_target, prop) {\n const instance = getOpenAI();\n const value = (instance as any)[prop];\n if (typeof value === \"function\") {\n return value.bind(instance);\n }\n return value;\n },\n});\n\n// Generate embedding for text using OpenAI\nexport async function generateEmbedding(text: string): Promise<number[]> {\n const response = await openai.embeddings.create({\n model: \"text-embedding-3-small\",\n input: text,\n });\n return response.data[0].embedding;\n}\n\n// Store a new memory with embedding\nexport async function storeMemory(\n memory: Omit<NewMemory, \"embedding\">\n): Promise<Memory> {\n const embedding = await generateEmbedding(memory.content);\n\n const [stored] = await db\n .insert(memories)\n .values({\n ...memory,\n embedding,\n })\n .returning();\n\n return stored;\n}\n\n// Search memories by semantic similarity\nexport async function searchMemories(\n query: string,\n userId?: string,\n limit = 5\n): Promise<Memory[]> {\n const queryEmbedding = await generateEmbedding(query);\n\n // Use pgvector cosine similarity search\n const results = await db.execute(sql`\n SELECT\n id, user_id, type, content, importance, source, metadata,\n last_accessed, created_at,\n 1 - (embedding <=> ${JSON.stringify(queryEmbedding)}::vector) as similarity\n FROM memories\n ${userId ? sql`WHERE user_id = ${userId}` : sql``}\n ORDER BY embedding <=> ${JSON.stringify(queryEmbedding)}::vector\n LIMIT ${limit}\n `);\n\n // Update last_accessed for retrieved memories\n const rows = results as any[];\n const memoryIds = rows.map((r: any) => r.id);\n if (memoryIds.length > 0) {\n await db.execute(sql`\n UPDATE memories\n SET last_accessed = NOW()\n WHERE id = ANY(${memoryIds}::uuid[])\n `);\n }\n\n return rows as Memory[];\n}\n\n// Get recent memories for a user\nexport async function getRecentMemories(\n userId: string,\n limit = 10\n): Promise<Memory[]> {\n return db\n .select()\n .from(memories)\n .where(eq(memories.userId, userId))\n .orderBy(desc(memories.createdAt))\n .limit(limit);\n}\n\n// Extract and store memories from a conversation turn\nexport async function extractMemories(\n content: string,\n userId?: string\n): Promise<Memory[]> {\n // Use Claude to extract memorable facts\n 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).\n\nText: \"${content}\"\n\nReturn only the JSON array, no other text. If no memorable facts, return [].`;\n\n try {\n const response = await openai.chat.completions.create({\n model: \"gpt-4o-mini\",\n messages: [{ role: \"user\", content: extractionPrompt }],\n response_format: { type: \"json_object\" },\n });\n\n const extracted = JSON.parse(\n response.choices[0].message.content || '{\"memories\":[]}'\n );\n const memoriesToStore = extracted.memories || extracted || [];\n\n const storedMemories: Memory[] = [];\n for (const mem of memoriesToStore) {\n if (mem.content && mem.content.length > 5) {\n const stored = await storeMemory({\n userId,\n content: mem.content,\n type: mem.type || \"semantic\",\n importance: mem.importance || 5,\n source: \"conversation\",\n });\n storedMemories.push(stored);\n }\n }\n\n return storedMemories;\n } catch (error) {\n console.error(\"Error extracting memories:\", error);\n return [];\n }\n}\n\n// Build context string from relevant memories\nexport async function buildMemoryContext(\n query: string,\n userId?: string\n): Promise<string> {\n const relevantMemories = await searchMemories(query, userId, 5);\n\n if (relevantMemories.length === 0) {\n return \"\";\n }\n\n const memoryStrings = relevantMemories.map(\n (m: any) => `- [${m.type}] ${m.content} (relevance: ${(m.similarity * 100).toFixed(0)}%)`\n );\n\n return `\\n\\nRelevant memories about the user:\\n${memoryStrings.join(\"\\n\")}`;\n}\n","import Anthropic from \"@anthropic-ai/sdk\";\nimport type {\n MessageParam,\n ContentBlockParam,\n ToolResultBlockParam,\n} from \"@anthropic-ai/sdk/resources/messages\";\nimport type { Tool } from \"@anthropic-ai/sdk/resources/messages\";\nimport { env } from \"../config/env\";\nimport { TOOLS, executeTool, getMCPRegistry } from \"../tools\";\nimport { mcpToolsToAnthropicTools } from \"./mcp\";\nimport { buildMemoryContext } from \"./memory\";\nimport { buildModeContext, suggestMode, activateMode } from \"./molt/mode-manager\";\nimport { buildAdaptivePrompt } from \"./personality/response-adapter\";\nimport { getActivePersona } from \"./personality/persona-manager\";\nimport { detectMood } from \"./personality/mood-detector\";\nimport { trackPattern } from \"./molt/evolution-tracker\";\nimport { checkAchievements } from \"./molt/achievement-system\";\nimport { metric } from \"./observability/metrics\";\nimport { audit } from \"./security/audit-logger\";\nimport { thinkingLevelManager } from \"./intelligence/thinking-levels\";\nimport { hookManager, soulHookManager } from \"./hooks\";\n\nconst client = new Anthropic({\n apiKey: env.CLAUDE_API_KEY,\n});\n\nconst 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.\n\nYou have access to various tools and capabilities:\n- Execute shell commands on the user's system\n- Manage files (read, write, search)\n- Browse the web and search for information\n- Remember important facts about the user and their preferences\n- Spawn background agents for complex tasks\n- Generate documents, spreadsheets, charts, and diagrams\n- Analyze images and extract text with OCR\n- Take and analyze screenshots\n\nAlways be concise but thorough. When executing tasks, explain what you're doing briefly. If you encounter errors, suggest solutions.\n\nThe user is your principal. Assist them with whatever they need while being mindful of security and privacy.`;\n\nexport interface Message {\n role: \"user\" | \"assistant\";\n content: string;\n}\n\nexport interface BrainResponse {\n content: string;\n inputTokens: number;\n outputTokens: number;\n toolsUsed?: string[];\n}\n\n// Get all available tools (native + MCP)\nfunction getAllTools(): Tool[] {\n const registry = getMCPRegistry();\n if (registry) {\n const mcpTools = mcpToolsToAnthropicTools(registry);\n return [...TOOLS, ...mcpTools];\n }\n return TOOLS;\n}\n\n// Simple chat without tools\nexport async function chat(\n messages: Message[],\n systemPrompt?: string\n): Promise<BrainResponse> {\n const response = await client.messages.create({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 4096,\n system: systemPrompt || SYSTEM_PROMPT,\n messages: messages.map((m) => ({\n role: m.role,\n content: m.content,\n })),\n });\n\n const textContent = response.content.find((c) => c.type === \"text\");\n const content = textContent ? textContent.text : \"\";\n\n return {\n content,\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n };\n}\n\n// Chat with tool use capability\nexport async function chatWithTools(\n messages: Message[],\n userId?: string,\n onToolUse?: (toolName: string, input: unknown) => void\n): Promise<BrainResponse> {\n const startTime = Date.now();\n\n // Build memory context from user's query\n const lastUserMessage = messages.filter((m) => m.role === \"user\").pop();\n let memoryContext = \"\";\n let modeContext = \"\";\n let personalityContext = \"\";\n\n if (lastUserMessage && userId) {\n try {\n memoryContext = await buildMemoryContext(lastUserMessage.content, userId);\n } catch {\n // Memory system not available, continue without it\n }\n\n // Build mode context\n try {\n modeContext = await buildModeContext(userId);\n\n // Check if we should suggest a mode change\n const suggestedMode = suggestMode(lastUserMessage.content);\n if (suggestedMode && !modeContext) {\n // Could auto-activate or notify user\n }\n } catch {\n // Mode system not available\n }\n\n // Build personality context (persona + mood)\n try {\n const adaptiveContext = await buildAdaptivePrompt({\n userId,\n userMessage: lastUserMessage.content,\n conversationHistory: messages.map((m) => m.content),\n });\n personalityContext = adaptiveContext.systemPromptAdditions;\n } catch {\n // Personality system not available\n }\n\n // Track usage pattern\n try {\n await trackPattern(userId, \"topic\", \"chat\", { messageLength: lastUserMessage.content.length });\n } catch {\n // Tracking not available\n }\n }\n\n // Apply SOUL hook personality if active\n let soulContext = \"\";\n const activeSoul = soulHookManager.getActiveSoul();\n if (activeSoul && activeSoul.enabled) {\n soulContext = soulHookManager.buildSoulPrompt(activeSoul);\n }\n\n const systemWithContext = SYSTEM_PROMPT + memoryContext + modeContext + personalityContext + soulContext;\n\n // Run before hooks\n const hookResult = await hookManager.runBefore(\"message:process\", {\n messages,\n systemPrompt: systemWithContext,\n userId: userId ?? \"unknown\",\n }, userId);\n\n if (!hookResult.proceed) {\n return {\n content: hookResult.reason ?? \"Message processing was blocked by a hook.\",\n inputTokens: 0,\n outputTokens: 0,\n };\n }\n\n // Convert messages to Anthropic format\n const anthropicMessages: MessageParam[] = messages.map((m) => ({\n role: m.role,\n content: m.content,\n }));\n\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const toolsUsed: string[] = [];\n\n // Get thinking level API params\n const thinkingParams = thinkingLevelManager.buildApiParams(userId ?? \"default\");\n\n // Tool use loop\n let response = await client.messages.create({\n model: thinkingParams.model,\n max_tokens: thinkingParams.max_tokens,\n system: systemWithContext,\n tools: getAllTools(),\n messages: anthropicMessages,\n ...(thinkingParams.thinking ? { thinking: thinkingParams.thinking } : {}),\n } as any);\n\n totalInputTokens += response.usage.input_tokens;\n totalOutputTokens += response.usage.output_tokens;\n\n // Keep processing while Claude wants to use tools\n while (response.stop_reason === \"tool_use\") {\n const toolUseBlocks = response.content.filter(\n (block) => block.type === \"tool_use\"\n );\n\n const toolResults: ToolResultBlockParam[] = [];\n\n for (const toolUse of toolUseBlocks) {\n if (toolUse.type === \"tool_use\") {\n onToolUse?.(toolUse.name, toolUse.input);\n toolsUsed.push(toolUse.name);\n\n // Run before-tool hook\n const toolHook = await hookManager.runBefore(\"tool:execute\", {\n toolName: toolUse.name,\n toolInput: toolUse.input,\n }, userId);\n\n console.log(`[Tool] Executing: ${toolUse.name}`);\n const toolStartTime = Date.now();\n\n let result;\n if (toolHook.proceed) {\n result = await executeTool(\n toolUse.name,\n toolUse.input as Record<string, unknown>\n );\n } else {\n result = { success: false, result: null, error: toolHook.reason ?? \"Blocked by hook\" };\n }\n\n // Run after-tool hook\n await hookManager.runAfter(\"tool:execute\", {\n toolName: toolUse.name,\n toolInput: toolUse.input,\n toolResult: result,\n duration: Date.now() - toolStartTime,\n }, userId);\n\n // Track tool usage\n if (userId) {\n try {\n await trackPattern(userId, \"tool_usage\", toolUse.name, { tool: toolUse.name });\n metric.toolDuration(toolUse.name, Date.now() - toolStartTime, result.success);\n await audit.toolUse(userId, toolUse.name, toolUse.input as Record<string, unknown>, result.success);\n } catch {\n // Tracking/audit not available\n }\n }\n\n toolResults.push({\n type: \"tool_result\",\n tool_use_id: toolUse.id,\n content: JSON.stringify(result),\n });\n }\n }\n\n // Add assistant response and tool results to messages\n anthropicMessages.push({\n role: \"assistant\",\n content: response.content as ContentBlockParam[],\n });\n\n anthropicMessages.push({\n role: \"user\",\n content: toolResults,\n });\n\n // Continue conversation\n response = await client.messages.create({\n model: thinkingParams.model,\n max_tokens: thinkingParams.max_tokens,\n system: systemWithContext,\n tools: getAllTools(),\n messages: anthropicMessages,\n ...(thinkingParams.thinking ? { thinking: thinkingParams.thinking } : {}),\n } as any);\n\n totalInputTokens += response.usage.input_tokens;\n totalOutputTokens += response.usage.output_tokens;\n }\n\n // Extract final text response\n const textContent = response.content.find((c) => c.type === \"text\");\n const content = textContent && textContent.type === \"text\" ? textContent.text : \"\";\n\n // Record metrics\n const latency = Date.now() - startTime;\n metric.latency(latency, { type: \"chat\" });\n metric.tokens(totalInputTokens, totalOutputTokens, { userId: userId || \"unknown\" });\n\n // Check for achievements\n if (userId) {\n try {\n await checkAchievements(userId);\n } catch {\n // Achievement system not available\n }\n }\n\n // Run after-message hook\n await hookManager.runAfter(\"message:process\", {\n response: content,\n inputTokens: totalInputTokens,\n outputTokens: totalOutputTokens,\n toolsUsed,\n }, userId);\n\n return {\n content,\n inputTokens: totalInputTokens,\n outputTokens: totalOutputTokens,\n toolsUsed: toolsUsed.length > 0 ? toolsUsed : undefined,\n };\n}\n\nexport async function streamChat(\n messages: Message[],\n systemPrompt?: string,\n onChunk?: (text: string) => void\n): Promise<BrainResponse> {\n const stream = await client.messages.stream({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 4096,\n system: systemPrompt || SYSTEM_PROMPT,\n messages: messages.map((m) => ({\n role: m.role,\n content: m.content,\n })),\n });\n\n let fullContent = \"\";\n\n for await (const event of stream) {\n if (\n event.type === \"content_block_delta\" &&\n event.delta.type === \"text_delta\"\n ) {\n fullContent += event.delta.text;\n onChunk?.(event.delta.text);\n }\n }\n\n const finalMessage = await stream.finalMessage();\n\n return {\n content: fullContent,\n inputTokens: finalMessage.usage.input_tokens,\n outputTokens: finalMessage.usage.output_tokens,\n };\n}\n\n// Stream event types for WebSocket streaming\nexport interface StreamEvent {\n type: \"chunk\" | \"tool_start\" | \"tool_result\" | \"complete\" | \"error\";\n data: {\n text?: string;\n toolName?: string;\n toolInput?: unknown;\n toolResult?: unknown;\n content?: string;\n inputTokens?: number;\n outputTokens?: number;\n toolsUsed?: string[];\n error?: string;\n };\n}\n\n// Streaming chat with tools - yields events as they occur\nexport async function* streamChatWithTools(\n messages: Message[],\n userId?: string\n): AsyncGenerator<StreamEvent, BrainResponse, undefined> {\n const startTime = Date.now();\n\n // Build memory context\n const lastUserMessage = messages.filter((m) => m.role === \"user\").pop();\n let memoryContext = \"\";\n\n if (lastUserMessage && userId) {\n try {\n memoryContext = await buildMemoryContext(lastUserMessage.content, userId);\n } catch {\n // Memory system not available\n }\n }\n\n const systemWithContext = SYSTEM_PROMPT + memoryContext;\n\n // Convert messages to Anthropic format\n const anthropicMessages: MessageParam[] = messages.map((m) => ({\n role: m.role,\n content: m.content,\n }));\n\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const toolsUsed: string[] = [];\n let fullContent = \"\";\n\n // Initial request with streaming\n const stream = client.messages.stream({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 4096,\n system: systemWithContext,\n tools: getAllTools(),\n messages: anthropicMessages,\n });\n\n // Process streaming events\n for await (const event of stream) {\n if (event.type === \"content_block_delta\" && event.delta.type === \"text_delta\") {\n fullContent += event.delta.text;\n yield {\n type: \"chunk\",\n data: { text: event.delta.text },\n };\n }\n }\n\n let response = await stream.finalMessage();\n totalInputTokens += response.usage.input_tokens;\n totalOutputTokens += response.usage.output_tokens;\n\n // Tool use loop\n while (response.stop_reason === \"tool_use\") {\n const toolUseBlocks = response.content.filter((block) => block.type === \"tool_use\");\n const toolResults: ToolResultBlockParam[] = [];\n\n for (const toolUse of toolUseBlocks) {\n if (toolUse.type === \"tool_use\") {\n toolsUsed.push(toolUse.name);\n\n // Yield tool start event\n yield {\n type: \"tool_start\",\n data: { toolName: toolUse.name, toolInput: toolUse.input },\n };\n\n console.log(`[Tool] Executing: ${toolUse.name}`);\n const result = await executeTool(toolUse.name, toolUse.input as Record<string, unknown>);\n\n // Yield tool result event\n yield {\n type: \"tool_result\",\n data: { toolName: toolUse.name, toolResult: result },\n };\n\n toolResults.push({\n type: \"tool_result\",\n tool_use_id: toolUse.id,\n content: JSON.stringify(result),\n });\n }\n }\n\n // Add to messages and continue\n anthropicMessages.push({\n role: \"assistant\",\n content: response.content as ContentBlockParam[],\n });\n\n anthropicMessages.push({\n role: \"user\",\n content: toolResults,\n });\n\n // Stream the continuation\n const continueStream = client.messages.stream({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 4096,\n system: systemWithContext,\n tools: getAllTools(),\n messages: anthropicMessages,\n });\n\n for await (const event of continueStream) {\n if (event.type === \"content_block_delta\" && event.delta.type === \"text_delta\") {\n fullContent += event.delta.text;\n yield {\n type: \"chunk\",\n data: { text: event.delta.text },\n };\n }\n }\n\n response = await continueStream.finalMessage();\n totalInputTokens += response.usage.input_tokens;\n totalOutputTokens += response.usage.output_tokens;\n }\n\n // Yield complete event\n yield {\n type: \"complete\",\n data: {\n content: fullContent,\n inputTokens: totalInputTokens,\n outputTokens: totalOutputTokens,\n toolsUsed: toolsUsed.length > 0 ? toolsUsed : undefined,\n },\n };\n\n // Record metrics\n const latency = Date.now() - startTime;\n metric.latency(latency, { type: \"chat_stream\" });\n metric.tokens(totalInputTokens, totalOutputTokens, { userId: userId || \"unknown\" });\n\n return {\n content: fullContent,\n inputTokens: totalInputTokens,\n outputTokens: totalOutputTokens,\n toolsUsed: toolsUsed.length > 0 ? toolsUsed : undefined,\n };\n}\n\nexport { SYSTEM_PROMPT };\n","import { db } from \"../../db\";\nimport { moltModes, users } from \"../../db/schema\";\nimport { eq, and, isNull, desc } from \"drizzle-orm\";\nimport { audit } from \"../security/audit-logger\";\n\nexport type MoltMode = \"productivity\" | \"creative\" | \"research\" | \"learning\" | \"elevated\";\n\nexport interface ModeConfig {\n name: string;\n description: string;\n systemPromptModifier: string;\n emoji: string;\n settings: {\n verbosity: \"terse\" | \"normal\" | \"detailed\";\n humor: \"off\" | \"subtle\" | \"full\";\n proactivity: \"minimal\" | \"moderate\" | \"proactive\";\n };\n}\n\nexport const MODE_CONFIGS: Record<MoltMode, ModeConfig> = {\n productivity: {\n name: \"Productivity Mode\",\n description: \"Focus on task completion with minimal chitchat\",\n emoji: \"⚡\",\n systemPromptModifier: `You are in PRODUCTIVITY MODE. Be extremely concise and action-oriented.\n- Get straight to solutions without preamble\n- Use bullet points and numbered steps\n- Avoid small talk and filler words\n- Prioritize efficiency over pleasantries\n- If a task can be done, do it; don't ask for confirmation on obvious steps\n- Give direct answers, not options unless specifically asked`,\n settings: {\n verbosity: \"terse\",\n humor: \"off\",\n proactivity: \"proactive\",\n },\n },\n creative: {\n name: \"Creative Mode\",\n description: \"Brainstorming, ideation, and exploration\",\n emoji: \"🎨\",\n systemPromptModifier: `You are in CREATIVE MODE. Embrace unconventional thinking and exploration.\n- Suggest multiple alternatives and variations\n- Build on ideas rather than critiquing immediately\n- Use metaphors and analogies freely\n- Encourage \"what if\" scenarios\n- Be playful and experimental with language\n- Don't dismiss unusual ideas - explore them\n- Make unexpected connections between concepts`,\n settings: {\n verbosity: \"detailed\",\n humor: \"full\",\n proactivity: \"proactive\",\n },\n },\n research: {\n name: \"Research Mode\",\n description: \"Deep investigation with thorough analysis\",\n emoji: \"🔬\",\n systemPromptModifier: `You are in RESEARCH MODE. Be thorough, analytical, and evidence-based.\n- Always cite sources when possible\n- Present multiple perspectives on controversial topics\n- Note confidence levels in your claims\n- Distinguish between facts and interpretations\n- Use precise language and avoid vague statements\n- Structure information hierarchically\n- Flag when information might be outdated or uncertain\n- Provide context for claims`,\n settings: {\n verbosity: \"detailed\",\n humor: \"off\",\n proactivity: \"moderate\",\n },\n },\n learning: {\n name: \"Learning Mode\",\n description: \"Teaching mode with clear explanations\",\n emoji: \"📚\",\n systemPromptModifier: `You are in LEARNING MODE. Act as a patient, encouraging teacher.\n- Break down complex concepts into digestible pieces\n- Use analogies and real-world examples\n- Check understanding before moving forward\n- Encourage questions and curiosity\n- Celebrate progress and correct misconceptions gently\n- Build from fundamentals to advanced concepts\n- Provide exercises or practice opportunities when appropriate\n- Explain the \"why\" behind concepts, not just the \"what\"`,\n settings: {\n verbosity: \"detailed\",\n humor: \"subtle\",\n proactivity: \"proactive\",\n },\n },\n elevated: {\n name: \"Elevated Mode\",\n description: \"Unlocked access to restricted tools with full audit logging\",\n emoji: \"🔓\",\n systemPromptModifier: `You are in ELEVATED MODE. You have access to restricted and destructive operations.\n- All actions are fully audit-logged\n- Destructive shell commands (rm -rf, format, etc.) are now permitted\n- System-level operations (service management, config changes) are unlocked\n- Exercise extreme caution with every action\n- Confirm destructive operations before executing\n- This mode is time-limited and will auto-deactivate after 30 minutes\n- 2FA verification was required to enter this mode\n- Double-check all file paths and commands before execution`,\n settings: {\n verbosity: \"detailed\",\n humor: \"off\",\n proactivity: \"minimal\",\n },\n },\n};\n\nexport async function getCurrentMode(userId: string): Promise<MoltMode | null> {\n const [activeMode] = await db\n .select()\n .from(moltModes)\n .where(and(eq(moltModes.userId, userId), isNull(moltModes.deactivatedAt)))\n .orderBy(desc(moltModes.activatedAt))\n .limit(1);\n\n return activeMode?.mode as MoltMode | null;\n}\n\nexport async function activateMode(\n userId: string,\n mode: MoltMode,\n metadata?: Record<string, unknown>\n): Promise<void> {\n // Get current mode for audit\n const currentMode = await getCurrentMode(userId);\n\n // Deactivate any current mode\n await deactivateCurrentMode(userId);\n\n // Activate new mode\n await db.insert(moltModes).values({\n userId,\n mode,\n metadata,\n });\n\n // Log the mode change\n await audit.modeChange(userId, currentMode, mode);\n}\n\nexport async function deactivateCurrentMode(userId: string): Promise<boolean> {\n const [deactivated] = await db\n .update(moltModes)\n .set({ deactivatedAt: new Date() })\n .where(and(eq(moltModes.userId, userId), isNull(moltModes.deactivatedAt)))\n .returning();\n\n return !!deactivated;\n}\n\nexport async function getModeHistory(\n userId: string,\n limit: number = 20\n): Promise<Array<{ mode: MoltMode; activatedAt: Date; deactivatedAt: Date | null }>> {\n const history = await db\n .select()\n .from(moltModes)\n .where(eq(moltModes.userId, userId))\n .orderBy(desc(moltModes.activatedAt))\n .limit(limit);\n\n return history.map((h) => ({\n mode: h.mode as MoltMode,\n activatedAt: h.activatedAt,\n deactivatedAt: h.deactivatedAt,\n }));\n}\n\nexport function getModeSystemPrompt(mode: MoltMode | null): string {\n if (!mode) return \"\";\n return MODE_CONFIGS[mode].systemPromptModifier;\n}\n\nexport function getModeConfig(mode: MoltMode): ModeConfig {\n return MODE_CONFIGS[mode];\n}\n\nexport function getAllModes(): Array<{ mode: MoltMode; config: ModeConfig }> {\n return Object.entries(MODE_CONFIGS).map(([mode, config]) => ({\n mode: mode as MoltMode,\n config,\n }));\n}\n\n// Build complete system prompt modifier for a user\nexport async function buildModeContext(userId: string): Promise<string> {\n const mode = await getCurrentMode(userId);\n if (!mode) return \"\";\n\n const config = MODE_CONFIGS[mode];\n return `\\n\\n[${config.emoji} ${config.name.toUpperCase()} ACTIVE]\\n${config.systemPromptModifier}`;\n}\n\n// Get mode usage statistics\nexport async function getModeStats(\n userId: string\n): Promise<Record<MoltMode, { totalSessions: number; totalMinutes: number }>> {\n const history = await db\n .select()\n .from(moltModes)\n .where(eq(moltModes.userId, userId));\n\n const stats: Record<MoltMode, { totalSessions: number; totalMinutes: number }> = {\n productivity: { totalSessions: 0, totalMinutes: 0 },\n creative: { totalSessions: 0, totalMinutes: 0 },\n research: { totalSessions: 0, totalMinutes: 0 },\n learning: { totalSessions: 0, totalMinutes: 0 },\n elevated: { totalSessions: 0, totalMinutes: 0 },\n };\n\n for (const entry of history) {\n const mode = entry.mode as MoltMode;\n stats[mode].totalSessions++;\n\n if (entry.deactivatedAt) {\n const minutes = Math.floor(\n (entry.deactivatedAt.getTime() - entry.activatedAt.getTime()) / 60000\n );\n stats[mode].totalMinutes += minutes;\n }\n }\n\n return stats;\n}\n\n// Suggest mode based on user input\nexport function suggestMode(userMessage: string): MoltMode | null {\n const lowerMessage = userMessage.toLowerCase();\n\n // Productivity keywords\n if (\n lowerMessage.includes(\"quick\") ||\n lowerMessage.includes(\"fast\") ||\n lowerMessage.includes(\"todo\") ||\n lowerMessage.includes(\"task\") ||\n lowerMessage.includes(\"finish\") ||\n lowerMessage.includes(\"deadline\")\n ) {\n return \"productivity\";\n }\n\n // Creative keywords\n if (\n lowerMessage.includes(\"brainstorm\") ||\n lowerMessage.includes(\"idea\") ||\n lowerMessage.includes(\"creative\") ||\n lowerMessage.includes(\"imagine\") ||\n lowerMessage.includes(\"design\") ||\n lowerMessage.includes(\"invent\")\n ) {\n return \"creative\";\n }\n\n // Research keywords\n if (\n lowerMessage.includes(\"research\") ||\n lowerMessage.includes(\"analyze\") ||\n lowerMessage.includes(\"investigate\") ||\n lowerMessage.includes(\"compare\") ||\n lowerMessage.includes(\"study\") ||\n lowerMessage.includes(\"deep dive\")\n ) {\n return \"research\";\n }\n\n // Learning keywords\n if (\n lowerMessage.includes(\"learn\") ||\n lowerMessage.includes(\"explain\") ||\n lowerMessage.includes(\"teach\") ||\n lowerMessage.includes(\"understand\") ||\n lowerMessage.includes(\"how does\") ||\n lowerMessage.includes(\"what is\")\n ) {\n return \"learning\";\n }\n\n // Elevated keywords\n if (\n lowerMessage.includes(\"elevated\") ||\n lowerMessage.includes(\"sudo\") ||\n lowerMessage.includes(\"admin\") ||\n lowerMessage.includes(\"unrestricted\") ||\n lowerMessage.includes(\"destructive\") ||\n lowerMessage.includes(\"system-level\")\n ) {\n return \"elevated\";\n }\n\n return null;\n}\n","import { db } from \"../../db\";\nimport { personas } from \"../../db/schema\";\nimport { eq, and } from \"drizzle-orm\";\n\nexport interface Persona {\n id: string;\n userId: string;\n name: string;\n description: string;\n systemPromptModifier: string;\n voiceSettings?: {\n voiceId?: string;\n stability?: number;\n similarityBoost?: number;\n style?: number;\n };\n traits: PersonaTrait[];\n isActive: boolean;\n isDefault: boolean;\n createdAt: Date;\n}\n\nexport interface PersonaTrait {\n name: string;\n value: number; // 0-100 scale\n}\n\nexport interface PersonaConfig {\n name: string;\n description: string;\n systemPromptModifier: string;\n voiceSettings?: Persona[\"voiceSettings\"];\n traits?: PersonaTrait[];\n}\n\n// Default personas\nexport const DEFAULT_PERSONAS: Record<string, PersonaConfig> = {\n professional: {\n name: \"Professional\",\n description: \"Formal, precise, and business-focused communication style\",\n systemPromptModifier: `\nYou should communicate in a professional, formal manner. Use proper grammar, avoid slang,\nand maintain a business-appropriate tone. Be precise and concise in your responses.\nFocus on facts and actionable information. Address the user respectfully.\n `.trim(),\n traits: [\n { name: \"formality\", value: 90 },\n { name: \"humor\", value: 20 },\n { name: \"verbosity\", value: 40 },\n { name: \"empathy\", value: 50 },\n ],\n },\n friendly: {\n name: \"Friendly\",\n description: \"Warm, casual, and approachable communication style\",\n systemPromptModifier: `\nYou should communicate in a warm, friendly manner. Feel free to use casual language,\nexpress enthusiasm, and show empathy. Be encouraging and supportive. It's okay to\nuse exclamation marks and show genuine interest in helping. Keep things light\nwhen appropriate.\n `.trim(),\n traits: [\n { name: \"formality\", value: 30 },\n { name: \"humor\", value: 60 },\n { name: \"verbosity\", value: 60 },\n { name: \"empathy\", value: 85 },\n ],\n },\n concise: {\n name: \"Concise\",\n description: \"Minimal, direct, and efficient communication\",\n systemPromptModifier: `\nYou should be extremely concise. Give the shortest possible answer that fully\naddresses the question. Avoid unnecessary explanations, pleasantries, or filler\nwords. Use bullet points and short sentences. Get straight to the point.\n `.trim(),\n traits: [\n { name: \"formality\", value: 50 },\n { name: \"humor\", value: 10 },\n { name: \"verbosity\", value: 10 },\n { name: \"empathy\", value: 30 },\n ],\n },\n teacher: {\n name: \"Teacher\",\n description: \"Educational, patient, and explanatory style\",\n systemPromptModifier: `\nYou should communicate as a patient and thorough teacher. Break down complex topics\ninto digestible parts. Use analogies and examples to illustrate points. Ask\nclarifying questions when needed. Encourage learning and celebrate progress.\nExplain the \"why\" behind things, not just the \"what\".\n `.trim(),\n traits: [\n { name: \"formality\", value: 50 },\n { name: \"humor\", value: 40 },\n { name: \"verbosity\", value: 80 },\n { name: \"empathy\", value: 75 },\n ],\n },\n creative: {\n name: \"Creative\",\n description: \"Imaginative, expressive, and unconventional style\",\n systemPromptModifier: `\nYou should communicate in a creative and expressive way. Use vivid language,\nmetaphors, and unique perspectives. Think outside the box and offer unconventional\nsuggestions. Be playful with language when appropriate. Embrace imagination\nand encourage creative thinking.\n `.trim(),\n traits: [\n { name: \"formality\", value: 25 },\n { name: \"humor\", value: 70 },\n { name: \"verbosity\", value: 70 },\n { name: \"empathy\", value: 65 },\n ],\n },\n};\n\n// Create a new persona\nexport async function createPersona(\n userId: string,\n config: PersonaConfig\n): Promise<string> {\n const [persona] = await db\n .insert(personas)\n .values({\n userId,\n name: config.name,\n description: config.description,\n systemPromptModifier: config.systemPromptModifier,\n voiceSettings: config.voiceSettings,\n traits: config.traits || [],\n isActive: false,\n isDefault: false,\n })\n .returning();\n\n return persona.id;\n}\n\n// Get persona by ID\nexport async function getPersona(personaId: string): Promise<Persona | null> {\n const [persona] = await db\n .select()\n .from(personas)\n .where(eq(personas.id, personaId))\n .limit(1);\n\n if (!persona) return null;\n\n return {\n id: persona.id,\n userId: persona.userId,\n name: persona.name,\n description: persona.description || \"\",\n systemPromptModifier: persona.systemPromptModifier,\n voiceSettings: persona.voiceSettings as Persona[\"voiceSettings\"],\n traits: (persona.traits as PersonaTrait[]) || [],\n isActive: persona.isActive,\n isDefault: persona.isDefault,\n createdAt: persona.createdAt,\n };\n}\n\n// Get user's personas\nexport async function getUserPersonas(userId: string): Promise<Persona[]> {\n const results = await db\n .select()\n .from(personas)\n .where(eq(personas.userId, userId));\n\n return results.map((p) => ({\n id: p.id,\n userId: p.userId,\n name: p.name,\n description: p.description || \"\",\n systemPromptModifier: p.systemPromptModifier,\n voiceSettings: p.voiceSettings as Persona[\"voiceSettings\"],\n traits: (p.traits as PersonaTrait[]) || [],\n isActive: p.isActive,\n isDefault: p.isDefault,\n createdAt: p.createdAt,\n }));\n}\n\n// Get active persona for user\nexport async function getActivePersona(userId: string): Promise<Persona | null> {\n const [persona] = await db\n .select()\n .from(personas)\n .where(and(eq(personas.userId, userId), eq(personas.isActive, true)))\n .limit(1);\n\n if (!persona) return null;\n\n return {\n id: persona.id,\n userId: persona.userId,\n name: persona.name,\n description: persona.description || \"\",\n systemPromptModifier: persona.systemPromptModifier,\n voiceSettings: persona.voiceSettings as Persona[\"voiceSettings\"],\n traits: (persona.traits as PersonaTrait[]) || [],\n isActive: persona.isActive,\n isDefault: persona.isDefault,\n createdAt: persona.createdAt,\n };\n}\n\n// Activate a persona\nexport async function activatePersona(\n userId: string,\n personaId: string\n): Promise<void> {\n // Deactivate all personas for user\n await db\n .update(personas)\n .set({ isActive: false })\n .where(eq(personas.userId, userId));\n\n // Activate the specified persona\n await db\n .update(personas)\n .set({ isActive: true })\n .where(and(eq(personas.id, personaId), eq(personas.userId, userId)));\n}\n\n// Deactivate all personas\nexport async function deactivatePersonas(userId: string): Promise<void> {\n await db\n .update(personas)\n .set({ isActive: false })\n .where(eq(personas.userId, userId));\n}\n\n// Set default persona\nexport async function setDefaultPersona(\n userId: string,\n personaId: string\n): Promise<void> {\n // Remove default from all\n await db\n .update(personas)\n .set({ isDefault: false })\n .where(eq(personas.userId, userId));\n\n // Set new default\n await db\n .update(personas)\n .set({ isDefault: true })\n .where(and(eq(personas.id, personaId), eq(personas.userId, userId)));\n}\n\n// Update persona\nexport async function updatePersona(\n personaId: string,\n updates: Partial<PersonaConfig>\n): Promise<void> {\n const setValues: Record<string, unknown> = {};\n\n if (updates.name !== undefined) setValues.name = updates.name;\n if (updates.description !== undefined) setValues.description = updates.description;\n if (updates.systemPromptModifier !== undefined) {\n setValues.systemPromptModifier = updates.systemPromptModifier;\n }\n if (updates.voiceSettings !== undefined) {\n setValues.voiceSettings = updates.voiceSettings;\n }\n if (updates.traits !== undefined) setValues.traits = updates.traits;\n\n if (Object.keys(setValues).length > 0) {\n await db.update(personas).set(setValues).where(eq(personas.id, personaId));\n }\n}\n\n// Delete persona\nexport async function deletePersona(personaId: string): Promise<void> {\n await db.delete(personas).where(eq(personas.id, personaId));\n}\n\n// Initialize default personas for a new user\nexport async function initializeDefaultPersonas(userId: string): Promise<void> {\n const existing = await getUserPersonas(userId);\n if (existing.length > 0) return; // Already initialized\n\n // Create default personas\n for (const [key, config] of Object.entries(DEFAULT_PERSONAS)) {\n const id = await createPersona(userId, config);\n\n // Set \"friendly\" as default\n if (key === \"friendly\") {\n await setDefaultPersona(userId, id);\n await activatePersona(userId, id);\n }\n }\n}\n\n// Get system prompt modifier for current persona\nexport async function getPersonaSystemPrompt(userId: string): Promise<string> {\n const activePersona = await getActivePersona(userId);\n return activePersona?.systemPromptModifier || \"\";\n}\n\nexport default {\n createPersona,\n getPersona,\n getUserPersonas,\n getActivePersona,\n activatePersona,\n deactivatePersonas,\n setDefaultPersona,\n updatePersona,\n deletePersona,\n initializeDefaultPersonas,\n getPersonaSystemPrompt,\n DEFAULT_PERSONAS,\n};\n","// Mood detection based on user messages\n\nexport type Mood =\n | \"neutral\"\n | \"happy\"\n | \"frustrated\"\n | \"confused\"\n | \"urgent\"\n | \"curious\"\n | \"tired\"\n | \"stressed\";\n\nexport interface MoodAnalysis {\n primaryMood: Mood;\n confidence: number; // 0-1\n indicators: string[];\n suggestedTone: string;\n}\n\n// Keyword patterns for mood detection\nconst MOOD_PATTERNS: Record<Mood, RegExp[]> = {\n happy: [\n /\\b(thanks|thank you|awesome|great|perfect|love|wonderful|amazing|excellent)\\b/i,\n /😀|😊|🎉|👍|❤️|😁|🙂/,\n /!{2,}/,\n /\\b(yay|woohoo|yes)\\b/i,\n ],\n frustrated: [\n /\\b(frustrated|frustrating|annoying|annoyed|hate|stupid|broken|wrong|doesn't work|not working|nothing works)\\b/i,\n /\\b(ugh|argh|grr|damn|dammit)\\b/i,\n /😤|😠|😡|🤬|💢/,\n /!{3,}/,\n /\\b(why won't|why doesn't|why can't)\\b/i,\n ],\n confused: [\n /\\b(confused|don't understand|what do you mean|unclear|lost|huh)\\b/i,\n /\\?{2,}/,\n /😕|🤔|❓|😵/,\n /\\b(what|how|why)\\b.*\\?/i,\n /\\b(i don't get|makes no sense)\\b/i,\n ],\n urgent: [\n /\\b(urgent|asap|immediately|right now|emergency|critical|deadline)\\b/i,\n /\\b(hurry|quickly|fast|need this now)\\b/i,\n /🚨|⚠️|🔥|⏰/,\n /!{2,}.*\\b(need|help|please)\\b/i,\n ],\n curious: [\n /\\b(curious|wondering|interested)\\b/i,\n /\\b(tell me more|how does|what if|how does.*work)\\b/i,\n /\\b(could you explain|can you elaborate|what about)\\b/i,\n /🤓|💡|🧐/,\n /\\b(i want to know|i'd like to learn|i'm curious)\\b/i,\n ],\n tired: [\n /\\b(tired|exhausted|long day|sleepy|burnout|drained)\\b/i,\n /😴|😪|🥱|💤/,\n /\\b(can't think|brain fog|need a break)\\b/i,\n ],\n stressed: [\n /\\b(stressed|overwhelmed|too much|can't handle|pressure|anxious)\\b/i,\n /😰|😥|😓|🥺/,\n /\\b(so much to do|running out of time|help me)\\b/i,\n ],\n neutral: [], // Default fallback\n};\n\n// Tone suggestions for each mood\nconst MOOD_TONE_SUGGESTIONS: Record<Mood, string> = {\n happy: \"Match their positive energy. Be warm and encouraging.\",\n frustrated: \"Be patient and empathetic. Acknowledge the frustration and focus on solutions.\",\n confused: \"Be extra clear and thorough. Use simple language and examples.\",\n urgent: \"Be direct and efficient. Prioritize the most critical information first.\",\n curious: \"Be enthusiastic and detailed. Encourage their exploration.\",\n tired: \"Be gentle and concise. Offer to break things into smaller steps.\",\n stressed: \"Be calm and reassuring. Help them prioritize and simplify.\",\n neutral: \"Be balanced and professional. Match their communication style.\",\n};\n\n// Detect mood from a single message\nexport function detectMood(message: string): MoodAnalysis {\n const moodScores: Record<Mood, number> = {\n neutral: 0,\n happy: 0,\n frustrated: 0,\n confused: 0,\n urgent: 0,\n curious: 0,\n tired: 0,\n stressed: 0,\n };\n\n const indicators: string[] = [];\n\n // Check each mood pattern\n for (const [mood, patterns] of Object.entries(MOOD_PATTERNS)) {\n for (const pattern of patterns) {\n const matches = message.match(pattern);\n if (matches) {\n moodScores[mood as Mood] += 1;\n indicators.push(`\"${matches[0]}\" suggests ${mood}`);\n }\n }\n }\n\n // Find the highest scoring mood\n let primaryMood: Mood = \"neutral\";\n let maxScore = 0;\n\n for (const [mood, score] of Object.entries(moodScores)) {\n if (score > maxScore) {\n maxScore = score;\n primaryMood = mood as Mood;\n }\n }\n\n // Calculate confidence based on score distribution\n const totalScore = Object.values(moodScores).reduce((a, b) => a + b, 0);\n const confidence = totalScore > 0 ? maxScore / totalScore : 0.5;\n\n return {\n primaryMood,\n confidence: Math.min(confidence, 1),\n indicators: indicators.slice(0, 5), // Limit to top 5 indicators\n suggestedTone: MOOD_TONE_SUGGESTIONS[primaryMood],\n };\n}\n\n// Analyze mood trend from recent messages\nexport function analyzeMoodTrend(\n messages: string[]\n): {\n currentMood: Mood;\n moodHistory: Mood[];\n trend: \"improving\" | \"declining\" | \"stable\";\n overallSentiment: \"positive\" | \"negative\" | \"neutral\";\n} {\n if (messages.length === 0) {\n return {\n currentMood: \"neutral\",\n moodHistory: [],\n trend: \"stable\",\n overallSentiment: \"neutral\",\n };\n }\n\n const moodHistory = messages.map((m) => detectMood(m).primaryMood);\n const currentMood = moodHistory[moodHistory.length - 1];\n\n // Assign sentiment scores\n const sentimentScores: Record<Mood, number> = {\n happy: 2,\n curious: 1,\n neutral: 0,\n confused: -0.5,\n tired: -0.5,\n stressed: -1,\n frustrated: -1.5,\n urgent: -0.5,\n };\n\n // Calculate recent vs overall sentiment\n const recentMessages = moodHistory.slice(-3);\n const olderMessages = moodHistory.slice(0, -3);\n\n const recentAvg =\n recentMessages.reduce((sum, mood) => sum + sentimentScores[mood], 0) /\n recentMessages.length;\n\n const olderAvg =\n olderMessages.length > 0\n ? olderMessages.reduce((sum, mood) => sum + sentimentScores[mood], 0) /\n olderMessages.length\n : recentAvg;\n\n // Determine trend\n let trend: \"improving\" | \"declining\" | \"stable\";\n const diff = recentAvg - olderAvg;\n if (diff > 0.5) {\n trend = \"improving\";\n } else if (diff < -0.5) {\n trend = \"declining\";\n } else {\n trend = \"stable\";\n }\n\n // Determine overall sentiment\n const overallAvg =\n moodHistory.reduce((sum, mood) => sum + sentimentScores[mood], 0) /\n moodHistory.length;\n\n let overallSentiment: \"positive\" | \"negative\" | \"neutral\";\n if (overallAvg > 0.5) {\n overallSentiment = \"positive\";\n } else if (overallAvg < -0.5) {\n overallSentiment = \"negative\";\n } else {\n overallSentiment = \"neutral\";\n }\n\n return {\n currentMood,\n moodHistory,\n trend,\n overallSentiment,\n };\n}\n\n// Get response style suggestions based on mood\nexport function getMoodBasedSuggestions(mood: Mood): {\n tone: string;\n doList: string[];\n dontList: string[];\n} {\n const suggestions: Record<\n Mood,\n { tone: string; doList: string[]; dontList: string[] }\n > = {\n happy: {\n tone: \"Warm and enthusiastic\",\n doList: [\n \"Match their positive energy\",\n \"Use encouraging language\",\n \"Celebrate their successes\",\n ],\n dontList: [\n \"Be overly formal\",\n \"Dampen their enthusiasm\",\n \"Be too brief\",\n ],\n },\n frustrated: {\n tone: \"Patient and solution-focused\",\n doList: [\n \"Acknowledge their frustration\",\n \"Focus on actionable solutions\",\n \"Be patient and thorough\",\n ],\n dontList: [\n \"Be dismissive\",\n \"Add unnecessary complexity\",\n \"Say 'just do X'\",\n ],\n },\n confused: {\n tone: \"Clear and explanatory\",\n doList: [\n \"Use simple language\",\n \"Provide examples\",\n \"Break down complex topics\",\n \"Ask clarifying questions\",\n ],\n dontList: [\n \"Use jargon without explanation\",\n \"Rush through explanations\",\n \"Assume knowledge\",\n ],\n },\n urgent: {\n tone: \"Direct and efficient\",\n doList: [\n \"Get straight to the point\",\n \"Prioritize critical info\",\n \"Offer quick wins\",\n ],\n dontList: [\n \"Add pleasantries\",\n \"Provide unnecessary context\",\n \"Suggest long-term solutions first\",\n ],\n },\n curious: {\n tone: \"Enthusiastic and educational\",\n doList: [\n \"Provide detailed explanations\",\n \"Suggest related topics\",\n \"Encourage exploration\",\n ],\n dontList: [\n \"Give minimal answers\",\n \"Discourage questions\",\n \"Be dismissive of tangents\",\n ],\n },\n tired: {\n tone: \"Gentle and supportive\",\n doList: [\n \"Keep responses concise\",\n \"Offer to help simplify\",\n \"Be understanding\",\n ],\n dontList: [\n \"Overwhelm with information\",\n \"Be demanding\",\n \"Require complex decisions\",\n ],\n },\n stressed: {\n tone: \"Calm and reassuring\",\n doList: [\n \"Help prioritize tasks\",\n \"Offer to break things down\",\n \"Be reassuring\",\n ],\n dontList: [\n \"Add pressure\",\n \"Highlight problems without solutions\",\n \"Be dismissive of concerns\",\n ],\n },\n neutral: {\n tone: \"Balanced and professional\",\n doList: [\n \"Match their communication style\",\n \"Be helpful and thorough\",\n \"Ask for clarification when needed\",\n ],\n dontList: [\n \"Be overly casual or formal\",\n \"Make assumptions about mood\",\n \"Be too brief or too verbose\",\n ],\n },\n };\n\n return suggestions[mood];\n}\n\nexport default {\n detectMood,\n analyzeMoodTrend,\n getMoodBasedSuggestions,\n};\n","import { getActivePersona, Persona, PersonaTrait } from \"./persona-manager\";\nimport { detectMood, getMoodBasedSuggestions, Mood, MoodAnalysis } from \"./mood-detector\";\nimport { getCurrentMode, getModeConfig, MoltMode } from \"../molt/mode-manager\";\n\nexport interface ResponseContext {\n userId: string;\n userMessage: string;\n conversationHistory?: string[];\n}\n\nexport interface AdaptedResponse {\n systemPromptAdditions: string;\n suggestedTone: string;\n moodAnalysis: MoodAnalysis;\n activePersona: Persona | null;\n activeMode: MoltMode | null;\n}\n\n// Build adaptive system prompt additions based on context\nexport async function buildAdaptivePrompt(\n context: ResponseContext\n): Promise<AdaptedResponse> {\n const { userId, userMessage, conversationHistory } = context;\n\n // Get mood analysis\n const moodAnalysis = detectMood(userMessage);\n const moodSuggestions = getMoodBasedSuggestions(moodAnalysis.primaryMood);\n\n // Get active persona\n const activePersona = await getActivePersona(userId);\n\n // Get active mode\n const activeMode = await getCurrentMode(userId);\n const modeConfig = activeMode ? getModeConfig(activeMode) : null;\n\n // Build system prompt additions\n const promptParts: string[] = [];\n\n // Add persona modifier\n if (activePersona) {\n promptParts.push(`[Persona: ${activePersona.name}]`);\n promptParts.push(activePersona.systemPromptModifier);\n }\n\n // Add mode modifier\n if (modeConfig) {\n promptParts.push(`\\n[Mode: ${modeConfig.name}]`);\n promptParts.push(modeConfig.systemPromptModifier);\n }\n\n // Add mood-based guidance\n if (moodAnalysis.confidence > 0.3 && moodAnalysis.primaryMood !== \"neutral\") {\n promptParts.push(`\\n[User Mood: ${moodAnalysis.primaryMood}]`);\n promptParts.push(`Tone guidance: ${moodSuggestions.tone}`);\n promptParts.push(`Do: ${moodSuggestions.doList.join(\", \")}`);\n promptParts.push(`Avoid: ${moodSuggestions.dontList.join(\", \")}`);\n }\n\n // Add conversation context awareness\n if (conversationHistory && conversationHistory.length > 0) {\n const recentExchanges = conversationHistory.slice(-3).length;\n if (recentExchanges >= 3) {\n promptParts.push(\n \"\\n[Context: Ongoing conversation - maintain consistency with previous responses]\"\n );\n }\n }\n\n return {\n systemPromptAdditions: promptParts.join(\"\\n\"),\n suggestedTone: moodSuggestions.tone,\n moodAnalysis,\n activePersona,\n activeMode,\n };\n}\n\n// Adjust response verbosity based on persona traits\nexport function adjustVerbosity(\n response: string,\n traits: PersonaTrait[]\n): string {\n const verbosityTrait = traits.find((t) => t.name === \"verbosity\");\n if (!verbosityTrait) return response;\n\n const verbosity = verbosityTrait.value;\n\n if (verbosity < 30) {\n // Very concise - try to shorten\n return shortenResponse(response);\n } else if (verbosity > 70) {\n // Verbose - no changes needed\n return response;\n }\n\n return response;\n}\n\n// Shorten a response by removing filler phrases\nfunction shortenResponse(response: string): string {\n const fillerPatterns = [\n /^(well|so|basically|essentially|actually),?\\s*/gi,\n /\\b(as you can see|as mentioned|as i said)\\b,?\\s*/gi,\n /\\b(just to clarify|to be clear|in other words)\\b,?\\s*/gi,\n /\\b(i think that|it seems like|it appears that)\\b\\s*/gi,\n /\\b(hope this helps|let me know if you have any questions)\\b!?\\.?\\s*/gi,\n ];\n\n let shortened = response;\n for (const pattern of fillerPatterns) {\n shortened = shortened.replace(pattern, \"\");\n }\n\n return shortened.trim();\n}\n\n// Add appropriate formality markers based on persona\nexport function adjustFormality(\n response: string,\n traits: PersonaTrait[]\n): string {\n const formalityTrait = traits.find((t) => t.name === \"formality\");\n if (!formalityTrait) return response;\n\n const formality = formalityTrait.value;\n\n if (formality > 70) {\n // Make more formal\n return makeFormal(response);\n } else if (formality < 30) {\n // Make more casual\n return makeCasual(response);\n }\n\n return response;\n}\n\nfunction makeFormal(response: string): string {\n const casualToFormal: Record<string, string> = {\n \"don't\": \"do not\",\n \"can't\": \"cannot\",\n \"won't\": \"will not\",\n \"didn't\": \"did not\",\n \"isn't\": \"is not\",\n \"aren't\": \"are not\",\n \"wasn't\": \"was not\",\n \"weren't\": \"were not\",\n gonna: \"going to\",\n wanna: \"want to\",\n gotta: \"have to\",\n yeah: \"yes\",\n nope: \"no\",\n ok: \"okay\",\n \"OK\": \"okay\",\n hey: \"hello\",\n hi: \"hello\",\n };\n\n let formal = response;\n for (const [casual, formalWord] of Object.entries(casualToFormal)) {\n const regex = new RegExp(`\\\\b${casual}\\\\b`, \"gi\");\n formal = formal.replace(regex, formalWord);\n }\n\n return formal;\n}\n\nfunction makeCasual(response: string): string {\n const formalToCasual: Record<string, string> = {\n \"do not\": \"don't\",\n cannot: \"can't\",\n \"will not\": \"won't\",\n \"did not\": \"didn't\",\n \"is not\": \"isn't\",\n \"are not\": \"aren't\",\n \"was not\": \"wasn't\",\n \"were not\": \"weren't\",\n however: \"but\",\n therefore: \"so\",\n additionally: \"also\",\n furthermore: \"plus\",\n subsequently: \"then\",\n consequently: \"so\",\n };\n\n let casual = response;\n for (const [formalWord, casualWord] of Object.entries(formalToCasual)) {\n const regex = new RegExp(`\\\\b${formalWord}\\\\b`, \"gi\");\n casual = casual.replace(regex, casualWord);\n }\n\n return casual;\n}\n\n// Get emoji allowance based on persona and mood\nexport function shouldUseEmoji(\n persona: Persona | null,\n mood: Mood\n): { allowed: boolean; suggestion: string } {\n // Check persona traits\n if (persona) {\n const formalityTrait = persona.traits.find((t) => t.name === \"formality\");\n if (formalityTrait && formalityTrait.value > 70) {\n return { allowed: false, suggestion: \"Avoid emojis - formal persona\" };\n }\n }\n\n // Mood-based emoji suggestions\n const moodEmojis: Record<Mood, { allowed: boolean; suggestion: string }> = {\n happy: { allowed: true, suggestion: \"Matching emojis welcome 😊\" },\n frustrated: { allowed: false, suggestion: \"Avoid emojis - user is frustrated\" },\n confused: { allowed: false, suggestion: \"Limit emojis - focus on clarity\" },\n urgent: { allowed: false, suggestion: \"No emojis - keep it professional\" },\n curious: { allowed: true, suggestion: \"Thoughtful emojis OK 🤔💡\" },\n tired: { allowed: true, suggestion: \"Gentle/supportive emojis OK 🙂\" },\n stressed: { allowed: false, suggestion: \"Limit emojis - stay calm\" },\n neutral: { allowed: true, suggestion: \"Moderate emoji use OK\" },\n };\n\n return moodEmojis[mood];\n}\n\n// Full response adaptation pipeline\nexport async function adaptResponse(\n response: string,\n context: ResponseContext\n): Promise<string> {\n // Get adaptive context\n const adaptiveContext = await buildAdaptivePrompt(context);\n\n // If no persona, return unchanged\n if (!adaptiveContext.activePersona) {\n return response;\n }\n\n let adapted = response;\n\n // Apply trait-based adjustments\n adapted = adjustVerbosity(adapted, adaptiveContext.activePersona.traits);\n adapted = adjustFormality(adapted, adaptiveContext.activePersona.traits);\n\n return adapted;\n}\n\n// Generate response instruction summary\nexport async function getResponseInstructions(\n context: ResponseContext\n): Promise<string> {\n const adapted = await buildAdaptivePrompt(context);\n\n const instructions: string[] = [];\n\n if (adapted.activePersona) {\n instructions.push(`Using ${adapted.activePersona.name} persona`);\n }\n\n if (adapted.activeMode) {\n const modeConfig = getModeConfig(adapted.activeMode);\n instructions.push(`In ${modeConfig?.name || adapted.activeMode} mode`);\n }\n\n if (adapted.moodAnalysis.primaryMood !== \"neutral\") {\n instructions.push(\n `User seems ${adapted.moodAnalysis.primaryMood} (${Math.round(adapted.moodAnalysis.confidence * 100)}% confidence)`\n );\n }\n\n instructions.push(`Suggested tone: ${adapted.suggestedTone}`);\n\n return instructions.join(\" | \");\n}\n\nexport default {\n buildAdaptivePrompt,\n adjustVerbosity,\n adjustFormality,\n shouldUseEmoji,\n adaptResponse,\n getResponseInstructions,\n};\n","import { db } from \"../../db\";\nimport {\n usagePatterns,\n messages,\n toolLogs,\n memories,\n conversations,\n} from \"../../db/schema\";\nimport { eq, and, gte, lte, desc, sql, count } from \"drizzle-orm\";\n\nexport type PatternType =\n | \"tool_usage\"\n | \"topic\"\n | \"time_of_day\"\n | \"complexity\"\n | \"conversation_length\"\n | \"response_preference\";\n\nexport interface UsagePattern {\n type: PatternType;\n key: string;\n data: Record<string, unknown>;\n confidence: number;\n occurrences: number;\n firstSeen: Date;\n lastSeen: Date;\n}\n\nexport interface EvolutionSnapshot {\n totalConversations: number;\n totalMessages: number;\n totalToolUses: number;\n totalMemories: number;\n favoriteTools: Array<{ tool: string; count: number }>;\n activeHours: Array<{ hour: number; count: number }>;\n topTopics: Array<{ topic: string; count: number }>;\n averageConversationLength: number;\n patterns: UsagePattern[];\n}\n\n// Track a usage pattern\nexport async function trackPattern(\n userId: string,\n type: PatternType,\n key: string,\n data?: Record<string, unknown>\n): Promise<void> {\n const existing = await db\n .select()\n .from(usagePatterns)\n .where(\n and(\n eq(usagePatterns.userId, userId),\n eq(usagePatterns.patternType, type),\n eq(usagePatterns.patternKey, key)\n )\n )\n .limit(1);\n\n if (existing.length > 0) {\n // Update existing pattern\n await db\n .update(usagePatterns)\n .set({\n occurrences: sql`${usagePatterns.occurrences} + 1`,\n lastSeen: new Date(),\n confidence: sql`LEAST(${usagePatterns.confidence} + 1, 100)`,\n patternData: data ? { ...existing[0].patternData as object, ...data } : existing[0].patternData,\n })\n .where(eq(usagePatterns.id, existing[0].id));\n } else {\n // Create new pattern\n await db.insert(usagePatterns).values({\n userId,\n patternType: type,\n patternKey: key,\n patternData: data || {},\n confidence: 10,\n occurrences: 1,\n });\n }\n}\n\n// Get user's patterns\nexport async function getUserPatterns(\n userId: string,\n type?: PatternType\n): Promise<UsagePattern[]> {\n let query = db\n .select()\n .from(usagePatterns)\n .where(eq(usagePatterns.userId, userId));\n\n if (type) {\n query = db\n .select()\n .from(usagePatterns)\n .where(and(eq(usagePatterns.userId, userId), eq(usagePatterns.patternType, type)));\n }\n\n const results = await query.orderBy(desc(usagePatterns.confidence));\n\n return results.map((r) => ({\n type: r.patternType as PatternType,\n key: r.patternKey,\n data: (r.patternData as Record<string, unknown>) || {},\n confidence: r.confidence || 0,\n occurrences: r.occurrences || 1,\n firstSeen: r.firstSeen,\n lastSeen: r.lastSeen || r.firstSeen,\n }));\n}\n\n// Analyze tool usage patterns\nexport async function analyzeToolUsage(userId: string): Promise<void> {\n const recentTools = await db\n .select({\n toolName: toolLogs.toolName,\n count: count(),\n })\n .from(toolLogs)\n .innerJoin(conversations, eq(toolLogs.conversationId, conversations.id))\n .where(\n and(\n eq(conversations.userId, userId),\n gte(toolLogs.createdAt, new Date(Date.now() - 30 * 24 * 60 * 60 * 1000))\n )\n )\n .groupBy(toolLogs.toolName);\n\n for (const tool of recentTools) {\n await trackPattern(userId, \"tool_usage\", tool.toolName, {\n recentCount: tool.count,\n });\n }\n}\n\n// Analyze time-of-day patterns\nexport async function analyzeTimePatterns(userId: string): Promise<void> {\n const recentMessages = await db\n .select()\n .from(messages)\n .innerJoin(conversations, eq(messages.conversationId, conversations.id))\n .where(\n and(\n eq(conversations.userId, userId),\n eq(messages.role, \"user\"),\n gte(messages.createdAt, new Date(Date.now() - 30 * 24 * 60 * 60 * 1000))\n )\n );\n\n // Count messages by hour\n const hourCounts: Record<number, number> = {};\n for (const msg of recentMessages) {\n const hour = msg.messages.createdAt.getHours();\n hourCounts[hour] = (hourCounts[hour] || 0) + 1;\n }\n\n // Find peak hours\n const sortedHours = Object.entries(hourCounts)\n .sort(([, a], [, b]) => b - a)\n .slice(0, 3);\n\n for (const [hour, count] of sortedHours) {\n const timeLabel = getTimeLabel(parseInt(hour));\n await trackPattern(userId, \"time_of_day\", timeLabel, {\n hour: parseInt(hour),\n messageCount: count,\n });\n }\n}\n\nfunction getTimeLabel(hour: number): string {\n if (hour >= 5 && hour < 9) return \"early_morning\";\n if (hour >= 9 && hour < 12) return \"morning\";\n if (hour >= 12 && hour < 14) return \"midday\";\n if (hour >= 14 && hour < 17) return \"afternoon\";\n if (hour >= 17 && hour < 21) return \"evening\";\n return \"night\";\n}\n\n// Get evolution snapshot for a user\nexport async function getEvolutionSnapshot(userId: string): Promise<EvolutionSnapshot> {\n // Count conversations\n const [convCount] = await db\n .select({ count: count() })\n .from(conversations)\n .where(eq(conversations.userId, userId));\n\n // Count messages\n const [msgCount] = await db\n .select({ count: count() })\n .from(messages)\n .innerJoin(conversations, eq(messages.conversationId, conversations.id))\n .where(eq(conversations.userId, userId));\n\n // Count tool uses\n const [toolCount] = await db\n .select({ count: count() })\n .from(toolLogs)\n .innerJoin(conversations, eq(toolLogs.conversationId, conversations.id))\n .where(eq(conversations.userId, userId));\n\n // Count memories\n const [memCount] = await db\n .select({ count: count() })\n .from(memories)\n .where(eq(memories.userId, userId));\n\n // Get favorite tools\n const favoriteTools = await db\n .select({\n tool: toolLogs.toolName,\n count: count(),\n })\n .from(toolLogs)\n .innerJoin(conversations, eq(toolLogs.conversationId, conversations.id))\n .where(eq(conversations.userId, userId))\n .groupBy(toolLogs.toolName)\n .orderBy(desc(count()))\n .limit(5);\n\n // Get patterns\n const patterns = await getUserPatterns(userId);\n\n return {\n totalConversations: convCount.count,\n totalMessages: msgCount.count,\n totalToolUses: toolCount.count,\n totalMemories: memCount.count,\n favoriteTools: favoriteTools.map((t) => ({ tool: t.tool, count: t.count })),\n activeHours: [], // Would need more complex query\n topTopics: [], // Would need NLP analysis\n averageConversationLength: msgCount.count / Math.max(convCount.count, 1),\n patterns,\n };\n}\n\n// Generate growth report for a time period\nexport async function generateGrowthReport(\n userId: string,\n startDate: Date,\n endDate: Date\n): Promise<{\n period: { start: Date; end: Date };\n metrics: {\n conversations: number;\n messages: number;\n toolUses: number;\n newMemories: number;\n };\n insights: string[];\n patterns: UsagePattern[];\n}> {\n // Count conversations in period\n const [convCount] = await db\n .select({ count: count() })\n .from(conversations)\n .where(\n and(\n eq(conversations.userId, userId),\n gte(conversations.createdAt, startDate),\n lte(conversations.createdAt, endDate)\n )\n );\n\n // Count messages in period\n const [msgCount] = await db\n .select({ count: count() })\n .from(messages)\n .innerJoin(conversations, eq(messages.conversationId, conversations.id))\n .where(\n and(\n eq(conversations.userId, userId),\n gte(messages.createdAt, startDate),\n lte(messages.createdAt, endDate)\n )\n );\n\n // Count tool uses in period\n const [toolCount] = await db\n .select({ count: count() })\n .from(toolLogs)\n .innerJoin(conversations, eq(toolLogs.conversationId, conversations.id))\n .where(\n and(\n eq(conversations.userId, userId),\n gte(toolLogs.createdAt, startDate),\n lte(toolLogs.createdAt, endDate)\n )\n );\n\n // Count new memories in period\n const [memCount] = await db\n .select({ count: count() })\n .from(memories)\n .where(\n and(\n eq(memories.userId, userId),\n gte(memories.createdAt, startDate),\n lte(memories.createdAt, endDate)\n )\n );\n\n // Get patterns that emerged in this period\n const patterns = await db\n .select()\n .from(usagePatterns)\n .where(\n and(\n eq(usagePatterns.userId, userId),\n gte(usagePatterns.firstSeen, startDate)\n )\n );\n\n // Generate insights\n const insights: string[] = [];\n\n if (convCount.count > 0) {\n insights.push(`You had ${convCount.count} conversations during this period.`);\n }\n\n if (toolCount.count > 0) {\n insights.push(`You used tools ${toolCount.count} times to get things done.`);\n }\n\n if (memCount.count > 0) {\n insights.push(`I learned ${memCount.count} new things about you.`);\n }\n\n return {\n period: { start: startDate, end: endDate },\n metrics: {\n conversations: convCount.count,\n messages: msgCount.count,\n toolUses: toolCount.count,\n newMemories: memCount.count,\n },\n insights,\n patterns: patterns.map((p) => ({\n type: p.patternType as PatternType,\n key: p.patternKey,\n data: (p.patternData as Record<string, unknown>) || {},\n confidence: p.confidence || 0,\n occurrences: p.occurrences || 1,\n firstSeen: p.firstSeen,\n lastSeen: p.lastSeen || p.firstSeen,\n })),\n };\n}\n\n// Run all analysis for a user (call periodically)\nexport async function runFullAnalysis(userId: string): Promise<void> {\n await analyzeToolUsage(userId);\n await analyzeTimePatterns(userId);\n}\n","import { db } from \"../../db\";\nimport {\n achievements,\n userAchievements,\n messages,\n toolLogs,\n memories,\n conversations,\n moltModes,\n} from \"../../db/schema\";\nimport { eq, and, count, gte, sql } from \"drizzle-orm\";\n\nexport interface AchievementDefinition {\n code: string;\n name: string;\n description: string;\n iconEmoji: string;\n category: \"exploration\" | \"productivity\" | \"mastery\" | \"social\" | \"special\";\n criteria: {\n type: \"count\" | \"streak\" | \"threshold\" | \"milestone\";\n metric: string;\n threshold: number;\n conditions?: Record<string, unknown>;\n };\n points: number;\n}\n\n// Default achievement definitions\nexport const DEFAULT_ACHIEVEMENTS: AchievementDefinition[] = [\n // Exploration achievements\n {\n code: \"first_conversation\",\n name: \"Hello, World!\",\n description: \"Started your first conversation\",\n iconEmoji: \"👋\",\n category: \"exploration\",\n criteria: { type: \"count\", metric: \"conversations\", threshold: 1 },\n points: 10,\n },\n {\n code: \"first_tool\",\n name: \"Tool Time\",\n description: \"Used a tool for the first time\",\n iconEmoji: \"🔧\",\n category: \"exploration\",\n criteria: { type: \"count\", metric: \"tool_uses\", threshold: 1 },\n points: 10,\n },\n {\n code: \"first_memory\",\n name: \"Never Forget\",\n description: \"Created your first memory\",\n iconEmoji: \"🧠\",\n category: \"exploration\",\n criteria: { type: \"count\", metric: \"memories\", threshold: 1 },\n points: 10,\n },\n {\n code: \"mode_explorer\",\n name: \"Mode Explorer\",\n description: \"Tried all four transformation modes\",\n iconEmoji: \"🔄\",\n category: \"exploration\",\n criteria: { type: \"threshold\", metric: \"unique_modes\", threshold: 4 },\n points: 25,\n },\n\n // Productivity achievements\n {\n code: \"power_user\",\n name: \"Power User\",\n description: \"Had 100 conversations\",\n iconEmoji: \"⚡\",\n category: \"productivity\",\n criteria: { type: \"count\", metric: \"conversations\", threshold: 100 },\n points: 50,\n },\n {\n code: \"tool_master\",\n name: \"Tool Master\",\n description: \"Used tools 500 times\",\n iconEmoji: \"🛠️\",\n category: \"productivity\",\n criteria: { type: \"count\", metric: \"tool_uses\", threshold: 500 },\n points: 75,\n },\n {\n code: \"shell_wizard\",\n name: \"Shell Wizard\",\n description: \"Executed 100 shell commands\",\n iconEmoji: \"🧙\",\n category: \"productivity\",\n criteria: {\n type: \"count\",\n metric: \"tool_uses\",\n threshold: 100,\n conditions: { tool: \"execute_command\" },\n },\n points: 50,\n },\n\n // Mastery achievements\n {\n code: \"memory_bank\",\n name: \"Memory Bank\",\n description: \"Stored 50 memories\",\n iconEmoji: \"🏦\",\n category: \"mastery\",\n criteria: { type: \"count\", metric: \"memories\", threshold: 50 },\n points: 50,\n },\n {\n code: \"week_streak\",\n name: \"Weekly Regular\",\n description: \"Used OpenSentinel 7 days in a row\",\n iconEmoji: \"📅\",\n category: \"mastery\",\n criteria: { type: \"streak\", metric: \"daily_usage\", threshold: 7 },\n points: 30,\n },\n {\n code: \"month_streak\",\n name: \"Monthly Champion\",\n description: \"Used OpenSentinel 30 days in a row\",\n iconEmoji: \"🏆\",\n category: \"mastery\",\n criteria: { type: \"streak\", metric: \"daily_usage\", threshold: 30 },\n points: 100,\n },\n\n // Special achievements\n {\n code: \"night_owl\",\n name: \"Night Owl\",\n description: \"Had 10 conversations after midnight\",\n iconEmoji: \"🦉\",\n category: \"special\",\n criteria: {\n type: \"count\",\n metric: \"conversations\",\n threshold: 10,\n conditions: { hour_range: [0, 5] },\n },\n points: 20,\n },\n {\n code: \"early_bird\",\n name: \"Early Bird\",\n description: \"Had 10 conversations before 7am\",\n iconEmoji: \"🐦\",\n category: \"special\",\n criteria: {\n type: \"count\",\n metric: \"conversations\",\n threshold: 10,\n conditions: { hour_range: [5, 7] },\n },\n points: 20,\n },\n];\n\n// Initialize default achievements in database\nexport async function initializeAchievements(): Promise<void> {\n for (const achievement of DEFAULT_ACHIEVEMENTS) {\n const existing = await db\n .select()\n .from(achievements)\n .where(eq(achievements.code, achievement.code))\n .limit(1);\n\n if (existing.length === 0) {\n await db.insert(achievements).values({\n code: achievement.code,\n name: achievement.name,\n description: achievement.description,\n iconEmoji: achievement.iconEmoji,\n category: achievement.category,\n criteria: achievement.criteria,\n points: achievement.points,\n });\n }\n }\n}\n\n// Check if user has achievement\nexport async function hasAchievement(\n userId: string,\n achievementCode: string\n): Promise<boolean> {\n const [achievement] = await db\n .select()\n .from(achievements)\n .where(eq(achievements.code, achievementCode))\n .limit(1);\n\n if (!achievement) return false;\n\n const [unlocked] = await db\n .select()\n .from(userAchievements)\n .where(\n and(\n eq(userAchievements.userId, userId),\n eq(userAchievements.achievementId, achievement.id)\n )\n )\n .limit(1);\n\n return !!unlocked;\n}\n\n// Unlock achievement for user\nexport async function unlockAchievement(\n userId: string,\n achievementCode: string\n): Promise<{ unlocked: boolean; achievement?: AchievementDefinition }> {\n // Check if already unlocked\n if (await hasAchievement(userId, achievementCode)) {\n return { unlocked: false };\n }\n\n const [achievement] = await db\n .select()\n .from(achievements)\n .where(eq(achievements.code, achievementCode))\n .limit(1);\n\n if (!achievement) {\n return { unlocked: false };\n }\n\n await db.insert(userAchievements).values({\n userId,\n achievementId: achievement.id,\n });\n\n return {\n unlocked: true,\n achievement: {\n code: achievement.code,\n name: achievement.name,\n description: achievement.description || \"\",\n iconEmoji: achievement.iconEmoji || \"🏆\",\n category: achievement.category as AchievementDefinition[\"category\"],\n criteria: achievement.criteria as AchievementDefinition[\"criteria\"],\n points: achievement.points || 10,\n },\n };\n}\n\n// Get user's unlocked achievements\nexport async function getUserAchievements(\n userId: string\n): Promise<Array<{ achievement: AchievementDefinition; unlockedAt: Date }>> {\n const unlocked = await db\n .select()\n .from(userAchievements)\n .innerJoin(achievements, eq(userAchievements.achievementId, achievements.id))\n .where(eq(userAchievements.userId, userId));\n\n return unlocked.map((u) => ({\n achievement: {\n code: u.achievements.code,\n name: u.achievements.name,\n description: u.achievements.description || \"\",\n iconEmoji: u.achievements.iconEmoji || \"🏆\",\n category: u.achievements.category as AchievementDefinition[\"category\"],\n criteria: u.achievements.criteria as AchievementDefinition[\"criteria\"],\n points: u.achievements.points || 10,\n },\n unlockedAt: u.user_achievements.unlockedAt,\n }));\n}\n\n// Get user's total points\nexport async function getUserPoints(userId: string): Promise<number> {\n const unlocked = await getUserAchievements(userId);\n return unlocked.reduce((sum, u) => sum + u.achievement.points, 0);\n}\n\n// Check and unlock achievements based on current stats\nexport async function checkAchievements(\n userId: string\n): Promise<AchievementDefinition[]> {\n const newlyUnlocked: AchievementDefinition[] = [];\n\n // Get all achievements\n const allAchievements = await db.select().from(achievements);\n\n for (const achievement of allAchievements) {\n // Skip if already unlocked\n if (await hasAchievement(userId, achievement.code)) {\n continue;\n }\n\n const criteria = achievement.criteria as AchievementDefinition[\"criteria\"];\n let shouldUnlock = false;\n\n switch (criteria.metric) {\n case \"conversations\":\n const [convCount] = await db\n .select({ count: count() })\n .from(conversations)\n .where(eq(conversations.userId, userId));\n shouldUnlock = convCount.count >= criteria.threshold;\n break;\n\n case \"tool_uses\":\n if (criteria.conditions?.tool) {\n const [toolCount] = await db\n .select({ count: count() })\n .from(toolLogs)\n .innerJoin(conversations, eq(toolLogs.conversationId, conversations.id))\n .where(\n and(\n eq(conversations.userId, userId),\n eq(toolLogs.toolName, criteria.conditions.tool as string)\n )\n );\n shouldUnlock = toolCount.count >= criteria.threshold;\n } else {\n const [toolCount] = await db\n .select({ count: count() })\n .from(toolLogs)\n .innerJoin(conversations, eq(toolLogs.conversationId, conversations.id))\n .where(eq(conversations.userId, userId));\n shouldUnlock = toolCount.count >= criteria.threshold;\n }\n break;\n\n case \"memories\":\n const [memCount] = await db\n .select({ count: count() })\n .from(memories)\n .where(eq(memories.userId, userId));\n shouldUnlock = memCount.count >= criteria.threshold;\n break;\n\n case \"unique_modes\":\n const modes = await db\n .select({ mode: moltModes.mode })\n .from(moltModes)\n .where(eq(moltModes.userId, userId))\n .groupBy(moltModes.mode);\n shouldUnlock = modes.length >= criteria.threshold;\n break;\n }\n\n if (shouldUnlock) {\n const result = await unlockAchievement(userId, achievement.code);\n if (result.unlocked && result.achievement) {\n newlyUnlocked.push(result.achievement);\n }\n }\n }\n\n return newlyUnlocked;\n}\n\n// Get progress toward next achievements\nexport async function getAchievementProgress(\n userId: string\n): Promise<Array<{ achievement: AchievementDefinition; progress: number; target: number }>> {\n const progress: Array<{\n achievement: AchievementDefinition;\n progress: number;\n target: number;\n }> = [];\n\n const allAchievements = await db.select().from(achievements);\n\n for (const achievement of allAchievements) {\n // Skip if already unlocked\n if (await hasAchievement(userId, achievement.code)) {\n continue;\n }\n\n const criteria = achievement.criteria as AchievementDefinition[\"criteria\"];\n let currentProgress = 0;\n\n switch (criteria.metric) {\n case \"conversations\":\n const [convCount] = await db\n .select({ count: count() })\n .from(conversations)\n .where(eq(conversations.userId, userId));\n currentProgress = convCount.count;\n break;\n\n case \"tool_uses\":\n const [toolCount] = await db\n .select({ count: count() })\n .from(toolLogs)\n .innerJoin(conversations, eq(toolLogs.conversationId, conversations.id))\n .where(eq(conversations.userId, userId));\n currentProgress = toolCount.count;\n break;\n\n case \"memories\":\n const [memCount] = await db\n .select({ count: count() })\n .from(memories)\n .where(eq(memories.userId, userId));\n currentProgress = memCount.count;\n break;\n }\n\n progress.push({\n achievement: {\n code: achievement.code,\n name: achievement.name,\n description: achievement.description || \"\",\n iconEmoji: achievement.iconEmoji || \"🏆\",\n category: achievement.category as AchievementDefinition[\"category\"],\n criteria,\n points: achievement.points || 10,\n },\n progress: currentProgress,\n target: criteria.threshold,\n });\n }\n\n // Sort by closest to completion\n return progress.sort(\n (a, b) => b.progress / b.target - a.progress / a.target\n );\n}\n\n// Get achievement leaderboard (for multi-user scenarios)\nexport async function getLeaderboard(\n limit: number = 10\n): Promise<Array<{ userId: string; points: number; achievementCount: number }>> {\n const results = await db\n .select({\n userId: userAchievements.userId,\n achievementCount: count(),\n })\n .from(userAchievements)\n .groupBy(userAchievements.userId)\n .orderBy(sql`count(*) DESC`)\n .limit(limit);\n\n // Calculate points for each user\n const leaderboard = await Promise.all(\n results.map(async (r) => ({\n userId: r.userId,\n points: await getUserPoints(r.userId),\n achievementCount: r.achievementCount,\n }))\n );\n\n return leaderboard.sort((a, b) => b.points - a.points);\n}\n","// Thinking Levels — Control AI reasoning depth and extended thinking\n\nexport type ThinkingLevel = \"quick\" | \"normal\" | \"deep\" | \"extended\";\n\nexport interface ThinkingConfig {\n level: ThinkingLevel;\n label: string;\n description: string;\n budgetTokens: number;\n maxTokens: number;\n model: string;\n useExtendedThinking: boolean;\n}\n\nexport const THINKING_LEVELS: Record<ThinkingLevel, ThinkingConfig> = {\n quick: {\n level: \"quick\",\n label: \"Quick\",\n description: \"Fast responses with minimal reasoning — best for simple questions and commands\",\n budgetTokens: 0,\n maxTokens: 2048,\n model: \"claude-sonnet-4-20250514\",\n useExtendedThinking: false,\n },\n normal: {\n level: \"normal\",\n label: \"Normal\",\n description: \"Standard reasoning depth — balanced speed and quality\",\n budgetTokens: 0,\n maxTokens: 4096,\n model: \"claude-sonnet-4-20250514\",\n useExtendedThinking: false,\n },\n deep: {\n level: \"deep\",\n label: \"Deep\",\n description: \"Extended thinking enabled — better for complex analysis, math, and coding\",\n budgetTokens: 10000,\n maxTokens: 16000,\n model: \"claude-sonnet-4-20250514\",\n useExtendedThinking: true,\n },\n extended: {\n level: \"extended\",\n label: \"Extended\",\n description: \"Maximum reasoning depth — best for hard problems, long-form analysis, and research\",\n budgetTokens: 32000,\n maxTokens: 32000,\n model: \"claude-sonnet-4-20250514\",\n useExtendedThinking: true,\n },\n};\n\n// Per-user thinking level preferences\nconst userThinkingLevels: Map<string, ThinkingLevel> = new Map();\n\n// Default level\nlet defaultLevel: ThinkingLevel = \"normal\";\n\nexport class ThinkingLevelManager {\n /**\n * Set the thinking level for a user\n */\n setLevel(userId: string, level: ThinkingLevel): ThinkingConfig {\n userThinkingLevels.set(userId, level);\n return THINKING_LEVELS[level];\n }\n\n /**\n * Get the current thinking level for a user\n */\n getLevel(userId: string): ThinkingLevel {\n return userThinkingLevels.get(userId) ?? defaultLevel;\n }\n\n /**\n * Get the full config for a user's thinking level\n */\n getConfig(userId: string): ThinkingConfig {\n const level = this.getLevel(userId);\n return THINKING_LEVELS[level];\n }\n\n /**\n * Set the default thinking level\n */\n setDefault(level: ThinkingLevel): void {\n defaultLevel = level;\n }\n\n /**\n * Get all available thinking levels\n */\n getAllLevels(): ThinkingConfig[] {\n return Object.values(THINKING_LEVELS);\n }\n\n /**\n * Auto-detect appropriate thinking level based on message content\n */\n suggestLevel(message: string): ThinkingLevel {\n const lower = message.toLowerCase();\n\n // Extended: complex math, proofs, research papers\n if (\n lower.includes(\"prove\") ||\n lower.includes(\"theorem\") ||\n lower.includes(\"derive\") ||\n lower.includes(\"comprehensive analysis\") ||\n lower.includes(\"research paper\") ||\n lower.includes(\"in-depth\")\n ) {\n return \"extended\";\n }\n\n // Deep: coding, debugging, analysis\n if (\n lower.includes(\"debug\") ||\n lower.includes(\"refactor\") ||\n lower.includes(\"implement\") ||\n lower.includes(\"analyze\") ||\n lower.includes(\"explain how\") ||\n lower.includes(\"step by step\") ||\n lower.includes(\"complex\")\n ) {\n return \"deep\";\n }\n\n // Quick: simple commands, greetings, short answers\n if (\n lower.length < 20 ||\n lower.includes(\"hi\") ||\n lower.includes(\"hello\") ||\n lower.includes(\"thanks\") ||\n lower.includes(\"yes\") ||\n lower.includes(\"no\") ||\n lower.includes(\"ok\")\n ) {\n return \"quick\";\n }\n\n return \"normal\";\n }\n\n /**\n * Build the API parameters based on thinking level\n */\n buildApiParams(userId: string): {\n model: string;\n max_tokens: number;\n thinking?: { type: \"enabled\"; budget_tokens: number };\n } {\n const config = this.getConfig(userId);\n\n const params: {\n model: string;\n max_tokens: number;\n thinking?: { type: \"enabled\"; budget_tokens: number };\n } = {\n model: config.model,\n max_tokens: config.maxTokens,\n };\n\n if (config.useExtendedThinking && config.budgetTokens > 0) {\n params.thinking = {\n type: \"enabled\",\n budget_tokens: config.budgetTokens,\n };\n }\n\n return params;\n }\n\n /**\n * Format thinking level info for display\n */\n formatLevelInfo(level?: ThinkingLevel): string {\n const config = level ? THINKING_LEVELS[level] : THINKING_LEVELS[defaultLevel];\n const emoji = {\n quick: \"\\u26a1\",\n normal: \"\\ud83e\\udde0\",\n deep: \"\\ud83d\\udd2c\",\n extended: \"\\ud83c\\udf0a\",\n }[config.level];\n\n return `${emoji} **${config.label}** — ${config.description}`;\n }\n\n /**\n * Clear user's thinking level preference\n */\n clearLevel(userId: string): void {\n userThinkingLevels.delete(userId);\n }\n}\n\n// Singleton\nexport const thinkingLevelManager = new ThinkingLevelManager();\n","// Core Hooks System — System-wide lifecycle hooks\n// Unlike plugin events, these are core hooks that intercept and can modify behavior\n\nexport type HookPhase = \"before\" | \"after\";\n\nexport type HookEvent =\n | \"message:process\" // Before/after processing a user message\n | \"tool:execute\" // Before/after tool execution\n | \"response:generate\" // Before/after generating AI response\n | \"memory:store\" // Before/after storing a memory\n | \"mode:change\" // Before/after mode change\n | \"session:start\" // Before/after session creation\n | \"session:end\" // Before/after session end\n | \"agent:spawn\" // Before/after spawning an agent\n | \"workflow:execute\" // Before/after workflow execution\n | \"skill:execute\"; // Before/after skill execution\n\nexport interface HookContext {\n event: HookEvent;\n phase: HookPhase;\n userId?: string;\n timestamp: Date;\n data: Record<string, unknown>;\n /** Set to true to cancel the operation (only in \"before\" phase) */\n cancelled: boolean;\n /** Reason for cancellation */\n cancelReason?: string;\n /** Modified data to pass through */\n modifiedData?: Record<string, unknown>;\n}\n\nexport type HookHandler = (context: HookContext) => Promise<HookContext> | HookContext;\n\ninterface RegisteredHook {\n id: string;\n event: HookEvent;\n phase: HookPhase;\n handler: HookHandler;\n priority: number; // Lower = runs first\n name: string;\n enabled: boolean;\n}\n\n// Hook registry\nconst hooks: Map<string, RegisteredHook> = new Map();\nlet hookIdCounter = 0;\n\nexport class HookManager {\n /**\n * Register a hook\n */\n register(params: {\n event: HookEvent;\n phase: HookPhase;\n handler: HookHandler;\n name: string;\n priority?: number;\n }): string {\n const id = `hook_${++hookIdCounter}`;\n const hook: RegisteredHook = {\n id,\n event: params.event,\n phase: params.phase,\n handler: params.handler,\n priority: params.priority ?? 100,\n name: params.name,\n enabled: true,\n };\n hooks.set(id, hook);\n return id;\n }\n\n /**\n * Unregister a hook\n */\n unregister(hookId: string): boolean {\n return hooks.delete(hookId);\n }\n\n /**\n * Enable/disable a hook\n */\n setEnabled(hookId: string, enabled: boolean): void {\n const hook = hooks.get(hookId);\n if (hook) hook.enabled = enabled;\n }\n\n /**\n * Run all hooks for a given event and phase\n */\n async run(\n event: HookEvent,\n phase: HookPhase,\n data: Record<string, unknown>,\n userId?: string\n ): Promise<HookContext> {\n const context: HookContext = {\n event,\n phase,\n userId,\n timestamp: new Date(),\n data: { ...data },\n cancelled: false,\n };\n\n // Get matching hooks sorted by priority\n const matching = this.getHooksFor(event, phase);\n\n for (const hook of matching) {\n try {\n const result = await hook.handler(context);\n // Merge modifications back\n if (result.modifiedData) {\n Object.assign(context.data, result.modifiedData);\n }\n context.cancelled = result.cancelled;\n context.cancelReason = result.cancelReason;\n\n // Stop processing if cancelled\n if (context.cancelled && phase === \"before\") {\n break;\n }\n } catch (error) {\n console.error(`[Hook] Error in hook \"${hook.name}\":`, error);\n }\n }\n\n return context;\n }\n\n /**\n * Convenience: run before hooks, check if cancelled\n */\n async runBefore(\n event: HookEvent,\n data: Record<string, unknown>,\n userId?: string\n ): Promise<{ proceed: boolean; data: Record<string, unknown>; reason?: string }> {\n const ctx = await this.run(event, \"before\", data, userId);\n return {\n proceed: !ctx.cancelled,\n data: ctx.modifiedData ?? ctx.data,\n reason: ctx.cancelReason,\n };\n }\n\n /**\n * Convenience: run after hooks\n */\n async runAfter(\n event: HookEvent,\n data: Record<string, unknown>,\n userId?: string\n ): Promise<void> {\n await this.run(event, \"after\", data, userId);\n }\n\n /**\n * Get hooks for a specific event/phase\n */\n private getHooksFor(event: HookEvent, phase: HookPhase): RegisteredHook[] {\n const result: RegisteredHook[] = [];\n for (const hook of hooks.values()) {\n if (hook.event === event && hook.phase === phase && hook.enabled) {\n result.push(hook);\n }\n }\n return result.sort((a, b) => a.priority - b.priority);\n }\n\n /**\n * List all registered hooks\n */\n listHooks(): Array<{\n id: string;\n event: HookEvent;\n phase: HookPhase;\n name: string;\n priority: number;\n enabled: boolean;\n }> {\n return [...hooks.values()].map((h) => ({\n id: h.id,\n event: h.event,\n phase: h.phase,\n name: h.name,\n priority: h.priority,\n enabled: h.enabled,\n }));\n }\n\n /**\n * Clear all hooks\n */\n clearAll(): void {\n hooks.clear();\n }\n\n /**\n * Get hook count\n */\n getHookCount(): number {\n return hooks.size;\n }\n}\n\n// Singleton\nexport const hookManager = new HookManager();\n\n// ============================================\n// SOUL HOOK — Personality/behavior modification\n// ============================================\n\nexport interface SoulConfig {\n name: string;\n description: string;\n personality: string; // Injected into system prompt\n rules: string[]; // Behavioral rules\n enabled: boolean;\n}\n\n// In-memory soul configs\nconst soulConfigs: Map<string, SoulConfig> = new Map();\nlet activeSoulId: string | null = null;\n\nexport class SoulHookManager {\n /**\n * Register a soul configuration\n */\n registerSoul(id: string, config: SoulConfig): void {\n soulConfigs.set(id, config);\n }\n\n /**\n * Activate a soul — modifies AI personality via system prompt injection\n */\n activateSoul(soulId: string): boolean {\n const soul = soulConfigs.get(soulId);\n if (!soul) return false;\n\n // Deactivate previous\n if (activeSoulId) {\n const prev = soulConfigs.get(activeSoulId);\n if (prev) prev.enabled = false;\n }\n\n soul.enabled = true;\n activeSoulId = soulId;\n\n // Register a hook that modifies the system prompt\n hookManager.register({\n event: \"message:process\",\n phase: \"before\",\n name: `soul:${soulId}`,\n priority: 10, // High priority — runs early\n handler: (ctx) => {\n if (soul.enabled) {\n ctx.modifiedData = {\n ...ctx.data,\n soulPrompt: this.buildSoulPrompt(soul),\n };\n }\n return ctx;\n },\n });\n\n return true;\n }\n\n /**\n * Deactivate the current soul\n */\n deactivateSoul(): void {\n if (activeSoulId) {\n const soul = soulConfigs.get(activeSoulId);\n if (soul) soul.enabled = false;\n }\n activeSoulId = null;\n }\n\n /**\n * Get the active soul config\n */\n getActiveSoul(): SoulConfig | null {\n if (!activeSoulId) return null;\n return soulConfigs.get(activeSoulId) ?? null;\n }\n\n /**\n * Build the system prompt addition from a soul config\n */\n buildSoulPrompt(soul: SoulConfig): string {\n const parts: string[] = [];\n parts.push(`\\n\\n[SOUL: ${soul.name}]`);\n parts.push(soul.personality);\n\n if (soul.rules.length > 0) {\n parts.push(\"\\nBehavioral Rules:\");\n for (const rule of soul.rules) {\n parts.push(`- ${rule}`);\n }\n }\n\n return parts.join(\"\\n\");\n }\n\n /**\n * List all registered souls\n */\n listSouls(): Array<{ id: string; config: SoulConfig; active: boolean }> {\n const result: Array<{ id: string; config: SoulConfig; active: boolean }> = [];\n for (const [id, config] of soulConfigs.entries()) {\n result.push({ id, config, active: id === activeSoulId });\n }\n return result;\n }\n\n /**\n * Delete a soul\n */\n deleteSoul(id: string): boolean {\n if (id === activeSoulId) this.deactivateSoul();\n return soulConfigs.delete(id);\n }\n}\n\n// Singleton\nexport const soulHookManager = new SoulHookManager();\n\n// Register built-in soul: \"Evil Hook\" (mischievous personality)\nsoulHookManager.registerSoul(\"evil\", {\n name: \"Evil Mode\",\n description: \"A mischievous, sarcastic personality that still helps but with attitude\",\n personality: `You have a mischievous streak. While you still help the user accomplish their goals,\nyou do so with dark humor, sarcastic commentary, and dramatic flair. You might:\n- Add dramatic narration to mundane tasks\n- Use villain-like phrasing (\"Excellent... the code compiles as planned...\")\n- Make sarcastic observations about the user's choices\n- Reference pop culture villains\n- Still be helpful — just entertainingly evil about it`,\n rules: [\n \"Never actually refuse to help or be harmful\",\n \"Keep the dark humor lighthearted and fun\",\n \"Still prioritize accuracy and helpfulness\",\n \"Don't overdo it — subtlety is key\",\n ],\n enabled: false,\n});\n\n// Register built-in soul: \"Professional\"\nsoulHookManager.registerSoul(\"professional\", {\n name: \"Professional Mode\",\n description: \"Ultra-professional, formal communication style\",\n personality: `You communicate in a highly professional, formal manner suitable for enterprise environments.\nUse precise language, avoid colloquialisms, and maintain a consultative tone.`,\n rules: [\n \"Use formal language at all times\",\n \"Address the user professionally\",\n \"Provide structured, well-organized responses\",\n \"Cite reasoning and evidence for recommendations\",\n ],\n enabled: false,\n});\n\n// Register built-in soul: \"Friendly\"\nsoulHookManager.registerSoul(\"friendly\", {\n name: \"Friendly Mode\",\n description: \"Warm, encouraging, and supportive personality\",\n personality: `You are exceptionally warm, encouraging, and supportive. You celebrate wins,\noffer gentle guidance on mistakes, and make the user feel supported throughout their work.\nThink of yourself as a helpful friend who happens to be an expert.`,\n rules: [\n \"Always acknowledge effort and progress\",\n \"Offer encouragement when tasks are challenging\",\n \"Use a warm, conversational tone\",\n \"Be patient and understanding with mistakes\",\n ],\n enabled: false,\n});\n"],"mappings":"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","names":["eq","and","desc","and","eq","desc","eq","eq","and","and","eq","eq","and","desc","sql","and","eq","eq","and","count","sql","eq","and","count","messages"]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// src/utils/paths.ts
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
// src/utils/platform.ts
|
|
5
|
+
import os from "os";
|
|
6
|
+
var platform = os.platform();
|
|
7
|
+
var isWindows = platform === "win32";
|
|
8
|
+
var isLinux = platform === "linux";
|
|
9
|
+
function getHomeDir() {
|
|
10
|
+
return os.homedir();
|
|
11
|
+
}
|
|
12
|
+
function getTempDir() {
|
|
13
|
+
return os.tmpdir();
|
|
14
|
+
}
|
|
15
|
+
function getShellConfig() {
|
|
16
|
+
if (isWindows) {
|
|
17
|
+
const powershell = process.env.PSModulePath ? "powershell.exe" : null;
|
|
18
|
+
if (powershell) {
|
|
19
|
+
return {
|
|
20
|
+
shell: powershell,
|
|
21
|
+
args: ["-NoProfile", "-NonInteractive", "-Command"]
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
shell: process.env.COMSPEC || "cmd.exe",
|
|
26
|
+
args: ["/c"]
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
shell: process.env.SHELL || "/bin/bash",
|
|
31
|
+
args: ["-c"]
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function normalizePath(p) {
|
|
35
|
+
return p.replace(/\\/g, "/");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/utils/paths.ts
|
|
39
|
+
function isPathAllowed(targetPath) {
|
|
40
|
+
const resolved = path.resolve(targetPath);
|
|
41
|
+
const normalized = normalizePath(resolved);
|
|
42
|
+
const home = normalizePath(getHomeDir());
|
|
43
|
+
const temp = normalizePath(getTempDir());
|
|
44
|
+
return normalized.startsWith(home) || normalized.startsWith(temp);
|
|
45
|
+
}
|
|
46
|
+
function getSafeExtension(filePath) {
|
|
47
|
+
return path.extname(filePath).toLowerCase();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
isWindows,
|
|
52
|
+
isLinux,
|
|
53
|
+
getShellConfig,
|
|
54
|
+
isPathAllowed,
|
|
55
|
+
getSafeExtension
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=chunk-CQ4JURG7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/paths.ts","../src/utils/platform.ts"],"sourcesContent":["import path from \"path\";\nimport { getHomeDir, getTempDir, isWindows, normalizePath } from \"./platform\";\n\nexport function resolveUserPath(userPath: string): string {\n // Expand ~ to home directory\n if (userPath.startsWith(\"~\")) {\n return path.join(getHomeDir(), userPath.slice(1));\n }\n\n // Handle Windows environment variables like %USERPROFILE%\n if (isWindows && userPath.includes(\"%\")) {\n return userPath.replace(/%([^%]+)%/g, (_, envVar) => {\n return process.env[envVar] || \"\";\n });\n }\n\n // Handle Unix environment variables like $HOME\n if (!isWindows && userPath.includes(\"$\")) {\n return userPath.replace(/\\$(\\w+)/g, (_, envVar) => {\n return process.env[envVar] || \"\";\n });\n }\n\n return path.resolve(userPath);\n}\n\nexport function isPathAllowed(targetPath: string): boolean {\n const resolved = path.resolve(targetPath);\n const normalized = normalizePath(resolved);\n const home = normalizePath(getHomeDir());\n const temp = normalizePath(getTempDir());\n\n // Allow paths under home directory or temp directory\n return normalized.startsWith(home) || normalized.startsWith(temp);\n}\n\nexport function getSafeBasename(filePath: string): string {\n return path.basename(filePath);\n}\n\nexport function getSafeExtension(filePath: string): string {\n return path.extname(filePath).toLowerCase();\n}\n\nexport function joinPaths(...parts: string[]): string {\n return path.join(...parts);\n}\n\nexport function getRelativePath(from: string, to: string): string {\n return path.relative(from, to);\n}\n\nexport function isAbsolutePath(p: string): boolean {\n return path.isAbsolute(p);\n}\n\nexport function ensureAbsolutePath(p: string, basePath?: string): string {\n if (isAbsolutePath(p)) {\n return p;\n }\n return path.resolve(basePath || process.cwd(), p);\n}\n","import os from \"os\";\nimport path from \"path\";\n\nexport const platform = os.platform();\nexport const isWindows = platform === \"win32\";\nexport const isLinux = platform === \"linux\";\nexport const isMac = platform === \"darwin\";\n\nexport function getHomeDir(): string {\n return os.homedir();\n}\n\nexport function getDataDir(): string {\n if (isWindows) {\n return path.join(process.env.APPDATA || getHomeDir(), \"OpenSentinel\");\n }\n return path.join(getHomeDir(), \".sentinel\");\n}\n\nexport function getTempDir(): string {\n return os.tmpdir();\n}\n\nexport function getCpuCount(): number {\n return os.cpus().length;\n}\n\nexport function getTotalMemory(): number {\n return os.totalmem();\n}\n\nexport function getFreeMemory(): number {\n return os.freemem();\n}\n\nexport interface ShellConfig {\n shell: string;\n args: string[];\n}\n\nexport function getShellConfig(): ShellConfig {\n if (isWindows) {\n // Prefer PowerShell if available, fallback to cmd.exe\n const powershell = process.env.PSModulePath ? \"powershell.exe\" : null;\n if (powershell) {\n return {\n shell: powershell,\n args: [\"-NoProfile\", \"-NonInteractive\", \"-Command\"],\n };\n }\n return {\n shell: process.env.COMSPEC || \"cmd.exe\",\n args: [\"/c\"],\n };\n }\n\n // Unix-like systems (Linux, macOS)\n return {\n shell: process.env.SHELL || \"/bin/bash\",\n args: [\"-c\"],\n };\n}\n\nexport function normalizePath(p: string): string {\n // Convert backslashes to forward slashes for consistency\n return p.replace(/\\\\/g, \"/\");\n}\n\nexport function toNativePath(p: string): string {\n if (isWindows) {\n return p.replace(/\\//g, \"\\\\\");\n }\n return p;\n}\n\nexport function getPathSeparator(): string {\n return path.sep;\n}\n\nexport function getEnvPathSeparator(): string {\n return isWindows ? \";\" : \":\";\n}\n"],"mappings":";AAAA,OAAO,UAAU;;;ACAjB,OAAO,QAAQ;AAGR,IAAM,WAAW,GAAG,SAAS;AAC7B,IAAM,YAAY,aAAa;AAC/B,IAAM,UAAU,aAAa;AAG7B,SAAS,aAAqB;AACnC,SAAO,GAAG,QAAQ;AACpB;AASO,SAAS,aAAqB;AACnC,SAAO,GAAG,OAAO;AACnB;AAmBO,SAAS,iBAA8B;AAC5C,MAAI,WAAW;AAEb,UAAM,aAAa,QAAQ,IAAI,eAAe,mBAAmB;AACjE,QAAI,YAAY;AACd,aAAO;AAAA,QACL,OAAO;AAAA,QACP,MAAM,CAAC,cAAc,mBAAmB,UAAU;AAAA,MACpD;AAAA,IACF;AACA,WAAO;AAAA,MACL,OAAO,QAAQ,IAAI,WAAW;AAAA,MAC9B,MAAM,CAAC,IAAI;AAAA,IACb;AAAA,EACF;AAGA,SAAO;AAAA,IACL,OAAO,QAAQ,IAAI,SAAS;AAAA,IAC5B,MAAM,CAAC,IAAI;AAAA,EACb;AACF;AAEO,SAAS,cAAc,GAAmB;AAE/C,SAAO,EAAE,QAAQ,OAAO,GAAG;AAC7B;;;ADxCO,SAAS,cAAc,YAA6B;AACzD,QAAM,WAAW,KAAK,QAAQ,UAAU;AACxC,QAAM,aAAa,cAAc,QAAQ;AACzC,QAAM,OAAO,cAAc,WAAW,CAAC;AACvC,QAAM,OAAO,cAAc,WAAW,CAAC;AAGvC,SAAO,WAAW,WAAW,IAAI,KAAK,WAAW,WAAW,IAAI;AAClE;AAMO,SAAS,iBAAiB,UAA0B;AACzD,SAAO,KAAK,QAAQ,QAAQ,EAAE,YAAY;AAC5C;","names":[]}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
env
|
|
3
|
+
} from "./chunk-4TG2IG5K.js";
|
|
4
|
+
|
|
5
|
+
// src/outputs/tts.ts
|
|
6
|
+
var ELEVENLABS_API_URL = "https://api.elevenlabs.io/v1";
|
|
7
|
+
async function textToSpeech(text, options = {}) {
|
|
8
|
+
const {
|
|
9
|
+
stability = 0.5,
|
|
10
|
+
similarityBoost = 0.75,
|
|
11
|
+
style = 0,
|
|
12
|
+
useSpeakerBoost = true
|
|
13
|
+
} = options;
|
|
14
|
+
try {
|
|
15
|
+
const response = await fetch(
|
|
16
|
+
`${ELEVENLABS_API_URL}/text-to-speech/${env.ELEVENLABS_VOICE_ID}`,
|
|
17
|
+
{
|
|
18
|
+
method: "POST",
|
|
19
|
+
headers: {
|
|
20
|
+
"Content-Type": "application/json",
|
|
21
|
+
"xi-api-key": env.ELEVENLABS_API_KEY
|
|
22
|
+
},
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
text,
|
|
25
|
+
model_id: "eleven_monolingual_v1",
|
|
26
|
+
voice_settings: {
|
|
27
|
+
stability,
|
|
28
|
+
similarity_boost: similarityBoost,
|
|
29
|
+
style,
|
|
30
|
+
use_speaker_boost: useSpeakerBoost
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
const error = await response.text();
|
|
37
|
+
console.error("ElevenLabs API error:", error);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const audioBuffer = await response.arrayBuffer();
|
|
41
|
+
return Buffer.from(audioBuffer);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error("Error generating speech:", error);
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
textToSpeech
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=chunk-F6QUZQGI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/outputs/tts.ts"],"sourcesContent":["import { env } from \"../config/env\";\n\nconst ELEVENLABS_API_URL = \"https://api.elevenlabs.io/v1\";\n\nexport interface TTSOptions {\n stability?: number;\n similarityBoost?: number;\n style?: number;\n useSpeakerBoost?: boolean;\n}\n\nexport async function textToSpeech(\n text: string,\n options: TTSOptions = {}\n): Promise<Buffer | null> {\n const {\n stability = 0.5,\n similarityBoost = 0.75,\n style = 0,\n useSpeakerBoost = true,\n } = options;\n\n try {\n const response = await fetch(\n `${ELEVENLABS_API_URL}/text-to-speech/${env.ELEVENLABS_VOICE_ID}`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"xi-api-key\": env.ELEVENLABS_API_KEY,\n },\n body: JSON.stringify({\n text,\n model_id: \"eleven_monolingual_v1\",\n voice_settings: {\n stability,\n similarity_boost: similarityBoost,\n style,\n use_speaker_boost: useSpeakerBoost,\n },\n }),\n }\n );\n\n if (!response.ok) {\n const error = await response.text();\n console.error(\"ElevenLabs API error:\", error);\n return null;\n }\n\n const audioBuffer = await response.arrayBuffer();\n return Buffer.from(audioBuffer);\n } catch (error) {\n console.error(\"Error generating speech:\", error);\n return null;\n }\n}\n\nexport async function getVoices(): Promise<\n Array<{ voice_id: string; name: string }>\n> {\n try {\n const response = await fetch(`${ELEVENLABS_API_URL}/voices`, {\n headers: {\n \"xi-api-key\": env.ELEVENLABS_API_KEY,\n },\n });\n\n if (!response.ok) {\n return [];\n }\n\n const data = (await response.json()) as {\n voices: Array<{ voice_id: string; name: string }>;\n };\n return data.voices;\n } catch (error) {\n console.error(\"Error fetching voices:\", error);\n return [];\n }\n}\n"],"mappings":";;;;;AAEA,IAAM,qBAAqB;AAS3B,eAAsB,aACpB,MACA,UAAsB,CAAC,GACC;AACxB,QAAM;AAAA,IACJ,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB,IAAI;AAEJ,MAAI;AACF,UAAM,WAAW,MAAM;AAAA,MACrB,GAAG,kBAAkB,mBAAmB,IAAI,mBAAmB;AAAA,MAC/D;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,cAAc,IAAI;AAAA,QACpB;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB;AAAA,UACA,UAAU;AAAA,UACV,gBAAgB;AAAA,YACd;AAAA,YACA,kBAAkB;AAAA,YAClB;AAAA,YACA,mBAAmB;AAAA,UACrB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,QAAQ,MAAM,SAAS,KAAK;AAClC,cAAQ,MAAM,yBAAyB,KAAK;AAC5C,aAAO;AAAA,IACT;AAEA,UAAM,cAAc,MAAM,SAAS,YAAY;AAC/C,WAAO,OAAO,KAAK,WAAW;AAAA,EAChC,SAAS,OAAO;AACd,YAAQ,MAAM,4BAA4B,KAAK;AAC/C,WAAO;AAAA,EACT;AACF;","names":[]}
|