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>
This commit is contained in:
205
ajarbot.py
Normal file
205
ajarbot.py
Normal file
@@ -0,0 +1,205 @@
|
||||
"""
|
||||
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()
|
||||
Reference in New Issue
Block a user