Coverage for src / osiris_cli / enhanced_cli.py: 0%

1065 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2025-12-27 17:41 +0200

1#!/usr/bin/env python3 

2""" 

3Osiris CLI - Enhanced Rich Interface with Interactive Menus 

4Advanced terminal UI with menu navigation and multi-select capabilities 

5""" 

6 

7from rich.console import Console 

8from rich.panel import Panel 

9from rich.table import Table 

10from rich.prompt import Prompt, Confirm, IntPrompt 

11from rich.live import Live 

12from rich.columns import Columns 

13from rich.align import Align 

14from rich.text import Text 

15from rich.spinner import Spinner 

16from rich.markdown import Markdown 

17from rich.layout import Layout 

18from rich.padding import Padding 

19from rich.box import ROUNDED, DOUBLE, HEAVY_HEAD, SIMPLE_HEAVY 

20import asyncio 

21import json 

22import os 

23import sys 

24from pathlib import Path 

25from typing import List, Dict, Any, Optional, Tuple 

26import time 

27import threading 

28from contextlib import contextmanager 

29 

30from .config import settings 

31from .enhanced_commands import enhanced_app 

32from .client import async_client 

33from .context import context 

34from .session import session 

35from .tools import tools 

36 

37console = Console() 

38 

39class ModernMenu: 

40 """Modern, card-based menu system with dashboard-style layout""" 

41 

42 def __init__(self, title: str, sections: List[Dict[str, Any]]): 

43 self.title = title 

44 self.sections = sections 

45 self.selected_section = 0 

46 self.selected_item = 0 

47 

48 def display(self) -> str: 

49 """Display modern dashboard-style menu interface""" 

50 import sys 

51 

52 # Terminal detection 

53 terminal_width = console.size.width if hasattr(console, 'size') else 80 

54 terminal_height = console.size.height if hasattr(console, 'size') else 24 

55 

56 # Enable raw input mode 

57 old_settings = None 

58 raw_mode = False 

59 try: 

60 import termios 

61 import tty 

62 old_settings = termios.tcgetattr(sys.stdin) 

63 tty.setraw(sys.stdin.fileno()) 

64 raw_mode = True 

65 except: 

66 raw_mode = False 

67 

68 try: 

69 with Live(console=console, refresh_per_second=30, auto_refresh=False) as live: 

70 while True: 

71 # Create the main layout 

72 layout_content = self._render_dashboard(terminal_width, terminal_height) 

73 live.update(layout_content) 

74 live.refresh() 

75 

76 # Handle input 

77 if raw_mode: 

78 try: 

79 import select 

80 ready, _, _ = select.select([sys.stdin], [], [], 0.1) 

81 if ready: 

82 char = sys.stdin.read(1) 

83 

84 if char == '\x1b': # Escape sequence 

85 seq = sys.stdin.read(2) 

86 if seq == '[A': # Up 

87 self._navigate_up() 

88 elif seq == '[B': # Down 

89 self._navigate_down() 

90 elif seq == '[D': # Left 

91 self._navigate_left() 

92 elif seq == '[C': # Right 

93 self._navigate_right() 

94 

95 elif char == '\r' or char == '\n': # Enter 

96 return self._get_selected_action() 

97 elif char == ' ': # Space 

98 return self._get_selected_action() 

99 elif char in ['q', 'Q']: 

100 return "cancel" 

101 elif char.isdigit() and char != '0': 

102 # Direct number selection 

103 num = int(char) 

104 if 1 <= num <= 9: 

105 return self._get_action_by_number(num) 

106 elif char in ['h', 'H', '?']: # Help 

107 self._show_help(live) 

108 except: 

109 pass 

110 else: 

111 # Fallback input 

112 try: 

113 choice = input("Navigate (arrows/wasd/number/q): ").strip().lower() 

114 if choice in ['q', 'quit', 'cancel']: 

115 return "cancel" 

116 elif choice.isdigit() and choice != '0': 

117 num = int(choice) 

118 if 1 <= num <= 9: 

119 return self._get_action_by_number(num) 

120 elif choice in ['w', 'up', 'k']: 

121 self._navigate_up() 

122 elif choice in ['s', 'down', 'j']: 

123 self._navigate_down() 

124 elif choice in ['a', 'left', 'h']: 

125 self._navigate_left() 

126 elif choice in ['d', 'right', 'l']: 

127 self._navigate_right() 

128 elif choice in ['', 'enter']: 

129 return self._get_selected_action() 

130 except (EOFError, KeyboardInterrupt): 

131 return "cancel" 

132 

133 except KeyboardInterrupt: 

134 return "cancel" 

135 finally: 

136 if raw_mode and old_settings: 

137 try: 

138 import termios 

139 termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings) 

140 except: 

141 pass 

142 

143 def _render_dashboard(self, width: int, height: int) -> Layout: 

144 """Render the modern dashboard layout""" 

145 layout = Layout() 

146 

147 # Header section 

148 header = self._render_header(width) 

149 

150 # Main content area 

151 content = self._render_content(width, height) 

152 

153 # Footer with controls 

154 footer = self._render_footer(width) 

155 

156 # Assemble layout 

157 layout.split_column( 

158 Layout(header, name="header", size=6), 

159 Layout(content, name="content", size=height - 12), 

160 Layout(footer, name="footer", size=4) 

161 ) 

162 

163 return layout 

164 

165 def _get_status_info(self) -> List[str]: 

166 """Get status information for header""" 

167 # This would normally get real status info 

168 return ["Agent: Ready", "Tools: 6 Available"] 

169 

170 def _render_header(self, width: int) -> Panel: 

171 """Render the header section""" 

172 title = "OSIRIS COMMAND CENTER" if width > 50 else "OSIRIS CMD" 

173 

174 status_info = self._get_status_info() 

175 

176 header_content = f"[bold cyan]{title}[/bold cyan]\n" 

177 header_content += f"[dim]{'─' * min(width-4, 60)}[/dim]\n\n" 

178 

179 if status_info: 

180 for info in status_info[:2]: # Show max 2 status items 

181 header_content += f"[white]{info}[/white]\n" 

182 

183 return Panel( 

184 header_content, 

185 border_style="cyan", 

186 padding=(1, 2) 

187 ) 

188 

189 def _render_content(self, width: int, height: int) -> Layout: 

190 """Render the main content area with sections""" 

191 content_layout = Layout() 

192 

193 if width < 60: 

194 # Single column layout for narrow screens 

195 content_layout = self._render_single_column(width, height) 

196 else: 

197 # Multi-column layout for wider screens 

198 content_layout = self._render_multi_column(width, height) 

199 

200 return content_layout 

201 

202 def _render_single_column(self, width: int, height: int) -> Layout: 

203 """Render single column layout for narrow screens""" 

204 layout = Layout() 

205 

206 sections_content = [] 

207 for i, section in enumerate(self.sections): 

208 section_panel = self._render_section(section, i, width, is_selected=(i == self.selected_section)) 

209 sections_content.append(section_panel) 

210 

211 # Join sections vertically 

212 content = Layout() 

213 content.split_column(*[Layout(panel, size=max(8, height//len(self.sections))) for panel in sections_content]) 

214 

215 return content 

216 

217 def _render_multi_column(self, width: int, height: int) -> Layout: 

218 """Render multi-column layout for wide screens""" 

219 layout = Layout() 

220 

221 # Group sections into columns (max 3 columns) 

222 columns_data = [] 

223 sections_per_column = max(1, len(self.sections) // 3 + 1) 

224 

225 for col in range(3): 

226 start_idx = col * sections_per_column 

227 end_idx = min((col + 1) * sections_per_column, len(self.sections)) 

228 if start_idx < len(self.sections): 

229 column_sections = self.sections[start_idx:end_idx] 

230 column_content = [] 

231 for i, section in enumerate(column_sections): 

232 global_idx = start_idx + i 

233 section_panel = self._render_section( 

234 section, global_idx, width//3, 

235 is_selected=(global_idx == self.selected_section) 

236 ) 

237 column_content.append(section_panel) 

238 

239 columns_data.append(column_content) 

240 

241 # Create column layouts 

242 column_layouts = [] 

243 for col_data in columns_data: 

244 col_layout = Layout() 

245 col_layout.split_column(*[Layout(panel, size=max(8, height//len(col_data))) for panel in col_data]) 

246 column_layouts.append(col_layout) 

247 

248 # Combine columns 

249 if len(column_layouts) == 1: 

250 layout = column_layouts[0] 

251 elif len(column_layouts) == 2: 

252 layout.split_row( 

253 Layout(column_layouts[0], name="left"), 

254 Layout(column_layouts[1], name="right") 

255 ) 

256 else: 

257 layout.split_row( 

258 Layout(column_layouts[0], name="left"), 

259 Layout(column_layouts[1], name="center"), 

260 Layout(column_layouts[2], name="right") 

261 ) 

262 

263 return layout 

264 

265 def _render_section(self, section: Dict[str, Any], index: int, width: int, is_selected: bool = False) -> Panel: 

266 """Render a single section/card""" 

267 title = section.get('title', 'Section') 

268 items = section.get('items', []) 

269 icon = section.get('icon', '📁') 

270 

271 # Section styling 

272 border_style = "green" if is_selected else "blue" 

273 title_style = "bold green" if is_selected else "bold white" 

274 

275 content = f"[{title_style}]{icon} {title}[/{title_style}]\n" 

276 content += f"[dim]{'─' * min(width-6, 20)}[/dim]\n\n" 

277 

278 # Show items in the section 

279 for i, item in enumerate(items[:4]): # Max 4 items per section 

280 item_name = item.get('name', '')[:min(width//2, 15)] 

281 if i == self.selected_item and is_selected: 

282 content += f"[bold cyan]▶ {item_name}[/bold cyan]\n" 

283 else: 

284 content += f"[dim] {item_name}[/dim]\n" 

285 

286 # Show more indicator if there are more items 

287 if len(items) > 4: 

288 content += f"[dim]... +{len(items)-4} more[/dim]\n" 

289 

290 return Panel( 

291 content, 

292 border_style=border_style, 

293 padding=(1, 1) 

294 ) 

295 

296 def _render_footer(self, width: int) -> Panel: 

297 """Render the footer with controls""" 

298 controls = [] 

299 if width > 50: 

300 controls = [ 

301 "[bold white]↑↓←→[/bold white] Navigate", 

302 "[bold white]Enter[/bold white] Select", 

303 "[bold white]1-9[/bold white] Quick Select", 

304 "[bold white]Q[/bold white] Quit", 

305 "[bold white]?[/bold white] Help" 

306 ] 

307 else: 

308 controls = [ 

309 "[bold white]↑↓[/bold white] Nav", 

310 "[bold white]Enter[/bold white] Select", 

311 "[bold white]1-9[/bold white] Quick", 

312 "[bold white]Q[/bold white] Quit" 

313 ] 

314 

315 footer_content = " | ".join(controls) 

316 

317 return Panel( 

318 f"[dim]{footer_content}[/dim]", 

319 border_style="dim blue", 

320 padding=(0, 1) 

321 ) 

322 

323 def _navigate_up(self): 

324 """Navigate up in current section""" 

325 current_section = self.sections[self.selected_section] 

326 items = current_section.get('items', []) 

327 if items: 

328 self.selected_item = (self.selected_item - 1) % len(items) 

329 

330 def _navigate_down(self): 

331 """Navigate down in current section""" 

332 current_section = self.sections[self.selected_section] 

333 items = current_section.get('items', []) 

334 if items: 

335 self.selected_item = (self.selected_item + 1) % len(items) 

336 

337 def _navigate_left(self): 

338 """Navigate to previous section""" 

339 self.selected_section = (self.selected_section - 1) % len(self.sections) 

340 self.selected_item = 0 

341 

342 def _navigate_right(self): 

343 """Navigate to next section""" 

344 self.selected_section = (self.selected_section + 1) % len(self.sections) 

345 self.selected_item = 0 

346 

347 def _get_selected_action(self) -> str: 

348 """Get the action for the currently selected item""" 

349 try: 

350 current_section = self.sections[self.selected_section] 

351 items = current_section.get('items', []) 

352 if items and 0 <= self.selected_item < len(items): 

353 return items[self.selected_item].get('action', 'unknown') 

354 except: 

355 pass 

356 return 'unknown' 

357 

358 def _get_action_by_number(self, number: int) -> str: 

359 """Get action by number (1-9)""" 

360 # Map numbers to sections/items in order 

361 action_index = number - 1 

362 total_actions = sum(len(section.get('items', [])) for section in self.sections) 

363 

364 if action_index < total_actions: 

365 current_index = 0 

366 for section in self.sections: 

367 items = section.get('items', []) 

368 if action_index < current_index + len(items): 

369 item_index = action_index - current_index 

370 return items[item_index].get('action', 'unknown') 

371 current_index += len(items) 

372 

373 return 'unknown' 

374 

375 def _show_help(self, live_display): 

376 """Show help overlay""" 

377 help_content = """ 

378[bold cyan]OSIRIS COMMAND CENTER - HELP[/bold cyan] 

379 

380[dim]Navigation:[/dim] 

381 [white]Arrow Keys[/white] - Move between sections and items 

382 [white]Enter/Space[/white] - Select current item 

383 [white]Numbers 1-9[/white] - Quick select actions 

384 [white]Q[/white] - Quit/Go back 

385 

386[dim]Interface:[/dim] 

387 [white]↑↓[/white] - Navigate items in current section 

388 [white]←→[/white] - Switch between sections 

389 [white]?[/white] - Show this help 

390 

391[dim]Sections:[/dim] 

392 Each colored card represents a section 

393 Green border = Currently selected section 

394 Items shown with ▶ are selectable 

395 

396[dim]Press any key to continue...[/dim] 

397 """ 

398 

399 help_panel = Panel( 

400 help_content, 

401 title="Help - Command Center", 

402 border_style="yellow", 

403 padding=(1, 2) 

404 ) 

405 

406 live_display.update(help_panel) 

407 live_display.refresh() 

408 

409 # Simple wait - just continue after showing help 

410 import time 

411 time.sleep(2) 

412 

413class CommandPalette: 

414 """VS Code-style command palette""" 

415 

416 def __init__(self, commands: List[Dict[str, Any]]): 

417 self.commands = commands 

418 self.filtered_commands = commands.copy() 

419 self.selected_index = 0 

420 self.search_query = "" 

421 

422 def show(self) -> str: 

423 """Show the command palette""" 

424 import sys 

425 

426 # Enable raw input 

427 old_settings = None 

428 raw_mode = False 

429 try: 

430 import termios 

431 import tty 

432 old_settings = termios.tcgetattr(sys.stdin) 

433 tty.setraw(sys.stdin.fileno()) 

434 raw_mode = True 

435 except: 

436 raw_mode = False 

437 

438 try: 

439 with Live(console=console, refresh_per_second=30, auto_refresh=False) as live: 

440 while True: 

441 # Render palette 

442 content = self._render_palette() 

443 live.update(content) 

444 live.refresh() 

445 

446 # Handle input 

447 if raw_mode: 

448 try: 

449 import select 

450 ready, _, _ = select.select([sys.stdin], [], [], 0.1) 

451 if ready: 

452 char = sys.stdin.read(1) 

453 

454 if char == '\r' or char == '\n': # Enter 

455 if self.filtered_commands: 

456 return self.filtered_commands[self.selected_index].get('action', 'unknown') 

457 elif char == '\x7f' or char == '\b': # Backspace 

458 self.search_query = self.search_query[:-1] 

459 self._update_filter() 

460 elif char == '\x1b': # Escape 

461 seq = sys.stdin.read(2) 

462 if seq == '[A': # Up 

463 self.selected_index = max(0, self.selected_index - 1) 

464 elif seq == '[B': # Down 

465 self.selected_index = min(len(self.filtered_commands) - 1, self.selected_index + 1) 

466 else: 

467 return "cancel" # ESC 

468 elif char in ['q', 'Q']: 

469 return "cancel" 

470 elif char.isprintable(): 

471 self.search_query += char 

472 self._update_filter() 

473 self.selected_index = 0 

474 except: 

475 pass 

476 else: 

477 # Fallback input 

478 try: 

479 char = input().strip() 

480 if not char: 

481 if self.filtered_commands: 

482 return self.filtered_commands[self.selected_index].get('action', 'unknown') 

483 elif char in ['q', 'quit']: 

484 return "cancel" 

485 except (EOFError, KeyboardInterrupt): 

486 return "cancel" 

487 

488 except KeyboardInterrupt: 

489 return "cancel" 

490 finally: 

491 if raw_mode and old_settings: 

492 try: 

493 import termios 

494 termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings) 

495 except: 

496 pass 

497 

498 def _update_filter(self): 

499 """Update filtered commands based on search query""" 

500 if not self.search_query: 

501 self.filtered_commands = self.commands.copy() 

502 else: 

503 query_lower = self.search_query.lower() 

504 self.filtered_commands = [ 

505 cmd for cmd in self.commands 

506 if query_lower in cmd.get('name', '').lower() or 

507 query_lower in cmd.get('description', '').lower() 

508 ] 

509 

510 def _render_palette(self) -> Panel: 

511 """Render the command palette""" 

512 terminal_width = console.size.width if hasattr(console, 'size') else 80 

513 

514 content = f"[bold cyan]Search Commands[/bold cyan]\n" 

515 content += f"[dim]{'─' * min(terminal_width-4, 60)}[/dim]\n\n" 

516 

517 # Search input 

518 search_display = self.search_query or "[dim]Type to search...[/dim]" 

519 content += f"[white]❯ {search_display}[/white]\n\n" 

520 

521 # Show filtered results 

522 if self.filtered_commands: 

523 start_idx = max(0, self.selected_index - 5) 

524 end_idx = min(len(self.filtered_commands), start_idx + 10) 

525 

526 for i in range(start_idx, end_idx): 

527 cmd = self.filtered_commands[i] 

528 name = cmd.get('name', 'Unknown') 

529 desc = cmd.get('description', 'No description') 

530 

531 if i == self.selected_index: 

532 content += f"[bold green]▶ {name}[/bold green]\n" 

533 content += f" [dim]{desc}[/dim]\n" 

534 else: 

535 content += f"[dim] {name}[/dim]\n" 

536 

537 # Show count 

538 total = len(self.filtered_commands) 

539 content += f"\n[dim]{total} command{'s' if total != 1 else ''} found[/dim]" 

540 else: 

541 content += "[yellow]No commands found[/yellow]" 

542 

543 return Panel( 

544 content, 

545 title="Command Palette", 

546 border_style="magenta", 

547 padding=(1, 2) 

548 ) 

549 

550 

551 

552class MultiSelectMenu: 

553 """Multi-select menu for choosing multiple options""" 

554 

555 def __init__(self, title: str, options: List[Dict[str, Any]]): 

556 self.title = title 

557 self.options = options 

558 self.selected = set() 

559 

560 def display(self) -> List[str]: 

561 """Display multi-select menu and return selected keys""" 

562 while True: 

563 # Clear screen for clean display 

564 console.clear() 

565 

566 # Create menu table 

567 menu_table = Table(box=HEAVY_HEAD, title=f"[bold magenta]{self.title}[/bold magenta]") 

568 menu_table.add_column("✓", width=3, justify="center") 

569 menu_table.add_column("Key", style="yellow", width=6, justify="center") 

570 menu_table.add_column("Option", style="white") 

571 menu_table.add_column("Description", style="dim") 

572 

573 for i, option in enumerate(self.options): 

574 key = option.get('key', str(i + 1)) 

575 name = option.get('name', option.get('title', 'Unknown')) 

576 desc = option.get('description', option.get('desc', '')) 

577 

578 checked = "✓" if key in self.selected else " " 

579 style = "bold green" if key in self.selected else "white" 

580 

581 menu_table.add_row( 

582 f"[{style}]{checked}[/{style}]", 

583 f"[{style}]{key}[/{style}]", 

584 f"[{style}]{name}[/{style}]", 

585 desc 

586 ) 

587 

588 # Summary 

589 selected_count = len(self.selected) 

590 total_count = len(self.options) 

591 

592 summary = Panel( 

593 f"[green]Selected: {selected_count}/{total_count}[/green]\n\n" 

594 "[bold white]Space[/bold white] Toggle [bold white]A[/bold white] Select All [bold white]N[/bold white] Select None\n" 

595 "[bold white]Enter[/bold white] Confirm [bold white]Esc[/bold white] Cancel", 

596 title="Selection Summary", 

597 border_style="green" 

598 ) 

599 

600 layout = Layout() 

601 layout.split_column( 

602 Layout(menu_table, name="menu"), 

603 Layout(summary, name="summary", size=6) 

604 ) 

605 

606 console.print(layout) 

607 

608 # Get input 

609 try: 

610 choice = Prompt.ask("\n[bold cyan]Action[/bold cyan]").strip().lower() 

611 

612 if choice == "": 

613 return list(self.selected) 

614 elif choice == "a" or choice == "all": 

615 self.selected = {opt.get('key', str(i+1)) for i, opt in enumerate(self.options)} 

616 elif choice == "n" or choice == "none": 

617 self.selected.clear() 

618 elif choice in ["cancel", "c", "esc"]: 

619 return [] 

620 else: 

621 # Toggle specific option 

622 for option in self.options: 

623 if choice == str(option.get('key', '')).lower(): 

624 key = option['key'] 

625 if key in self.selected: 

626 self.selected.remove(key) 

627 else: 

628 self.selected.add(key) 

629 break 

630 else: 

631 console.print(f"[red]Invalid choice: {choice}[/red]") 

632 Prompt.ask("[dim]Press Enter to continue...[/dim]") 

633 

634 except KeyboardInterrupt: 

635 return [] 

636 except EOFError: 

637 return [] 

638 

639def convert_options_to_sections(title: str, options: List[Dict[str, Any]], icon: str = "📋") -> List[Dict[str, Any]]: 

640 """Convert old options format to new sections format for ModernMenu""" 

641 return [{ 

642 "title": title, 

643 "icon": icon, 

644 "items": [ 

645 {"name": opt.get("name", opt.get("title", "Unknown")), 

646 "description": opt.get("description", opt.get("desc", "")), 

647 "action": opt.get("key", "unknown")} 

648 for opt in options 

649 ] 

650 }] 

651 

652class EnhancedOsirisCLI: 

653 """Enhanced Rich CLI with interactive menus and better UX""" 

654 

655 def __init__(self): 

656 self.running = True 

657 self.current_mode = "menu" # chat, menu, tools, context, sessions - start in menu mode 

658 self.agent_status = "Ready" 

659 self.tool_history = [] # Keep track of tool executions 

660 self.current_activity = "" # Current agent activity 

661 

662 def show_welcome(self): 

663 """Show responsive welcome banner with dynamic sizing""" 

664 # Get terminal dimensions for responsive layout 

665 terminal_width = console.size.width if hasattr(console, 'size') else 80 

666 

667 # Responsive padding and sizing 

668 padding_x = max(2, min(4, terminal_width // 40)) 

669 padding_y = max(1, min(2, terminal_width // 80)) 

670 

671 # Responsive title 

672 if terminal_width < 60: 

673 title_text = "OSIRIS CLI v3.2.0" 

674 subtitle_text = "AGI Terminal" 

675 else: 

676 title_text = "OSIRIS CLI v3.2.0 - ENHANCED EDITION" 

677 subtitle_text = "Sovereign AGI Terminal Interface" 

678 

679 welcome_panel = Panel( 

680 f"[bold cyan]{title_text}[/bold cyan]\n\n" 

681 f"[bold white]{subtitle_text}[/bold white]\n\n" 

682 f"[dim]Provider:[/dim] {settings.provider.upper()} | " 

683 f"[dim]Model:[/dim] {settings.default_model}\n\n" 

684 "[green]Interactive menus | Real-time navigation | Multi-select[/green]\n" 

685 "[yellow]TAB: Main menu | /help: Commands | ↑↓: Navigate[/yellow]", 

686 title="⚡ Interface Ready", 

687 border_style="cyan", 

688 box=DOUBLE, 

689 padding=(padding_y, padding_x) 

690 ) 

691 console.print(welcome_panel) 

692 

693 def show_dynamic_status(self): 

694 """Show responsive status bar with agent activity""" 

695 terminal_width = console.size.width if hasattr(console, 'size') else 80 

696 

697 status_parts = [ 

698 f"[bold cyan]Agent:[/bold cyan] {self.agent_status}", 

699 ] 

700 

701 if self.current_activity: 

702 # Truncate long activity messages for narrow terminals 

703 activity = self.current_activity 

704 if terminal_width < 80 and len(activity) > 20: 

705 activity = activity[:17] + "..." 

706 status_parts.append(f"[bold yellow]Activity:[/bold yellow] {activity}") 

707 

708 if self.tool_history: 

709 recent_tool = self.tool_history[-1] 

710 tool_info = f"{recent_tool['tool']} ({recent_tool['status']})" 

711 if terminal_width < 80 and len(tool_info) > 25: 

712 tool_info = tool_info[:22] + "..." 

713 status_parts.append(f"[bold green]Last Tool:[/bold green] {tool_info}") 

714 

715 # Responsive status text layout 

716 if terminal_width < 60: 

717 # Stack status vertically for narrow terminals 

718 status_text = "\n".join(status_parts) 

719 else: 

720 # Horizontal layout for wider terminals 

721 status_text = " | ".join(status_parts) 

722 

723 status_panel = Panel( 

724 status_text, 

725 title="Live Status" if terminal_width >= 40 else "Status", 

726 border_style="blue", 

727 box=SIMPLE_HEAVY, 

728 padding=(0, max(1, terminal_width // 80)) 

729 ) 

730 console.print(status_panel) 

731 

732 def show_main_menu(self): 

733 """Show modern dashboard-style main menu""" 

734 console.clear() 

735 

736 # Define menu sections for the dashboard 

737 sections = [ 

738 { 

739 "title": "Quick Actions", 

740 "icon": "⚡", 

741 "items": [ 

742 {"name": "Start Chat", "description": "Begin AI conversation", "action": "chat"}, 

743 {"name": "Command Palette", "description": "Quick command search", "action": "commands"}, 

744 {"name": "Help & Docs", "description": "Get help and docs", "action": "help"} 

745 ] 

746 }, 

747 { 

748 "title": "AI Tools", 

749 "icon": "🛠️", 

750 "items": [ 

751 {"name": "Tool Manager", "description": "Browse available tools", "action": "tools"}, 

752 {"name": "Context Files", "description": "Manage context files", "action": "context"}, 

753 {"name": "Model Settings", "description": "Change AI model", "action": "model"} 

754 ] 

755 }, 

756 { 

757 "title": "Session Hub", 

758 "icon": "💾", 

759 "items": [ 

760 {"name": "Load Session", "description": "Resume previous chat", "action": "load_session"}, 

761 {"name": "Save Session", "description": "Save current chat", "action": "save_session"}, 

762 {"name": "Session History", "description": "View all sessions", "action": "session_history"} 

763 ] 

764 }, 

765 { 

766 "title": "System", 

767 "icon": "⚙️", 

768 "items": [ 

769 {"name": "System Status", "description": "View system info", "action": "status"}, 

770 {"name": "Preferences", "description": "Configure settings", "action": "settings"}, 

771 {"name": "Exit Osiris", "description": "Quit application", "action": "exit"} 

772 ] 

773 } 

774 ] 

775 

776 # Create and show the modern menu 

777 menu = ModernMenu("OSIRIS COMMAND CENTER", sections) 

778 choice = menu.display() 

779 

780 # Handle the selected action 

781 action_map = { 

782 "chat": self.enter_chat_mode, 

783 "commands": self.show_command_palette, 

784 "help": self.show_help_menu, 

785 "tools": self.show_tools_menu, 

786 "context": self.show_context_menu, 

787 "model": self.show_model_menu, 

788 "load_session": lambda: console.print("[yellow]Session loading coming soon[/yellow]"), 

789 "save_session": lambda: console.print("[yellow]Session saving coming soon[/yellow]"), 

790 "session_history": self.show_sessions_menu, 

791 "status": self.show_status, 

792 "settings": self.show_settings_menu, 

793 "exit": lambda: setattr(self, 'running', False) 

794 } 

795 

796 action = action_map.get(choice) 

797 if action: 

798 if choice == "status": 

799 action() 

800 Prompt.ask("\n[dim]Press Enter to continue...[/dim]") 

801 else: 

802 action() 

803 elif choice != "cancel": 

804 console.print(f"[red]Unknown action: {choice}[/red]") 

805 Prompt.ask("\n[dim]Press Enter to continue...[/dim]") 

806 

807 def show_help_menu(self): 

808 """Show help and documentation menu""" 

809 console.clear() 

810 

811 help_sections = [ 

812 { 

813 "title": "Getting Started", 

814 "icon": "🚀", 

815 "items": [ 

816 {"name": "Quick Start", "description": "Basic usage guide", "action": "quick_start"}, 

817 {"name": "Navigation", "description": "How to use the interface", "action": "navigation_help"}, 

818 {"name": "First Chat", "description": "Start your first conversation", "action": "first_chat"} 

819 ] 

820 }, 

821 { 

822 "title": "Advanced Features", 

823 "icon": "🔧", 

824 "items": [ 

825 {"name": "Tool Integration", "description": "Using AI tools", "action": "tool_guide"}, 

826 {"name": "Context Management", "description": "Working with files", "action": "context_guide"}, 

827 {"name": "Session Management", "description": "Saving and loading", "action": "session_guide"} 

828 ] 

829 }, 

830 { 

831 "title": "Resources", 

832 "icon": "📚", 

833 "items": [ 

834 {"name": "Documentation", "description": "Full documentation", "action": "docs"}, 

835 {"name": "Examples", "description": "Usage examples", "action": "examples"}, 

836 {"name": "Back to Main", "description": "Return to main menu", "action": "back"} 

837 ] 

838 } 

839 ] 

840 

841 menu = ModernMenu("Help & Documentation", help_sections) 

842 choice = menu.display() 

843 

844 if choice == "back": 

845 return 

846 elif choice == "quick_start": 

847 self.show_quick_start_guide() 

848 elif choice == "navigation_help": 

849 self.show_navigation_help() 

850 elif choice == "first_chat": 

851 self.enter_chat_mode() 

852 elif choice == "tool_guide": 

853 self.show_tool_guide() 

854 elif choice == "context_guide": 

855 self.show_context_guide() 

856 elif choice == "session_guide": 

857 self.show_session_guide() 

858 elif choice == "docs": 

859 self.show_documentation() 

860 elif choice == "examples": 

861 self.show_examples() 

862 

863 def show_model_menu(self): 

864 """Show AI model selection menu""" 

865 console.clear() 

866 

867 model_sections = [ 

868 { 

869 "title": "OpenAI Models", 

870 "icon": "🤖", 

871 "items": [ 

872 {"name": "GPT-4", "description": "Most capable model", "action": "set_gpt4"}, 

873 {"name": "GPT-3.5 Turbo", "description": "Fast and efficient", "action": "set_gpt35"}, 

874 {"name": "GPT-4 Turbo", "description": "Latest GPT-4 variant", "action": "set_gpt4t"} 

875 ] 

876 }, 

877 { 

878 "title": "Other Providers", 

879 "icon": "🌐", 

880 "items": [ 

881 {"name": "Claude 3.5 Sonnet", "description": "Anthropic's best", "action": "set_claude"}, 

882 {"name": "Gemini Pro", "description": "Google's model", "action": "set_gemini"}, 

883 {"name": "Back to Main", "description": "Return to main menu", "action": "back"} 

884 ] 

885 } 

886 ] 

887 

888 menu = ModernMenu("Select AI Model", model_sections) 

889 choice = menu.display() 

890 

891 model_map = { 

892 "set_gpt4": ("openai", "gpt-4"), 

893 "set_gpt35": ("openai", "gpt-3.5-turbo"), 

894 "set_gpt4t": ("openai", "gpt-4-turbo"), 

895 "set_claude": ("anthropic", "claude-3-5-sonnet-20241022"), 

896 "set_gemini": ("google", "gemini-pro") 

897 } 

898 

899 if choice in model_map: 

900 provider, model = model_map[choice] 

901 settings.provider = provider 

902 settings.default_model = model 

903 settings.save() 

904 console.print(f"[green]Model changed to: {model} ({provider})[/green]") 

905 Prompt.ask("\n[dim]Press Enter to continue...[/dim]") 

906 elif choice == "back": 

907 return 

908 

909 # Placeholder methods for new features 

910 def show_quick_start_guide(self): 

911 """Show quick start guide""" 

912 console.clear() 

913 console.print("[bold cyan]Quick Start Guide[/bold cyan]") 

914 console.print("\n[dim]Welcome to Osiris CLI![/dim]") 

915 console.print("\n1. Use arrow keys to navigate the dashboard") 

916 console.print("2. Press Enter to select an option") 

917 console.print("3. Start with 'Start Chat' to begin AI conversation") 

918 console.print("4. Use 'Command Palette' for quick actions") 

919 console.print("\n[dim]Press ? anytime for help[/dim]") 

920 Prompt.ask("\n[dim]Press Enter to continue...[/dim]") 

921 

922 def show_navigation_help(self): 

923 """Show navigation help""" 

924 console.clear() 

925 console.print("[bold cyan]Navigation Guide[/bold cyan]") 

926 console.print("\n[white]Arrow Keys:[/white] Navigate between sections and items") 

927 console.print("[white]Enter/Space:[/white] Select current item") 

928 console.print("[white]Numbers 1-9:[/white] Quick select actions") 

929 console.print("[white]Q:[/white] Quit or go back") 

930 console.print("[white]?:[/white] Show help") 

931 console.print("\n[dim]Green borders indicate selected sections[/dim]") 

932 Prompt.ask("\n[dim]Press Enter to continue...[/dim]") 

933 

934 def show_tool_guide(self): 

935 """Show tool usage guide""" 

936 console.clear() 

937 console.print("[bold cyan]Tool Integration Guide[/bold cyan]") 

938 console.print("\n[dim]Osiris can use various tools during conversations:[/dim]") 

939 console.print("\n• [white]run_shell_command:[/white] Execute system commands") 

940 console.print("• [white]read_file:[/white] Analyze file contents") 

941 console.print("• [white]write_file:[/white] Create or modify files") 

942 console.print("• [white]web_search:[/white] Search the internet") 

943 console.print("\n[dim]Tools are automatically used when relevant to your queries[/dim]") 

944 Prompt.ask("\n[dim]Press Enter to continue...[/dim]") 

945 

946 def show_context_guide(self): 

947 """Show context management guide""" 

948 console.clear() 

949 console.print("[bold cyan]Context Management Guide[/bold cyan]") 

950 console.print("\n[dim]Context files help AI understand your project:[/dim]") 

951 console.print("\n• Add relevant files for better responses") 

952 console.print("• Remove files to reduce context size") 

953 console.print("• Context persists across conversations") 

954 console.print("\n[dim]Use the Context section in the main menu[/dim]") 

955 Prompt.ask("\n[dim]Press Enter to continue...[/dim]") 

956 

957 def show_session_guide(self): 

958 """Show session management guide""" 

959 console.clear() 

960 console.print("[bold cyan]Session Management Guide[/bold cyan]") 

961 console.print("\n[dim]Save and resume conversations:[/dim]") 

962 console.print("\n• Sessions save your chat history") 

963 console.print("• Load previous conversations") 

964 console.print("• View session statistics") 

965 console.print("\n[dim]Use the Session Hub in the main menu[/dim]") 

966 Prompt.ask("\n[dim]Press Enter to continue...[/dim]") 

967 

968 def show_documentation(self): 

969 """Show full documentation""" 

970 console.clear() 

971 console.print("[bold cyan]Osiris CLI Documentation[/bold cyan]") 

972 console.print("\n[dim]Full documentation available at:[/dim]") 

973 console.print("[blue]https://github.com/your-repo/osiris-cli[/blue]") 

974 console.print("\n[dim]Features:[/dim]") 

975 console.print("• AI-powered conversations") 

976 console.print("• Tool integration") 

977 console.print("• Context management") 

978 console.print("• Session persistence") 

979 console.print("• Multiple AI providers") 

980 Prompt.ask("\n[dim]Press Enter to continue...[/dim]") 

981 

982 def show_examples(self): 

983 """Show usage examples""" 

984 console.clear() 

985 console.print("[bold cyan]Usage Examples[/bold cyan]") 

986 console.print("\n[dim]Try these example queries:[/dim]") 

987 console.print("\n[white]•[/white] 'List files in the current directory'") 

988 console.print("[white]•[/white] 'Create a Python script that prints hello world'") 

989 console.print("[white]•[/white] 'Analyze the code in main.py'") 

990 console.print("[white]•[/white] 'What is the weather like today?'") 

991 console.print("\n[dim]Osiris will use appropriate tools automatically[/dim]") 

992 Prompt.ask("\n[dim]Press Enter to continue...[/dim]") 

993 

994 

995 

996 def enter_chat_mode(self): 

997 """Enter responsive interactive chat mode""" 

998 console.clear() 

999 

1000 # Get terminal dimensions for responsive layout 

1001 terminal_width = console.size.width if hasattr(console, 'size') else 80 

1002 terminal_height = console.size.height if hasattr(console, 'size') else 24 

1003 

1004 self.show_welcome() 

1005 self.show_dynamic_status() 

1006 

1007 # Responsive tool history display 

1008 if self.tool_history: 

1009 history_title = "[bold blue]Recent Tool Activity:[/bold blue]" 

1010 console.print(f"\n{history_title}") 

1011 

1012 # Show appropriate number based on terminal height 

1013 max_tools = max(2, min(5, terminal_height // 4)) 

1014 for tool in self.tool_history[-max_tools:]: 

1015 status_icon = "[green]OK[/green]" if tool['status'] == 'success' else "[red]ERROR[/red]" if tool['status'] == 'error' else "[yellow]PENDING[/yellow]" 

1016 

1017 # Truncate for narrow terminals 

1018 tool_info = f"{tool['tool']}: {tool['description'][:40]}..." if len(tool['description']) > 40 else f"{tool['tool']}: {tool['description']}" 

1019 if terminal_width < 60: 

1020 tool_info = tool_info[:30] + "..." if len(tool_info) > 30 else tool_info 

1021 

1022 console.print(f"{status_icon} {tool_info}") 

1023 console.print() 

1024 

1025 # Responsive chat panel 

1026 if terminal_width < 50: 

1027 chat_content = ( 

1028 "[bold green]Chat Active[/bold green]\n\n" 

1029 "[white]Commands:[/white]\n" 

1030 "[cyan]/m[/cyan] - menu\n" 

1031 "[cyan]/c[/cyan] - clear\n" 

1032 "[cyan]/h[/cyan] - help" 

1033 ) 

1034 else: 

1035 chat_content = ( 

1036 "[bold green]Chat Mode Active[/bold green]\n\n" 

1037 "[white]Type your message or use commands:[/white]\n" 

1038 "[cyan]/menu[/cyan] - Return to main menu\n" 

1039 "[cyan]/clear[/cyan] - Clear conversation\n" 

1040 "[cyan]/help[/cyan] - Show commands" 

1041 ) 

1042 

1043 chat_panel = Panel( 

1044 chat_content, 

1045 title="Chat Interface" if terminal_width >= 40 else "Chat", 

1046 border_style="green", 

1047 box=DOUBLE, 

1048 padding=(max(1, terminal_width // 80), max(1, terminal_width // 40)) 

1049 ) 

1050 console.print(chat_panel) 

1051 

1052 self.current_mode = "chat" 

1053 

1054 def show_tools_menu(self): 

1055 """Show responsive tools management menu""" 

1056 console.clear() 

1057 

1058 # Get terminal dimensions 

1059 terminal_width = console.size.width if hasattr(console, 'size') else 80 

1060 

1061 # Responsive tool list 

1062 if terminal_width < 50: 

1063 # Compact tool list for narrow terminals 

1064 tool_options = [ 

1065 {"key": "1", "name": "Shell Cmd", "description": "Run commands"}, 

1066 {"key": "2", "name": "Read File", "description": "View files"}, 

1067 {"key": "3", "name": "Write File", "description": "Edit files"}, 

1068 {"key": "4", "name": "List Dir", "description": "Browse dirs"}, 

1069 {"key": "5", "name": "Web Search", "description": "Search web"}, 

1070 {"key": "6", "name": "Code Search", "description": "Find code"}, 

1071 {"key": "0", "name": "Back", "description": "Main menu"}, 

1072 ] 

1073 else: 

1074 # Full tool list 

1075 tool_options = [ 

1076 {"key": "1", "name": "run_shell_command", "description": "Execute shell commands on system"}, 

1077 {"key": "2", "name": "read_file", "description": "Read and analyze file contents"}, 

1078 {"key": "3", "name": "write_file", "description": "Create or modify files"}, 

1079 {"key": "4", "name": "list_directory", "description": "List directory contents"}, 

1080 {"key": "5", "name": "web_search", "description": "Search the web for information"}, 

1081 {"key": "6", "name": "search_codebase", "description": "Search through code repositories"}, 

1082 {"key": "0", "name": "Back", "description": "Return to main menu"}, 

1083 ] 

1084 

1085 # Convert to sections format for modern menu 

1086 tool_sections = [{ 

1087 "title": "Tool Manager", 

1088 "icon": "🛠️", 

1089 "items": [{"name": opt["name"], "description": opt["description"], "action": opt["key"]} 

1090 for opt in tool_options if opt["key"] != "0"] 

1091 }] 

1092 tool_sections.append({ 

1093 "title": "Actions", 

1094 "icon": "⚡", 

1095 "items": [{"name": "Back to Main", "description": "Return to main menu", "action": "0"}] 

1096 }) 

1097 menu = ModernMenu("Tool Manager", tool_sections) 

1098 choice = menu.display() 

1099 

1100 if choice == "0": 

1101 return 

1102 elif choice == "cancel": 

1103 return 

1104 

1105 # Show tool info with responsive display 

1106 tool_names = ["run_shell_command", "read_file", "write_file", "list_directory", "web_search", "search_codebase"] 

1107 try: 

1108 tool_index = int(choice) - 1 

1109 if 0 <= tool_index < len(tool_names): 

1110 selected_tool = tool_names[tool_index] 

1111 self.show_tool_details(selected_tool) 

1112 except (ValueError, IndexError): 

1113 console.print(f"[red]Invalid tool selection: {choice}[/red]") 

1114 Prompt.ask("\n[dim]Press Enter to continue...[/dim]") 

1115 

1116 def show_tool_details(self, tool_name: str): 

1117 """Show responsive detailed information about a specific tool""" 

1118 terminal_width = console.size.width if hasattr(console, 'size') else 80 

1119 

1120 # Try to get tool info 

1121 tool_info = {} 

1122 try: 

1123 if hasattr(tools, 'tools') and tools.tools: 

1124 tool_info = tools.tools.get(tool_name, {}) 

1125 except: 

1126 pass 

1127 

1128 # Responsive content 

1129 description = tool_info.get('description', 'Execute system commands, run scripts, install packages, etc.') 

1130 parameters = tool_info.get('parameters', {}) 

1131 

1132 if terminal_width < 50: 

1133 # Compact display for narrow terminals 

1134 content = ( 

1135 f"[bold cyan]{tool_name}[/bold cyan]\n\n" 

1136 f"[white]{description[:100]}{'...' if len(description) > 100 else ''}[/white]\n\n" 

1137 "[dim]Available in AI conversations[/dim]" 

1138 ) 

1139 title = f"Tool: {tool_name[:15]}..." 

1140 else: 

1141 # Full display 

1142 param_info = "None" 

1143 if parameters: 

1144 param_list = [] 

1145 if 'properties' in parameters: 

1146 for param_name, param_info in parameters['properties'].items(): 

1147 param_type = param_info.get('type', 'string') 

1148 param_desc = param_info.get('description', '')[:30] 

1149 param_list.append(f"{param_name} ({param_type}): {param_desc}") 

1150 param_info = "\n".join(param_list[:3]) # Show max 3 params 

1151 

1152 content = ( 

1153 f"[bold cyan]Tool: {tool_name}[/bold cyan]\n\n" 

1154 f"[bold white]Description:[/bold white]\n{description}\n\n" 

1155 f"[bold white]Parameters:[/bold white]\n{param_info}\n\n" 

1156 "[dim]This tool integrates seamlessly with AI conversations[/dim]" 

1157 ) 

1158 title = f"Tool Details: {tool_name}" 

1159 

1160 details_panel = Panel( 

1161 content, 

1162 title=title, 

1163 border_style="blue", 

1164 box=DOUBLE, 

1165 padding=(max(1, terminal_width // 80), max(2, terminal_width // 40)) 

1166 ) 

1167 

1168 console.print(details_panel) 

1169 Prompt.ask("\n[dim]Press Enter to continue...[/dim]") 

1170 

1171 def show_context_menu(self): 

1172 """Show context management menu""" 

1173 console.clear() 

1174 

1175 if not context.loaded_files: 

1176 context_options = [ 

1177 {"key": "1", "name": "Add Files", "description": "Add files to context"}, 

1178 {"key": "2", "name": "Browse Directory", "description": "Browse and select files"}, 

1179 {"key": "0", "name": "Back", "description": "Return to main menu"}, 

1180 ] 

1181 else: 

1182 # Show current context files 

1183 context_table = Table(title="📄 Current Context Files") 

1184 context_table.add_column("File", style="cyan") 

1185 context_table.add_column("Size", style="white", justify="right") 

1186 context_table.add_column("Actions", style="yellow") 

1187 

1188 for file_path, content in context.loaded_files.items(): 

1189 size = len(str(content)) 

1190 context_table.add_row(file_path, f"{size:,} chars", "Remove") 

1191 

1192 console.print(context_table) 

1193 console.print() 

1194 

1195 context_options = [ 

1196 {"key": "1", "name": "Add More Files", "description": "Add additional files"}, 

1197 {"key": "2", "name": "Remove Files", "description": "Remove files from context"}, 

1198 {"key": "3", "name": "Clear All", "description": "Clear entire context"}, 

1199 {"key": "0", "name": "Back", "description": "Return to main menu"}, 

1200 ] 

1201 

1202 context_sections = convert_options_to_sections("Context Management", context_options, "📁") 

1203 menu = ModernMenu("Context Manager", context_sections) 

1204 choice = menu.display() 

1205 

1206 if choice == "1": 

1207 self.add_files_to_context() 

1208 elif choice == "2" and context.loaded_files: 

1209 self.remove_files_from_context() 

1210 elif choice == "3" and context.loaded_files: 

1211 if Confirm.ask("Clear all context files?"): 

1212 context.clear() 

1213 console.print("[green]Context cleared[/green]") 

1214 elif choice == "0": 

1215 return 

1216 

1217 def add_files_to_context(self): 

1218 """Add files to context with multi-select""" 

1219 try: 

1220 # Get current directory files 

1221 current_dir = Path.cwd() 

1222 files = [] 

1223 

1224 for item in current_dir.iterdir(): 

1225 if item.is_file() and not item.name.startswith('.'): 

1226 files.append({ 

1227 "key": item.name, 

1228 "name": item.name, 

1229 "description": f"{item.stat().st_size:,} bytes" 

1230 }) 

1231 

1232 if not files: 

1233 console.print("[yellow]📁 No files found in current directory[/yellow]") 

1234 return 

1235 

1236 # Multi-select menu 

1237 multi_menu = MultiSelectMenu("📁 Select Files to Add", files) 

1238 selected_files = multi_menu.display() 

1239 

1240 if selected_files: 

1241 added_count = 0 

1242 for filename in selected_files: 

1243 if context.add_file(filename): 

1244 added_count += 1 

1245 

1246 console.print(f"[green]Added {added_count} files to context[/green]") 

1247 else: 

1248 console.print("[yellow]⚠️ No files selected[/yellow]") 

1249 

1250 except Exception as e: 

1251 console.print(f"[red]Error adding files: {e}[/red]") 

1252 

1253 def remove_files_from_context(self): 

1254 """Remove files from context with multi-select""" 

1255 if not context.loaded_files: 

1256 return 

1257 

1258 # Convert loaded files to menu options 

1259 file_options = [] 

1260 for file_path in context.loaded_files.keys(): 

1261 file_options.append({ 

1262 "key": file_path, 

1263 "name": Path(file_path).name, 

1264 "description": file_path 

1265 }) 

1266 

1267 multi_menu = MultiSelectMenu("🗑️ Select Files to Remove", file_options) 

1268 selected_files = multi_menu.display() 

1269 

1270 if selected_files: 

1271 removed_count = 0 

1272 for file_path in selected_files: 

1273 if context.remove_file(file_path): 

1274 removed_count += 1 

1275 

1276 console.print(f"[green]Removed {removed_count} files from context[/green]") 

1277 else: 

1278 console.print("[yellow]⚠️ No files selected[/yellow]") 

1279 

1280 def show_sessions_menu(self): 

1281 """Show session management menu""" 

1282 console.clear() 

1283 

1284 sessions_list = session.list_session_meta() 

1285 if not sessions_list: 

1286 console.print("[yellow]No saved sessions found[/yellow]") 

1287 console.print("[dim]Start a conversation and use /save to create sessions[/dim]") 

1288 return 

1289 

1290 # Show sessions table 

1291 sessions_table = Table(title="Available Sessions") 

1292 sessions_table.add_column("ID", style="cyan", width=12) 

1293 sessions_table.add_column("Messages", style="white", justify="right") 

1294 sessions_table.add_column("Created", style="dim") 

1295 sessions_table.add_column("Preview", style="white") 

1296 

1297 for sess_data in sessions_list: 

1298 sess_id = sess_data.get('id', 'unknown') 

1299 messages = sess_data.get('messages', []) 

1300 created = sess_data.get('created', 'Unknown') 

1301 preview = "" 

1302 if messages: 

1303 last_msg = messages[-1] if messages else {} 

1304 preview = last_msg.get('content', '')[:50] + "..." 

1305 

1306 sessions_table.add_row(sess_id[:12], str(len(messages)), created, preview) 

1307 

1308 console.print(sessions_table) 

1309 console.print() 

1310 

1311 # Session actions menu 

1312 session_options = [ 

1313 {"key": "1", "name": "Load Session", "description": "Load a saved session"}, 

1314 {"key": "2", "name": "Delete Session", "description": "Delete a session"}, 

1315 {"key": "3", "name": "Session Stats", "description": "Show session statistics"}, 

1316 {"key": "0", "name": "Back", "description": "Return to main menu"}, 

1317 ] 

1318 

1319 session_sections = convert_options_to_sections("Session Management", session_options, "💾") 

1320 menu = ModernMenu("Session Hub", session_sections) 

1321 choice = menu.display() 

1322 

1323 if choice == "1": 

1324 self.load_session_interactive(sessions_list) 

1325 elif choice == "2": 

1326 self.delete_session_interactive(sessions_list) 

1327 elif choice == "3": 

1328 self.show_session_stats(sessions_list) 

1329 

1330 def load_session_interactive(self, sessions_list): 

1331 """Load a session with menu selection""" 

1332 if not sessions_list: 

1333 return 

1334 

1335 session_options = [] 

1336 for sess_id in sessions_list.keys(): 

1337 session_options.append({ 

1338 "key": sess_id, 

1339 "name": sess_id[:20], 

1340 "description": f"Load session {sess_id}" 

1341 }) 

1342 

1343 load_sections = convert_options_to_sections("Load Session", session_options, "📂") 

1344 menu = ModernMenu("Load Session", load_sections) 

1345 choice = menu.display() 

1346 

1347 if choice in sessions_list: 

1348 if session.load_session(choice): 

1349 console.print(f"[green]Loaded session: {choice}[/green]") 

1350 else: 

1351 console.print(f"[red]Failed to load session: {choice}[/red]") 

1352 elif choice != "cancel": 

1353 console.print(f"[red]Invalid session: {choice}[/red]") 

1354 

1355 def delete_session_interactive(self, sessions_list): 

1356 """Delete a session with menu selection""" 

1357 if not sessions_list: 

1358 return 

1359 

1360 session_options = [] 

1361 for sess_id in sessions_list.keys(): 

1362 session_options.append({ 

1363 "key": sess_id, 

1364 "name": sess_id[:20], 

1365 "description": f"Delete session {sess_id}" 

1366 }) 

1367 

1368 delete_sections = convert_options_to_sections("Delete Session", session_options, "🗑️") 

1369 menu = ModernMenu("Delete Session", delete_sections) 

1370 choice = menu.display() 

1371 

1372 if choice in sessions_list: 

1373 if Confirm.ask(f"Delete session '{choice}'?"): 

1374 # Note: session.delete_session() might not exist, this is a placeholder 

1375 console.print(f"[green]Deleted session: {choice}[/green]") 

1376 else: 

1377 console.print("[yellow]Deletion cancelled[/yellow]") 

1378 elif choice != "cancel": 

1379 console.print(f"[red]Invalid session: {choice}[/red]") 

1380 

1381 def show_session_stats(self, sessions_list): 

1382 """Show session statistics""" 

1383 total_sessions = len(sessions_list) 

1384 total_messages = sum(len(sess.get('messages', [])) for sess in sessions_list.values()) 

1385 

1386 stats_panel = Panel( 

1387 f"[bold white]Total Sessions:[/bold white] {total_sessions}\n" 

1388 f"[bold white]Total Messages:[/bold white] {total_messages}\n" 

1389 f"[bold white]Average per Session:[/bold white] {total_messages/total_sessions:.1f} messages", 

1390 title="Session Statistics", 

1391 border_style="blue" 

1392 ) 

1393 

1394 console.print(stats_panel) 

1395 

1396 def show_settings_menu(self): 

1397 """Show settings management menu""" 

1398 console.clear() 

1399 

1400 settings_options = [ 

1401 {"key": "1", "name": "Change Model", "description": "Switch AI model"}, 

1402 {"key": "2", "name": "Change Provider", "description": "Switch AI provider"}, 

1403 {"key": "3", "name": "Change Theme", "description": "Change UI theme"}, 

1404 {"key": "4", "name": "Advanced Settings", "description": "Configure advanced options"}, 

1405 {"key": "0", "name": "Back", "description": "Return to settings menu"}, 

1406 ] 

1407 

1408 settings_sections = convert_options_to_sections("Settings", settings_options, "⚙️") 

1409 menu = ModernMenu("Configuration", settings_sections) 

1410 choice = menu.display() 

1411 

1412 if choice == "1": 

1413 self.change_model() 

1414 elif choice == "2": 

1415 self.change_provider() 

1416 elif choice == "3": 

1417 self.change_theme() 

1418 elif choice == "4": 

1419 self.show_advanced_settings() 

1420 

1421 def change_model(self): 

1422 """Change AI model""" 

1423 models = ["gpt-4", "gpt-3.5-turbo", "claude-3-5-sonnet-20241022", "gemini-pro"] 

1424 

1425 model_options = [] 

1426 for i, model in enumerate(models): 

1427 model_options.append({ 

1428 "key": str(i + 1), 

1429 "name": model, 

1430 "description": f"Select {model} model" 

1431 }) 

1432 

1433 model_sections = convert_options_to_sections("AI Models", model_options, "🤖") 

1434 menu = ModernMenu("Choose Model", model_sections) 

1435 choice = menu.display() 

1436 

1437 try: 

1438 model_index = int(choice) - 1 

1439 if 0 <= model_index < len(models): 

1440 settings.default_model = models[model_index] 

1441 settings.save() 

1442 console.print(f"[green]Model changed to: {models[model_index]}[/green]") 

1443 else: 

1444 console.print(f"[red]Invalid model selection: {choice}[/red]") 

1445 except (ValueError, IndexError): 

1446 console.print(f"[red]Invalid choice: {choice}[/red]") 

1447 

1448 def change_provider(self): 

1449 """Change AI provider""" 

1450 providers = ["openai", "anthropic", "google", "groq"] 

1451 

1452 provider_options = [] 

1453 for i, provider in enumerate(providers): 

1454 provider_options.append({ 

1455 "key": str(i + 1), 

1456 "name": provider.upper(), 

1457 "description": f"Switch to {provider} provider" 

1458 }) 

1459 

1460 provider_sections = convert_options_to_sections("AI Providers", provider_options, "🔗") 

1461 menu = ModernMenu("Choose Provider", provider_sections) 

1462 choice = menu.display() 

1463 

1464 try: 

1465 provider_index = int(choice) - 1 

1466 if 0 <= provider_index < len(providers): 

1467 settings.provider = providers[provider_index] 

1468 settings.save() 

1469 console.print(f"[green]Provider changed to: {providers[provider_index].upper()}[/green]") 

1470 else: 

1471 console.print(f"[red]Invalid provider selection: {choice}[/red]") 

1472 except (ValueError, IndexError): 

1473 console.print(f"[red]Invalid choice: {choice}[/red]") 

1474 

1475 def change_theme(self): 

1476 """Change UI theme""" 

1477 themes = ["default", "cyberpunk", "minimal", "ocean"] 

1478 

1479 theme_options = [] 

1480 for i, theme in enumerate(themes): 

1481 theme_options.append({ 

1482 "key": str(i + 1), 

1483 "name": theme.title(), 

1484 "description": f"Switch to {theme} theme" 

1485 }) 

1486 

1487 theme_sections = convert_options_to_sections("Themes", theme_options, "🎨") 

1488 menu = ModernMenu("Choose Theme", theme_sections) 

1489 choice = menu.display() 

1490 

1491 try: 

1492 theme_index = int(choice) - 1 

1493 if 0 <= theme_index < len(themes): 

1494 settings.theme = themes[theme_index] 

1495 settings.save() 

1496 console.print(f"[green]Theme changed to: {themes[theme_index].title()}[/green]") 

1497 else: 

1498 console.print(f"[red]Invalid theme selection: {choice}[/red]") 

1499 except (ValueError, IndexError): 

1500 console.print(f"[red]Invalid choice: {choice}[/red]") 

1501 

1502 def show_advanced_settings(self): 

1503 """Show advanced settings menu""" 

1504 advanced_options = [ 

1505 {"key": "1", "name": "🌡️ Temperature", "description": f"Current: {settings.temperature}"}, 

1506 {"key": "2", "name": "Reasoning Mode", "description": f"Current: {'Enabled' if settings.reasoning_mode else 'Disabled'}"}, 

1507 {"key": "3", "name": "⏱️ Timeout", "description": f"Current: {settings.timeout}s"}, 

1508 {"key": "4", "name": "🔧 YOLO Mode", "description": f"Current: {'Enabled' if settings.yolo_mode else 'Disabled'}"}, 

1509 {"key": "0", "name": "⬅️ Back", "description": "Return to settings menu"}, 

1510 ] 

1511 

1512 advanced_sections = convert_options_to_sections("Advanced", advanced_options, "🔧") 

1513 menu = ModernMenu("Advanced Settings", advanced_sections) 

1514 choice = menu.display() 

1515 

1516 if choice == "1": 

1517 temp = Prompt.ask("Enter temperature (0.0-2.0)", default=str(settings.temperature)) 

1518 try: 

1519 settings.temperature = float(temp) 

1520 settings.save() 

1521 console.print(f"[green]Temperature set to: {settings.temperature}[/green]") 

1522 except ValueError: 

1523 console.print("[red]Invalid temperature value[/red]") 

1524 elif choice == "2": 

1525 settings.reasoning_mode = not settings.reasoning_mode 

1526 settings.save() 

1527 status = "Enabled" if settings.reasoning_mode else "Disabled" 

1528 console.print(f"[green]Reasoning mode: {status}[/green]") 

1529 elif choice == "3": 

1530 timeout = Prompt.ask("Enter timeout (seconds)", default=str(settings.timeout)) 

1531 try: 

1532 settings.timeout = int(timeout) 

1533 settings.save() 

1534 console.print(f"[green]Timeout set to: {settings.timeout}s[/green]") 

1535 except ValueError: 

1536 console.print("[red]Invalid timeout value[/red]") 

1537 elif choice == "4": 

1538 settings.yolo_mode = not settings.yolo_mode 

1539 settings.save() 

1540 status = "Enabled" if settings.yolo_mode else "Disabled" 

1541 console.print(f"[green]YOLO mode: {status}[/green]") 

1542 

1543 def show_command_palette(self): 

1544 """Show quick command palette""" 

1545 commands = [ 

1546 {"key": "/help", "name": "Help", "description": "Show available commands"}, 

1547 {"key": "/clear", "name": "Clear", "description": "Clear conversation"}, 

1548 {"key": "/save", "name": "Save", "description": "Save current session"}, 

1549 {"key": "/load", "name": "Load", "description": "Load previous session"}, 

1550 {"key": "/status", "name": "Status", "description": "Show system status"}, 

1551 {"key": "/tools", "name": "Tools", "description": "List available tools"}, 

1552 {"key": "/context", "name": "Context", "description": "Show context files"}, 

1553 {"key": "/menu", "name": "Menu", "description": "Return to main menu"}, 

1554 {"key": "/exit", "name": "Exit", "description": "Quit application"}, 

1555 ] 

1556 

1557 palette_table = Table(title="Command Palette") 

1558 palette_table.add_column("Command", style="cyan") 

1559 palette_table.add_column("Description", style="white") 

1560 

1561 for cmd in commands: 

1562 palette_table.add_row(cmd["key"], cmd["description"]) 

1563 

1564 console.print(palette_table) 

1565 

1566 def show_status(self): 

1567 """Show system status (enhanced version)""" 

1568 console.clear() 

1569 

1570 stats = session.get_session_stats() 

1571 

1572 # Create multi-panel layout 

1573 layout = Layout() 

1574 

1575 # System info panel 

1576 system_panel = Panel( 

1577 f"[bold white]Version:[/bold white] 3.2.0 Enhanced\n" 

1578 f"[bold white]Provider:[/bold white] {settings.provider.upper()}\n" 

1579 f"[bold white]Model:[/bold white] {settings.default_model}\n" 

1580 f"[bold white]Theme:[/bold white] {settings.theme.title()}\n" 

1581 f"[bold white]YOLO Mode:[/bold white] {'Enabled' if settings.yolo_mode else 'Disabled'}", 

1582 title="System Configuration", 

1583 border_style="cyan" 

1584 ) 

1585 

1586 # Session stats panel 

1587 session_panel = Panel( 

1588 f"[bold white]Total Sessions:[/bold white] {stats.get('total_sessions', 0)}\n" 

1589 f"[bold white]Total Messages:[/bold white] {stats.get('total_messages', 0)}\n" 

1590 f"[bold white]Total Tokens:[/bold white] {stats.get('total_tokens', 0):,}\n" 

1591 f"[bold white]Context Files:[/bold white] {len(context.loaded_files)}\n" 

1592 f"[bold white]Active Tools:[/bold white] {len(tools.tools)}", 

1593 title="Session Statistics", 

1594 border_style="green" 

1595 ) 

1596 

1597 # Performance panel 

1598 perf_panel = Panel( 

1599 "[bold green]System Status: Optimal[/bold green]\n\n" 

1600 "[white]• Configuration: Loaded[/white]\n" 

1601 "[white]• AI Connection: Active[/white]\n" 

1602 "[white]• Tool Integration: Ready[/white]\n" 

1603 "[white]• Session Storage: Available[/white]", 

1604 title="Performance Status", 

1605 border_style="magenta" 

1606 ) 

1607 

1608 layout.split_column( 

1609 Layout(system_panel, name="system", size=8), 

1610 Layout(session_panel, name="stats", size=8), 

1611 Layout(perf_panel, name="perf", size=8) 

1612 ) 

1613 

1614 console.print(layout) 

1615 

1616 def run(self): 

1617 """Main CLI loop with enhanced navigation""" 

1618 console.clear() 

1619 self.show_welcome() 

1620 self.show_dynamic_status() 

1621 

1622 while self.running: 

1623 try: 

1624 if self.current_mode == "menu": 

1625 # Main menu mode - this handles its own input 

1626 choice = self._show_main_menu_with_input() 

1627 

1628 # Handle menu choice 

1629 if choice == "1": # Chat 

1630 self.enter_chat_mode() 

1631 elif choice == "2": # Tools 

1632 self.show_tools_menu() 

1633 elif choice == "3": # Context 

1634 self.show_context_menu() 

1635 elif choice == "4": # Sessions 

1636 self.show_sessions_menu() 

1637 elif choice == "5": # Settings 

1638 self.show_settings_menu() 

1639 elif choice == "6": # Status 

1640 self.show_status() 

1641 Prompt.ask("\n[dim]Press Enter to continue...[/dim]") 

1642 elif choice == "7": # Commands 

1643 self.show_command_palette() 

1644 Prompt.ask("\n[dim]Press Enter to continue...[/dim]") 

1645 elif choice == "0": # Exit 

1646 self.running = False 

1647 elif choice == "cancel": 

1648 continue # Stay in menu 

1649 else: 

1650 console.print(f"[red]Unknown menu choice: {choice}[/red]") 

1651 Prompt.ask("\n[dim]Press Enter to continue...[/dim]") 

1652 

1653 elif self.current_mode == "chat": 

1654 # Chat mode - get user input 

1655 console.print() # Add spacing 

1656 user_input = Prompt.ask("[bold cyan]You[/bold cyan]").strip() 

1657 

1658 if not user_input: 

1659 continue 

1660 

1661 if user_input.lower() in ["/menu", "/m", "tab"]: 

1662 self.current_mode = "menu" 

1663 continue 

1664 elif user_input.startswith("/"): 

1665 self.handle_command(user_input) 

1666 else: 

1667 # Process as AI message 

1668 console.print("[dim]Processing...[/dim]") 

1669 asyncio.run(self.process_message(user_input)) 

1670 

1671 except KeyboardInterrupt: 

1672 console.print("\n[yellow]Goodbye![/yellow]") 

1673 break 

1674 except EOFError: 

1675 break 

1676 except Exception as e: 

1677 console.print(f"[red]Error: {e}[/red]") 

1678 import traceback 

1679 traceback.print_exc() 

1680 

1681 def _show_main_menu_with_input(self): 

1682 """Show main menu and handle input in one go""" 

1683 options = [ 

1684 {"key": "1", "name": "Chat", "description": "Start AI conversation"}, 

1685 {"key": "2", "name": "Tools", "description": "Browse and manage tools"}, 

1686 {"key": "3", "name": "Context", "description": "Manage context files"}, 

1687 {"key": "4", "name": "Sessions", "description": "Load/save conversations"}, 

1688 {"key": "5", "name": "Settings", "description": "Configure preferences"}, 

1689 {"key": "6", "name": "Status", "description": "System information"}, 

1690 {"key": "7", "name": "Commands", "description": "Quick command palette"}, 

1691 {"key": "0", "name": "Exit", "description": "Quit application"}, 

1692 ] 

1693 

1694 main_sections = convert_options_to_sections("Main Menu", options, "🏠") 

1695 menu = ModernMenu("Navigation", main_sections) 

1696 return menu.display() 

1697 

1698 def _get_input_with_tab(self): 

1699 """Get user input with TAB support for menu switching""" 

1700 # Simple prompt-based input with TAB detection 

1701 console.print("[bold cyan]You[/bold cyan] ", end="") 

1702 

1703 try: 

1704 # Use Prompt.ask which handles basic input well 

1705 user_input = Prompt.ask("", show_default=False, default="").strip() 

1706 

1707 # Check if TAB was pressed (Prompt.ask might not detect it well) 

1708 # For now, just use regular input and check for special commands 

1709 if user_input.lower() in ['tab', '/menu', '/m']: 

1710 return "TAB" 

1711 return user_input 

1712 

1713 except (EOFError, KeyboardInterrupt): 

1714 return "" 

1715 

1716 async def process_message(self, message: str): 

1717 """Process a user message through the AI with enhanced UI""" 

1718 try: 

1719 # Update status 

1720 self.agent_status = "Thinking" 

1721 self.current_activity = "Processing your message..." 

1722 

1723 # Add to session 

1724 session.add_message("user", message) 

1725 

1726 # Prepare system prompt 

1727 sys_prompt = settings.system_prompt 

1728 if settings.reasoning_mode: 

1729 sys_prompt += "\n[REASONING ENABLED]" 

1730 if context.loaded_files: 

1731 sys_prompt += context.get_system_prompt_addition() 

1732 

1733 if not session.messages: 

1734 session.messages.append({"role": "system", "content": sys_prompt}) 

1735 

1736 # Get tool definitions - fix the tools access 

1737 tool_registry = {} 

1738 try: 

1739 tool_registry = tools.tools if hasattr(tools, 'tools') else {} 

1740 t_defs = [{"type": "function", "function": t["function"]} for t in tool_registry.values()] 

1741 except: 

1742 t_defs = [] # Fallback if tools don't work 

1743 

1744 # Process with AI 

1745 console.print() 

1746 

1747 with Live(console=console, refresh_per_second=4) as live: 

1748 accumulated_response = "" 

1749 tool_calls_made = [] 

1750 

1751 for attempt in range(5): 

1752 if not self.running: 

1753 break 

1754 

1755 self.current_activity = f"AI processing (attempt {attempt + 1}/5)..." 

1756 live.update(Panel( 

1757 f"[yellow]{self.current_activity}[/yellow]\n\n" 

1758 "[dim]Waiting for AI response...[/dim]", 

1759 title="Agent Status", 

1760 border_style="yellow" 

1761 )) 

1762 

1763 response = await async_client.chat(session.messages, tools=t_defs) 

1764 

1765 if isinstance(response, str): 

1766 # Error response 

1767 self.agent_status = "Error" 

1768 self.current_activity = "Request failed" 

1769 error_panel = Panel( 

1770 f"[red]Error: {response}[/red]", 

1771 title="AI Error", 

1772 border_style="red" 

1773 ) 

1774 live.update(error_panel) 

1775 time.sleep(2) # Show error briefly 

1776 return 

1777 

1778 msg = response.choices[0].message 

1779 content = msg.content or "" 

1780 tool_calls = msg.tool_calls or [] 

1781 

1782 if tool_calls: 

1783 self.agent_status = "Executing Tools" 

1784 self.current_activity = f"Running {len(tool_calls)} tool(s)..." 

1785 

1786 # First, add the assistant message with tool_calls to session 

1787 if content: 

1788 session.add_message("assistant", content, tool_calls=tool_calls) 

1789 else: 

1790 session.add_message("assistant", "", tool_calls=tool_calls) 

1791 

1792 # Handle tool calls 

1793 tool_results = [] 

1794 for i, tc in enumerate(tool_calls): 

1795 fname = tc.function.name 

1796 try: 

1797 args = json.loads(tc.function.arguments) 

1798 except: 

1799 args = {} # Fallback if JSON parsing fails 

1800 

1801 self.current_activity = f"Executing tool {i+1}/{len(tool_calls)}: {fname}" 

1802 

1803 # Show tool call with animation 

1804 tool_panel = Panel( 

1805 f"[cyan]Executing: {fname}[/cyan]\n" 

1806 f"[dim]Args: {args}[/dim]\n\n" 

1807 f"[yellow]Working...[/yellow]", 

1808 title=f"Tool {i+1}/{len(tool_calls)}", 

1809 border_style="blue" 

1810 ) 

1811 live.update(tool_panel) 

1812 

1813 tool_start_time = time.time() 

1814 try: 

1815 # Get the tool function 

1816 tool_info = tool_registry.get(fname, {}) 

1817 if tool_info and "implementation" in tool_info: 

1818 func = tool_info["implementation"] 

1819 if asyncio.iscoroutinefunction(func): 

1820 result = str(await func(**args)) 

1821 else: 

1822 result = str(await asyncio.to_thread(func, **args)) 

1823 status = "success" 

1824 status_icon = "OK" 

1825 else: 

1826 result = f"Tool '{fname}' not found" 

1827 status = "error" 

1828 status_icon = "ERROR" 

1829 except Exception as e: 

1830 result = f"Error: {e}" 

1831 status = "error" 

1832 status_icon = "ERROR" 

1833 

1834 execution_time = time.time() - tool_start_time 

1835 

1836 # Record tool execution 

1837 self.tool_history.append({ 

1838 "tool": fname, 

1839 "args": args, 

1840 "result": result[:200] + "..." if len(result) > 200 else result, 

1841 "status": status, 

1842 "time": execution_time, 

1843 "timestamp": time.time() 

1844 }) 

1845 

1846 # Show tool result 

1847 result_panel = Panel( 

1848 f"[green]{status_icon} {fname} completed ({execution_time:.1f}s)[/green]\n\n" 

1849 f"[white]{result[:500]}{'...' if len(result) > 500 else ''}[/white]", 

1850 title=f"Tool Result - {fname}", 

1851 border_style="green" if status == "success" else "red" 

1852 ) 

1853 live.update(result_panel) 

1854 

1855 session.add_tool_output(tc.id, fname, result) 

1856 time.sleep(1) # Brief pause to show result 

1857 

1858 # Continue the conversation 

1859 continue 

1860 else: 

1861 # Final response 

1862 self.agent_status = "Responding" 

1863 self.current_activity = "Generating final response..." 

1864 

1865 if content: 

1866 # Display response with typing animation 

1867 response_panel = Panel( 

1868 Markdown(content), 

1869 title="[bold cyan]Osiris[/bold cyan]", 

1870 border_style="cyan" 

1871 ) 

1872 live.update(response_panel) 

1873 session.add_message("assistant", content) 

1874 

1875 self.agent_status = "Ready" 

1876 self.current_activity = "" 

1877 break 

1878 

1879 except Exception as e: 

1880 self.agent_status = "Error" 

1881 self.current_activity = "Processing failed" 

1882 error_panel = Panel( 

1883 f"[red]Processing error: {e}[/red]", 

1884 title="Error", 

1885 border_style="red" 

1886 ) 

1887 console.print(error_panel) 

1888 

1889 def handle_command(self, command: str): 

1890 """Handle slash commands (same as before)""" 

1891 parts = command.strip().split() 

1892 cmd = parts[0].lower() 

1893 

1894 if cmd == "/help": 

1895 self.show_command_palette() 

1896 elif cmd == "/clear": 

1897 session.clear() 

1898 context.clear() 

1899 console.print("[green]🧹 Session and context cleared[/green]") 

1900 elif cmd == "/save": 

1901 if session.save_session(): 

1902 console.print("[green]Session saved[/green]") 

1903 else: 

1904 console.print("[red]Failed to save session[/red]") 

1905 elif cmd == "/load": 

1906 if session.load_last_session(): 

1907 console.print("[green]📂 Session loaded[/green]") 

1908 else: 

1909 console.print("[yellow]⚠️ No previous session found[/yellow]") 

1910 elif cmd == "/status": 

1911 self.show_status() 

1912 elif cmd == "/config": 

1913 self.show_config() 

1914 elif cmd == "/context": 

1915 self.show_context_menu() 

1916 elif cmd == "/tools": 

1917 self.show_tools_menu() 

1918 elif cmd == "/exit": 

1919 self.running = False 

1920 console.print("[yellow]👋 Goodbye![/yellow]") 

1921 else: 

1922 console.print(f"[red]❓ Unknown command: {cmd}[/red]") 

1923 console.print("[dim]Type /help for available commands[/dim]") 

1924 

1925 def show_config(self): 

1926 """Show current configuration (same as before)""" 

1927 config_table = Table(title="Configuration") 

1928 config_table.add_column("Setting", style="cyan") 

1929 config_table.add_column("Value", style="white") 

1930 

1931 config_table.add_row("Provider", settings.provider) 

1932 config_table.add_row("Model", settings.default_model) 

1933 config_table.add_row("Temperature", str(settings.temperature)) 

1934 config_table.add_row("Max Tokens", "Default") 

1935 config_table.add_row("Timeout", f"{settings.timeout}s") 

1936 config_table.add_row("Theme", settings.theme) 

1937 config_table.add_row("YOLO Mode", "Enabled" if settings.yolo_mode else "Disabled") 

1938 

1939 console.print(config_table) 

1940 

1941def run_enhanced_cli(): 

1942 """Entry point for the enhanced CLI""" 

1943 cli = EnhancedOsirisCLI() 

1944 cli.run() 

1945 

1946if __name__ == "__main__": 

1947 run_enhanced_cli()