MCPcopy Create free account
hub / github.com/MoonshotAI/kimi-code / mergeWorkspaces

Function mergeWorkspaces

apps/kimi-web/src/lib/mergeWorkspaces.ts:41–119  ·  view source on GitHub ↗
(input: MergeWorkspacesInput)

Source from the content-addressed store, hash-verified

39 * derived workspace (id = root = cwd). Real workspaces win on root.
40 */
41export function mergeWorkspaces(input: MergeWorkspacesInput): AppWorkspace[] {
42 const {
43 workspaces,
44 sessions,
45 hiddenWorkspaceRoots,
46 activeRoot,
47 activeBranch,
48 sessionsHasMoreByWorkspace,
49 } = input;
50
51 const hidden = new Set(hiddenWorkspaceRoots);
52 const byRoot = new Map<string, AppWorkspace>();
53 // Real workspaces win on root (unless the user removed them from the sidebar).
54 // Keep the FIRST entry per root: the daemon orders by last_opened_at desc, so
55 // the most recently opened (typically the canonical re-add) comes first. This
56 // must match `workspaceIdForSession` / the sidebar's first-match session
57 // assignment — if byRoot kept a different id than sessions are counted and
58 // grouped under, the only rendered workspace would look empty.
59 for (const w of workspaces) {
60 if (hidden.has(w.root)) continue;
61 if (!byRoot.has(w.root)) byRoot.set(w.root, { ...w });
62 }
63 // Derive from sessions for any cwd without a real workspace.
64 for (const s of sessions) {
65 const root = s.cwd;
66 if (!root) continue;
67 if (hidden.has(root)) continue; // removed from the sidebar — keep it hidden
68 if (!byRoot.has(root)) {
69 byRoot.set(root, {
70 // Use the session's REAL daemon workspace_id (wd_<slug>_<hash>) so
71 // createSession({ workspaceId }) is accepted; fall back to cwd only
72 // when the daemon hasn't tagged the session yet.
73 id: s.workspaceId ?? root,
74 root,
75 name: basename(root),
76 isGitRepo: false,
77 sessionCount: 0,
78 });
79 }
80 }
81 // Compute live session counts.
82 const counts = new Map<string, number>();
83 for (const s of sessions) {
84 const wid = workspaceIdForSession(workspaces, s);
85 counts.set(wid, (counts.get(wid) ?? 0) + 1);
86 }
87
88 // Order: real workspaces in listWorkspaces order, then derived workspaces
89 // sorted by root path so the order is stable (not tied to session activity).
90 // Hidden roots must be excluded here too — `byRoot` skips them, so a hidden
91 // real workspace would otherwise make `byRoot.get(root)` return undefined.
92 //
93 // Dedup by root: the registry can legitimately hold two entries for the same
94 // folder (e.g. a legacy id from an older encodeWorkDirKey plus the current
95 // one). `byRoot` already collapses them, but a duplicated root in the
96 // ordering list would render the same workspace twice — and because both
97 // copies share an id, selecting one would highlight both.
98 const realRoots = [...new Set(workspaces.filter((w) => !hidden.has(w.root)).map((w) => w.root))];

Callers 2

Calls 7

basenameFunction · 0.90
keysMethod · 0.80
workspaceIdForSessionFunction · 0.70
hasMethod · 0.65
setMethod · 0.65
getMethod · 0.65
pushMethod · 0.45

Tested by

no test coverage detected