i-self 0.4.3

Personal developer-companion CLI: scans your repos, indexes code semantically, watches your activity, and moves AI-agent sessions between tools (Claude Code, Aider, Goose, OpenAI Codex CLI, Continue.dev, OpenCode).
use crate::tracking::ActivityTracker;
use anyhow::Result;
use clap::Parser;
use std::path::PathBuf;

#[derive(Parser)]
pub struct TrackingCommand {
    #[arg(short, long, default_value = "7")]
    pub days: u32,

    #[arg(short, long)]
    pub start: bool,

    #[arg(short, long)]
    pub end: bool,

    #[arg(short, long)]
    pub project: Option<String>,

    #[arg(short, long)]
    pub language: Option<String>,
}

impl TrackingCommand {
    pub async fn run(&self) -> Result<()> {
        let data_dir = dirs::data_dir()
            .unwrap_or_else(|| PathBuf::from("."))
            .join("i-self");

        let mut tracker = ActivityTracker::new(data_dir.clone());
        tracker.load().await?;

        if self.start {
            let session = tracker.start_session(
                self.project.clone(),
                self.language.clone(),
            );
            println!("Started session: {}", session.id);
            println!("Project: {:?}", self.project);
            println!("Language: {:?}", self.language);
            return Ok(());
        }

        if self.end {
            let session_id = tracker.sessions.last().map(|s| s.id.clone());
            if let Some(id) = session_id {
                tracker.end_session(&id);
                tracker.save().await?;
                println!("Ended session: {}", id);
            }
            return Ok(());
        }

        let summary = tracker.get_summary(self.days);
        println!("\n=== Activity Summary (Last {} days) ===\n", self.days);
        println!("Total Sessions: {}", summary.total_sessions);
        println!("Total Coding Time: {} hours", summary.total_coding_time_seconds / 3600);
        println!("Total Idle Time: {} hours", summary.total_idle_time_seconds / 3600);
        println!("Average Session: {} minutes", summary.average_session_length_seconds / 60);
        println!("Commits: {}", summary.commit_count);

        if let Some(hour) = summary.most_productive_hour {
            println!("Most Productive Hour: {}:00", hour);
        }

        if !summary.projects_worked.is_empty() {
            println!("\nProjects Worked:");
            for project in &summary.projects_worked {
                println!("  - {}", project);
            }
        }

        if !summary.languages_used.is_empty() {
            println!("\nLanguages Used:");
            for (lang, count) in &summary.languages_used {
                println!("  - {}: {} sessions", lang, count);
            }
        }

        let patterns = tracker.get_work_patterns(self.days);
        if !patterns.is_empty() {
            println!("\nWork Patterns:");
            for pattern in patterns.iter().take(5) {
                let day_name = match pattern.day_of_week {
                    0 => "Mon",
                    1 => "Tue",
                    2 => "Wed",
                    3 => "Thu",
                    4 => "Fri",
                    5 => "Sat",
                    _ => "Sun",
                };
                println!("  {} {}:00 - {} sessions, {} min avg",
                    day_name, pattern.hour, pattern.activity_level as usize, pattern.typical_duration_minutes);
            }
        }

        Ok(())
    }
}