Files
ajarbot/ajarbot.py
Jordan Ramos a8665d8c72 Refactor: Clean up obsolete files and organize codebase structure
This commit removes deprecated modules and reorganizes code into logical directories:

Deleted files (superseded by newer systems):
- claude_code_server.py (replaced by agent-sdk direct integration)
- heartbeat.py (superseded by scheduled_tasks.py)
- pulse_brain.py (unused in production)
- config/pulse_brain_config.py (obsolete config)

Created directory structure:
- examples/ (7 example files: example_*.py, demo_*.py)
- tests/ (5 test files: test_*.py)

Updated imports:
- agent.py: Removed heartbeat module and all enable_heartbeat logic
- bot_runner.py: Removed heartbeat parameter from Agent initialization
- llm_interface.py: Updated deprecated claude_code_server message

Preserved essential files:
- hooks.py (for future use)
- adapters/skill_integration.py (for future use)
- All Google integration tools (Gmail, Calendar, Contacts)
- GLM provider code (backward compatibility)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-15 09:57:39 -07:00

206 lines
6.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Unified launcher for ajarbot with pre-flight checks.
This launcher:
1. Performs environment checks (Node.js, Claude CLI auth)
2. Sets sensible defaults (agent-sdk mode)
3. Delegates to bot_runner.main() for actual execution
Usage:
python ajarbot.py # Run with default config
python ajarbot.py --config custom.yaml # Use custom config file
python ajarbot.py --init # Generate config template
python ajarbot.py --setup-google # Set up Google OAuth
python ajarbot.py --health # Run health check
Environment variables:
AJARBOT_LLM_MODE # LLM mode: "agent-sdk" or "api" (default: agent-sdk)
AJARBOT_SLACK_BOT_TOKEN # Slack bot token (xoxb-...)
AJARBOT_SLACK_APP_TOKEN # Slack app token (xapp-...)
AJARBOT_TELEGRAM_BOT_TOKEN # Telegram bot token
ANTHROPIC_API_KEY # Claude API key (only needed for api mode)
"""
import os
import sys
import shutil
import subprocess
from pathlib import Path
class PreflightCheck:
"""Performs environment checks before launching the bot."""
def __init__(self):
self.warnings = []
self.errors = []
def check_nodejs(self) -> bool:
"""Check if Node.js is available (required for agent-sdk mode)."""
try:
result = subprocess.run(
["node", "--version"],
capture_output=True,
text=True,
timeout=5
)
if result.returncode == 0:
version = result.stdout.strip()
print(f"✓ Node.js found: {version}")
return True
else:
self.warnings.append("Node.js not found (required for agent-sdk mode)")
return False
except FileNotFoundError:
self.warnings.append("Node.js not found (required for agent-sdk mode)")
return False
except Exception as e:
self.warnings.append(f"Error checking Node.js: {e}")
return False
def check_claude_cli_auth(self) -> bool:
"""Check if Claude CLI is authenticated."""
try:
result = subprocess.run(
["claude", "auth", "status"],
capture_output=True,
text=True,
timeout=5
)
if result.returncode == 0 and "Authenticated" in result.stdout:
print("✓ Claude CLI authenticated")
return True
else:
self.warnings.append("Claude CLI not authenticated (run: claude auth login)")
return False
except FileNotFoundError:
self.warnings.append("Claude CLI not found (install from: https://claude.ai/download)")
return False
except Exception as e:
self.warnings.append(f"Error checking Claude CLI: {e}")
return False
def check_python_version(self) -> bool:
"""Check if Python version is compatible."""
version_info = sys.version_info
if version_info >= (3, 10):
print(f"✓ Python {version_info.major}.{version_info.minor}.{version_info.micro}")
return True
else:
self.errors.append(
f"Python 3.10+ required (found {version_info.major}.{version_info.minor}.{version_info.micro})"
)
return False
def check_env_file(self) -> bool:
"""Check if .env file exists (for API key storage)."""
env_path = Path(".env")
if env_path.exists():
print(f"✓ .env file found")
return True
else:
self.warnings.append(".env file not found (create one if using API mode)")
return False
def check_config_file(self) -> bool:
"""Check if adapter config exists."""
config_path = Path("config/adapters.local.yaml")
if config_path.exists():
print(f"✓ Config file found: {config_path}")
return True
else:
self.warnings.append(
"config/adapters.local.yaml not found (run: python ajarbot.py --init)"
)
return False
def set_default_llm_mode(self):
"""Set default LLM mode to agent-sdk if not specified."""
if "AJARBOT_LLM_MODE" not in os.environ:
os.environ["AJARBOT_LLM_MODE"] = "agent-sdk"
print(" Using LLM mode: agent-sdk (default)")
else:
mode = os.environ["AJARBOT_LLM_MODE"]
print(f" Using LLM mode: {mode} (from environment)")
def run_all_checks(self) -> bool:
"""Run all pre-flight checks. Returns True if safe to proceed."""
print("=" * 60)
print("Ajarbot Pre-Flight Checks")
print("=" * 60)
print()
# Critical checks
self.check_python_version()
# LLM mode dependent checks
llm_mode = os.environ.get("AJARBOT_LLM_MODE", "agent-sdk")
if llm_mode == "agent-sdk":
print("\n[Agent SDK Mode Checks]")
self.check_nodejs()
self.check_claude_cli_auth()
elif llm_mode == "api":
print("\n[API Mode Checks]")
has_env = self.check_env_file()
if has_env:
if not os.environ.get("ANTHROPIC_API_KEY"):
self.errors.append("ANTHROPIC_API_KEY not set in .env file (required for API mode)")
else:
self.errors.append(".env file with ANTHROPIC_API_KEY required for API mode")
# Common checks
print("\n[Configuration Checks]")
self.check_config_file()
# Display results
print()
print("=" * 60)
if self.errors:
print("ERRORS (must fix before running):")
for error in self.errors:
print(f"{error}")
print()
return False
if self.warnings:
print("WARNINGS (optional, but recommended):")
for warning in self.warnings:
print(f"{warning}")
print()
print("Pre-flight checks complete!")
print("=" * 60)
print()
return True
def main():
"""Main entry point with pre-flight checks."""
# Set default LLM mode before checks
checker = PreflightCheck()
checker.set_default_llm_mode()
# Special commands that bypass pre-flight checks
bypass_commands = ["--init", "--help", "-h"]
if any(arg in sys.argv for arg in bypass_commands):
# Import and run bot_runner directly
from bot_runner import main as bot_main
bot_main()
return
# Run pre-flight checks for normal operation
if not checker.run_all_checks():
print("\nPre-flight checks failed. Please fix the errors above.")
sys.exit(1)
# All checks passed - delegate to bot_runner
print("Launching ajarbot...\n")
from bot_runner import main as bot_main
bot_main()
if __name__ == "__main__":
main()