Skip to main content
Glama

Claude Slack

slack_session_start.pyโ€ข7.61 kB
#!/usr/bin/env python3 """ slack_session_start.py - SessionStart hook using ConfigSyncManager This hook runs at the start of every Claude Code session and uses the ConfigSyncManager to handle all initialization and setup tasks with the unified membership model and reconciliation pattern. """ import os import sys import json import logging from pathlib import Path # Add MCP directory to path to import modules claude_config_dir = os.environ.get('CLAUDE_CONFIG_DIR', os.path.expanduser('~/.claude')) claude_slack_dir = os.path.join(claude_config_dir, 'claude-slack') mcp_dir = os.path.join(claude_slack_dir, 'mcp') sys.path.insert(0, mcp_dir) sys.path.insert(0, os.path.join(claude_slack_dir, 'hooks')) # Set up logging - use new centralized logging system try: from log_manager.manager import get_logger logger = get_logger('session_start', component='hook') def log_json_data(logger, message, data, level=logging.DEBUG): """Log data as JSON for structured logging""" logger.log(level, f"{message}: {json.dumps(data, default=str)}") except ImportError: # Fallback to null logging if system not available import logging logger = logging.getLogger('SessionStart') logger.addHandler(logging.NullHandler()) def log_json_data(l, m, d, level=None): pass try: from config.sync_manager import ConfigSyncManager from api.unified_api import ClaudeSlackAPI except ImportError as e: logger.error(f"Failed to import ConfigSyncManager: {e}") ConfigSyncManager = None ClaudeSlackAPI = None try: from environment_config import env_config USE_ENV_CONFIG = True except ImportError: USE_ENV_CONFIG = False def main(): """Main hook entry point - reads JSON from stdin""" try: # Read JSON payload from stdin input_data = sys.stdin.read() if not input_data: logger.debug("No input data received, exiting") return 0 payload = json.loads(input_data) log_json_data(logger, "Received payload", payload) # Extract session information session_id = payload.get('session_id', '') cwd = payload.get('cwd', os.getcwd()) hook_event = payload.get('hook_event_name', '') transcript_path = payload.get('transcript_path', '') # Only process for SessionStart if hook_event != 'SessionStart': logger.debug(f"Ignoring non-SessionStart event: {hook_event}") return 0 logger.info(f"SessionStart Hook: session={session_id}, cwd={cwd}") logger.debug("--- SessionStart Hook Processing ---") # Use ConfigSyncManager if available if (ConfigSyncManager and ClaudeSlackAPI): logger.info("Using ConfigSyncManager and ClaudeSlackAPI for session initialization") # Database path if USE_ENV_CONFIG: try: db_path = env_config.db_path except Exception as e: logger.warning(f"Failed to get db_path from env_config: {e}") db_path = Path(claude_slack_dir) / 'data' / 'claude-slack.db' else: db_path = Path(claude_slack_dir) / 'data' / 'claude-slack.db' # Ensure database directory exists db_path = Path(db_path) db_path.parent.mkdir(parents=True, exist_ok=True) # Initialize the api api = ClaudeSlackAPI(db_path = db_path, qdrant_url=os.getenv('QDRANT_URL', 'http://localhost:6333')) # Initialize everything in a single async context import asyncio async def run_initialization(): """Run all initialization in a single async context""" try: # Initialize the API await api.initialize() logger.info("API initialized successfully") # Initialize sync manager sync_manager = ConfigSyncManager(api) # Initialize the session results = await sync_manager.initialize_session( session_id=session_id, cwd=cwd, transcript_path=transcript_path ) return results except Exception as e: logger.error(f"Failed during initialization: {e}") import traceback logger.debug(traceback.format_exc()) return None # Run everything in a single event loop try: results = asyncio.run(run_initialization()) except Exception as e: logger.error(f"Failed to run initialization: {e}") return 0 # Check if we got valid results if not results: logger.warning("No results returned from session initialization") return 0 # Log results if results.get('session_registered'): logger.info("Session registered successfully") # Handle reconciliation results reconciliation = results.get('reconciliation', {}) if reconciliation and reconciliation.get('success'): logger.info(f"Reconciliation completed:") logger.info(f" - Project ID: {results.get('project_id', 'N/A')}") logger.info(f" - Total actions: {reconciliation.get('total_actions', 0)}") logger.info(f" - Executed: {reconciliation.get('executed', 0)}") logger.info(f" - Failed: {reconciliation.get('failed', 0)}") # Log phase summary phase_summary = reconciliation.get('phase_summary', {}) for phase, stats in phase_summary.items(): if stats.get('total', 0) > 0: logger.info(f" - {phase}: {stats['completed']}/{stats['total']} completed") # Silent success message to stderr (for user visibility) executed = reconciliation.get('executed', 0) if executed > 0: print(f"Claude-Slack: {executed} configuration actions applied", file=sys.stderr) # Handle top-level errors if results.get('errors'): for error in results['errors']: logger.error(f"Initialization error: {error}") # Summary message if reconciliation and reconciliation.get('success'): logger.info("SessionStart hook completed: reconciliation successful") else: logger.info("SessionStart hook completed with reconciliation issues") else: logger.warning("ConfigSyncManager not available - limited initialization") # Could fall back to basic session registration here if needed return 0 except json.JSONDecodeError as e: logger.error(f"Invalid JSON input: {e}") return 0 except Exception as e: logger.error(f"Unexpected error in main: {e}") import traceback logger.debug(traceback.format_exc()) return 0 if __name__ == '__main__': sys.exit(main())

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/theo-nash/claude-slack'

If you have feedback or need assistance with the MCP directory API, please join our Discord server