use std::path::{Path, PathBuf};
pub fn encode_project_dir(working_directory: &Path) -> String {
working_directory
.to_string_lossy()
.chars()
.map(|c| if c == '/' || c == '.' { '-' } else { c })
.collect()
}
pub fn transcript_path(
home: &Path,
working_directory: &Path,
session_id: impl AsRef<str>,
) -> PathBuf {
home.join(".claude")
.join("projects")
.join(encode_project_dir(working_directory))
.join(format!("{}.jsonl", session_id.as_ref()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encoding_matches_observed_cli_behavior() {
for (dir, expect) in [
(
"/home/u/repos/rust-code-agent-sdks",
"-home-u-repos-rust-code-agent-sdks",
),
(
"/home/u/repos/inboxnegative.com",
"-home-u-repos-inboxnegative-com",
),
(
"/home/u/repos/x/.worktrees/y",
"-home-u-repos-x--worktrees-y",
),
("/tmp/reset-probe", "-tmp-reset-probe"),
] {
assert_eq!(encode_project_dir(Path::new(dir)), expect);
}
}
#[test]
fn transcript_path_assembles_under_the_given_home() {
let p = transcript_path(Path::new("/fake/home"), Path::new("/work/dir.x"), "abc-123");
assert_eq!(
p,
Path::new("/fake/home/.claude/projects/-work-dir-x/abc-123.jsonl")
);
}
#[test]
fn encoding_is_lossy_by_design() {
assert_eq!(
encode_project_dir(Path::new("/a/b.c")),
encode_project_dir(Path::new("/a/b/c")),
);
}
}