mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-07-09 17:29:12 +00:00
fix(agent-core-v2): dedupe workspace registry entries by root
Port v1 #1221: collapse registered workspaces that share a root in list(), preferring the entry whose id matches the current canonical encodeWorkDirKey, so a legacy workspaces.json (v1-compatible) does not render the same folder twice through GET /workspaces.
This commit is contained in:
parent
d0f969bc30
commit
7c094d8d6f
2 changed files with 49 additions and 1 deletions
|
|
@ -49,7 +49,7 @@ export class WorkspaceRegistryService implements IWorkspaceRegistry {
|
|||
list(): Promise<readonly Workspace[]> {
|
||||
return this.runExclusive(async () => {
|
||||
const cache = await this.ensureLoaded();
|
||||
return [...cache.values()];
|
||||
return dedupeByRoot(cache);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -174,6 +174,30 @@ function parseSessionIndexLine(line: string): SessionIndexLine | undefined {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse registered workspaces that share a `root`. The persisted catalog
|
||||
* (v1-compatible `workspaces.json`) can hold legacy entries whose id was
|
||||
* computed by an older `encodeWorkDirKey` (e.g. realpath-based on Windows) for
|
||||
* the same folder, so one root may map to multiple ids. Prefer the entry whose
|
||||
* id matches the current canonical key so current sessions' `workspace_id`
|
||||
* still resolves and the same folder is not listed twice.
|
||||
*/
|
||||
function dedupeByRoot(cache: ReadonlyMap<string, Workspace>): Workspace[] {
|
||||
const byRoot = new Map<string, Workspace>();
|
||||
for (const ws of cache.values()) {
|
||||
const existing = byRoot.get(ws.root);
|
||||
if (existing === undefined) {
|
||||
byRoot.set(ws.root, ws);
|
||||
continue;
|
||||
}
|
||||
const canonicalId = encodeWorkDirKey(ws.root);
|
||||
if (existing.id !== canonicalId && ws.id === canonicalId) {
|
||||
byRoot.set(ws.root, ws);
|
||||
}
|
||||
}
|
||||
return [...byRoot.values()];
|
||||
}
|
||||
|
||||
registerScopedService(
|
||||
LifecycleScope.App,
|
||||
IWorkspaceRegistry,
|
||||
|
|
|
|||
|
|
@ -167,4 +167,28 @@ describe('WorkspaceRegistryService (file-backed)', () => {
|
|||
await build().delete(created.id);
|
||||
expect(await restart().get(created.id)).toBeUndefined();
|
||||
});
|
||||
|
||||
it('collapses duplicate registered entries for the same root, preferring the canonical id', async () => {
|
||||
const root = join(homeDir, 'dup');
|
||||
const canonicalId = encodeWorkDirKey(root);
|
||||
// Simulate a registry that also holds a legacy id for the same folder (e.g.
|
||||
// one produced by an older encodeWorkDirKey).
|
||||
const legacyId = 'wd_duplegacy_deadbeef0000';
|
||||
const entry: PersistedWorkspaceEntry = {
|
||||
root,
|
||||
name: 'dup',
|
||||
created_at: '2026-01-01T00:00:00.000Z',
|
||||
last_opened_at: '2026-01-01T00:00:00.000Z',
|
||||
};
|
||||
await writeWorkspacesJson({
|
||||
// Legacy first so the canonical entry must actively replace it.
|
||||
[legacyId]: entry,
|
||||
[canonicalId]: entry,
|
||||
});
|
||||
|
||||
const list = await build().list();
|
||||
const matches = list.filter((w) => w.root === root);
|
||||
expect(matches).toHaveLength(1);
|
||||
expect(matches[0]?.id).toBe(canonicalId);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue