session: trace resolve/attach/compact points for #2707 wrong-session theory
This commit is contained in:
parent
7a826f9ee2
commit
1bbc09e9dd
4 changed files with 72 additions and 12 deletions
|
|
@ -44,12 +44,21 @@ impl SessionStore {
|
|||
/// Find the `<uuid>.jsonl` in the project dir whose `customTitle` equals
|
||||
/// `title` (the value `--name` sets, stored in a `custom-title` event).
|
||||
///
|
||||
/// Reads each session file line by line and stops at the first match, so a
|
||||
/// huge transcript isn't slurped into memory. Returns `None` if no session
|
||||
/// carries the title or the project dir is absent. Non-`.jsonl` files
|
||||
/// (including anything already archived to `*.jsonl.archived`) are skipped.
|
||||
/// Reads each session file line by line, so a huge transcript isn't
|
||||
/// slurped into memory. Returns `None` if no session carries the title or
|
||||
/// the project dir is absent. Non-`.jsonl` files (including anything
|
||||
/// already archived to `*.jsonl.archived`) are skipped.
|
||||
///
|
||||
/// Unlike the old first-match-wins scan, this keeps going past the first
|
||||
/// hit so a *second* same-titled file — which would otherwise resolve to
|
||||
/// whichever one `read_dir` happens to yield first, i.e. filesystem-order
|
||||
/// luck — logs a `tracing::warn!` instead of silently picking one. The
|
||||
/// first match found is still what's returned (unchanged resolution
|
||||
/// behaviour); this is a diagnostic for the "wrong session resumed"
|
||||
/// report, not a fix.
|
||||
#[must_use]
|
||||
pub fn find_by_title(&self, title: &str) -> Option<PathBuf> {
|
||||
let mut found: Option<PathBuf> = None;
|
||||
for entry in std::fs::read_dir(self.project_dir()).ok()?.flatten() {
|
||||
let path = entry.path();
|
||||
if path.extension().and_then(|e| e.to_str()) != Some("jsonl") {
|
||||
|
|
@ -58,15 +67,27 @@ impl SessionStore {
|
|||
let Ok(file) = std::fs::File::open(&path) else {
|
||||
continue;
|
||||
};
|
||||
if std::io::BufReader::new(file)
|
||||
let matches = std::io::BufReader::new(file)
|
||||
.lines()
|
||||
.map_while(std::result::Result::ok)
|
||||
.any(|line| line_sets_title(&line, title))
|
||||
{
|
||||
return Some(path);
|
||||
.any(|line| line_sets_title(&line, title));
|
||||
if !matches {
|
||||
continue;
|
||||
}
|
||||
match &found {
|
||||
None => found = Some(path),
|
||||
Some(first) => {
|
||||
tracing::warn!(
|
||||
title,
|
||||
first = %first.display(),
|
||||
also = %path.display(),
|
||||
"find_by_title: multiple session files share this title — \
|
||||
resuming the first one found (readdir order, not deterministic)"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
found
|
||||
}
|
||||
|
||||
/// Archive the session titled `title` by renaming its backing file
|
||||
|
|
@ -83,12 +104,22 @@ impl SessionStore {
|
|||
/// [`Error::Io`] if the rename fails.
|
||||
pub fn archive_by_title(&self, title: &str) -> Result<Option<PathBuf>> {
|
||||
let Some(path) = self.find_by_title(title) else {
|
||||
tracing::info!(
|
||||
title,
|
||||
"archive_by_title: no session file found for this title"
|
||||
);
|
||||
return Ok(None);
|
||||
};
|
||||
let mut target = path.clone().into_os_string();
|
||||
target.push(".archived");
|
||||
let target = PathBuf::from(target);
|
||||
std::fs::rename(&path, &target).map_err(Error::Io)?;
|
||||
tracing::info!(
|
||||
title,
|
||||
from = %path.display(),
|
||||
to = %target.display(),
|
||||
"archive_by_title: renamed session file"
|
||||
);
|
||||
Ok(Some(target))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue