refactor(schedule): make absolute times explicit

This commit is contained in:
Tianyi Cui
2026-08-09 16:30:11 +08:00
parent 3d6498e91b
commit b7ec8429a9
109 changed files with 1248 additions and 3219 deletions

View File

@@ -12,11 +12,8 @@ import TypertRegistry from '@deepseek-ai/dsh-typert-registry'
import * as RuntimeClient from '../src/client/index.ts'
import type { SessionsService } from '../src/client/sessions/service.ts'
import type { WorkspacesService } from '../src/client/workspaces/service.ts'
import { resolvedClientTimeZone } from '../src/client/time-zone.ts'
import { FakeApiClient, ok } from './fake-api.ts'
const CLIENT_TIME_ZONE = resolvedClientTimeZone()
interface Bench {
ctx: Context
api: FakeApiClient
@@ -105,10 +102,7 @@ describe('runtime client apply', () => {
const sessions = bench.ctx.get('sessions') as SessionsService
const workspaces = bench.ctx.get('workspaces') as WorkspacesService
expect(bench.api.callsOf('session.create')).toEqual([{
workspaceId: 'w-recent',
timeZone: CLIENT_TIME_ZONE,
}])
expect(bench.api.callsOf('session.create')).toEqual([{ workspaceId: 'w-recent' }])
expect(sessions.list.getSnapshot().current).toBe('fk-new')
sessions.clear()

View File

@@ -6,13 +6,11 @@
import { describe, expect, it, vi } from 'vitest'
import type { SessionId } from '@deepseek-ai/dsh-client-connection/client'
import { SessionManager } from '../src/client/sessions/manager.ts'
import { resolvedClientTimeZone } from '../src/client/time-zone.ts'
import { FakeApiClient, deferred, err, ok } from './fake-api.ts'
import { entries, plainTurn } from './event-script.ts'
const S1 = 'fk-m1' as SessionId
const S2 = 'fk-m2' as SessionId
const CLIENT_TIME_ZONE = resolvedClientTimeZone()
type SummaryOver = Partial<{
updatedAt: number
@@ -710,11 +708,7 @@ describe('remaining branches', () => {
api.onCreate = () => Promise.resolve(ok({ sessionId: S1 }))
const manager = new SessionManager(api)
await manager.create({ cwd: '/tmp/w', sessionId: S1 })
expect(api.callsOf('session.create')).toEqual([{
cwd: '/tmp/w',
sessionId: S1,
timeZone: CLIENT_TIME_ZONE,
}])
expect(api.callsOf('session.create')).toEqual([{ cwd: '/tmp/w', sessionId: S1 }])
expect(manager.getListSnapshot().items[0]).toMatchObject({ sessionId: S1, cwd: '/tmp/w' })
await manager.create({ cwd: '/tmp/w' }) // same id returned: no duplicate row
expect(manager.getListSnapshot().items).toHaveLength(1)

View File

@@ -11,7 +11,6 @@ import type { SessionEvent } from '@deepseek-ai/dsh-session/types'
import { MAX_TIMER_DELAY_MS } from '@deepseek-ai/dsh-timeout'
import type { SessionId } from '@deepseek-ai/dsh-client-connection/client'
import { Session } from '../src/client/sessions/session.ts'
import { resolvedClientTimeZone } from '../src/client/time-zone.ts'
import { FakeApiClient, deferred, err, ok } from './fake-api.ts'
import { entries, ev, plainTurn } from './event-script.ts'
@@ -20,7 +19,6 @@ const at = (seq: number, e: Record<string, unknown>): SessionEvent =>
const SID = 'fk-s1' as SessionId
const PARENT = 'fk-parent' as SessionId
const CLIENT_TIME_ZONE = resolvedClientTimeZone()
afterEach(() => {
vi.unstubAllGlobals()
@@ -724,11 +722,11 @@ describe('prompt and cancel errors', () => {
expect(result.ok).toBe(true)
// Monotone: settlement alone does not step the phase anywhere.
expect(session.getSnapshot().composerPhase).toBe('engaging')
expect(api.callsOf('session.prompt')).toEqual([{
expect(api.callsOf('session.prompt')).toMatchObject([{
sessionId: SID,
mode: 'queue',
content: [{ type: 'text', text: '要发的' }],
clientTimeZone: CLIENT_TIME_ZONE,
clientTimeZone: new Intl.DateTimeFormat().resolvedOptions().timeZone,
}])
// First content lands (running turn): engaging → active.
session.handleRunning(true)

View File

@@ -10,11 +10,9 @@ import { Context } from 'cordis'
import { afterEach, describe, expect, it, vi } from 'vitest'
import type { SessionId } from '@deepseek-ai/dsh-client-connection/client'
import { SessionCreateError, SessionsService, scopeOf } from '../src/client/sessions/service.ts'
import { resolvedClientTimeZone } from '../src/client/time-zone.ts'
import { FakeApiClient, deferred, err, ok } from './fake-api.ts'
const sid = (s: string): SessionId => s as SessionId
const CLIENT_TIME_ZONE = resolvedClientTimeZone()
interface Bench {
ctx: Context
@@ -454,11 +452,7 @@ describe('create', () => {
const b = bench()
b.api.onCreate = () => Promise.resolve(ok({ sessionId: sid('fresh') }))
await expect(b.svc.create({ cwd: '/w', sessionId: sid('fresh') })).resolves.toBe('fresh')
expect(b.api.callsOf('session.create')).toEqual([{
cwd: '/w',
sessionId: 'fresh',
timeZone: CLIENT_TIME_ZONE,
}])
expect(b.api.callsOf('session.create')).toEqual([{ cwd: '/w', sessionId: 'fresh' }])
b.api.onCreate = () => Promise.resolve({
rpcId: 'e' as never,
result: { ok: false as const, error: { code: 'internal' as const, message: '爆了', details: {} } },

View File

@@ -12,11 +12,11 @@ describe('browser time zone', () => {
)
})
it('fails loud when the runtime exposes no zone', () => {
it.each([undefined, ''])('fails loud when the runtime exposes no zone %#', (timeZone) => {
const options = new Intl.DateTimeFormat().resolvedOptions()
vi.spyOn(Intl.DateTimeFormat.prototype, 'resolvedOptions').mockReturnValue({
...options,
timeZone: '',
timeZone: timeZone as string,
})
expect(() => resolvedClientTimeZone()).toThrow('browser time zone is unavailable')

View File

@@ -2,14 +2,12 @@ import { Context } from 'cordis'
import { describe, expect, it } from 'vitest'
import type { SessionId, WorkspaceId, WorkspaceView } from '@deepseek-ai/dsh-client-connection/client'
import { SessionsService } from '../src/client/sessions/service.ts'
import { resolvedClientTimeZone } from '../src/client/time-zone.ts'
import { WorkspaceManager } from '../src/client/workspaces/manager.ts'
import { DirectoryBrowseError, WorkspaceCreateError, WorkspacesService } from '../src/client/workspaces/service.ts'
import { FakeApiClient, deferred, err, ok } from './fake-api.ts'
const sid = (id: string): SessionId => id as SessionId
const wid = (id: string): WorkspaceId => id as WorkspaceId
const CLIENT_TIME_ZONE = resolvedClientTimeZone()
function workspace(id: string, sessionIds: SessionId[] = [], createdAt = '2026-01-01T00:00:00.000Z'): WorkspaceView {
return {
@@ -190,10 +188,7 @@ describe('WorkspacesService', () => {
// Miss: beta has only a non-blank session → host create with workspaceId.
api.onCreate = () => Promise.resolve(ok({ sessionId: sid('s-fresh') }))
await expect(workspaces.connectWorkspace(wid('beta'))).resolves.toBe('s-fresh')
expect(api.callsOf('session.create')).toEqual([{
workspaceId: 'beta',
timeZone: CLIENT_TIME_ZONE,
}])
expect(api.callsOf('session.create')).toEqual([{ workspaceId: 'beta' }])
// Same guarantee on the create arm (draft hand-off writes the machine pre-open).
expect(sessions.binding(sid('s-fresh'))).toBeDefined()
@@ -201,10 +196,7 @@ describe('WorkspacesService', () => {
// never reused, a fresh accounted session is created instead.
api.onCreate = () => Promise.resolve(ok({ sessionId: sid('s-fresh-3') }))
await expect(workspaces.connectWorkspace(wid('gamma'))).resolves.toBe('s-fresh-3')
expect(api.callsOf('session.create')).toEqual([
{ workspaceId: 'beta', timeZone: CLIENT_TIME_ZONE },
{ workspaceId: 'gamma', timeZone: CLIENT_TIME_ZONE },
])
expect(api.callsOf('session.create')).toEqual([{ workspaceId: 'beta' }, { workspaceId: 'gamma' }])
// Unknown workspace fails loud instead of silently creating in nowhere.
await expect(workspaces.connectWorkspace(wid('ghost'))).rejects.toThrow(/unknown workspace ghost/)
@@ -419,10 +411,7 @@ describe('startInitialSelection', () => {
await b.sessions.refresh()
// Store notifications and the connect round trip are microtask-batched.
await new Promise(resolve => setTimeout(resolve, 0))
expect(b.api.callsOf('session.create')).toEqual([{
workspaceId: 'recent',
timeZone: CLIENT_TIME_ZONE,
}])
expect(b.api.callsOf('session.create')).toEqual([{ workspaceId: 'recent' }])
expect(b.sessions.list.getSnapshot().current).toBe('s-new')
stop()
})