{"version":3,"sources":["/home/mkabumattar/work/withrawi/rawi/dist/chunk-PFLY5EL5.cjs","../src/cli/commands/chat/managers/session.manager.ts"],"names":["SessionManager","dbManager","options","profile","recentSessions","chalk","selectedSessionId","error","SessionNotFoundError","ProfileMismatchError"],"mappings":"AAAA;AACA,wDAAsD,wBCD1B,4CACE,4EACZ,IAcLA,CAAAA,CAAN,KAAqB,CAClB,WAER,CAAYC,CAAAA,CAA4B,CACtC,IAAA,CAAK,SAAA,CAAYA,CACnB,CAEA,MAAM,kBAAA,CAAmBC,CAAAA,CAAuC,CAC9D,GAAI,CACF,IAAMC,CAAAA,CAAUD,CAAAA,CAAQ,OAAA,EAAW,SAAA,CAEnC,EAAA,CAAIA,CAAAA,CAAQ,UAAA,CACV,OAAO,MAAM,IAAA,CAAK,gBAAA,CAAiBC,CAAO,CAAA,CAG5C,EAAA,CAAID,CAAAA,CAAQ,OAAA,CAEV,MAAA,CADgB,MAAM,IAAA,CAAK,eAAA,CAAgBA,CAAAA,CAAQ,OAAA,CAASC,CAAO,CAAA,CAAA,CACpD,SAAA,CAGjB,IAAMC,CAAAA,CAAiB,MAAM,IAAA,CAAK,iBAAA,CAAkBD,CAAAA,CAAS,CAAC,CAAA,CAE9D,EAAA,CAAIC,CAAAA,CAAe,MAAA,GAAW,CAAA,CAC5B,OAAA,OAAA,CAAQ,GAAA,CACNC,eAAAA,CAAM,GAAA,CAAI,qDAAqD,CACjE,CAAA,CACO,MAAM,IAAA,CAAK,gBAAA,CAAiBF,CAAO,CAAA,CAG5C,IAAMG,CAAAA,CACJ,MAAM,IAAA,CAAK,uBAAA,CAAwBF,CAAc,CAAA,CAEnD,OAAIE,CAAAA,GAAsB,IAAA,CACjB,MAAM,IAAA,CAAK,gBAAA,CAAiBH,CAAO,CAAA,CAAA,CAG5C,MAAM,IAAA,CAAK,eAAA,CAAgBG,CAAAA,CAAmBH,CAAO,CAAA,CAC9CG,CAAAA,CACT,CAAA,KAAA,CAASC,CAAAA,CAAO,CACd,EAAA,CACEA,EAAAA,WAAiBC,mBAAAA,EACjBD,EAAAA,WAAiBE,mBAAAA,CAEjB,OAAA,OAAA,CAAQ,KAAA,CAAMJ,eAAAA,CAAM,GAAA,CAAI,CAAA,OAAA,EAAKE,CAAAA,CAAM,OAAO,CAAA,CAAA;AA4JjB,0BAAA;AAwDd,qCAAA;AAuEW,oCAAA;AAgKE,+BAAA;AA4BA,mBAAA;AAEH,2BAAA;AAqBV,UAAA;AAAA;AACwC;AAAA;AACT;AAAA;AAGU;AAAA;AACnB;AACU;AAC6B;AACA;AACvB;AAAA;AAIrC;AAAA;AAIwB;AAAA;AAAyB;AAAA;AAAA;AAAA;AAInD;AAKlB;ADpiBsxB","file":"/home/mkabumattar/work/withrawi/rawi/dist/chunk-PFLY5EL5.cjs","sourcesContent":[null,"import {writeFileSync} from 'node:fs';\nimport {confirm, select} from '@inquirer/prompts';\nimport chalk from 'chalk';\nimport type {DatabaseManager} from '../../../../core/database/manager.js';\nimport {\n  type ChatOptions,\n  type ChatSession,\n  DatabaseConnectionError,\n  type DeleteSessionOptions,\n  type EnhancedChatSession,\n  type ExportSessionsOptions,\n  type ListSessionsOptions,\n  ProfileMismatchError,\n  SessionNotFoundError,\n} from '../types.js';\n\nexport class SessionManager {\n  private dbManager: DatabaseManager;\n\n  constructor(dbManager: DatabaseManager) {\n    this.dbManager = dbManager;\n  }\n\n  async handleSessionStart(options: ChatOptions): Promise<string> {\n    try {\n      const profile = options.profile || 'default';\n\n      if (options.newSession) {\n        return await this.createNewSession(profile);\n      }\n\n      if (options.session) {\n        const session = await this.continueSession(options.session, profile);\n        return session.sessionId;\n      }\n\n      const recentSessions = await this.getRecentSessions(profile, 5);\n\n      if (recentSessions.length === 0) {\n        console.log(\n          chalk.dim('No recent sessions found. Creating a new session...'),\n        );\n        return await this.createNewSession(profile);\n      }\n\n      const selectedSessionId =\n        await this.displaySessionSelection(recentSessions);\n\n      if (selectedSessionId === null) {\n        return await this.createNewSession(profile);\n      }\n\n      await this.continueSession(selectedSessionId, profile);\n      return selectedSessionId;\n    } catch (error) {\n      if (\n        error instanceof SessionNotFoundError ||\n        error instanceof ProfileMismatchError\n      ) {\n        console.error(chalk.red(`❌ ${error.message}`));\n        console.log(chalk.dim('Falling back to creating a new session...'));\n        return await this.createNewSession(options.profile || 'default');\n      }\n\n      if (error instanceof DatabaseConnectionError) {\n        console.error(chalk.red(`❌ Database error: ${error.message}`));\n        console.log(chalk.dim('Creating temporary session...'));\n        return await this.dbManager.createEmergencySession(\n          options.profile || 'default',\n          'chat',\n        );\n      }\n\n      throw error;\n    }\n  }\n\n  async createNewSession(profile: string, title?: string): Promise<string> {\n    try {\n      const sessionId = await this.dbManager.createSession(\n        profile,\n        title,\n        'chat',\n      );\n      console.log(chalk.green(`✅ Created new session: ${sessionId}`));\n      return sessionId;\n    } catch (error) {\n      console.error(chalk.red(`❌ Failed to create session: ${error}`));\n      throw new DatabaseConnectionError(\n        'Failed to create new session',\n        error instanceof Error ? error : new Error(String(error)),\n      );\n    }\n  }\n\n  async continueSession(\n    sessionId: string,\n    profile: string,\n  ): Promise<EnhancedChatSession> {\n    try {\n      const session = await this.dbManager.getSession(sessionId);\n\n      if (!session) {\n        throw new SessionNotFoundError(sessionId, profile);\n      }\n\n      if (session.profile !== profile) {\n        throw new ProfileMismatchError(sessionId, profile, session.profile);\n      }\n\n      const messages = await this.dbManager.getMessages(sessionId);\n\n      console.log(chalk.green(`✅ Continuing session: ${sessionId}`));\n      if (session.title) {\n        console.log(chalk.dim(`📝 Title: ${session.title}`));\n      }\n      console.log(chalk.dim(`💬 Messages: ${messages.length}`));\n\n      return {\n        sessionId: session.id,\n        profile: session.profile,\n        title: session.title,\n        messages,\n        displaySessionInfo: () => this.displaySessionInfo(session),\n        displayConversationHistory: (limit?: number) =>\n          this.displayConversationHistory(messages, limit),\n        addUserMessage: async (content: string) => {\n          await this.dbManager.addMessage(\n            sessionId,\n            'user',\n            content,\n            'unknown',\n            'unknown',\n          );\n        },\n        addAssistantMessage: async (content: string, metadata: any) => {\n          await this.dbManager.addMessage(\n            sessionId,\n            'assistant',\n            content,\n            metadata.provider || 'unknown',\n            metadata.model || 'unknown',\n            metadata.temperature,\n            metadata.maxTokens,\n            metadata,\n          );\n        },\n        updateSessionTitle: async (newTitle: string) => {\n          await this.dbManager.updateSessionTitle(sessionId, newTitle);\n        },\n        getSessionStats: () => ({\n          messageCount: messages.length,\n          createdAt: session.createdAt,\n          updatedAt: session.updatedAt,\n          duration: this.calculateDuration(\n            session.createdAt,\n            session.updatedAt,\n          ),\n          providers: Array.from(new Set(messages.map((m) => m.provider))),\n          models: Array.from(new Set(messages.map((m) => m.model))),\n        }),\n      };\n    } catch (error) {\n      if (\n        error instanceof SessionNotFoundError ||\n        error instanceof ProfileMismatchError\n      ) {\n        throw error;\n      }\n\n      console.error(chalk.red(`❌ Failed to continue session: ${error}`));\n      throw new DatabaseConnectionError(\n        'Failed to continue session',\n        error instanceof Error ? error : new Error(String(error)),\n      );\n    }\n  }\n\n  async getRecentSessions(profile: string, limit = 10): Promise<ChatSession[]> {\n    try {\n      return await this.dbManager.getSessions({profile, limit});\n    } catch (error) {\n      console.error(chalk.red(`❌ Failed to get recent sessions: ${error}`));\n      throw new DatabaseConnectionError(\n        'Failed to retrieve recent sessions',\n        error instanceof Error ? error : new Error(String(error)),\n      );\n    }\n  }\n\n  async displaySessionSelection(\n    sessions: ChatSession[],\n  ): Promise<string | null> {\n    console.log(chalk.bold.blue('\\n🔍 Recent Sessions:'));\n\n    const choices = [\n      {\n        name: chalk.green('➕ Create new session'),\n        value: 'new',\n      },\n      ...sessions.map((session) => ({\n        name: this.formatSessionChoice(session),\n        value: session.id,\n      })),\n    ];\n\n    try {\n      const answer = await select({\n        message: 'Choose a session to continue or create a new one:',\n        choices,\n      });\n\n      return answer === 'new' ? null : answer;\n    } catch (error) {\n      if (error instanceof Error && error.name === 'ExitPromptError') {\n        console.log(chalk.yellow('\\n👋 Session selection cancelled'));\n        process.exit(0);\n      }\n      throw error;\n    }\n  }\n\n  async listSessions(options: ListSessionsOptions): Promise<void> {\n    try {\n      const sessions = await this.dbManager.getSessions({\n        profile: options.profile,\n        limit: options.limit || 20,\n        fromDate: options.fromDate,\n        toDate: options.toDate,\n      });\n\n      if (sessions.length === 0) {\n        console.log(chalk.dim('No sessions found.'));\n        return;\n      }\n\n      const format = options.format || 'table';\n\n      switch (format) {\n        case 'json':\n          console.log(JSON.stringify(sessions, null, 2));\n          break;\n        case 'summary':\n          this.displaySessionsSummary(sessions);\n          break;\n        default:\n          this.displaySessionsTable(sessions);\n          break;\n      }\n    } catch (error) {\n      console.error(chalk.red(`❌ Failed to list sessions: ${error}`));\n      throw new DatabaseConnectionError(\n        'Failed to list sessions',\n        error instanceof Error ? error : new Error(String(error)),\n      );\n    }\n  }\n\n  async deleteSession(\n    sessionId: string,\n    options: DeleteSessionOptions,\n  ): Promise<boolean> {\n    try {\n      const session = await this.dbManager.getSession(sessionId);\n      if (!session) {\n        console.error(chalk.red(`❌ Session '${sessionId}' not found`));\n        return false;\n      }\n\n      if (!options.force && options.confirm !== false) {\n        const shouldDelete = await confirm({\n          message: `Are you sure you want to delete session '${sessionId}'${session.title ? ` (${session.title})` : ''}? This will delete all ${session.messageCount} messages.`,\n          default: false,\n        });\n\n        if (!shouldDelete) {\n          console.log(chalk.dim('Session deletion cancelled.'));\n          return false;\n        }\n      }\n\n      const deleted = await this.dbManager.deleteSession(sessionId);\n\n      if (deleted) {\n        console.log(\n          chalk.green(`✅ Session '${sessionId}' deleted successfully`),\n        );\n      } else {\n        console.error(chalk.red(`❌ Failed to delete session '${sessionId}'`));\n      }\n\n      return deleted;\n    } catch (error) {\n      if (error instanceof Error && error.name === 'ExitPromptError') {\n        console.log(chalk.yellow('\\n👋 Session deletion cancelled'));\n        return false;\n      }\n\n      console.error(chalk.red(`❌ Failed to delete session: ${error}`));\n      throw new DatabaseConnectionError(\n        'Failed to delete session',\n        error instanceof Error ? error : new Error(String(error)),\n      );\n    }\n  }\n\n  async renameSession(sessionId: string, newTitle: string): Promise<boolean> {\n    try {\n      const session = await this.dbManager.getSession(sessionId);\n      if (!session) {\n        console.error(chalk.red(`❌ Session '${sessionId}' not found`));\n        return false;\n      }\n\n      if (!newTitle || newTitle.trim().length === 0) {\n        console.error(chalk.red('❌ Session title cannot be empty'));\n        return false;\n      }\n\n      const trimmedTitle = newTitle.trim();\n      if (trimmedTitle.length > 200) {\n        console.error(\n          chalk.red('❌ Session title cannot exceed 200 characters'),\n        );\n        return false;\n      }\n\n      const updated = await this.dbManager.updateSessionTitle(\n        sessionId,\n        trimmedTitle,\n      );\n\n      if (updated) {\n        console.log(\n          chalk.green(`✅ Session '${sessionId}' renamed to: ${trimmedTitle}`),\n        );\n      } else {\n        console.error(chalk.red(`❌ Failed to rename session '${sessionId}'`));\n      }\n\n      return updated;\n    } catch (error) {\n      console.error(chalk.red(`❌ Failed to rename session: ${error}`));\n      throw new DatabaseConnectionError(\n        'Failed to rename session',\n        error instanceof Error ? error : new Error(String(error)),\n      );\n    }\n  }\n\n  async exportSessions(options: ExportSessionsOptions): Promise<string> {\n    try {\n      const exportData = await this.dbManager.exportChatHistory({\n        profile: options.profile,\n        fromDate: options.fromDate,\n        toDate: options.toDate,\n      });\n\n      let sessionsToExport = exportData.sessions;\n      let messagesToExport = exportData.messages;\n\n      if (options.sessions && options.sessions.length > 0) {\n        sessionsToExport = exportData.sessions.filter((session) =>\n          options.sessions!.includes(session.id),\n        );\n        messagesToExport = Object.fromEntries(\n          Object.entries(exportData.messages).filter(([sessionId]) =>\n            options.sessions!.includes(sessionId),\n          ),\n        );\n      }\n\n      if (sessionsToExport.length === 0) {\n        console.log(chalk.dim('No sessions found to export.'));\n        return '';\n      }\n\n      const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\n      const filename =\n        options.output || `rawi-sessions-${timestamp}.${options.format}`;\n\n      let content: string;\n\n      switch (options.format) {\n        case 'json':\n          content = JSON.stringify(\n            {\n              exportedAt: new Date().toISOString(),\n              sessions: sessionsToExport,\n              messages: messagesToExport,\n              stats: exportData.stats,\n            },\n            null,\n            2,\n          );\n          break;\n        case 'markdown':\n          content = this.formatSessionsAsMarkdown(\n            sessionsToExport,\n            messagesToExport,\n          );\n          break;\n        default:\n          throw new Error(`Unsupported export format: ${options.format}`);\n      }\n\n      writeFileSync(filename, content, 'utf8');\n\n      console.log(\n        chalk.green(\n          `✅ Exported ${sessionsToExport.length} sessions to: ${filename}`,\n        ),\n      );\n      return filename;\n    } catch (error) {\n      console.error(chalk.red(`❌ Failed to export sessions: ${error}`));\n      throw new DatabaseConnectionError(\n        'Failed to export sessions',\n        error instanceof Error ? error : new Error(String(error)),\n      );\n    }\n  }\n\n  private formatSessionChoice(session: ChatSession): string {\n    const age = this.formatAge(session.updatedAt);\n    const title = session.title || 'Untitled';\n    const messageCount = session.messageCount;\n\n    return `${chalk.cyan(session.id.slice(0, 8))} - ${chalk.white(title)} ${chalk.dim(`(${messageCount} messages, ${age})`)}`;\n  }\n\n  private formatAge(dateString: string): string {\n    const date = new Date(dateString);\n    const now = new Date();\n    const diffMs = now.getTime() - date.getTime();\n    const diffMins = Math.floor(diffMs / (1000 * 60));\n    const diffHours = Math.floor(diffMs / (1000 * 60 * 60));\n    const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n    if (diffMins < 60) {\n      return `${diffMins}m ago`;\n    } else if (diffHours < 24) {\n      return `${diffHours}h ago`;\n    } else {\n      return `${diffDays}d ago`;\n    }\n  }\n\n  private calculateDuration(createdAt: string, updatedAt: string): string {\n    const created = new Date(createdAt);\n    const updated = new Date(updatedAt);\n    const diffMs = updated.getTime() - created.getTime();\n    const diffMins = Math.floor(diffMs / (1000 * 60));\n    const diffHours = Math.floor(diffMs / (1000 * 60 * 60));\n    const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n    if (diffMins < 60) {\n      return `${diffMins} minutes`;\n    } else if (diffHours < 24) {\n      return `${diffHours} hours`;\n    } else {\n      return `${diffDays} days`;\n    }\n  }\n\n  private displaySessionInfo(session: ChatSession): void {\n    console.log(chalk.dim(`ID: ${session.id}`));\n    console.log(chalk.dim(`Profile: ${session.profile}`));\n    if (session.title) {\n      console.log(chalk.dim(`Title: ${session.title}`));\n    }\n    console.log(\n      chalk.dim(`Created: ${new Date(session.createdAt).toLocaleString()}`),\n    );\n    console.log(\n      chalk.dim(`Updated: ${new Date(session.updatedAt).toLocaleString()}`),\n    );\n    console.log(chalk.dim(`Messages: ${session.messageCount}`));\n  }\n\n  private displayConversationHistory(messages: any[], limit?: number): void {\n    const messagesToShow = limit ? messages.slice(-limit) : messages;\n\n    if (messagesToShow.length === 0) {\n      console.log(chalk.dim('No previous messages in this session.'));\n      return;\n    }\n\n    console.log(chalk.bold.blue('\\n💬 Conversation History:'));\n    messagesToShow.forEach((message) => {\n      const role =\n        message.role === 'user' ? chalk.blue('You') : chalk.green('Assistant');\n      const content =\n        message.content.length > 100\n          ? `${message.content.substring(0, 100)}...`\n          : message.content;\n      console.log(`${role}: ${chalk.dim(content)}`);\n    });\n    console.log('');\n  }\n\n  private displaySessionsTable(sessions: ChatSession[]): void {\n    console.log(chalk.bold.blue('\\n📋 Sessions:'));\n    console.log(\n      chalk.dim(\n        'ID'.padEnd(10) +\n          'Title'.padEnd(30) +\n          'Messages'.padEnd(10) +\n          'Updated'.padEnd(20),\n      ),\n    );\n    console.log(chalk.dim('-'.repeat(70)));\n\n    sessions.forEach((session) => {\n      const id = session.id.slice(0, 8);\n      const title = (session.title || 'Untitled').slice(0, 28);\n      const messages = session.messageCount.toString();\n      const updated = this.formatAge(session.updatedAt);\n\n      console.log(\n        chalk.cyan(id.padEnd(10)) +\n          chalk.white(title.padEnd(30)) +\n          chalk.dim(messages.padEnd(10)) +\n          chalk.dim(updated.padEnd(20)),\n      );\n    });\n    console.log('');\n  }\n\n  private displaySessionsSummary(sessions: ChatSession[]): void {\n    console.log(chalk.bold.blue('\\n📋 Sessions Summary:'));\n    sessions.forEach((session) => {\n      console.log(chalk.cyan(`\\n🔹 ${session.id.slice(0, 8)}`));\n      console.log(chalk.white(`   Title: ${session.title || 'Untitled'}`));\n      console.log(chalk.dim(`   Messages: ${session.messageCount}`));\n      console.log(\n        chalk.dim(\n          `   Created: ${new Date(session.createdAt).toLocaleString()}`,\n        ),\n      );\n      console.log(\n        chalk.dim(\n          `   Updated: ${new Date(session.updatedAt).toLocaleString()}`,\n        ),\n      );\n    });\n    console.log('');\n  }\n\n  private formatSessionsAsMarkdown(\n    sessions: ChatSession[],\n    messages: Record<string, any[]>,\n  ): string {\n    let markdown = '# Rawi Chat Sessions Export\\n\\n';\n    markdown += `Exported on: ${new Date().toLocaleString()}\\n\\n`;\n    markdown += `Total sessions: ${sessions.length}\\n\\n`;\n\n    sessions.forEach((session) => {\n      markdown += `## Session: ${session.title || 'Untitled'}\\n\\n`;\n      markdown += `- **ID**: ${session.id}\\n`;\n      markdown += `- **Profile**: ${session.profile}\\n`;\n      markdown += `- **Created**: ${new Date(session.createdAt).toLocaleString()}\\n`;\n      markdown += `- **Updated**: ${new Date(session.updatedAt).toLocaleString()}\\n`;\n      markdown += `- **Messages**: ${session.messageCount}\\n\\n`;\n\n      const sessionMessages = messages[session.id] || [];\n      if (sessionMessages.length > 0) {\n        markdown += '### Conversation\\n\\n';\n        sessionMessages.forEach((message) => {\n          const role = message.role === 'user' ? '**You**' : '**Assistant**';\n          const timestamp = new Date(message.timestamp).toLocaleString();\n          markdown += `${role} _(${timestamp})_:\\n\\n${message.content}\\n\\n---\\n\\n`;\n        });\n      }\n\n      markdown += '\\n';\n    });\n\n    return markdown;\n  }\n}\n"]}