diff --git a/scripts/last30days.py b/scripts/last30days.py index a46beb7..29230fe 100644 --- a/scripts/last30days.py +++ b/scripts/last30days.py @@ -26,8 +26,6 @@ from pathlib import Path SCRIPT_DIR = Path(__file__).parent.resolve() sys.path.insert(0, str(SCRIPT_DIR)) -from typing import Optional - from lib import ( bird_x, dates, @@ -47,47 +45,6 @@ from lib import ( ) -def setup_bird_if_needed(progress: ui.ProgressDisplay) -> Optional[str]: - """Check Bird status and offer installation if needed. - - Returns: - 'bird' if Bird is ready to use, - 'declined' if user declined install, - None if Bird not available and couldn't be installed. - """ - status = bird_x.get_bird_status() - - # Already working - if status["authenticated"]: - return 'bird' - - # Installed but not authenticated - if status["installed"]: - progress.show_bird_auth_help() - return None - - # Not installed - offer to install if npm available - if status["can_install"]: - if progress.prompt_bird_install(): - success, message = bird_x.install_bird() - if success: - # Check if auth works now - username = bird_x.is_bird_authenticated() - if username: - progress.show_bird_install_success(username) - return 'bird' - else: - progress.show_bird_auth_help() - return None - else: - progress.show_bird_install_failed(message) - return None - else: - return 'declined' - - return None - - def load_fixture(name: str) -> dict: """Load a fixture file.""" fixture_path = SCRIPT_DIR.parent / "fixtures" / name @@ -405,33 +362,23 @@ def main(): else: depth = "default" - # Load config first to check Bird availability - config = env.get_config() - - # Check Bird availability and offer install if needed (before topic validation) - x_source_status = env.get_x_source_status(config) - x_source = x_source_status["source"] - - # If no X source and Bird can be installed, offer it - if x_source is None and x_source_status["can_install_bird"]: - # Create minimal progress for Bird prompts (no topic yet) - temp_progress = ui.ProgressDisplay("setup", show_banner=False) - bird_result = setup_bird_if_needed(temp_progress) - if bird_result == 'bird': - x_source = 'bird' - # Refresh status - x_source_status = env.get_x_source_status(config) - - # Now validate topic + # Validate topic first (matches original NUX) if not args.topic: print("Error: Please provide a topic to research.", file=sys.stderr) print("Usage: python3 last30days.py [options]", file=sys.stderr) sys.exit(1) + # Load config + config = env.get_config() + + # Auto-detect Bird (no prompts - just use it if available) + x_source_status = env.get_x_source_status(config) + x_source = x_source_status["source"] # 'bird', 'xai', or None + # Initialize progress display with topic progress = ui.ProgressDisplay(args.topic, show_banner=True) - # Check available sources (now accounting for Bird) + # Check available sources (accounting for Bird auto-detection) available = env.get_available_sources(config) # Override available if Bird is ready diff --git a/scripts/lib/env.py b/scripts/lib/env.py index 481a65a..2ff7001 100644 --- a/scripts/lib/env.py +++ b/scripts/lib/env.py @@ -85,21 +85,27 @@ def get_available_sources(config: Dict[str, Any]) -> str: def get_missing_keys(config: Dict[str, Any]) -> str: - """Determine which API keys are missing. + """Determine which sources are missing (accounting for Bird). Returns: 'both', 'reddit', 'x', or 'none' """ has_openai = bool(config.get('OPENAI_API_KEY')) has_xai = bool(config.get('XAI_API_KEY')) - if has_openai and has_xai: + # Check if Bird provides X access (import here to avoid circular dependency) + from . import bird_x + has_bird = bird_x.is_bird_installed() and bird_x.is_bird_authenticated() + + has_x = has_xai or has_bird + + if has_openai and has_x: return 'none' elif has_openai: - return 'x' # Missing xAI key - elif has_xai: + return 'x' # Missing X source + elif has_x: return 'reddit' # Missing OpenAI key else: - return 'both' # Missing both keys + return 'both' # Missing both def validate_sources(requested: str, available: str, include_web: bool = False) -> tuple[str, Optional[str]]: diff --git a/scripts/lib/ui.py b/scripts/lib/ui.py index 5fa147e..9f2768e 100644 --- a/scripts/lib/ui.py +++ b/scripts/lib/ui.py @@ -84,13 +84,14 @@ PROMO_MESSAGE = f""" {Colors.YELLOW}{Colors.BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━{Colors.RESET} {Colors.YELLOW}⚡ UNLOCK THE FULL POWER OF /last30days{Colors.RESET} -{Colors.DIM}Right now you're using web search only. Add API keys to unlock:{Colors.RESET} +{Colors.DIM}Right now you're using web search only. Unlock more sources:{Colors.RESET} {Colors.YELLOW}🟠 Reddit{Colors.RESET} - Real upvotes, comments, and community insights └─ Add OPENAI_API_KEY (uses OpenAI's web_search for Reddit) {Colors.CYAN}🔵 X (Twitter){Colors.RESET} - Real-time posts, likes, reposts from creators - └─ Add XAI_API_KEY (uses xAI's live X search) + └─ {Colors.GREEN}FREE:{Colors.RESET} npm install -g @steipete/bird {Colors.DIM}(uses browser session){Colors.RESET} + └─ {Colors.DIM}Or:{Colors.RESET} Add XAI_API_KEY (paid API) {Colors.DIM}Setup:{Colors.RESET} Edit {Colors.BOLD}~/.config/last30days/.env{Colors.RESET} {Colors.YELLOW}{Colors.BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━{Colors.RESET} @@ -100,13 +101,14 @@ PROMO_MESSAGE_PLAIN = """ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ⚡ UNLOCK THE FULL POWER OF /last30days -Right now you're using web search only. Add API keys to unlock: +Right now you're using web search only. Unlock more sources: 🟠 Reddit - Real upvotes, comments, and community insights └─ Add OPENAI_API_KEY (uses OpenAI's web_search for Reddit) 🔵 X (Twitter) - Real-time posts, likes, reposts from creators - └─ Add XAI_API_KEY (uses xAI's live X search) + └─ FREE: npm install -g @steipete/bird (uses browser session) + └─ Or: Add XAI_API_KEY (paid API) Setup: Edit ~/.config/last30days/.env ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ @@ -118,13 +120,15 @@ PROMO_SINGLE_KEY = { {Colors.DIM}💡 Tip: Add {Colors.YELLOW}OPENAI_API_KEY{Colors.RESET}{Colors.DIM} to ~/.config/last30days/.env for Reddit data with real engagement metrics!{Colors.RESET} """, "x": f""" -{Colors.DIM}💡 Tip: Add {Colors.CYAN}XAI_API_KEY{Colors.RESET}{Colors.DIM} to ~/.config/last30days/.env for X/Twitter data with real likes & reposts!{Colors.RESET} +{Colors.DIM}💡 Tip: For X/Twitter data with real likes & reposts:{Colors.RESET} + {Colors.GREEN}FREE:{Colors.RESET} npm install -g @steipete/bird {Colors.DIM}(uses browser session){Colors.RESET} + {Colors.DIM}Or: Add XAI_API_KEY to ~/.config/last30days/.env{Colors.RESET} """, } PROMO_SINGLE_KEY_PLAIN = { "reddit": "\n💡 Tip: Add OPENAI_API_KEY to ~/.config/last30days/.env for Reddit data with real engagement metrics!\n", - "x": "\n💡 Tip: Add XAI_API_KEY to ~/.config/last30days/.env for X/Twitter data with real likes & reposts!\n", + "x": "\n💡 Tip: For X/Twitter data with real likes & reposts:\n FREE: npm install -g @steipete/bird (uses browser session)\n Or: Add XAI_API_KEY to ~/.config/last30days/.env\n", } # Bird CLI prompts