Files
galaxy/app/src/ai/agent_sdk/driver/harness/json_utils.rs
T

68 lines
2.2 KiB
Rust

//! Shared JSON read/merge/write helpers for third-party harness config prep.
//!
//! Third-party CLIs like Claude Code and Gemini CLI persist onboarding, trust,
//! and auth state in JSON files. The harness preparation step
//! needs to set a few keys on those files without clobbering
//! user-owned state. These helpers allow us to read and merge with existing
//! JSON file state easily.
use std::path::Path;
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use serde_json::Value;
/// Read a JSON file as `T`, or return `T::default()` if the file does not exist.
///
/// Returns an error if the file exists but cannot be read or parsed.
pub(super) fn read_json_file_or_default<T>(path: &Path) -> Result<T>
where
T: Default + for<'de> Deserialize<'de>,
{
let content = match std::fs::read_to_string(path) {
Ok(content) => content,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
return Ok(T::default());
}
Err(e) => {
return Err(
anyhow::Error::from(e).context(format!("Failed to read {}", path.display()))
);
}
};
serde_json::from_str(&content).with_context(|| format!("Failed to parse {}", path.display()))
}
/// Serialize `value` as pretty JSON and write it to `path`, creating parent
/// directories as needed. `serialize_error` is used as the context for the
/// serialization step so the caller-facing error is specific to the config
/// file being written.
pub(super) fn write_json_file<T>(
path: &Path,
value: &T,
serialize_error: &'static str,
) -> Result<()>
where
T: Serialize,
{
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)
.with_context(|| format!("Failed to create {}", parent.display()))?;
}
std::fs::write(
path,
serde_json::to_vec_pretty(value).context(serialize_error)?,
)
.with_context(|| format!("Failed to write {}", path.display()))
}
/// Serialize a slice of JSON values as a JSONL byte string (one value per line).
pub(super) fn entries_to_jsonl(entries: &[Value]) -> Result<Vec<u8>> {
let mut buf = Vec::new();
for entry in entries {
serde_json::to_writer(&mut buf, entry)?;
buf.push(b'\n');
}
Ok(buf)
}