slash-lib 0.1.0

Executor types and high-level API for the slash-command language
Documentation
use obfsck::{obfuscate_text, ObfuscationLevel};
use slash_lang::parser::ast::Arg;

use crate::command::{MethodDef, SlashCommand};
use crate::executor::{CommandOutput, ExecutionError, PipeValue};

/// `/obfsck` — redact secrets and PII from piped content.
///
/// `/read(.env) | /obfsck` — redact at Standard level (default).
/// `/read(logs.txt) | /obfsck.level(paranoid)` — redact at Paranoid level.
/// `/obfsck(some inline text)` — redact the primary arg directly.
///
/// Levels: `minimal`, `standard` (default), `paranoid`.
///
/// Pure Rust via the obfsck library. No subprocess.
pub struct Obfsck;

impl SlashCommand for Obfsck {
    fn name(&self) -> &str {
        "obfsck"
    }

    fn methods(&self) -> &[MethodDef] {
        static METHODS: [MethodDef; 1] = [MethodDef::with_value("level")];
        &METHODS
    }

    fn execute(
        &self,
        primary: Option<&str>,
        args: &[Arg],
        input: Option<&PipeValue>,
    ) -> Result<CommandOutput, ExecutionError> {
        let level_str = args
            .iter()
            .find(|a| a.name == "level")
            .and_then(|a| a.value.as_deref())
            .unwrap_or("standard");

        let level = ObfuscationLevel::parse(level_str).ok_or_else(|| {
            ExecutionError::Runner(format!(
                "/obfsck: unknown level '{}' — use minimal, standard, or paranoid",
                level_str
            ))
        })?;

        let text = if let Some(primary) = primary {
            primary.to_string()
        } else {
            match input {
                Some(PipeValue::Bytes(b)) => String::from_utf8_lossy(b).into_owned(),
                Some(PipeValue::Context(ctx)) => ctx.to_json(),
                None => return Err(ExecutionError::Runner("/obfsck: no input to redact".into())),
            }
        };

        let (redacted, _map) = obfuscate_text(&text, level);

        Ok(CommandOutput {
            stdout: Some(redacted.into_bytes()),
            stderr: None,
            success: true,
        })
    }
}