()
| 442 | let cleanupRegistered = false |
| 443 | |
| 444 | function getProject(): Project { |
| 445 | if (!project) { |
| 446 | project = new Project() |
| 447 | |
| 448 | // Register flush as a cleanup handler (only once) |
| 449 | if (!cleanupRegistered) { |
| 450 | registerCleanup(async () => { |
| 451 | // Flush queued writes first, then re-append session metadata |
| 452 | // (customTitle, tag) so they always appear in the last 64KB tail |
| 453 | // window. readLiteMetadata only reads the tail to extract these |
| 454 | // fields — if enough messages are appended after a /rename, the |
| 455 | // custom-title entry gets pushed outside the window and --resume |
| 456 | // shows the auto-generated firstPrompt instead. |
| 457 | await project?.flush() |
| 458 | try { |
| 459 | project?.reAppendSessionMetadata() |
| 460 | } catch { |
| 461 | // Best-effort — don't let metadata re-append crash the cleanup |
| 462 | } |
| 463 | }) |
| 464 | cleanupRegistered = true |
| 465 | } |
| 466 | } |
| 467 | return project |
| 468 | } |
| 469 | |
| 470 | /** |
| 471 | * Reset the Project singleton's flush state for testing. |
no test coverage detected