fix(hub,cli): coerce null session activeAt so resume cannot 500 (#1026)

Legacy rows and inserts left sessions.active_at NULL while SessionSchema
required a number, so CLI GET /cli/sessions/:id failed Zod and resume
surfaced HTTP 500. Persist active_at on insert, harden hub read coerce,
and nullish-transform activeAt in SessionSchema (output stays number).

Fixes #1025

Co-authored-by: Debian <heavygee@oos-linux.in.lockhouse>
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
HeavyGee
2026-07-13 09:00:17 +08:00
committed by GitHub
co-authored by Debian Cursor
parent f6ad345339
commit 8ee04500b9
7 changed files with 213 additions and 3 deletions
@@ -0,0 +1,63 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { configuration } from '@/configuration'
const axiosGetMock = vi.hoisted(() => vi.fn())
vi.mock('axios', () => ({
default: {
get: axiosGetMock,
post: vi.fn()
}
}))
vi.mock('@/api/auth', () => ({
getAuthToken: () => 'cli-token'
}))
import { ApiClient } from './api'
describe('ApiClient.getSession activeAt coerce', () => {
const now = 1_710_000_000_000
beforeEach(() => {
configuration._setApiUrl('https://hapi.example.com')
configuration._setExtraHeaders({})
axiosGetMock.mockReset()
})
it('accepts hub payloads with null activeAt without throwing', async () => {
axiosGetMock.mockResolvedValue({
data: {
session: {
id: '11111111-1111-4111-8111-111111111111',
namespace: 'default',
seq: 1,
createdAt: now,
updatedAt: now,
active: false,
activeAt: null,
metadata: {
path: '/tmp/project',
host: 'test-host'
},
metadataVersion: 1,
agentState: null,
agentStateVersion: 0,
thinking: false,
thinkingAt: now,
todos: [],
model: null,
modelReasoningEffort: null,
effort: null,
serviceTier: null
}
}
})
const client = await ApiClient.create()
const session = await client.getSession('11111111-1111-4111-8111-111111111111')
expect(session.activeAt).toBe(0)
expect(typeof session.activeAt).toBe('number')
})
})