mirror of
https://github.com/NanmiCoder/claude-code-haha.git
synced 2026-10-10 11:53:10 +08:00
merge: integrate QA-003 checkpoint follow-up
This commit is contained in:
@@ -3426,6 +3426,54 @@ describe('Sessions API', () => {
|
||||
expect(body.index?.lastErrorCode === null || typeof body.index?.lastErrorCode === 'string').toBe(true)
|
||||
})
|
||||
|
||||
it('GET turn-checkpoints accepts a known memory session across workspace changes and persistence restore', async () => {
|
||||
await fs.writeFile(path.join(tmpDir, 'settings.json'), JSON.stringify({ cleanupPeriodDays: 0 }))
|
||||
resetSettingsCache()
|
||||
const created = await fetch(`${baseUrl}/api/sessions`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ workDir: tmpDir }),
|
||||
})
|
||||
expect(created.status).toBe(201)
|
||||
const { sessionId } = await created.json() as { sessionId: string }
|
||||
const { sessionService } = await import('../services/sessionService.js')
|
||||
const selectedWorkDir = await fs.mkdtemp(path.join(tmpDir, 'selected-project-'))
|
||||
// The runtime launch boundary records the user's selected working folder
|
||||
// even though retention zero deliberately never materializes a JSONL.
|
||||
await sessionService.appendSessionMetadata(sessionId, { workDir: selectedWorkDir })
|
||||
expect(await sessionService.getSessionWorkDir(sessionId)).toBe(selectedWorkDir)
|
||||
|
||||
for (const days of [0, 365]) {
|
||||
await fs.writeFile(path.join(tmpDir, 'settings.json'), JSON.stringify({ cleanupPeriodDays: days }))
|
||||
resetSettingsCache()
|
||||
const response = await fetch(`${baseUrl}/api/sessions/${sessionId}/turn-checkpoints`)
|
||||
expect(response.status).toBe(200)
|
||||
expect(await response.json()).toEqual({ checkpoints: [] })
|
||||
expect(await sessionService.getSessionMessagesWithEvidence(sessionId)).toEqual({
|
||||
messages: [], transcriptEvidenceComplete: false,
|
||||
})
|
||||
expect(await sessionService.findSessionFile(sessionId)).toBeNull()
|
||||
}
|
||||
|
||||
// After new enabled content reaches disk, it takes precedence over the
|
||||
// retained launch metadata and produces normal completed-turn checkpoints.
|
||||
await writeSessionFile(sanitizePath(selectedWorkDir), sessionId, [
|
||||
{ type: 'session-meta', workDir: selectedWorkDir },
|
||||
{ type: 'user', uuid: 'public-user', parentUuid: null, timestamp: '2026-09-10T00:00:00.000Z', message: { role: 'user', content: 'public prompt' } },
|
||||
{ type: 'assistant', uuid: 'public-assistant', parentUuid: 'public-user', timestamp: '2026-09-10T00:00:01.000Z', message: { role: 'assistant', content: 'public reply' } },
|
||||
])
|
||||
const restored = await fetch(`${baseUrl}/api/sessions/${sessionId}/turn-checkpoints`)
|
||||
expect(restored.status).toBe(200)
|
||||
const body = await restored.json() as { checkpoints: Array<{ target: { targetUserMessageId: string } }> }
|
||||
expect(body.checkpoints).toHaveLength(1)
|
||||
expect(body.checkpoints[0]?.target.targetUserMessageId).toBe('public-user')
|
||||
expect((await sessionService.getSessionMessagesWithEvidence(sessionId)).transcriptEvidenceComplete).toBe(true)
|
||||
|
||||
await sessionService.deleteSession(sessionId)
|
||||
expect((await fetch(`${baseUrl}/api/sessions/${sessionId}/turn-checkpoints`)).status).toBe(404)
|
||||
expect((await fetch(`${baseUrl}/api/sessions/${crypto.randomUUID()}/turn-checkpoints`)).status).toBe(404)
|
||||
})
|
||||
|
||||
it('POST /api/sessions should create a session', async () => {
|
||||
const workDir = await fs.mkdtemp(path.join(tmpDir, 'api-session-'))
|
||||
const res = await fetch(`${baseUrl}/api/sessions`, {
|
||||
|
||||
@@ -3761,6 +3761,12 @@ export class SessionService {
|
||||
): Promise<SessionMessagesWithEvidence> {
|
||||
const found = await this.findSessionFile(sessionId)
|
||||
if (!found) {
|
||||
// Retention-zero sessions intentionally have no transcript. The desktop
|
||||
// still asks for turn checkpoints after each live reply; lack of saved
|
||||
// evidence is not a missing session, nor proof of an empty history.
|
||||
if (this.memoryLaunchInfo.has(this.memorySessionKey(sessionId))) {
|
||||
return { messages: [], transcriptEvidenceComplete: false }
|
||||
}
|
||||
throw ApiError.notFound(`Session not found: ${sessionId}`)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user