use std::{
fs,
path::{Path, PathBuf},
time::SystemTime,
};
use super::{
CAPTURE_ENV, CapturePaths, Harness, Invocation, SpawnPlan, capture_id, is_uuid, jsonl_head,
leading_uuid, push_unique, same_cwd, shell_quote, sole_id, unix_millis, v7_millis,
within_window_ms,
};
const RESUME_HINT: &str = "omp --resume ";
const MAIN_LABEL: &str = "Main";
pub struct Omp;
impl Harness for Omp {
fn home_env_var(&self) -> &'static str {
"PI_CODING_AGENT_SESSION_DIR"
}
fn home_dot_dir(&self) -> &'static str {
".omp/agent/sessions"
}
fn resolve_home(&self, env: &dyn Fn(&str) -> Option<PathBuf>) -> Option<PathBuf> {
let set = |key: &str| env(key).filter(|p| !p.as_os_str().is_empty());
if let Some(sessions) = set(self.home_env_var()) {
return Some(sessions);
}
let profile = match env("OMP_PROFILE") {
Some(p) => p,
None => env("PI_PROFILE").unwrap_or_default(),
};
let profile = profile
.to_str()
.map(str::trim)
.filter(|p| !p.is_empty() && *p != "default")
.map(PathBuf::from);
if let (None, Some(agent)) = (&profile, set("PI_CODING_AGENT_DIR")) {
return Some(agent.join("sessions"));
}
if let Some(xdg) = set("XDG_DATA_HOME") {
let data = match &profile {
Some(p) => xdg.join("omp").join("profiles").join(p),
None => xdg.join("omp"),
};
if data.exists() {
return Some(data.join("sessions"));
}
}
let config = env("HOME")?.join(set("PI_CONFIG_DIR").unwrap_or_else(|| ".omp".into()));
let root = match &profile {
Some(p) => config.join("profiles").join(p),
None => config,
};
Some(root.join("agent").join("sessions"))
}
fn shape(&self) -> (&'static str, &'static str) {
("omp", "--resume")
}
fn instrument(
&self,
_inv: &Invocation,
capture: &CapturePaths,
_home: Option<&Path>,
) -> SpawnPlan {
SpawnPlan {
args_suffix: format!(
" -e {}",
shell_quote(&capture.omp_capture.to_string_lossy())
),
env: vec![(
CAPTURE_ENV.into(),
capture.capture_file.clone().into_os_string(),
)],
injected_id: None,
}
}
fn parse_capture(&self, payload: &str) -> Option<String> {
capture_id(&jzon::parse(payload).ok()?, "sessionId")
}
fn scrape_exit(&self, text: &str) -> Option<String> {
let mut last: Option<String> = None;
for (i, _) in text.match_indices(RESUME_HINT) {
let Some(id) = leading_uuid(&text[i + RESUME_HINT.len()..]) else {
continue;
};
let head = &text[..i];
let head = &head[head.rfind(['\n', '\r']).map_or(0, |n| n + 1)..];
if let Some(label) = head.strip_suffix(": ")
&& label.trim() != MAIN_LABEL
{
continue;
}
last = Some(id.to_string());
}
last
}
fn correlate_fs(&self, cwd: &Path, spawned: SystemTime, home: Option<&Path>) -> Option<String> {
let sessions = self.home_root(home)?;
let spawn_ms = unix_millis(spawned)?;
let canon = cwd.canonicalize().ok();
let mut dirs = vec![sessions.clone()];
dirs.extend(
fs::read_dir(&sessions)
.ok()?
.flatten()
.filter(|e| e.file_type().is_ok_and(|t| t.is_dir()))
.map(|e| e.path()),
);
let mut survivors: Vec<String> = Vec::new();
for dir in dirs {
let Ok(entries) = fs::read_dir(dir) else {
continue;
};
for entry in entries.flatten() {
let name = entry.file_name();
let Some(id) = name
.to_str()
.and_then(|n| n.strip_suffix(".jsonl"))
.and_then(|stem| stem.rsplit_once('_'))
.map(|(_, id)| id)
.filter(|id| is_uuid(id))
else {
continue;
};
let Some(ms) = v7_millis(id) else { continue };
if !within_window_ms(u128::from(ms), spawn_ms) {
continue;
}
if !header_cwd_matches(&entry.path(), cwd, canon.as_deref()) {
continue;
}
push_unique(&mut survivors, id.to_string());
}
}
sole_id(survivors)
}
}
fn header_cwd_matches(path: &Path, cwd: &Path, canon: Option<&Path>) -> bool {
let Some(records) = jsonl_head(path, 2) else {
return false;
};
for record in records.into_iter().flatten() {
if record["type"].as_str() != Some("session") {
continue;
}
return record["cwd"].as_str().is_some_and(|c| {
let header = Path::new(c);
same_cwd(header, cwd, canon)
|| canon.is_some_and(|canon| header.canonicalize().is_ok_and(|h| h == canon))
});
}
false
}
#[cfg(test)]
mod tests {
use std::time::Duration;
use super::*;
use crate::{
harness::fixtures::{ID, OTHER, assert_all_opaque, assert_corpus_scrape, paths},
testutil::{temp, v7_at},
};
const SPAWN_MS: u64 = 1_786_000_000_000;
const CWD: &str = "/work/proj";
const CAPTURED: &str = "01a0077c-e18e-7000-ae0b-016f4834b6e9";
fn spawned() -> SystemTime {
SystemTime::UNIX_EPOCH + Duration::from_millis(SPAWN_MS)
}
fn title_slot() -> String {
let head = concat!(
r#"{"type":"title","v":1,"title":"Run ls -la","source":"auto","#,
r#""updatedAt":"2026-08-15T22:19:51.048Z","pad":""#
);
let tail = r#""}"#;
format!("{head}{}{tail}", " ".repeat(256 - head.len() - tail.len()))
}
fn write_named(sessions: &Path, bucket: &str, file: &str, id: &str, cwd: &str, slot: bool) {
let dir = sessions.join(bucket);
fs::create_dir_all(&dir).unwrap();
let mut body = String::new();
if slot {
body.push_str(&title_slot());
body.push('\n');
}
body.push_str(&format!(
r#"{{"type":"session","version":3,"id":"{id}","timestamp":"2026-08-15T22:19:51.048Z","cwd":"{cwd}","title":"Run ls -la"}}"#
));
body.push_str("\n{\"type\":\"message\",\"role\":\"assistant\"}\n");
fs::write(dir.join(file), body).unwrap();
}
fn write_session(sessions: &Path, bucket: &str, id: &str, cwd: &str, slot: bool) {
let file = format!("2026-08-15T22-19-51-048Z_{id}.jsonl");
write_named(sessions, bucket, &file, id, cwd, slot);
}
fn home(env: &[(&str, &str)]) -> Option<PathBuf> {
Omp.resolve_home(&|key| {
env.iter()
.find(|(name, _)| *name == key)
.map(|(_, value)| PathBuf::from(value))
})
}
#[test]
fn everything_else_is_opaque_and_never_rewritten() {
let opaque: Vec<String> = ["omp -c", "omp --continue", "omp --resume", "ompx"]
.iter()
.map(|s| s.to_string())
.chain([
format!("omp -r {ID}"),
format!("omp --session {ID}"),
format!("omp --resume {}", &ID[..8]),
"omp -p 'fix the tests'".to_string(),
])
.collect();
assert_all_opaque(&Omp, ID, &opaque);
}
#[test]
fn instrument_loads_the_extension_for_either_accepted_shape() {
for cmd in ["omp".to_string(), format!("omp --resume {ID}")] {
let inv = Omp.detect(&cmd).unwrap();
let plan = Omp.instrument(&inv, &paths(), None);
assert_eq!(plan.injected_id, None, "{cmd}");
assert_eq!(
plan.args_suffix, " -e '/tmp/Application Support/omp-capture.js'",
"{cmd}"
);
assert_eq!(
plan.env,
vec![(
CAPTURE_ENV.into(),
PathBuf::from("/tmp/cap/session.json").into_os_string()
)],
"{cmd}"
);
}
}
#[test]
fn parse_capture_returns_only_strict_ids() {
for reason in ["session_start", "session_switch"] {
let payload = format!(
r#"{{"reason":"{reason}","sessionId":"{CAPTURED}","sessionFile":"/s/2026-08-15T22-13-39-854Z_{CAPTURED}.jsonl","cwd":"/work/proj"}}"#
);
assert_eq!(Omp.parse_capture(&payload).as_deref(), Some(CAPTURED));
}
assert_eq!(Omp.parse_capture("not json"), None);
assert_eq!(Omp.parse_capture("{}"), None);
assert_eq!(Omp.parse_capture(r#"{"sessionId":"my session"}"#), None);
assert_eq!(Omp.parse_capture(r#"{"sessionId":"x'; rm -rf ~'"}"#), None);
assert_eq!(
Omp.parse_capture(&format!(r#"{{"sessionId":"{}"}}"#, CAPTURED.to_uppercase())),
None
);
assert_eq!(Omp.parse_capture(""), None);
}
#[test]
fn scrape_exit_reads_the_hint_and_takes_the_last() {
let hint = format!("Resume this session with omp --resume {ID}");
assert_eq!(Omp.scrape_exit(&hint).as_deref(), Some(ID));
let both = format!(
"Resume this session with omp --resume {OTHER}\n...\n\
Resume this session with omp --resume {ID}\n"
);
assert_eq!(Omp.scrape_exit(&both).as_deref(), Some(ID));
let crash = format!("[Recovery]\n Main: omp --resume {ID}\n");
assert_eq!(Omp.scrape_exit(&crash).as_deref(), Some(ID));
let sub_a = "22222222-3333-4444-8555-666666666666";
let sub_b = "33333333-4444-4555-8666-777777777777";
let subagents =
format!(" agent-1: omp --resume {sub_a}\n agent-2: omp --resume {sub_b}\n");
let swarm = format!("[Recovery]\n Main: omp --resume {ID}\n{subagents}");
assert_eq!(Omp.scrape_exit(&swarm).as_deref(), Some(ID));
let orphans = format!("[Recovery]\n{subagents}");
assert_eq!(Omp.scrape_exit(&orphans), None);
let recovered = format!("{orphans}...\nResume this session with omp --resume {ID}\n");
assert_eq!(Omp.scrape_exit(&recovered).as_deref(), Some(ID));
assert_eq!(Omp.scrape_exit("no hint here"), None);
assert_eq!(Omp.scrape_exit("omp --resume NOT-A-UUID"), None);
assert_eq!(Omp.scrape_exit(&format!("omp --resume {ID}ff")), None);
}
#[test]
fn correlate_fs_requires_a_unique_in_window_session_for_the_cwd() {
let sessions = temp("omp_correlate");
let id = v7_at(SPAWN_MS + 4_000, 1);
write_session(&sessions, "bucket", &id, CWD, true);
assert_eq!(
Omp.correlate_fs(Path::new(CWD), spawned(), Some(&sessions))
.as_deref(),
Some(id.as_str())
);
assert_eq!(
Omp.correlate_fs(Path::new("/elsewhere"), spawned(), Some(&sessions)),
None
);
let late = v7_at(SPAWN_MS + 90_000, 2);
write_session(&sessions, "late", &late, "/late/proj", true);
assert_eq!(
Omp.correlate_fs(Path::new("/late/proj"), spawned(), Some(&sessions)),
None
);
write_session(&sessions, "bucket", &v7_at(SPAWN_MS + 8_000, 3), CWD, true);
assert_eq!(
Omp.correlate_fs(Path::new(CWD), spawned(), Some(&sessions)),
None
);
}
#[test]
fn correlate_fs_reads_a_flat_store_and_a_bucketed_one() {
let sessions = temp("omp_layouts");
let flat = v7_at(SPAWN_MS + 3_000, 8);
write_session(&sessions, "", &flat, CWD, true);
let nested = v7_at(SPAWN_MS + 5_000, 9);
write_session(&sessions, "bucket", &nested, "/work/other", true);
assert_eq!(
Omp.correlate_fs(Path::new(CWD), spawned(), Some(&sessions))
.as_deref(),
Some(flat.as_str())
);
assert_eq!(
Omp.correlate_fs(Path::new("/work/other"), spawned(), Some(&sessions))
.as_deref(),
Some(nested.as_str())
);
assert_eq!(
Omp.correlate_fs(Path::new("/elsewhere"), spawned(), Some(&sessions)),
None
);
}
#[test]
fn correlate_fs_collapses_one_session_seen_in_two_buckets() {
let sessions = temp("omp_dupe");
let id = v7_at(SPAWN_MS + 6_000, 10);
write_session(&sessions, "encoded", &id, CWD, true);
write_session(&sessions, "--legacy--", &id, CWD, true);
assert_eq!(
Omp.correlate_fs(Path::new(CWD), spawned(), Some(&sessions))
.as_deref(),
Some(id.as_str())
);
}
#[test]
fn correlate_fs_matches_a_header_holding_an_alias_of_the_cwd() {
let tmp = temp("omp_alias");
let (real, alias) = (tmp.join("real"), tmp.join("alias"));
fs::create_dir_all(&real).unwrap();
std::os::unix::fs::symlink(&real, &alias).unwrap();
let physical = real.canonicalize().unwrap();
let sessions = tmp.join("sessions");
let id = v7_at(SPAWN_MS + 7_000, 11);
write_session(&sessions, "bucket", &id, alias.to_str().unwrap(), true);
assert_eq!(
Omp.correlate_fs(&physical, spawned(), Some(&sessions))
.as_deref(),
Some(id.as_str())
);
}
#[test]
fn correlate_fs_reads_a_legacy_file_whose_header_is_line_one() {
let sessions = temp("omp_legacy");
let id = v7_at(SPAWN_MS + 1_000, 5);
write_session(&sessions, "bucket", &id, CWD, false);
assert_eq!(
Omp.correlate_fs(Path::new(CWD), spawned(), Some(&sessions))
.as_deref(),
Some(id.as_str())
);
}
#[test]
fn correlate_fs_refuses_names_and_buckets_it_cannot_read() {
let sessions = temp("omp_names");
let v4 = format!("2026-08-15T22-19-51-048Z_{ID}.jsonl");
write_named(&sessions, "v4", &v4, ID, CWD, true);
let good = v7_at(SPAWN_MS + 1_000, 6);
write_named(
&sessions,
"nosep",
&format!("{good}.jsonl"),
&good,
CWD,
true,
);
fs::create_dir_all(sessions.join("empty")).unwrap();
assert_eq!(
Omp.correlate_fs(Path::new(CWD), spawned(), Some(&sessions)),
None
);
write_session(&sessions, "good", &good, CWD, true);
assert_eq!(
Omp.correlate_fs(Path::new(CWD), spawned(), Some(&sessions))
.as_deref(),
Some(good.as_str())
);
}
#[test]
fn correlate_fs_matches_a_symlinked_cwd_through_its_canonical_form() {
let tmp = temp("omp_canon");
let (real, link) = (tmp.join("real"), tmp.join("link"));
fs::create_dir_all(&real).unwrap();
std::os::unix::fs::symlink(&real, &link).unwrap();
let canonical = real.canonicalize().unwrap();
let sessions = tmp.join("sessions");
let id = v7_at(SPAWN_MS + 2_000, 4);
write_session(&sessions, "bucket", &id, canonical.to_str().unwrap(), true);
assert_eq!(
Omp.correlate_fs(&link, spawned(), Some(&sessions))
.as_deref(),
Some(id.as_str())
);
}
#[test]
fn resolve_home_walks_the_store_root_chain() {
assert_eq!(
home(&[("HOME", "/h")]),
Some("/h/.omp/agent/sessions".into())
);
assert_eq!(
home(&[
("HOME", "/h"),
("PI_CONFIG_DIR", ".alt"),
("PI_CODING_AGENT_DIR", "/a"),
("PI_CODING_AGENT_SESSION_DIR", "/s"),
]),
Some("/s".into())
);
assert_eq!(
home(&[("HOME", "/h"), ("PI_CODING_AGENT_SESSION_DIR", "")]),
Some("/h/.omp/agent/sessions".into())
);
assert_eq!(
home(&[("HOME", "/h"), ("PI_CODING_AGENT_DIR", "/a")]),
Some("/a/sessions".into())
);
assert_eq!(
home(&[
("HOME", "/h"),
("PI_CODING_AGENT_DIR", "/a"),
("PI_PROFILE", "work"),
]),
Some("/h/.omp/profiles/work/agent/sessions".into())
);
assert_eq!(
home(&[("HOME", "/h"), ("OMP_PROFILE", "default")]),
Some("/h/.omp/agent/sessions".into())
);
assert_eq!(
home(&[
("HOME", "/h"),
("PI_PROFILE", " default "),
("PI_CODING_AGENT_DIR", "/a"),
]),
Some("/a/sessions".into())
);
assert_eq!(
home(&[("HOME", "/h"), ("OMP_PROFILE", " work ")]),
Some("/h/.omp/profiles/work/agent/sessions".into())
);
assert_eq!(
home(&[("HOME", "/h"), ("OMP_PROFILE", " ")]),
Some("/h/.omp/agent/sessions".into())
);
assert_eq!(
home(&[("HOME", "/h"), ("OMP_PROFILE", "a"), ("PI_PROFILE", "b")]),
Some("/h/.omp/profiles/a/agent/sessions".into())
);
assert_eq!(
home(&[
("HOME", "/h"),
("OMP_PROFILE", ""),
("PI_PROFILE", "b"),
("PI_CODING_AGENT_DIR", "/a"),
]),
Some("/a/sessions".into())
);
assert_eq!(
home(&[("HOME", "/h"), ("PI_CONFIG_DIR", ".alt")]),
Some("/h/.alt/agent/sessions".into())
);
assert_eq!(
home(&[("HOME", "/h"), ("PI_CONFIG_DIR", "/abs")]),
Some("/abs/agent/sessions".into())
);
assert_eq!(
home(&[("PI_CODING_AGENT_DIR", "/a")]),
Some("/a/sessions".into())
);
assert_eq!(home(&[]), None);
}
#[test]
fn resolve_home_redirects_to_xdg_only_when_that_directory_exists() {
let dir = temp("omp_xdg");
let xdg = dir.to_str().unwrap();
assert_eq!(
home(&[("HOME", "/h"), ("XDG_DATA_HOME", xdg)]),
Some("/h/.omp/agent/sessions".into())
);
fs::create_dir_all(dir.join("omp")).unwrap();
assert_eq!(
home(&[("HOME", "/h"), ("XDG_DATA_HOME", xdg)]),
Some(dir.join("omp/sessions"))
);
let profile = [
("HOME", "/h"),
("XDG_DATA_HOME", xdg),
("OMP_PROFILE", "work"),
];
assert_eq!(
home(&profile),
Some("/h/.omp/profiles/work/agent/sessions".into())
);
fs::create_dir_all(dir.join("omp/profiles/work")).unwrap();
assert_eq!(home(&profile), Some(dir.join("omp/profiles/work/sessions")));
assert_eq!(
home(&[
("HOME", "/h"),
("XDG_DATA_HOME", xdg),
("PI_CODING_AGENT_DIR", "/a"),
]),
Some("/a/sessions".into())
);
assert_eq!(
home(&[("XDG_DATA_HOME", xdg)]),
Some(dir.join("omp/sessions"))
);
}
#[test]
fn corpus_scrape_recovers_the_exit_hint_id() {
assert_corpus_scrape(
&Omp,
include_bytes!("../../tests/corpus/omp_resume.bin"),
"01a0078a-7714-7000-9927-f167df9b6476",
);
}
}