rawi
Version:
Rawi (راوي) is the developer-friendly AI CLI that brings the power of 11 major AI providers directly to your terminal. With seamless shell integration, persistent conversations, and 200+ specialized prompt templates, Rawi transforms your command line into
1 lines • 13 kB
Source Map (JSON)
{"version":3,"sources":["/home/mkabumattar/work/withrawi/rawi/dist/chunk-TEI25NEM.cjs","../src/cli/commands/chat/actions/advanced-operations.ts"],"names":["AdvancedSessionOperations","sessionManager","profile","options","chalk","sessions","totalSessions","totalMessages","sum","session","averageMessages","oldestSession","oldest","newestSession","newest"],"mappings":"AAAA;ACAA,mFAAoB,oEACE,4CACD,4EACH,6FACA,IAILA,CAAAA,CAAN,KAAgC,CACpB,WAGjB,CAAYC,CAAAA,CAAgCC,CAAAA,CAAiB,CAC3D,IAAA,CAAK,cAAA,CAAiBD,CAAAA,CACtB,IAAA,CAAK,OAAA,CAAUC,CACjB,CAEA,MAAM,cAAA,CAAeC,CAAAA,CAAqC,CACxD,GAAI,CACF,OAAA,CAAQ,GAAA,CAAIC,eAAAA,CAAM,IAAA,CAAK,CAAA;AAAA,4BAAA,CAAyB,CAAC,CAAA,CACjD,OAAA,CAAQ,GAAA,CAAIA,eAAAA,CAAM,IAAA,CAAK,QAAA,CAAI,MAAA,CAAO,EAAE,CAAC,CAAC,CAAA,CAEtC,IAAMC,CAAAA,CAAW,MAAM,IAAA,CAAK,cAAA,CAAe,YAAA,CAAa,CACtD,OAAA,CAAS,IAAA,CAAK,OAAA,CACd,QAAA,CAAUF,CAAAA,CAAQ,QAAA,CAClB,MAAA,CAAQA,CAAAA,CAAQ,MAAA,CAChB,IAAA,CAAM,MACR,CAAC,CAAA,CAEKG,CAAAA,CAAgBD,CAAAA,CAAS,MAAA,CACzBE,CAAAA,CAAgBF,CAAAA,CAAS,MAAA,CAC7B,CAACG,CAAAA,CAAKC,CAAAA,CAAAA,EAAYD,CAAAA,CAAAA,CAAOC,CAAAA,CAAQ,YAAA,EAAgB,CAAA,CAAA,CACjD,CACF,CAAA,CAEA,EAAA,CAAIH,CAAAA,GAAkB,CAAA,CAAG,CACvB,OAAA,CAAQ,GAAA,CAAIF,eAAAA,CAAM,MAAA,CAAO,8BAAuB,CAAC,CAAA,CACjD,MACF,CAEA,IAAMM,CAAAA,CAAkB,IAAA,CAAK,KAAA,CAAMH,CAAAA,CAAgBD,CAAa,CAAA,CAC1DK,CAAAA,CAAgBN,CAAAA,CAAS,MAAA,CAAO,CAACO,CAAAA,CAAQH,CAAAA,CAAAA,EAC7C,IAAI,IAAA,CAAKA,CAAAA,CAAQ,SAAS,CAAA,CAAI,IAAI,IAAA,CAAKG,CAAAA,CAAO,SAAS,CAAA,CACnDH,CAAAA,CACAG,CACN,CAAA,CACMC,CAAAA,CAAgBR,CAAAA,CAAS,MAAA,CAAO,CAACS,CAAAA,CAAQL,CAAAA,CAAAA,EAC7C,IAAI,IAAA,CAAKA,CAAAA,CAAQ,SAAS,CAAA,CAAI,IAAI,IAAA,CAAKK,CAAAA,CAAO,SAAS,CAAA,CACnDL,CAAAA,CACAK,CACN,CAAA,CAEA,OAAA,CAAQ,GAAA,CACNV,eAAAA,CAAM,KAAA,CAAM,CAAA,0BAAA,EAAsBA,eAAAA,CAAM,IAAA,CAAKE,CAAa,CAAC,CAAA,CAAA;AAsCtC,+BAAA;AAwB0C,kCAAA;AAgC1C,mCAAA;AAqDC,yDAAA;AA+ChB,4BAAA;AAwF8B;AAOO;AACc;AACf;AAclD;ADzVkhB","file":"/home/mkabumattar/work/withrawi/rawi/dist/chunk-TEI25NEM.cjs","sourcesContent":[null,"import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport {select} from '@inquirer/prompts';\nimport chalk from 'chalk';\nimport Table from 'cli-table3';\nimport type {SessionManager} from '../../../../core/session/index.js';\nimport type {ChatOptions} from '../types.js';\n\nexport class AdvancedSessionOperations {\n private readonly sessionManager: SessionManager;\n private readonly profile: string;\n\n constructor(sessionManager: SessionManager, profile: string) {\n this.sessionManager = sessionManager;\n this.profile = profile;\n }\n\n async showStatistics(options: ChatOptions): Promise<void> {\n try {\n console.log(chalk.cyan('\\n📊 Session Statistics'));\n console.log(chalk.gray('─'.repeat(50)));\n\n const sessions = await this.sessionManager.listSessions({\n profile: this.profile,\n fromDate: options.fromDate,\n toDate: options.toDate,\n type: 'chat',\n });\n\n const totalSessions = sessions.length;\n const totalMessages = sessions.reduce(\n (sum, session) => sum + (session.messageCount || 0),\n 0,\n );\n\n if (totalSessions === 0) {\n console.log(chalk.yellow('📝 No sessions found.'));\n return;\n }\n\n const averageMessages = Math.round(totalMessages / totalSessions);\n const oldestSession = sessions.reduce((oldest, session) =>\n new Date(session.createdAt) < new Date(oldest.createdAt)\n ? session\n : oldest,\n );\n const newestSession = sessions.reduce((newest, session) =>\n new Date(session.createdAt) > new Date(newest.createdAt)\n ? session\n : newest,\n );\n\n console.log(\n chalk.white(`📋 Total Sessions: ${chalk.bold(totalSessions)}`),\n );\n console.log(\n chalk.white(`💬 Total Messages: ${chalk.bold(totalMessages)}`),\n );\n console.log(\n chalk.white(\n `📈 Average Messages per Session: ${chalk.bold(averageMessages)}`,\n ),\n );\n console.log(\n chalk.white(\n `📅 Date Range: ${this.formatDate(oldestSession.createdAt)} → ${this.formatDate(newestSession.createdAt)}`,\n ),\n );\n\n const topSessions = sessions\n .sort((a, b) => (b.messageCount || 0) - (a.messageCount || 0))\n .slice(0, 5);\n\n console.log(chalk.cyan('\\n🏆 Most Active Sessions:'));\n topSessions.forEach((session, index) => {\n const title = session.title || 'Untitled';\n const messageCount = session.messageCount || 0;\n console.log(\n chalk.white(`${index + 1}. ${title} (${messageCount} messages)`),\n );\n });\n } catch (error) {\n console.error(chalk.red(`❌ Failed to show statistics: ${error}`));\n }\n }\n\n async backupSessions(\n backupPath: string,\n options: ChatOptions,\n ): Promise<void> {\n try {\n console.log(chalk.cyan(`\\n💾 Backing up sessions to: ${backupPath}`));\n\n const exportData = await this.sessionManager.exportSessions('json', {\n profile: this.profile,\n fromDate: options.fromDate,\n toDate: options.toDate,\n });\n\n const backup = {\n timestamp: new Date().toISOString(),\n profile: this.profile,\n version: '1.0.0',\n data: exportData,\n };\n\n const dir = path.dirname(backupPath);\n await fs.mkdir(dir, {recursive: true});\n\n await fs.writeFile(backupPath, JSON.stringify(backup, null, 2), 'utf8');\n\n console.log(chalk.green('✅ Backup completed successfully!'));\n console.log(chalk.blue(`📁 File: ${backupPath}`));\n console.log(\n chalk.blue(\n `📊 Stats: ${backup.data.sessions.length} sessions, ${Object.values(backup.data.messages).flat().length} messages`,\n ),\n );\n } catch (error) {\n console.error(chalk.red(`❌ Backup failed: ${error}`));\n throw error;\n }\n }\n\n async restoreSessions(backupPath: string): Promise<void> {\n try {\n console.log(chalk.cyan(`\\n📥 Restoring sessions from: ${backupPath}`));\n\n const backupData = await fs.readFile(backupPath, 'utf8');\n const backup = JSON.parse(backupData);\n\n if (!backup.data || !backup.data.sessions) {\n throw new Error('Invalid backup file format');\n }\n\n console.log(\n chalk.yellow(\n '⚠️ This will import sessions. Existing sessions with same IDs may be overwritten.',\n ),\n );\n\n console.log(\n chalk.blue(\n `📊 Backup contains: ${backup.data.sessions.length} sessions, ${Object.values(backup.data.messages).flat().length} messages`,\n ),\n );\n console.log(chalk.blue(`📅 Backup created: ${backup.timestamp}`));\n console.log(chalk.blue(`👤 Original profile: ${backup.profile}`));\n\n console.log(chalk.green('✅ Restore simulation completed!'));\n console.log(\n chalk.gray(\n 'Note: Actual restore functionality would be implemented with database operations.',\n ),\n );\n } catch (error) {\n console.error(chalk.red(`❌ Restore failed: ${error}`));\n throw error;\n }\n }\n\n async batchDeleteSessions(\n pattern: string,\n options: ChatOptions,\n ): Promise<void> {\n try {\n console.log(\n chalk.cyan(`\\n🗑️ Batch delete sessions matching pattern: \"${pattern}\"`),\n );\n\n const sessions = await this.sessionManager.listSessions({\n profile: this.profile,\n fromDate: options.fromDate,\n toDate: options.toDate,\n type: 'chat',\n });\n\n const matchingSessions = sessions.filter((session) => {\n const titleMatch = (session.title || '')\n .toLowerCase()\n .includes(pattern.toLowerCase());\n const idMatch = session.id\n .toLowerCase()\n .includes(pattern.toLowerCase());\n return titleMatch || idMatch;\n });\n\n if (matchingSessions.length === 0) {\n console.log(\n chalk.yellow(`📝 No sessions found matching pattern \"${pattern}\"`),\n );\n return;\n }\n\n console.log(\n chalk.yellow(\n `⚠️ Found ${matchingSessions.length} sessions matching the pattern:`,\n ),\n );\n matchingSessions.forEach((session) => {\n const title = session.title || 'Untitled';\n console.log(\n chalk.white(` • ${title} (${session.id.substring(0, 8)}...)`),\n );\n });\n\n console.log(\n chalk.red(\n `\\n🚨 This would delete ${matchingSessions.length} sessions!`,\n ),\n );\n console.log(\n chalk.gray(\n 'Note: Actual batch delete would require user confirmation.',\n ),\n );\n } catch (error) {\n console.error(chalk.red(`❌ Batch delete failed: ${error}`));\n throw error;\n }\n }\n\n async formatSessions(\n sessions: any[],\n format: 'json' | 'table' | 'summary',\n ): Promise<string> {\n switch (format) {\n case 'json':\n return JSON.stringify(sessions, null, 2);\n\n case 'summary':\n return this.formatSessionsSummary(sessions);\n default:\n return this.formatSessionsTable(sessions);\n }\n }\n\n private formatSessionsTable(sessions: any[]): string {\n if (sessions.length === 0) {\n return chalk.yellow('No sessions found.');\n }\n\n const table = new Table({\n head: [\n chalk.cyan('ID'),\n chalk.cyan('Title'),\n chalk.cyan('Profile'),\n chalk.cyan('Messages'),\n chalk.cyan('Created'),\n chalk.cyan('Last Updated'),\n ],\n colWidths: [40, 25, 12, 10, 20, 15],\n style: {\n head: [],\n border: ['grey'],\n compact: false,\n },\n });\n\n sessions.forEach((session) => {\n const title = session.title || 'Untitled';\n const messageCount = session.messageCount || 0;\n const createdDate = this.formatDate(session.createdAt);\n const updatedTime = this.formatRelativeTime(\n session.updatedAt || session.createdAt,\n );\n\n table.push([\n chalk.white(session.id),\n chalk.white(title.length > 22 ? `${title.substring(0, 19)}...` : title),\n chalk.gray(session.profile),\n chalk.yellow(messageCount.toString()),\n chalk.gray(createdDate),\n chalk.gray(updatedTime),\n ]);\n });\n\n return table.toString();\n }\n\n async selectSessionInteractively(sessions: any[]): Promise<string | null> {\n if (sessions.length === 0) {\n console.log(chalk.yellow('No sessions found.'));\n return null;\n }\n\n const choices = sessions.map((session) => ({\n name: `${session.title || 'Untitled'} (${session.messageCount || 0} messages) - ${this.formatRelativeTime(session.updatedAt)}`,\n value: session.id,\n description: `ID: ${session.id}`,\n }));\n\n choices.push({\n name: chalk.green('+ Create new session'),\n value: 'new',\n description: 'Start a fresh conversation',\n });\n\n try {\n const selectedId = await select({\n message: 'Select a session to continue:',\n choices,\n pageSize: 10,\n });\n\n return selectedId === 'new' ? null : selectedId;\n } catch (_error) {\n return null;\n }\n }\n\n private formatRelativeTime(dateString: string): string {\n const now = Date.now();\n const date = new Date(dateString).getTime();\n const diffMs = now - date;\n\n const diffSeconds = Math.floor(diffMs / 1000);\n const diffMinutes = Math.floor(diffSeconds / 60);\n const diffHours = Math.floor(diffMinutes / 60);\n const diffDays = Math.floor(diffHours / 24);\n\n if (diffDays > 0) return `${diffDays}d ago`;\n if (diffHours > 0) return `${diffHours}h ago`;\n if (diffMinutes > 0) return `${diffMinutes}m ago`;\n return `${diffSeconds}s ago`;\n }\n\n private formatSessionsSummary(sessions: any[]): string {\n if (sessions.length === 0) {\n return 'No sessions found.';\n }\n\n let summary = chalk.cyan(\n `📋 Session Summary (${sessions.length} sessions)\\n`,\n );\n summary += `${chalk.gray('─'.repeat(50))}\\n`;\n\n sessions.forEach((session, index) => {\n const title = session.title || 'Untitled';\n const messageCount = session.messageCount || 0;\n const date = this.formatDate(session.updatedAt || session.createdAt);\n\n summary += chalk.white(`${index + 1}. ${title}\\n`);\n summary += chalk.gray(` ${messageCount} messages • ${date}\\n`);\n if (index < sessions.length - 1) summary += '\\n';\n });\n\n return summary;\n }\n\n private formatDate(dateString: string): string {\n const date = new Date(dateString);\n return date.toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n }\n}\n"]}