MCPcopy
hub / github.com/slopus/happy / GitStatusSync

Class GitStatusSync

packages/happy-app/sources/sync/gitStatusSync.ts:16–279  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

14
15
16export class GitStatusSync {
17 // Map project keys to sync instances
18 private projectSyncMap = new Map<string, InvalidateSync>();
19 // Map session IDs to project keys for cleanup
20 private sessionToProjectKey = new Map<string, string>();
21 // Debounce timers to coalesce rapid invalidations (e.g. new-message + update-session arriving together)
22 private debounceTimers = new Map<string, ReturnType<typeof setTimeout>>();
23
24 /**
25 * Get project key string for a session
26 */
27 private getProjectKeyForSession(sessionId: string): string | null {
28 const session = storage.getState().sessions[sessionId];
29 if (!session?.metadata?.machineId || !session?.metadata?.path) {
30 return null;
31 }
32 return `${session.metadata.machineId}:${session.metadata.path}`;
33 }
34
35 /**
36 * Get or create git status sync for a session (creates project-based sync)
37 */
38 getSync(sessionId: string): InvalidateSync {
39 const projectKey = this.getProjectKeyForSession(sessionId);
40 if (!projectKey) {
41 // Return a no-op sync if no valid project
42 return new InvalidateSync(async () => {});
43 }
44
45 // Map session to project key
46 this.sessionToProjectKey.set(sessionId, projectKey);
47
48 let sync = this.projectSyncMap.get(projectKey);
49 if (!sync) {
50 sync = new InvalidateSync(() => this.fetchGitStatusForProject(sessionId, projectKey));
51 this.projectSyncMap.set(projectKey, sync);
52 }
53 return sync;
54 }
55
56 /**
57 * Invalidate git status for a session (triggers refresh for the entire project).
58 * Debounces rapid calls (e.g. new-message + update-session arriving together)
59 * to avoid duplicate RPC round-trips.
60 */
61 invalidate(sessionId: string): void {
62 const projectKey = this.sessionToProjectKey.get(sessionId);
63 if (projectKey) {
64 const existing = this.debounceTimers.get(projectKey);
65 if (existing) clearTimeout(existing);
66
67 this.debounceTimers.set(projectKey, setTimeout(() => {
68 this.debounceTimers.delete(projectKey);
69 const sync = this.projectSyncMap.get(projectKey);
70 if (sync) {
71 sync.invalidate();
72 }
73 }, 300));

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected