clawshell 0.1.1

A security privileged process for the OpenClaw ecosystem.
use std::path::{Path, PathBuf};

use thiserror::Error;

use crate::migration::core::{
    AmbiguityResolutionError, AmbiguityResolver, ConfigVersion, ConfigVersionParseError,
};

#[derive(Debug, Clone, Default)]
pub struct TargetMigrationOutput {
    pub content: String,
    pub applied_steps: Vec<String>,
    pub warnings: Vec<String>,
}

#[derive(Debug, Error)]
pub enum TargetError {
    #[error("failed to parse TOML: {0}")]
    TomlParse(#[from] toml::de::Error),

    #[error("failed to serialize TOML: {0}")]
    TomlSerialize(#[from] toml::ser::Error),

    #[error("configuration must be a top-level TOML table")]
    TopLevelTableExpected,

    #[error("top-level 'version' must be a string, got {found}")]
    VersionMustBeString { found: String },

    #[error("invalid top-level 'version' value '{value}': {source}")]
    InvalidVersionValue {
        value: String,
        #[source]
        source: ConfigVersionParseError,
    },

    #[error("configuration migration required: missing top-level 'version' (expected {expected})")]
    MigrationRequiredMissingVersion {
        expected: ConfigVersion,
        path: PathBuf,
    },

    #[error(
        "configuration migration required: found version {found} but current version is {expected}"
    )]
    MigrationRequiredVersionMismatch {
        found: ConfigVersion,
        expected: ConfigVersion,
        path: PathBuf,
    },

    #[error("migration aborted: source version {from} is newer than target {to}")]
    DowngradeAborted {
        from: ConfigVersion,
        to: ConfigVersion,
    },

    #[error("migration aborted: {reason}")]
    MigrationAborted { reason: String },

    #[error("invalid configuration after migration: {details}")]
    Validation { details: String },

    #[error(transparent)]
    Ambiguity(#[from] AmbiguityResolutionError),
}

pub trait MigrationTarget: std::fmt::Debug {
    fn name(&self) -> &'static str;
    fn path(&self) -> &Path;

    fn detect_version(&self, content: &str) -> Result<Option<ConfigVersion>, TargetError>;

    fn migrate(
        &self,
        content: &str,
        from: &ConfigVersion,
        to: &ConfigVersion,
        resolver: &mut dyn AmbiguityResolver,
    ) -> Result<TargetMigrationOutput, TargetError>;

    fn validate(&self, content: &str) -> Result<(), TargetError>;
}