magi-code 0.82.1

Repository-aware CLI coding agent for terminal work
Documentation
//! Read-snapshot evidence, not a loaded-skill cache. Ranges address the original
//! tool output; replay redaction/truncation must be validated before projection.

use serde::{Deserialize, Serialize};
use serde_json::Value;
use sha2::{Digest, Sha256};

const PROVENANCE_VERSION: u8 = 1;
const MAX_SKILL_READS: usize = 8;
const MAX_SOURCE_BYTES: usize = 1024;

/// `identity` commits to the selected descriptor path, access policy, skill and
/// reference, full snapshot digest, and exact selector/raw mode. `sha256` binds
/// the delivered selection; neither digest alone establishes context coverage.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub(crate) struct SkillReadProvenance {
    pub(crate) version: u8,
    pub(crate) identity: String,
    pub(crate) source: String,
    pub(crate) start: usize,
    pub(crate) end: usize,
    pub(crate) sha256: String,
}

impl SkillReadProvenance {
    pub(crate) fn validates(&self, output: &str) -> bool {
        self.version == PROVENANCE_VERSION
            && valid_digest(&self.identity)
            && valid_digest(&self.sha256)
            && self.source.starts_with("skill://")
            && self.source.len() <= MAX_SOURCE_BYTES
            && !self.source.chars().any(char::is_control)
            && self.start < self.end
            && output.is_char_boundary(self.start)
            && output.is_char_boundary(self.end)
            && output
                .get(self.start..self.end)
                .is_some_and(|slice| digest_hex(slice.as_bytes()) == self.sha256)
    }
}

pub(crate) fn validated_skill_reads(
    tool_name: &str,
    success: bool,
    output: &str,
    metadata: &Value,
) -> Vec<SkillReadProvenance> {
    if tool_name != "read" || !success {
        return Vec::new();
    }
    let Some(values) = metadata.get("skill_reads").and_then(Value::as_array) else {
        return Vec::new();
    };
    if values.len() > MAX_SKILL_READS {
        return Vec::new();
    }
    let Ok(reads) = values
        .iter()
        .cloned()
        .map(serde_json::from_value)
        .collect::<Result<Vec<SkillReadProvenance>, _>>()
    else {
        return Vec::new();
    };
    if reads.iter().any(|read| !read.validates(output))
        || reads.windows(2).any(|pair| pair[0].end > pair[1].start)
    {
        return Vec::new();
    }
    reads
}

pub(super) fn digest_hex(bytes: &[u8]) -> String {
    crate::hex::lower_hex(Sha256::digest(bytes))
}

fn valid_digest(value: &str) -> bool {
    value.len() == 64
        && value
            .bytes()
            .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
}