Skip to content

Commit ac3851c

Browse files
leogrpoiana
authored andcommitted
fix(ctl): derive Codex session_index path from the last sessions segment
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
1 parent 57c669d commit ac3851c

1 file changed

Lines changed: 18 additions & 4 deletions

File tree

tools/premptictl/src/logs_pretty.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ impl FsSessionNameResolver {
205205
let index_path = codex_session_index_path(transcript_path)?;
206206
let cur_len = std::fs::metadata(&index_path).ok().map(|m| m.len());
207207
let entry = self.codex.entry(index_path.clone()).or_default();
208+
// When the index can't be stat'd (`cur_len` is None — missing or
209+
// unreadable), we intentionally keep any last-known name rather than
210+
// blank it: Codex appends to the index and never deletes it
211+
// mid-session, so a transient stat failure shouldn't drop the label.
208212
if let Some(len) = cur_len {
209213
// The index is tiny and rename only appends; on any size change
210214
// we rebuild from scratch, which keeps "last line wins" trivial.
@@ -267,12 +271,15 @@ fn scan_transcript_incremental(path: &str, entry: &mut ResolverEntry) {
267271

268272
/// Derive `<codex_home>/session_index.jsonl` from a Codex rollout transcript
269273
/// path shaped like `<codex_home>/sessions/YYYY/MM/DD/rollout-*.jsonl`. Splits
270-
/// on the `sessions` directory segment so a custom `CODEX_HOME` works, and
271-
/// handles both `/` and `\` separators. Returns `None` when the path has no
272-
/// `sessions` segment (i.e. it isn't a Codex rollout path).
274+
/// on the *last* `sessions` segment (`rfind`), so a custom `CODEX_HOME` that
275+
/// itself contains a `sessions` component still resolves correctly — the date
276+
/// and `rollout-*` components are never `sessions`, so the deepest match is
277+
/// always the real session dir. Handles both `/` and `\` separators. Returns
278+
/// `None` when the path has no `sessions` segment (i.e. it isn't a Codex
279+
/// rollout path).
273280
fn codex_session_index_path(transcript_path: &str) -> Option<String> {
274281
for sep in ["/sessions/", "\\sessions\\"] {
275-
if let Some(idx) = transcript_path.find(sep) {
282+
if let Some(idx) = transcript_path.rfind(sep) {
276283
let home = &transcript_path[..idx];
277284
let slash = &sep[..1];
278285
return Some(format!("{home}{slash}session_index.jsonl"));
@@ -2183,6 +2190,13 @@ mod tests {
21832190
.as_deref(),
21842191
Some(r"C:\Users\u\.codex\session_index.jsonl")
21852192
);
2193+
// A CODEX_HOME whose own path contains a `sessions` segment must still
2194+
// resolve to the deepest (real) session dir — `rfind`, not `find`.
2195+
assert_eq!(
2196+
codex_session_index_path("/home/sessions/.codex/sessions/2026/06/25/rollout-x.jsonl")
2197+
.as_deref(),
2198+
Some("/home/sessions/.codex/session_index.jsonl")
2199+
);
21862200
// Not a Codex rollout path → no index.
21872201
assert_eq!(
21882202
codex_session_index_path("/home/u/.claude/projects/x/abc.jsonl"),

0 commit comments

Comments
 (0)