UNPKG

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 11.9 kB
{"version":3,"sources":["/home/mkabumattar/work/withrawi/rawi/dist/chunk-XTIYUVOQ.cjs","../src/cli/commands/chat/actions/session-selector.ts"],"names":["SessionSelector","sessionManager","profile","sessions","query","lowerQuery","session","titleMatch","profileMatch","idMatch","dateString","text","maxLength"],"mappings":"AAAA;ACAA,yFAA0B,4EACR,IAiBLA,CAAAA,CAAN,KAAsB,CACV,WAGjB,CAAYC,CAAAA,CAAgCC,CAAAA,CAAiB,CAC3D,IAAA,CAAK,cAAA,CAAiBD,CAAAA,CACtB,IAAA,CAAK,OAAA,CAAUC,CACjB,CAEQ,cAAA,CAAeC,CAAAA,CAAiBC,CAAAA,CAAsB,CAC5D,EAAA,CAAI,CAACA,CAAAA,CAAM,IAAA,CAAK,CAAA,CAAG,OAAOD,CAAAA,CAE1B,IAAME,CAAAA,CAAaD,CAAAA,CAAM,WAAA,CAAY,CAAA,CACrC,OAAOD,CAAAA,CAAS,MAAA,CAAQG,CAAAA,EAAY,CAClC,IAAMC,CAAAA,CAAAA,CAAcD,CAAAA,CAAQ,KAAA,EAAS,EAAA,CAAA,CAClC,WAAA,CAAY,CAAA,CACZ,QAAA,CAASD,CAAU,CAAA,CAChBG,CAAAA,CAAeF,CAAAA,CAAQ,OAAA,CAAQ,WAAA,CAAY,CAAA,CAAE,QAAA,CAASD,CAAU,CAAA,CAChEI,CAAAA,CAAUH,CAAAA,CAAQ,EAAA,CAAG,WAAA,CAAY,CAAA,CAAE,QAAA,CAASD,CAAU,CAAA,CAE5D,OAAOE,CAAAA,EAAcC,CAAAA,EAAgBC,CACvC,CAAC,CACH,CAEQ,UAAA,CAAWC,CAAAA,CAA4B,CAE7C,OADa,IAAI,IAAA,CAAKA,CAAU,CAAA,CACpB,kBAAA,CAAmB,OAAA,CAAS,CACtC,IAAA,CAAM,SAAA,CACN,KAAA,CAAO,OAAA,CACP,GAAA,CAAK,SAAA,CACL,IAAA,CAAM,SAAA,CACN,MAAA,CAAQ,SACV,CAAC,CACH,CAEQ,YAAA,CAAaC,CAAAA,CAAcC,CAAAA,CAA2B,CAC5D,OAAID,CAAAA,CAAK,MAAA,EAAUC,CAAAA,CAAkBD,CAAAA,CAC9B,CAAA,EAAA;AA4CsC,2BAAA;AA8G7C,8BAAA;AAoCuB,4BAAA;AAgBR,oBAAA;AA4CjB,+BAAA;AD1S4hB","file":"/home/mkabumattar/work/withrawi/rawi/dist/chunk-XTIYUVOQ.cjs","sourcesContent":[null,"import * as readline from 'node:readline/promises';\nimport chalk from 'chalk';\nimport type {SessionManager} from '../../../../core/session/index.js';\nimport type {ChatSession} from '../../../../core/shared/types.js';\n\nexport interface SessionSelectionOptions {\n showPreview?: boolean;\n enableSearch?: boolean;\n allowCreateNew?: boolean;\n maxResults?: number;\n}\n\nexport interface SessionActionChoice {\n action: 'continue' | 'delete' | 'rename' | 'export' | 'cancel' | 'create-new';\n sessionId?: string;\n newTitle?: string;\n}\n\nexport class SessionSelector {\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 private searchSessions(sessions: any[], query: string): any[] {\n if (!query.trim()) return sessions;\n\n const lowerQuery = query.toLowerCase();\n return sessions.filter((session) => {\n const titleMatch = (session.title || '')\n .toLowerCase()\n .includes(lowerQuery);\n const profileMatch = session.profile.toLowerCase().includes(lowerQuery);\n const idMatch = session.id.toLowerCase().includes(lowerQuery);\n\n return titleMatch || profileMatch || idMatch;\n });\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 hour: '2-digit',\n minute: '2-digit',\n });\n }\n\n private truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return `${text.substring(0, maxLength - 3)}...`;\n }\n\n async selectSession(\n options: SessionSelectionOptions = {},\n ): Promise<string | null> {\n const {\n showPreview = true,\n enableSearch = true,\n allowCreateNew = true,\n maxResults = 10,\n } = options;\n\n console.log(chalk.cyan('\\n🔍 Session Selection'));\n console.log(chalk.gray('─'.repeat(50)));\n\n let sessions = await this.sessionManager.listSessions({\n profile: this.profile,\n limit: maxResults,\n type: 'chat',\n });\n\n if (sessions.length === 0) {\n console.log(chalk.yellow('📝 No existing sessions found.'));\n if (allowCreateNew) {\n console.log(chalk.green('🆕 Creating a new session...'));\n return null;\n }\n return null;\n }\n\n if (enableSearch && sessions.length > 5) {\n const searchQuery = await this.promptForSearch();\n if (searchQuery) {\n sessions = this.searchSessions(sessions, searchQuery);\n if (sessions.length === 0) {\n console.log(\n chalk.yellow(`🔍 No sessions found matching \"${searchQuery}\"`),\n );\n return this.selectSession(options);\n }\n }\n }\n\n this.displaySessionList(sessions, showPreview);\n\n const selectedIndex = await this.promptForSelection(\n sessions.length,\n allowCreateNew,\n );\n\n if (selectedIndex === -1) {\n return null;\n }\n\n if (selectedIndex === -2) {\n return null;\n }\n\n const selectedSession = sessions[selectedIndex];\n\n const action = await this.showSessionActionMenu(selectedSession);\n\n switch (action.action) {\n case 'continue':\n return selectedSession.id;\n\n case 'delete':\n await this.sessionManager.deleteSession(selectedSession.id, {\n force: true,\n });\n console.log(\n chalk.green(`✅ Session \"${selectedSession.title}\" deleted.`),\n );\n return this.selectSession(options);\n\n case 'rename':\n if (action.newTitle) {\n await this.sessionManager.updateSessionTitle(\n selectedSession.id,\n action.newTitle,\n this.profile,\n );\n console.log(\n chalk.green(`✅ Session renamed to \"${action.newTitle}\"`),\n );\n }\n return this.selectSession(options);\n\n case 'export':\n await this.exportSession(selectedSession);\n return this.selectSession(options);\n\n case 'create-new':\n return null;\n default:\n return null;\n }\n }\n\n private async promptForSearch(): Promise<string | null> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n const query = await rl.question(\n chalk.blue('🔍 Search sessions (or press Enter to skip): '),\n );\n return query.trim() || null;\n } finally {\n rl.close();\n }\n }\n\n private displaySessionList(\n sessions: ChatSession[],\n showPreview: boolean,\n ): void {\n console.log(chalk.cyan(`\\n📋 Available Sessions (${sessions.length})`));\n console.log(chalk.gray('─'.repeat(50)));\n\n sessions.forEach((session, index) => {\n const number = chalk.cyan(`${index + 1}.`);\n const title = chalk.white(session.title);\n const date = chalk.gray(this.formatDate(session.updatedAt));\n const messageCount = chalk.yellow(\n `(${session.messageCount || 0} messages)`,\n );\n\n console.log(`${number} ${title} ${messageCount}`);\n console.log(` ${chalk.gray('Last updated:')} ${date}`);\n\n if (showPreview && session.title) {\n const preview = this.truncateText(session.title, 80);\n console.log(\n ` ${chalk.gray('Title preview:')} ${chalk.italic(preview)}`,\n );\n }\n\n console.log();\n });\n }\n\n private async promptForSelection(\n sessionCount: number,\n allowCreateNew: boolean,\n ): Promise<number> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n let prompt = chalk.blue(`\\n🎯 Select session (1-${sessionCount})`);\n\n if (allowCreateNew) {\n prompt += chalk.blue(', \"n\" for new');\n }\n\n prompt += chalk.blue(', or \"q\" to quit: ');\n\n const input = await rl.question(prompt);\n const trimmed = input.trim().toLowerCase();\n\n if (trimmed === 'q' || trimmed === 'quit') {\n return -2;\n }\n\n if (trimmed === 'n' || trimmed === 'new') {\n return -1;\n }\n\n const index = Number.parseInt(trimmed, 10) - 1;\n\n if (Number.isNaN(index) || index < 0 || index >= sessionCount) {\n console.log(chalk.red('❌ Invalid selection. Please try again.'));\n return this.promptForSelection(sessionCount, allowCreateNew);\n }\n\n return index;\n } finally {\n rl.close();\n }\n }\n\n private async showSessionActionMenu(\n session: ChatSession,\n ): Promise<SessionActionChoice> {\n console.log(chalk.cyan(`\\n⚡ Actions for \"${session.title}\"`));\n console.log(chalk.gray('─'.repeat(50)));\n console.log(chalk.white('1. Continue chat'));\n console.log(chalk.yellow('2. Rename session'));\n console.log(chalk.blue('3. Export session'));\n console.log(chalk.red('4. Delete session'));\n console.log(chalk.green('5. Create new session'));\n console.log(chalk.gray('6. Cancel'));\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n const choice = await rl.question(\n chalk.blue('\\n🎯 Select action (1-6): '),\n );\n\n switch (choice.trim()) {\n case '1':\n return {action: 'continue', sessionId: session.id};\n\n case '2': {\n const newTitle = await rl.question(\n chalk.blue('📝 Enter new title: '),\n );\n if (newTitle.trim()) {\n return {\n action: 'rename',\n sessionId: session.id,\n newTitle: newTitle.trim(),\n };\n }\n return {action: 'cancel'};\n }\n\n case '3':\n return {action: 'export', sessionId: session.id};\n\n case '4': {\n const confirm = await rl.question(\n chalk.red(`⚠️ Delete \"${session.title}\"? (y/N): `),\n );\n if (confirm.toLowerCase() === 'y') {\n return {action: 'delete', sessionId: session.id};\n }\n return {action: 'cancel'};\n }\n\n case '5':\n return {action: 'create-new'};\n default:\n return {action: 'cancel'};\n }\n } finally {\n rl.close();\n }\n }\n\n private async exportSession(session: ChatSession): Promise<void> {\n try {\n const exportData = await this.sessionManager.exportSessions('json', {\n profile: this.profile,\n sessions: [session.id],\n });\n\n const filename = `session-${session.id.substring(0, 8)}-${new Date().toISOString().split('T')[0]}.json`;\n\n console.log(chalk.green('✅ Session export prepared:'));\n console.log(chalk.blue(`📁 Filename: ${filename}`));\n console.log(\n chalk.gray(\n `📊 Stats: ${exportData.sessions.length} session, ${Object.values(exportData.messages).flat().length} messages`,\n ),\n );\n\n console.log(chalk.gray('📋 Export data structure created successfully'));\n } catch (error) {\n console.error(chalk.red(`❌ Export failed: ${error}`));\n }\n }\n\n async quickSelectSession(query?: string): Promise<string | null> {\n const sessions = await this.sessionManager.listSessions({\n profile: this.profile,\n limit: 20,\n type: 'chat',\n });\n\n if (sessions.length === 0) {\n return null;\n }\n\n let filteredSessions = sessions;\n\n if (query) {\n filteredSessions = this.searchSessions(sessions, query);\n\n if (filteredSessions.length === 0) {\n console.log(chalk.yellow(`🔍 No sessions found matching \"${query}\"`));\n return null;\n }\n\n if (filteredSessions.length === 1) {\n const session = filteredSessions[0];\n console.log(chalk.green(`🎯 Found session: \"${session.title}\"`));\n return session.id;\n }\n }\n\n return this.selectSession({\n showPreview: true,\n enableSearch: false,\n allowCreateNew: true,\n maxResults: 10,\n });\n }\n}\n"]}