fix: don't mint worktreeMeta from a sidebar sort-order snapshot (#9342)
`worktrees:persistSortOrder` (ipc/worktrees.ts) and `persistManagedWorktreeSortOrder`
(orca-runtime.ts) call `store.setWorktreeMeta(id, { sortOrder })` for every id the
renderer sends. `setWorktreeMeta` has no repo-existence check, so a stale id the
client still lists — e.g. a removed repo's `${repoId}::${path}` that lingers in the
renderer's order — gets a brand-new `worktreeMeta` entry minted on every sidebar
snapshot, resurrecting an orphan/duplicate workspace on the next launch.
A sort-order snapshot must only reorder worktrees that already exist, never create
one. Guard both call sites with `getWorktreeMeta` so absent ids are skipped.
Co-authored-by: fanyunqian.1 <fanyunqian.1@bytedance.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
dd642cb3e3
commit
d8499fae16
|
|
@ -540,6 +540,22 @@ describe('registerWorktreeHandlers', () => {
|
|||
expect(handlers['worktrees:getBranchRenameFailureOutput']).toBeDefined()
|
||||
})
|
||||
|
||||
it('persistSortOrder only reorders existing worktrees and never mints meta for a stale id', () => {
|
||||
const liveId = 'repo-1::/workspace/repo'
|
||||
const staleId = 'removed-repo::/workspace/gone'
|
||||
// Only the live worktree has meta; the stale id (e.g. a removed repo the
|
||||
// renderer still lists) has none and must be skipped, not created.
|
||||
store.getWorktreeMeta.mockImplementation((id: string) =>
|
||||
id === liveId ? ({ instanceId: 'x' } as never) : undefined
|
||||
)
|
||||
|
||||
handlers['worktrees:persistSortOrder'](null, { orderedIds: [liveId, staleId] })
|
||||
|
||||
const orderedTargets = store.setWorktreeMeta.mock.calls.map((call) => call[0])
|
||||
expect(orderedTargets).toContain(liveId)
|
||||
expect(orderedTargets).not.toContain(staleId)
|
||||
})
|
||||
|
||||
it('prefetches the local default create base through the runtime refresh cache', async () => {
|
||||
const repo = {
|
||||
id: 'repo-1',
|
||||
|
|
|
|||
|
|
@ -2067,6 +2067,14 @@ export function registerWorktreeHandlers(
|
|||
}
|
||||
const now = Date.now()
|
||||
for (let i = 0; i < args.orderedIds.length; i++) {
|
||||
// Why: a sidebar-order snapshot must only reorder worktrees that already
|
||||
// exist — it must never create one. Without this guard a stale id the
|
||||
// renderer still lists (e.g. a removed repo's `${repoId}::${path}`) gets a
|
||||
// fresh worktreeMeta entry minted here, resurrecting an orphan/duplicate
|
||||
// workspace on the next launch. setWorktreeMeta has no repo-existence check.
|
||||
if (!store.getWorktreeMeta(args.orderedIds[i])) {
|
||||
continue
|
||||
}
|
||||
// Descending timestamps: first item gets highest sortOrder so b - a sorts first-wins on cold start.
|
||||
store.setWorktreeMeta(args.orderedIds[i], { sortOrder: now - i * 1000 })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19973,6 +19973,12 @@ export class OrcaRuntimeService {
|
|||
const now = Date.now()
|
||||
let updated = 0
|
||||
for (let i = 0; i < orderedIds.length; i++) {
|
||||
// Why: a sort-order snapshot must only reorder existing worktrees, never
|
||||
// mint new meta — a stale id would otherwise resurrect an orphan workspace
|
||||
// (setWorktreeMeta has no repo-existence check).
|
||||
if (!this.store.getWorktreeMeta(orderedIds[i])) {
|
||||
continue
|
||||
}
|
||||
this.store.setWorktreeMeta(orderedIds[i], { sortOrder: now - i * 1000 })
|
||||
updated++
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue