#!/bin/bash # scripts/claude-start.sh # Description: Start Claude Code with persistent session management for AI Stack Deployer # Usage: ./scripts/claude-start.sh [session-name] [additional-flags] set -e # Exit on error set -u # Exit on undefined variable # Configuration PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$PROJECT_ROOT" # Store sessions in user's home directory, NOT in project root SESSION_DIR="$HOME/.claude/sessions/ai-stack-deployer" mkdir -p "$SESSION_DIR" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' MAGENTA='\033[0;35m' NC='\033[0m' # No Color # Helper functions function success() { echo -e "${GREEN}✅ $1${NC}" } function error() { echo -e "${RED}❌ $1${NC}" exit 1 } function info() { echo -e "${BLUE}ℹ️ $1${NC}" } function warning() { echo -e "${YELLOW}⚠️ $1${NC}" } function header() { echo "" echo -e "${MAGENTA}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${MAGENTA}$1${NC}" echo -e "${MAGENTA}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" } # Generate UUID v4 function generate_uuid() { if command -v uuidgen &> /dev/null; then uuidgen | tr '[:upper:]' '[:lower:]' elif command -v python3 &> /dev/null; then python3 -c "import uuid; print(str(uuid.uuid4()))" else # Fallback: use random + timestamp echo "$(date +%s)-$(( RANDOM % 100000 ))-$(( RANDOM % 100000 ))-$(( RANDOM % 100000 ))" fi } # Get or create session function get_or_create_session() { local SESSION_NAME="${1:-$(date +%Y%m%d-%H%M)}" local SESSION_FILE="$SESSION_DIR/$SESSION_NAME.session" # Check if session exists if [ -f "$SESSION_FILE" ]; then # Load existing session source "$SESSION_FILE" info "Resuming session: ${MAGENTA}$SESSION_NAME${NC}" info "Session ID: ${BLUE}$CLAUDE_SESSION_ID${NC}" info "Started: $CLAUDE_SESSION_START" # Calculate session age if command -v python3 &> /dev/null; then SESSION_AGE=$(python3 -c " from datetime import datetime start = datetime.strptime('$CLAUDE_SESSION_START', '%Y-%m-%d %H:%M:%S') age = datetime.now() - start days = age.days hours = age.seconds // 3600 print(f'{days}d {hours}h') " 2>/dev/null || echo "N/A") info "Age: $SESSION_AGE" fi # Update last used timestamp echo "export CLAUDE_SESSION_LAST_USED=\"$(date +%Y-%m-%d\ %H:%M:%S)\"" >> "$SESSION_FILE" else # Create new session CLAUDE_SESSION_ID=$(generate_uuid) CLAUDE_SESSION_NAME="$SESSION_NAME" CLAUDE_SESSION_START="$(date +%Y-%m-%d\ %H:%M:%S)" CLAUDE_SESSION_LAST_USED="$(date +%Y-%m-%d\ %H:%M:%S)" # Save session cat > "$SESSION_FILE" << SESSIONEOF # Claude Code Session: $SESSION_NAME # Created: $CLAUDE_SESSION_START export CLAUDE_SESSION_ID="$CLAUDE_SESSION_ID" export CLAUDE_SESSION_NAME="$SESSION_NAME" export CLAUDE_SESSION_START="$CLAUDE_SESSION_START" export CLAUDE_SESSION_LAST_USED="$CLAUDE_SESSION_LAST_USED" export CLAUDE_SESSION_PROJECT="ai-stack-deployer" export CLAUDE_SESSION_MCP_GROUP="project_ai_stack_deployer" SESSIONEOF success "Created new session: ${MAGENTA}$SESSION_NAME${NC}" info "Session ID: ${BLUE}$CLAUDE_SESSION_ID${NC}" info "Session file: $SESSION_FILE" fi # Export variables export CLAUDE_SESSION_ID export CLAUDE_SESSION_NAME export CLAUDE_SESSION_START export CLAUDE_SESSION_LAST_USED export CLAUDE_SESSION_PROJECT="ai-stack-deployer" export CLAUDE_SESSION_MCP_GROUP="project_ai_stack_deployer" } # Main script logic function main() { local SESSION_NAME="${1:-$(date +%Y%m%d-%H%M)}" shift || true # Remove first argument if it exists local ADDITIONAL_FLAGS="$@" header "AI Stack Deployer - Claude Code Session Manager" # Get or create session get_or_create_session "$SESSION_NAME" # Display helpful information echo "" info "Starting Claude Code with persistent session..." echo "" warning "Session Environment Variables:" echo " CLAUDE_SESSION_ID=$CLAUDE_SESSION_ID" echo " CLAUDE_SESSION_NAME=$CLAUDE_SESSION_NAME" echo " CLAUDE_SESSION_PROJECT=$CLAUDE_SESSION_PROJECT" echo " CLAUDE_SESSION_MCP_GROUP=$CLAUDE_SESSION_MCP_GROUP" echo "" info "Permission Mode: ${CLAUDE_PERMISSION_MODE:-bypassPermissions} (set CLAUDE_PERMISSION_MODE to override)" echo "" info "Quick Commands:" echo " 🔧 Dev server: bun run dev" echo " 🚀 MCP server: bun run mcp" echo " ✅ Type check: bun run typecheck" echo " 🧪 Test clients: bun run src/test-clients.ts" echo "" info "Memory Management:" echo " 🧠 Search: graphiti-memory_search_memory_facts({query: '...', group_ids: ['project_ai_stack_deployer']})" echo " 💾 Store: graphiti-memory_add_memory({name: '...', episode_body: '...', group_id: 'project_ai_stack_deployer'})" echo "" # Start Claude Code with session ID header "Starting Claude Code" echo "" # Build Claude Code command CLAUDE_CMD="claude --session-id \"$CLAUDE_SESSION_ID\"" # Add permission mode (default: bypassPermissions, override with CLAUDE_PERMISSION_MODE env var) PERMISSION_MODE="${CLAUDE_PERMISSION_MODE:-bypassPermissions}" CLAUDE_CMD="$CLAUDE_CMD --permission-mode $PERMISSION_MODE" # Add additional flags if provided if [ -n "$ADDITIONAL_FLAGS" ]; then CLAUDE_CMD="$CLAUDE_CMD $ADDITIONAL_FLAGS" fi info "Command: $CLAUDE_CMD" echo "" # Execute Claude Code eval $CLAUDE_CMD # After Claude Code exits echo "" header "Session Ended" success "Session complete: $CLAUDE_SESSION_NAME" info "Session ID: $CLAUDE_SESSION_ID" echo "" warning "Don't forget to store your learnings in Graphiti Memory!" echo "Example:" echo "" echo "graphiti-memory_add_memory({" echo " name: \"Session: $CLAUDE_SESSION_NAME - $(date +%Y-%m-%d)\"," echo " episode_body: \"Accomplished: [...]. Decisions: [...]. Issues: [...].\"," echo " group_id: \"project_ai_stack_deployer\"" echo "})" echo "" } # Run main function main "$@"