列出所有会话(用于 --resume 选择界面)。 对应 Reference: EP09 §8 listSessionsImpl() 使用两阶段策略
(self)
| 374 | return session |
| 375 | |
| 376 | def list_sessions(self) -> list[dict]: |
| 377 | """ |
| 378 | 列出所有会话(用于 --resume 选择界面)。 |
| 379 | |
| 380 | 对应 Reference: EP09 §8 |
| 381 | listSessionsImpl() 使用两阶段策略 |
| 382 | """ |
| 383 | sessions = [] |
| 384 | for filename in os.listdir(self.base_dir): |
| 385 | if not filename.endswith(".jsonl"): |
| 386 | continue |
| 387 | path = os.path.join(self.base_dir, filename) |
| 388 | session_id = filename[:-6] # 去掉 .jsonl |
| 389 | |
| 390 | # 快速读取:只读头尾 |
| 391 | # 对应 Reference: EP09 §4 |
| 392 | # readHeadAndTail(filePath, fileSize, buf) |
| 393 | # LITE_READ_BUF_SIZE = 65536 (64KB) |
| 394 | first_prompt = "" |
| 395 | last_prompt = "" |
| 396 | mtime = os.path.getmtime(path) |
| 397 | |
| 398 | with open(path, "r") as f: |
| 399 | for line in f: |
| 400 | line = line.strip() |
| 401 | if not line: |
| 402 | continue |
| 403 | try: |
| 404 | entry = json.loads(line) |
| 405 | except json.JSONDecodeError: |
| 406 | continue |
| 407 | if entry.get("type") == "user" and not first_prompt: |
| 408 | blocks = entry.get("blocks", []) |
| 409 | for b in blocks: |
| 410 | if b.get("type") == "text": |
| 411 | first_prompt = b["text"][:80] |
| 412 | break |
| 413 | if entry.get("type") == "last-prompt": |
| 414 | last_prompt = entry.get("text", "")[:80] |
| 415 | |
| 416 | sessions.append({ |
| 417 | "session_id": session_id, |
| 418 | "first_prompt": first_prompt, |
| 419 | "last_prompt": last_prompt or first_prompt, |
| 420 | "modified": mtime, |
| 421 | }) |
| 422 | |
| 423 | # 按修改时间降序排列 |
| 424 | sessions.sort(key=lambda s: s["modified"], reverse=True) |
| 425 | return sessions |
| 426 | |
| 427 | |
| 428 | # ============================================================ |