84 lines
1.8 KiB
Python
84 lines
1.8 KiB
Python
#!/usr/bin/env python3
|
|
|
|
"ts lists the Codex sessions from .codex, because codex default impl of ts doesnt work"
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
import re
|
|
|
|
PATTERN = re.compile(
|
|
# r"^rollout-"
|
|
r"(?P<date>\d{4}-\d{2}-\d{2})"
|
|
r"T"
|
|
r"(?P<time>\d{2}-\d{2}-\d{2})"
|
|
r"-(?P<uuid>[0-9a-fA-F-]{36})"
|
|
r"\.jsonl$"
|
|
)
|
|
|
|
|
|
def iter_session_files(root: Path):
|
|
yield from root.glob("**/*.jsonl")
|
|
|
|
|
|
def parse_session_filename(name: str):
|
|
match = PATTERN.search(name)
|
|
if not match:
|
|
return None
|
|
|
|
started = datetime.strptime(
|
|
f'{match.group("date")} {match.group("time")}',
|
|
"%Y-%m-%d %H-%M-%S",
|
|
)
|
|
|
|
return {
|
|
"uuid": match.group("uuid"),
|
|
"started": started,
|
|
}
|
|
|
|
|
|
def format_size(size: int) -> str:
|
|
units = ["B", "KB", "MB", "GB", "TB"]
|
|
value = float(size)
|
|
|
|
for unit in units:
|
|
if value < 1024 or unit == units[-1]:
|
|
if unit == "B":
|
|
return f"{size} B"
|
|
return f"{value:.1f} {unit}"
|
|
value /= 1024
|
|
raise ValueError() # unreachable
|
|
|
|
|
|
def format_session_line(file: Path) -> str | None:
|
|
parsed = parse_session_filename(file.name)
|
|
if parsed is None:
|
|
return None
|
|
|
|
stat = file.stat()
|
|
modified = datetime.fromtimestamp(stat.st_mtime)
|
|
size = format_size(stat.st_size)
|
|
|
|
return (
|
|
f'{parsed["started"]:%Y-%m-%d %H:%M:%S} | '
|
|
f"updated {modified:%Y-%m-%d %H:%M:%S} | "
|
|
f"{size:>8} | "
|
|
f'codex resume {parsed["uuid"]}'
|
|
)
|
|
|
|
|
|
def main():
|
|
sessions = Path.home() / ".codex" / "sessions"
|
|
|
|
for file in iter_session_files(sessions):
|
|
line = format_session_line(file)
|
|
if line is not None:
|
|
print(line)
|
|
|
|
print("done")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|