use crate::config::Config;
#[cfg(not(target_os = "emscripten"))]
use crate::harness::HarnessBundle;
use std::path::Path;
pub(crate) fn claude_convo(config: &Config) -> toolpath_claude::ClaudeConvo {
let mut resolver = toolpath_claude::PathResolver::new();
if let Some(home) = config.home_dir() {
resolver = resolver.with_home(home);
}
if let Some(dir) = &config.claude_config_dir {
resolver = resolver.with_claude_dir(dir.clone());
}
toolpath_claude::ClaudeConvo::with_resolver(resolver)
}
pub(crate) fn gemini_convo(config: &Config) -> toolpath_gemini::GeminiConvo {
let mut resolver = toolpath_gemini::PathResolver::new();
if let Some(home) = config.home_dir() {
resolver = resolver.with_home(home);
}
toolpath_gemini::GeminiConvo::with_resolver(resolver)
}
pub(crate) fn codex_convo(config: &Config) -> toolpath_codex::CodexConvo {
let mut resolver = toolpath_codex::PathResolver::new();
if let Some(home) = config.home_dir() {
resolver = resolver.with_home(home);
}
toolpath_codex::CodexConvo::with_resolver(resolver)
}
pub(crate) fn copilot_convo(config: &Config) -> toolpath_copilot::CopilotConvo {
let mut resolver = toolpath_copilot::PathResolver::new();
if let Some(home) = config.home_dir() {
resolver = resolver.with_home(home);
}
if let Some(dir) = &config.copilot_home {
resolver = resolver.with_copilot_dir(dir);
}
toolpath_copilot::CopilotConvo::with_resolver(resolver)
}
#[cfg(not(target_os = "emscripten"))]
pub(crate) fn opencode_convo(config: &Config) -> toolpath_opencode::OpencodeConvo {
let mut resolver = toolpath_opencode::PathResolver::new();
if let Some(home) = config.home_dir() {
resolver = resolver.with_home(home);
}
if let Some(xdg) = &config.xdg_data_home {
resolver = resolver.with_data_dir(xdg.join("opencode"));
}
toolpath_opencode::OpencodeConvo::with_resolver(resolver)
}
#[cfg(not(target_os = "emscripten"))]
pub(crate) fn cursor_convo(config: &Config) -> toolpath_cursor::CursorConvo {
let mut resolver = toolpath_cursor::PathResolver::new();
if let Some(home) = config.home_dir() {
resolver = resolver.with_home(home);
}
#[cfg(windows)]
if let Some(appdata) = &config.appdata {
resolver = resolver.with_user_data_dir(appdata.join("Cursor"));
}
toolpath_cursor::CursorConvo::with_resolver(resolver)
}
pub(crate) fn pi_convo(config: &Config, base: Option<&Path>) -> toolpath_pi::PiConvo {
let mut resolver = toolpath_pi::PathResolver::new();
if let Some(home) = config.home_dir() {
resolver = resolver.with_home(home);
}
if let Some(dir) = base {
resolver = resolver.with_sessions_dir(dir);
}
toolpath_pi::PiConvo::with_resolver(resolver)
}
#[cfg(not(target_os = "emscripten"))]
pub(crate) fn harness_bundle(config: &Config) -> HarnessBundle {
HarnessBundle {
claude: Some(claude_convo(config)),
gemini: Some(gemini_convo(config)),
codex: Some(codex_convo(config)),
copilot: Some(copilot_convo(config)),
opencode: Some(opencode_convo(config)),
cursor: Some(cursor_convo(config)),
pi: Some(pi_convo(config, None)),
}
}
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use super::*;
use std::path::PathBuf;
fn config_with_home() -> Config {
Config {
home: Some(PathBuf::from("/home/jailed")),
..Config::default()
}
}
#[test]
fn claude_convo_roots_at_config_home() {
let manager = claude_convo(&config_with_home());
assert_eq!(
manager.resolver().projects_dir().unwrap(),
PathBuf::from("/home/jailed/.claude/projects")
);
}
#[test]
fn claude_convo_honors_claude_config_dir() {
let config = Config {
claude_config_dir: Some(PathBuf::from("/home/jailed/.config/claude")),
..config_with_home()
};
let manager = claude_convo(&config);
assert_eq!(
manager.resolver().projects_dir().unwrap(),
PathBuf::from("/home/jailed/.config/claude/projects")
);
}
#[test]
fn gemini_convo_roots_at_config_home() {
let manager = gemini_convo(&config_with_home());
assert_eq!(
manager.resolver().gemini_dir().unwrap(),
PathBuf::from("/home/jailed/.gemini")
);
}
#[test]
fn codex_convo_roots_at_config_home() {
let manager = codex_convo(&config_with_home());
assert_eq!(
manager.resolver().sessions_root().unwrap(),
PathBuf::from("/home/jailed/.codex/sessions")
);
}
#[test]
fn copilot_convo_injects_copilot_dir() {
let config = Config {
home: Some(PathBuf::from("/home/jailed")),
copilot_home: Some(PathBuf::from("/copilot/root")),
..Config::default()
};
let manager = copilot_convo(&config);
assert_eq!(
manager.resolver().copilot_dir().unwrap(),
PathBuf::from("/copilot/root")
);
}
#[test]
fn opencode_convo_injects_data_dir() {
let config = Config {
home: Some(PathBuf::from("/home/jailed")),
xdg_data_home: Some(PathBuf::from("/xdg/data")),
..Config::default()
};
let manager = opencode_convo(&config);
assert_eq!(
manager.resolver().db_path().unwrap(),
PathBuf::from("/xdg/data/opencode/opencode.db")
);
}
#[test]
fn cursor_convo_roots_at_config_home() {
let manager = cursor_convo(&config_with_home());
assert_eq!(
manager.resolver().anysphere_dir().unwrap(),
PathBuf::from("/home/jailed/.cursor")
);
}
#[test]
fn convos_fall_back_to_config_userprofile() {
let config = Config {
userprofile: Some(PathBuf::from("/users/jailed")),
..Config::default()
};
let manager = claude_convo(&config);
assert_eq!(
manager.resolver().projects_dir().unwrap(),
PathBuf::from("/users/jailed/.claude/projects")
);
}
#[cfg(windows)]
#[test]
fn cursor_convo_injects_user_data_dir_from_appdata() {
let config = Config {
home: Some(PathBuf::from("/home/jailed")),
appdata: Some(PathBuf::from("/appdata/roaming")),
..Config::default()
};
let manager = cursor_convo(&config);
assert_eq!(
manager.resolver().db_path().unwrap(),
PathBuf::from("/appdata/roaming/Cursor/User/globalStorage/state.vscdb")
);
}
#[test]
fn pi_convo_roots_at_config_home() {
let manager = pi_convo(&config_with_home(), None);
assert_eq!(
manager.resolver().sessions_dir(),
PathBuf::from("/home/jailed/.pi/agent/sessions")
);
}
#[test]
fn pi_convo_base_replaces_the_sessions_dir() {
let manager = pi_convo(&config_with_home(), Some(Path::new("/pi/base")));
assert_eq!(manager.resolver().sessions_dir(), PathBuf::from("/pi/base"));
}
#[test]
fn harness_bundle_roots_providers_at_config_home() {
let bundle = harness_bundle(&config_with_home());
assert_eq!(
bundle.claude.unwrap().resolver().projects_dir().unwrap(),
PathBuf::from("/home/jailed/.claude/projects")
);
assert_eq!(
bundle.pi.unwrap().resolver().sessions_dir(),
PathBuf::from("/home/jailed/.pi/agent/sessions")
);
}
}