truth-mirror 0.9.0

Truthfulness gate and adversarial reviewer harness for AI coding agents.
Documentation
pub(crate) fn shellish_token_segments(line: &str) -> Vec<Vec<&str>> {
    let mut segments = Vec::new();
    let mut segment = Vec::new();
    let mut token_start = None;
    let mut in_single_quote = false;
    let mut in_double_quote = false;

    for (index, character) in line.char_indices() {
        if character == '\'' && !in_double_quote {
            if token_start.is_none() {
                token_start = Some(index);
            }
            in_single_quote = !in_single_quote;
        } else if character == '"' && !in_single_quote {
            if token_start.is_none() {
                token_start = Some(index);
            }
            in_double_quote = !in_double_quote;
        } else if !in_single_quote && !in_double_quote && character.is_whitespace() {
            push_shellish_token(line, &mut token_start, index, &mut segment);
        } else if !in_single_quote && !in_double_quote && is_shell_command_separator(character) {
            push_shellish_token(line, &mut token_start, index, &mut segment);
            if !segment.is_empty() {
                segments.push(std::mem::take(&mut segment));
            }
        } else if token_start.is_none() {
            token_start = Some(index);
        }
    }

    push_shellish_token(line, &mut token_start, line.len(), &mut segment);
    if !segment.is_empty() {
        segments.push(segment);
    }
    segments
}

fn push_shellish_token<'a>(
    line: &'a str,
    token_start: &mut Option<usize>,
    end: usize,
    segment: &mut Vec<&'a str>,
) {
    if let Some(start) = token_start.take() {
        let token = line[start..end].trim_matches(|character| matches!(character, '\'' | '"'));
        if !token.is_empty() {
            segment.push(token);
        }
    }
}

fn is_shell_command_separator(character: char) -> bool {
    matches!(character, ';' | '&' | '|' | '(' | ')')
}

#[cfg(test)]
mod tests {
    #[test]
    fn shellish_tokens_stay_scoped_to_command_segments() {
        let segments = super::shellish_token_segments(
            "exec truth --version && hook-dispatch commit-msg \"$@\"; truth hook-dispatch pre-push",
        );

        assert_eq!(
            segments,
            vec![
                vec!["exec", "truth", "--version"],
                vec!["hook-dispatch", "commit-msg", "$@"],
                vec!["truth", "hook-dispatch", "pre-push"],
            ]
        );
    }

    #[test]
    fn quoted_separators_do_not_split_segments() {
        let segments = super::shellish_token_segments(
            "exec \"/usr/local/bin/truth\" hook-dispatch commit-msg \"path;with|separators\" && echo done",
        );

        assert_eq!(
            segments,
            vec![
                vec![
                    "exec",
                    "/usr/local/bin/truth",
                    "hook-dispatch",
                    "commit-msg",
                    "path;with|separators",
                ],
                vec!["echo", "done"],
            ]
        );
    }
}