fix: ACP loadSession 历史记录恢复失败 — 用 resolveSessionFilePath 替代 getProjectDir 定位 session 文件
- params.cwd 可能与 session 文件实际存储的项目目录不一致(子目录、 hash 算法差异等),导致 getProjectDir 推算出的路径找不到文件 - 改用 resolveSessionFilePath(sessionId, cwd) 按 sessionId 跨项目 搜索,先精确匹配再 fallback 全项目扫描 - 切换回已缓存的 session 时也回放历史消息给客户端 - createSession 内部 switchSession 保留 sessionProjectDir 不被覆盖为 null
This commit is contained in:
parent
3a261f7444
commit
1ce561ca6c
|
|
@ -82,6 +82,15 @@ mock.module('../../../utils/listSessionsImpl.js', () => ({
|
||||||
listSessionsImpl: mock(async () => []),
|
listSessionsImpl: mock(async () => []),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
const mockResolveSessionFilePath = mock(async () => ({
|
||||||
|
filePath: '/fake/project/dir/session.jsonl',
|
||||||
|
projectPath: '/tmp',
|
||||||
|
fileSize: 100,
|
||||||
|
}))
|
||||||
|
mockModulePreservingExports('../../../utils/sessionStoragePortable.js', {
|
||||||
|
resolveSessionFilePath: mockResolveSessionFilePath,
|
||||||
|
})
|
||||||
|
|
||||||
const mockGetMainLoopModel = mock(() => 'claude-sonnet-4-6')
|
const mockGetMainLoopModel = mock(() => 'claude-sonnet-4-6')
|
||||||
|
|
||||||
mock.module('../../../utils/model/model.js', () => ({
|
mock.module('../../../utils/model/model.js', () => ({
|
||||||
|
|
@ -746,4 +755,76 @@ describe('AcpAgent', () => {
|
||||||
expect(commit.input).toEqual({ hint: '[message]' })
|
expect(commit.input).toEqual({ hint: '[message]' })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('sessionId alignment with global state', () => {
|
||||||
|
test('newSession calls switchSession with the generated sessionId', async () => {
|
||||||
|
const agent = new AcpAgent(makeConn())
|
||||||
|
const res = await agent.newSession({ cwd: '/tmp' } as any)
|
||||||
|
expect(mockSwitchSession).toHaveBeenCalledWith(res.sessionId, null)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('resumeSession calls switchSession with the requested sessionId', async () => {
|
||||||
|
const agent = new AcpAgent(makeConn())
|
||||||
|
const requestedId = 'resume-test-session-id'
|
||||||
|
await agent.unstable_resumeSession({
|
||||||
|
sessionId: requestedId,
|
||||||
|
cwd: '/tmp',
|
||||||
|
mcpServers: [],
|
||||||
|
} as any)
|
||||||
|
|
||||||
|
expect(mockSwitchSession).toHaveBeenCalledWith(
|
||||||
|
requestedId,
|
||||||
|
expect.any(String),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('loadSession calls switchSession with the requested sessionId', async () => {
|
||||||
|
const agent = new AcpAgent(makeConn())
|
||||||
|
const requestedId = 'load-test-session-id'
|
||||||
|
await agent.loadSession({
|
||||||
|
sessionId: requestedId,
|
||||||
|
cwd: '/tmp',
|
||||||
|
mcpServers: [],
|
||||||
|
} as any)
|
||||||
|
|
||||||
|
expect(mockSwitchSession).toHaveBeenCalledWith(
|
||||||
|
requestedId,
|
||||||
|
expect.any(String),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('resumeSession with existing session still calls switchSession', async () => {
|
||||||
|
const agent = new AcpAgent(makeConn())
|
||||||
|
const { sessionId } = await agent.newSession({ cwd: '/tmp' } as any)
|
||||||
|
mockSwitchSession.mockClear()
|
||||||
|
|
||||||
|
// Resume the same session — should still align global state
|
||||||
|
await agent.unstable_resumeSession({
|
||||||
|
sessionId,
|
||||||
|
cwd: '/tmp',
|
||||||
|
mcpServers: [],
|
||||||
|
} as any)
|
||||||
|
|
||||||
|
expect(mockSwitchSession).toHaveBeenCalledWith(
|
||||||
|
sessionId,
|
||||||
|
expect.any(String),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('prompt does not trigger additional switchSession for multi-session', async () => {
|
||||||
|
const agent = new AcpAgent(makeConn())
|
||||||
|
await agent.newSession({ cwd: '/tmp' } as any)
|
||||||
|
await agent.newSession({ cwd: '/tmp' } as any)
|
||||||
|
mockSwitchSession.mockClear()
|
||||||
|
|
||||||
|
// Prompts should not call switchSession — alignment happens at session creation
|
||||||
|
const s1 = agent.sessions.keys().next().value
|
||||||
|
await agent.prompt({
|
||||||
|
sessionId: s1,
|
||||||
|
prompt: [{ type: 'text', text: 'hello' }],
|
||||||
|
} as any)
|
||||||
|
expect(mockSwitchSession).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user