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 serde::{Deserialize, Serialize};

#[derive(Clone, Serialize, Deserialize)]
pub struct NotificationManager {
    app_name: String,
}

impl NotificationManager {
    pub fn new() -> Self {
        Self {
            app_name: "i-self".to_string(),
        }
    }

    pub fn send(&self, title: &str, body: &str) -> Result<()> {
        #[cfg(target_os = "macos")]
        {
            std::process::Command::new("osascript")
                .args([
                    "-e",
                    &format!(
                        "display notification \"{}\" with title \"{}\"",
                        body.replace('"', "\\\""),
                        title.replace('"', "\\\"")
                    ),
                ])
                .output()?;
        }

        #[cfg(target_os = "linux")]
        {
            std::process::Command::new("notify-send")
                .args([
                    "-a",
                    &self.app_name,
                    "-u",
                    "normal",
                    title,
                    body,
                ])
                .output()?;
        }

        #[cfg(target_os = "windows")]
        {
            use std::process::Command;
            let script = format!(
                r#"Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('{}', '{}')"#,
                body.replace("'", "''"),
                title.replace("'", "''")
            );
            Command::new("powershell")
                .args(["-Command", &script])
                .output()?;
        }

        Ok(())
    }

    pub fn send_with_screenshot(&self, title: &str, body: &str, screenshot_path: &std::path::Path) -> Result<()> {
        #[cfg(target_os = "macos")]
        {
            let script = format!(
                r#"display notification "{}" with title "{}" screenshot "{}""#,
                body.replace('"', "\\\""),
                title.replace('"', "\\\""),
                screenshot_path.display()
            );
            std::process::Command::new("osascript")
                .args(["-e", &script])
                .output()?;
        }

        #[cfg(not(target_os = "macos"))]
        {
            self.send(title, body)?;
        }

        Ok(())
    }
}

impl Default for NotificationManager {
    fn default() -> Self {
        Self::new()
    }
}

/// Convenience: send a desktop notification without instantiating a manager.
/// Used by the automation engine, which fires off ad-hoc notifications and
/// doesn't keep state across calls.
pub fn send_notification(title: &str, body: &str) -> Result<()> {
    NotificationManager::new().send(title, body)
}