refactor(bridge): migrate gravity bridge to pure websocket gateway architecture, deleting legacy local file scanners and dependencies
This commit is contained in:
96
extension/src/brain-watcher.ts
Normal file
96
extension/src/brain-watcher.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
import { WSBridgeClient } from './ws-client';
|
||||
|
||||
export interface BrainWatcherContext {
|
||||
logToFile: (msg: string) => void;
|
||||
wsBridge: WSBridgeClient;
|
||||
projectName: string;
|
||||
}
|
||||
|
||||
export class BrainWatcher {
|
||||
private brainDir: string;
|
||||
private ctx: BrainWatcherContext;
|
||||
private currentSessionId: string = '';
|
||||
private watcher: fs.FSWatcher | null = null;
|
||||
private lastEventTimes: Map<string, number> = new Map();
|
||||
|
||||
constructor(ctx: BrainWatcherContext) {
|
||||
this.ctx = ctx;
|
||||
// The bridgePath is ~/.gemini/antigravity/bridge, so brain is sibling
|
||||
this.brainDir = path.join(os.homedir(), '.gemini', 'antigravity', 'brain');
|
||||
}
|
||||
|
||||
public updateSession(sessionId: string) {
|
||||
if (!sessionId || this.currentSessionId === sessionId) {
|
||||
return;
|
||||
}
|
||||
this.currentSessionId = sessionId;
|
||||
this.startWatching(sessionId);
|
||||
}
|
||||
|
||||
private startWatching(sessionId: string) {
|
||||
this.stop();
|
||||
|
||||
const sessionDir = path.join(this.brainDir, sessionId);
|
||||
if (!fs.existsSync(sessionDir)) {
|
||||
// It might not be created yet, poll gently
|
||||
setTimeout(() => this.startWatching(sessionId), 2000);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.watcher = fs.watch(sessionDir, { persistent: false }, (eventType, filename) => {
|
||||
if (!filename || !filename.endsWith('.md')) return;
|
||||
|
||||
// Dedup rapid events
|
||||
const now = Date.now();
|
||||
const last = this.lastEventTimes.get(filename) || 0;
|
||||
if (now - last < 500) return; // 500ms debounce
|
||||
this.lastEventTimes.set(filename, now);
|
||||
|
||||
this.handleFileChange(sessionDir, filename, eventType);
|
||||
});
|
||||
this.ctx.logToFile(`[BRAIN-WATCHER] Started watching session: ${sessionId.substring(0, 8)}`);
|
||||
} catch (e: any) {
|
||||
this.ctx.logToFile(`[BRAIN-WATCHER] Failed to watch ${sessionId}: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
private handleFileChange(dir: string, filename: string, rawEventType: string) {
|
||||
const filePath = path.join(dir, filename);
|
||||
let content = '';
|
||||
let eventType = 'file_changed';
|
||||
|
||||
try {
|
||||
if (fs.existsSync(filePath)) {
|
||||
content = fs.readFileSync(filePath, 'utf-8');
|
||||
} else {
|
||||
eventType = 'file_deleted';
|
||||
}
|
||||
} catch (e) {
|
||||
// File might be locked or deleted during read
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.ctx.wsBridge && this.ctx.wsBridge.isConnected()) {
|
||||
this.ctx.wsBridge.sendBrainEvent({
|
||||
event_type: eventType,
|
||||
conversation_id: this.currentSessionId,
|
||||
file_name: filename,
|
||||
content: content,
|
||||
timestamp: Date.now() / 1000,
|
||||
project_name: this.ctx.projectName,
|
||||
});
|
||||
this.ctx.logToFile(`[BRAIN-WATCHER] Sent ${eventType} for ${filename}`);
|
||||
}
|
||||
}
|
||||
|
||||
public stop() {
|
||||
if (this.watcher) {
|
||||
this.watcher.close();
|
||||
this.watcher = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user