()
| 477 | let cleanupRegistered = false |
| 478 | |
| 479 | function getProject(): Project { |
| 480 | if (!project) { |
| 481 | project = new Project() |
| 482 | |
| 483 | // Register flush as a cleanup handler (only once) |
| 484 | if (!cleanupRegistered) { |
| 485 | registerCleanup(async () => { |
| 486 | // Flush queued writes first, then re-append session metadata |
| 487 | // (customTitle, tag) so they always appear in the last 64KB tail |
| 488 | // window. readLiteMetadata only reads the tail to extract these |
| 489 | // fields — if enough messages are appended after a /rename, the |
| 490 | // custom-title entry gets pushed outside the window and --resume |
| 491 | // shows the auto-generated firstPrompt instead. |
| 492 | await project?.flush() |
| 493 | try { |
| 494 | project?.reAppendSessionMetadata() |
| 495 | } catch { |
| 496 | // Best-effort — don't let metadata re-append crash the cleanup |
| 497 | } |
| 498 | }) |
| 499 | cleanupRegistered = true |
| 500 | } |
| 501 | } |
| 502 | return project |
| 503 | } |
| 504 | |
| 505 | /** |
| 506 | * Reset the Project singleton's flush state for testing. |
no test coverage detected