mirror of
https://github.com/stablyai/orca.git
synced 2026-09-28 16:02:45 +00:00
Fix mobile legacy inventory reset and stale completion regression
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
This commit is contained in:
@@ -22,6 +22,8 @@ function client(sendRequest: RpcClient['sendRequest']): RpcClient {
|
||||
describe('native host session native chat operations', () => {
|
||||
it('stops the agent with a bare Escape that carries no enter at all', async () => {
|
||||
const sendRequest = vi.fn<RpcClient['sendRequest']>().mockResolvedValue({
|
||||
id: 'test',
|
||||
_meta: { runtimeId: 'host' },
|
||||
ok: true,
|
||||
result: { delivered: true }
|
||||
})
|
||||
@@ -40,6 +42,8 @@ describe('native host session native chat operations', () => {
|
||||
// The shared chat write refuses to start under a 2s residual budget. Stop does not: the
|
||||
// call it replaced tried on whatever was left and could be accepted.
|
||||
const sendRequest = vi.fn<RpcClient['sendRequest']>().mockResolvedValue({
|
||||
id: 'test',
|
||||
_meta: { runtimeId: 'host' },
|
||||
ok: true,
|
||||
result: { send: { accepted: true } }
|
||||
})
|
||||
@@ -61,33 +65,57 @@ describe('native host session native chat operations', () => {
|
||||
})
|
||||
|
||||
it('ignores an older inventory completion after cache reset', async () => {
|
||||
const deferred: Array<(value: any) => void> = []
|
||||
const deferred: Array<(value: Awaited<ReturnType<RpcClient['sendRequest']>>) => void> = []
|
||||
const sendRequest = vi.fn<RpcClient['sendRequest']>((method) => {
|
||||
if (method === 'files.searchPaths')
|
||||
if (method === 'files.searchPaths') {
|
||||
return Promise.resolve({
|
||||
id: 'test',
|
||||
_meta: { runtimeId: 'host' },
|
||||
ok: false,
|
||||
error: { code: 'method_not_found', message: 'unsupported' }
|
||||
})
|
||||
}
|
||||
return new Promise((resolve) => deferred.push(resolve))
|
||||
})
|
||||
const operations = nativeHostSessionNativeChatOperations(client(sendRequest))
|
||||
const old = operations.searchFiles(target(), 'fresh')
|
||||
await vi.waitFor(() => expect(deferred).toHaveLength(1))
|
||||
const overlapping = operations.searchFiles(target(), 'old')
|
||||
operations.resetFileSearchCache('wt-1')
|
||||
const fresh = operations.searchFiles(target(), 'fresh')
|
||||
deferred[1]?.({ ok: true, result: { files: [{ relativePath: 'fresh.ts' }] } })
|
||||
await vi.waitFor(() => expect(deferred).toHaveLength(2))
|
||||
deferred[1]!({
|
||||
id: 'test',
|
||||
_meta: { runtimeId: 'host' },
|
||||
ok: true,
|
||||
result: { files: [{ relativePath: 'fresh.ts' }] }
|
||||
})
|
||||
await expect(fresh).resolves.toEqual(['fresh.ts'])
|
||||
deferred[0]?.({ ok: true, result: { files: [{ relativePath: 'old.ts' }] } })
|
||||
await old
|
||||
deferred[0]!({
|
||||
id: 'test',
|
||||
_meta: { runtimeId: 'host' },
|
||||
ok: true,
|
||||
result: { files: [{ relativePath: 'old.ts' }] }
|
||||
})
|
||||
await expect(old).resolves.toBeNull()
|
||||
await expect(overlapping).resolves.toBeNull()
|
||||
await expect(operations.searchFiles(target(), 'fresh')).resolves.toEqual(['fresh.ts'])
|
||||
})
|
||||
|
||||
it('keeps the legacy file inventory scoped to the workspace that produced it', async () => {
|
||||
const sendRequest = vi.fn<RpcClient['sendRequest']>(async (method, params) => {
|
||||
if (method === 'files.searchPaths') {
|
||||
return { ok: false, error: { code: 'method_not_found', message: 'unsupported' } }
|
||||
return {
|
||||
id: 'test',
|
||||
_meta: { runtimeId: 'host' },
|
||||
ok: false,
|
||||
error: { code: 'method_not_found', message: 'unsupported' }
|
||||
}
|
||||
}
|
||||
const worktree = (params as { worktree: string }).worktree
|
||||
return {
|
||||
id: 'test',
|
||||
_meta: { runtimeId: 'host' },
|
||||
ok: true,
|
||||
result: {
|
||||
files:
|
||||
|
||||
@@ -28,7 +28,6 @@ export function nativeHostSessionNativeChatOperations(
|
||||
const legacyPathsByWorkspace = new Map<string, string[]>()
|
||||
const legacyLoadByWorkspace = new Map<string, Promise<string[] | null>>()
|
||||
const legacyGenerationByWorkspace = new Map<string, number>()
|
||||
const legacyGenerationByWorkspace = new Map<string, number>()
|
||||
return {
|
||||
async readability(workspaceId) {
|
||||
if (isFloatingWorkspaceWorktreeId(workspaceId)) {
|
||||
@@ -74,6 +73,7 @@ export function nativeHostSessionNativeChatOperations(
|
||||
resetFileSearchCache(workspaceId) {
|
||||
searchSupported = null
|
||||
legacyPathsByWorkspace.delete(workspaceId)
|
||||
legacyLoadByWorkspace.delete(workspaceId)
|
||||
legacyGenerationByWorkspace.set(
|
||||
workspaceId,
|
||||
(legacyGenerationByWorkspace.get(workspaceId) ?? 0) + 1
|
||||
@@ -108,26 +108,33 @@ export function nativeHostSessionNativeChatOperations(
|
||||
.sendRequest('files.list', {
|
||||
worktree: `id:${target.workspaceId}`
|
||||
})
|
||||
.then((response) => (response.ok ? extractPaths(response.result) : null))
|
||||
legacyLoad = request.finally(() => {
|
||||
if (legacyLoadByWorkspace.get(target.workspaceId) === legacyLoad) {
|
||||
legacyLoadByWorkspace.delete(target.workspaceId)
|
||||
}
|
||||
})
|
||||
legacyLoadByWorkspace.set(target.workspaceId, legacyLoad)
|
||||
const paths = await legacyLoad
|
||||
if ((legacyGenerationByWorkspace.get(target.workspaceId) ?? 0) !== generation) {
|
||||
return null
|
||||
}
|
||||
if (!paths) return null
|
||||
legacyPaths = paths
|
||||
legacyPathsByWorkspace.set(target.workspaceId, paths)
|
||||
} else {
|
||||
const paths = await legacyLoad
|
||||
if (!paths) return null
|
||||
legacyPaths = paths
|
||||
legacyPathsByWorkspace.set(target.workspaceId, paths)
|
||||
.then((response) => {
|
||||
if (
|
||||
!response.ok ||
|
||||
(legacyGenerationByWorkspace.get(target.workspaceId) ?? 0) !== generation
|
||||
) {
|
||||
return null
|
||||
}
|
||||
const paths = extractPaths(response.result)
|
||||
legacyPathsByWorkspace.set(target.workspaceId, paths)
|
||||
return paths
|
||||
})
|
||||
.finally(() => {
|
||||
if (
|
||||
legacyLoadByWorkspace.get(target.workspaceId) === request &&
|
||||
!legacyPathsByWorkspace.has(target.workspaceId)
|
||||
) {
|
||||
legacyLoadByWorkspace.delete(target.workspaceId)
|
||||
}
|
||||
})
|
||||
legacyLoad = request
|
||||
legacyLoadByWorkspace.set(target.workspaceId, request)
|
||||
}
|
||||
const paths = await legacyLoad
|
||||
if (!paths) {
|
||||
return null
|
||||
}
|
||||
legacyPaths = paths
|
||||
}
|
||||
return rankSuggestions(legacyPaths, query, FILE_RESULT_LIMIT)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user