fix: delete codex sessions with backup#227
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds support for deleting Codex sessions by backing up and removing Codex session artifacts (session file, history/index entries, and optional sqlite thread row), along with tests for key deletion scenarios.
Changes:
- Add Codex-specific delete path in
deleteSession()with backup creation and artifact cleanup. - Implement helpers to collect/remove JSONL session references and prune empty session directories.
- Add node:test coverage for Codex deletion (session file + history/index; history-only).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| test/codex-delete.test.js | Adds tests validating Codex deletion behavior and backup creation. |
| src/data.js | Implements Codex-aware deletion, backups, JSONL cleanup helpers, and cache invalidation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| function tmpDir() { | ||
| return fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'codbash-codex-delete-'))); | ||
| } |
| } | ||
|
|
||
| test('deleteSession removes Codex artifacts after creating a backup', () => { | ||
| const home = tmpDir(); |
| function getCodexDeleteBackupRoot() { | ||
| if (process.env.CODEBASH_DELETE_BACKUP_DIR) { | ||
| return path.resolve(process.env.CODEBASH_DELETE_BACKUP_DIR); | ||
| } | ||
|
|
||
| const userBackup = path.join(ALL_HOMES[0], 'backup', 'codex'); | ||
| if (fs.existsSync(userBackup)) return path.join(userBackup, 'codbash-deleted'); | ||
|
|
||
| return path.join(CODEX_DIR, 'backups', 'codbash-deleted'); | ||
| } |
| function removeJsonlLinesForSession(filePath, sessionId) { | ||
| if (!fs.existsSync(filePath)) return 0; | ||
| const lines = readLines(filePath); | ||
| const filtered = lines.filter(line => codexLineSessionId(line) !== sessionId); | ||
| const removed = lines.length - filtered.length; | ||
| if (removed > 0) { | ||
| fs.writeFileSync(filePath, filtered.length ? filtered.join('\n') + '\n' : ''); | ||
| } | ||
| return removed; | ||
| } |
| const safeId = safeSqlString(sessionId); | ||
| const stateDb = path.join(CODEX_DIR, 'state_5.sqlite'); | ||
| if (safeId && fs.existsSync(stateDb)) { | ||
| try { | ||
| execFileSync('sqlite3', [stateDb, `DELETE FROM threads WHERE id = '${safeId}';`], { | ||
| timeout: 5000, | ||
| windowsHide: true, | ||
| stdio: ['pipe', 'pipe', 'pipe'], | ||
| }); | ||
| deleted.push('codex state thread'); | ||
| } catch {} | ||
| } |
|
Thanks for this — the Codex delete-with-backup logic is genuinely valuable; today deleting a Codex session on Two things before it can come out of draft:
Minor: the |
No description provided.