memorph 0.1.11

Convert, import, and export AI coding sessions between Claude Code, Codex, and OpenCode
Documentation
use clap::{Parser, Subcommand};

#[derive(Parser)]
#[command(name = "memorph")]
#[command(about = "Convert, import, and export AI coding sessions")]
#[command(disable_version_flag = true)]
pub struct Cli {
    /// Print version
    #[arg(short = 'v', long = "version", action = clap::ArgAction::SetTrue)]
    pub version: bool,

    #[command(subcommand)]
    pub command: Option<Commands>,
}

#[derive(Subcommand)]
pub enum Commands {
    /// List sessions (default: current workspace only)
    List {
        /// Show all sessions across all workspaces
        #[arg(long)]
        all: bool,
        /// Filter to a provider (repeatable)
        #[arg(short, long, value_name = "PROVIDER")]
        provider: Vec<String>,
    },
    /// Export a session to file(s)
    Export {
        /// Source provider ID
        #[arg(value_name = "PROVIDER")]
        provider: String,
        /// Session ID
        #[arg(value_name = "SESSION_ID")]
        session_id: String,
        /// Output filename prefix (default: SESSION_ID)
        #[arg(short, long, value_name = "PREFIX")]
        output: Option<String>,
        /// Output format: json, md, html, morph, both (default: json)
        #[arg(short, long, value_name = "FORMAT", default_value = "json")]
        format: String,
    },
    /// Import a session into a target tool directory
    Import {
        /// Target provider ID
        #[arg(value_name = "PROVIDER")]
        provider: String,
        /// Path to .json/.md/.html/.morph file, or session ID for re-export
        #[arg(value_name = "FILE_OR_ID")]
        file_or_id: String,
        /// Target project directory (default: current directory)
        #[arg(short, long, value_name = "DIR")]
        to_dir: Option<String>,
    },
    /// Remove a session
    Remove {
        /// Provider ID
        #[arg(value_name = "PROVIDER")]
        provider: String,
        /// Session ID to remove
        #[arg(value_name = "SESSION_ID")]
        session_id: String,
    },
    /// Rename a session
    Rename {
        /// Provider ID
        #[arg(value_name = "PROVIDER")]
        provider: String,
        /// Session ID to rename
        #[arg(value_name = "SESSION_ID")]
        session_id: String,
        /// New title
        #[arg(value_name = "NEW_TITLE")]
        new_title: String,
    },
    /// Switch a session from one provider to another (one-shot)
    Switch {
        /// Source provider ID
        #[arg(value_name = "FROM")]
        from: String,
        /// Target provider ID
        #[arg(value_name = "TO")]
        to: String,
        /// Source session ID (if omitted, uses the most recent session in current workspace)
        #[arg(short, long, value_name = "ID")]
        session_id: Option<String>,
        /// Target project directory (default: current directory)
        #[arg(short, long, value_name = "DIR")]
        to_dir: Option<String>,
    },
    /// Find sessions by directory, title, or ID pattern
    Find {
        /// Filter by project directory path (fuzzy match)
        #[arg(short, long, value_name = "DIR")]
        dir: Option<String>,
        /// Filter by session ID or title pattern (fuzzy match)
        #[arg(short, long, value_name = "PATTERN")]
        session: Option<String>,
        /// Restrict to provider (can be used multiple times)
        #[arg(short, long, value_name = "PROVIDER")]
        provider: Vec<String>,
    },
    /// Manage shared multi-provider sessions
    Share {
        #[command(subcommand)]
        command: ShareCommands,
    },
    /// Start the web UI server (recommended)
    Web {
        /// Port to listen on
        #[arg(short, long, default_value = "3737")]
        port: u16,
        /// Don't auto-open browser
        #[arg(long)]
        no_open: bool,
    },
    /// Start the web UI server (legacy alias for `memorph web`)
    Serve {
        /// Port to listen on
        #[arg(short, long, default_value = "3737")]
        port: u16,
        /// Don't auto-open browser
        #[arg(long)]
        no_open: bool,
    },
    /// Start the API server only
    Api {
        /// Port to listen on
        #[arg(short, long, default_value = "3737")]
        port: u16,
    },
    /// Start the interactive TUI
    Tui,
    /// Update memorph using the detected install source
    Update,
}

#[derive(Subcommand)]
pub enum ShareCommands {
    /// Create a shared session from an existing provider session
    Create {
        /// Source provider ID
        #[arg(value_name = "PROVIDER")]
        provider: String,
        /// Source session ID
        #[arg(value_name = "SESSION_ID")]
        session_id: String,
        /// Target provider to bind; repeat for multiple targets
        #[arg(long = "to", short = 't', value_name = "PROVIDER")]
        targets: Vec<String>,
        /// Target project directory for newly created provider sessions
        #[arg(short, long, value_name = "DIR")]
        to_dir: Option<String>,
        /// Shared session title
        #[arg(long, value_name = "TITLE")]
        title: Option<String>,
    },
    /// Add a provider holding to an existing shared group
    Bind {
        /// Shared group ID
        #[arg(value_name = "GROUP_ID")]
        group_id: String,
        /// Provider ID to bind
        #[arg(value_name = "PROVIDER")]
        provider: String,
        /// Existing provider session ID to bind; omitted creates a new provider session
        #[arg(long, short = 's', value_name = "SESSION_ID")]
        session_id: Option<String>,
        /// Target project directory for newly created provider sessions
        #[arg(short, long, value_name = "DIR")]
        to_dir: Option<String>,
    },
    /// Remove a holding from a shared group
    Unbind {
        /// Shared group ID
        #[arg(value_name = "GROUP_ID")]
        group_id: String,
        /// Holding ID from `share list` or `share status`
        #[arg(value_name = "HOLDING_ID")]
        holding_id: String,
    },
    /// Remove a shared session record
    Remove {
        /// Shared group ID
        #[arg(value_name = "GROUP_ID")]
        group_id: String,
        /// Also delete provider sessions when the provider supports deletion
        #[arg(long)]
        delete_provider_sessions: bool,
    },
    /// Rename a shared session title
    Rename {
        /// Shared group ID
        #[arg(value_name = "GROUP_ID")]
        group_id: String,
        /// New title
        #[arg(value_name = "TITLE")]
        title: String,
    },
    /// List shared sessions and their holdings
    List,
    /// Show detailed shared-session status
    Status {
        /// Optional shared group ID
        #[arg(value_name = "GROUP_ID")]
        group_id: Option<String>,
    },
    /// Push sync from a specific holding to all others, or auto-sync from latest
    Sync {
        /// Shared group ID
        #[arg(value_name = "GROUP_ID")]
        group_id: String,
        /// Holding ID to push from; omitted triggers auto-sync from latest
        #[arg(long, value_name = "HOLDING_ID")]
        from_holding: Option<String>,
    },
    /// Push sync from a specific holding to all others
    Push {
        /// Shared group ID
        #[arg(value_name = "GROUP_ID")]
        group_id: String,
        /// Holding ID to push from
        #[arg(value_name = "HOLDING_ID")]
        holding_id: String,
    },
}