use async_trait::async_trait;
use std::path::Path;
use tokio_util::sync::CancellationToken;
use crate::error::RuntimeResult;
#[derive(Debug, Clone)]
pub struct ShellResult {
pub exit_code: i32,
pub stdout: String,
pub stderr: String,
}
#[async_trait]
pub trait SessionEnv: Send + Sync {
async fn read_file(
&self,
path: &Path,
max_lines: usize,
max_bytes: usize,
) -> RuntimeResult<String>;
async fn read_file_full(&self, path: &Path, max_bytes: usize) -> RuntimeResult<String>;
async fn write_file(&self, path: &Path, content: &str) -> RuntimeResult<()>;
async fn exec(
&self,
command: &str,
cwd: &Path,
timeout_ms: Option<u64>,
cancel: &CancellationToken,
) -> RuntimeResult<ShellResult>;
async fn glob(&self, pattern: &str, limit: usize) -> RuntimeResult<Vec<String>>;
async fn grep(
&self,
pattern: &str,
paths: &[&str],
max_matches: usize,
) -> RuntimeResult<Vec<String>>;
}
#[derive(Debug, Clone, Copy)]
pub struct Limits {
pub max_read_lines: usize,
pub max_read_bytes: usize,
pub max_grep_matches: usize,
pub max_glob_results: usize,
pub max_grep_line_length: usize,
pub max_edit_bytes: usize,
}
impl Default for Limits {
fn default() -> Self {
Self {
max_read_lines: 2000,
max_read_bytes: 50 * 1024,
max_grep_matches: 100,
max_glob_results: 1000,
max_grep_line_length: 500,
max_edit_bytes: 256 * 1024,
}
}
}
pub async fn read_all(env: &dyn SessionEnv, path: &Path) -> RuntimeResult<String> {
env.read_file(path, usize::MAX, usize::MAX).await
}