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).
#![allow(dead_code)]

use anyhow::Result;
use std::path::PathBuf;

pub struct ScreenshotCapture {
    save_dir: PathBuf,
    interval_secs: u64,
    latest_path: Option<PathBuf>,
}

impl ScreenshotCapture {
    pub fn new(save_dir: PathBuf, interval_secs: u64) -> Result<Self> {
        std::fs::create_dir_all(&save_dir)?;
        
        Ok(Self {
            save_dir,
            interval_secs,
            latest_path: None,
        })
    }

    pub async fn capture(&mut self) -> Result<Option<PathBuf>> {
        let timestamp = chrono::Utc::now().format("%Y%m%d_%H%M%S").to_string();
        let filename = format!("screenshot_{}.png", timestamp);
        let path = self.save_dir.join(&filename);

        #[cfg(target_os = "macos")]
        {
            let output = std::process::Command::new("screencapture")
                .arg("-x")
                .arg(&path)
                .output()?;
            
            if output.status.success() && path.exists() {
                self.latest_path = Some(path.clone());
                return Ok(Some(path));
            }
        }

        #[cfg(target_os = "linux")]
        {
            let output = std::process::Command::new("gnome-screenshot")
                .arg("-f")
                .arg(&path)
                .output()?;
            
            if output.status.success() && path.exists() {
                self.latest_path = Some(path.clone());
                return Ok(Some(path));
            }

            let output = std::process::Command::new("import")
                .arg("-window")
                .arg("root")
                .arg(&path)
                .output()?;
            
            if output.status.success() && path.exists() {
                self.latest_path = Some(path.clone());
                return Ok(Some(path));
            }
        }

        #[cfg(target_os = "windows")]
        {
            use std::process::Command;
            let script = format!(
                "Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.Screen]::PrimaryScreen.Bitmap.Save('{}')",
                path.display()
            );
            Command::new("powershell")
                .args(["-Command", &script])
                .output()?;
            
            if path.exists() {
                self.latest_path = Some(path.clone());
                return Ok(Some(path));
            }
        }

        Ok(None)
    }

    pub fn get_latest_path(&self) -> Option<PathBuf> {
        self.latest_path.clone()
    }

    pub fn get_save_dir(&self) -> &PathBuf {
        &self.save_dir
    }

    pub fn cleanup_old_screenshots(&self, keep_last: u32) -> Result<u32> {
        let mut entries: Vec<_> = std::fs::read_dir(&self.save_dir)?
            .filter_map(|e| e.ok())
            .filter(|e| e.path().extension().map(|ext| ext == "png").unwrap_or(false))
            .collect();

        entries.sort_by_key(|e| std::cmp::Reverse(e.metadata().ok().and_then(|m| m.modified().ok())));

        let mut removed = 0;
        for entry in entries.iter().skip(keep_last as usize) {
            if std::fs::remove_file(entry.path()).is_ok() {
                removed += 1;
            }
        }

        Ok(removed)
    }
}