Skip to content

Commit 9dbbd3d

Browse files
fix(vscode): use polling as primary watcher for network/FUSE filesystems
fs.watch silently fails on Gitpod, WSL, and Docker volume mounts without throwing — events only appear after a window reload. Switch to setInterval(500ms) for session detection and setInterval(300ms) for event tailing as the primary mechanism. fs.watch is kept as a best-effort secondary trigger where it works. Bumps to v0.1.2. Co-authored-by: Ona <no-reply@ona.com>
1 parent 75dffe4 commit 9dbbd3d

2 files changed

Lines changed: 37 additions & 32 deletions

File tree

vscode-extension/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "agent-strace",
33
"displayName": "agent-strace",
44
"description": "Live session overlay for agent-strace: status bar, gutter annotations, and event stream panel.",
5-
"version": "0.1.1",
5+
"version": "0.1.2",
66
"publisher": "Siddhant-K-code",
77
"license": "MIT",
88
"repository": {

vscode-extension/src/traceStore.ts

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ export class TraceWatcher extends vscode.Disposable {
114114

115115
private activeSessionWatcher: fs.FSWatcher | null = null;
116116
private eventsWatcher: fs.FSWatcher | null = null;
117-
private pollTimer: NodeJS.Timeout | null = null;
117+
private pollTimer: ReturnType<typeof setInterval> | null = null;
118118

119119
constructor(workspaceRoot: string, traceDir: string) {
120120
super(() => this.dispose());
@@ -140,23 +140,23 @@ export class TraceWatcher extends vscode.Disposable {
140140
// -------------------------------------------------------------------------
141141

142142
private _watchActiveSessionFile(): void {
143-
// Watch the parent directory so we catch creation of .active-session
144143
const dir = this.traceDir;
145-
if (!fs.existsSync(dir)) {
146-
// Retry when the directory appears
147-
this.pollTimer = setTimeout(() => this._watchActiveSessionFile(), 2000);
148-
return;
149-
}
150144

151-
try {
152-
this.activeSessionWatcher = fs.watch(dir, (_event, filename) => {
153-
if (filename === ".active-session") {
154-
this._checkActiveSession();
155-
}
156-
});
157-
} catch {
158-
// Fall back to polling if fs.watch fails (e.g. network FS)
159-
this.pollTimer = setInterval(() => this._checkActiveSession(), 1000);
145+
// Always use polling as primary — fs.watch silently fails on network/FUSE
146+
// filesystems (e.g. Gitpod, WSL, Docker volumes) without throwing.
147+
this.pollTimer = setInterval(() => this._checkActiveSession(), 500);
148+
149+
// Also try fs.watch as a faster secondary trigger (best-effort)
150+
if (fs.existsSync(dir)) {
151+
try {
152+
this.activeSessionWatcher = fs.watch(dir, (_event, filename) => {
153+
if (filename === ".active-session") {
154+
this._checkActiveSession();
155+
}
156+
});
157+
} catch {
158+
// polling already running, ignore
159+
}
160160
}
161161
}
162162

@@ -226,21 +226,26 @@ export class TraceWatcher extends vscode.Disposable {
226226

227227
private _watchEventsFile(sessionId: string): void {
228228
const eventsFile = path.join(this.traceDir, sessionId, "events.ndjson");
229-
if (!fs.existsSync(eventsFile)) { return; }
230229

231-
try {
232-
this.eventsWatcher = fs.watch(eventsFile, () => {
233-
this._readNewEvents();
234-
});
235-
} catch {
236-
// Polling fallback
237-
const timer = setInterval(() => {
238-
if (this.currentSessionId !== sessionId) {
239-
clearInterval(timer);
240-
return;
241-
}
242-
this._readNewEvents();
243-
}, 500);
230+
// Always poll — fs.watch silently fails on network/FUSE filesystems.
231+
// 300ms gives snappy updates without hammering the FS.
232+
const timer = setInterval(() => {
233+
if (this.currentSessionId !== sessionId) {
234+
clearInterval(timer);
235+
return;
236+
}
237+
this._readNewEvents();
238+
}, 300);
239+
240+
// Also try fs.watch as a faster secondary trigger (best-effort)
241+
if (fs.existsSync(eventsFile)) {
242+
try {
243+
this.eventsWatcher = fs.watch(eventsFile, () => {
244+
this._readNewEvents();
245+
});
246+
} catch {
247+
// polling already running, ignore
248+
}
244249
}
245250
}
246251

@@ -384,7 +389,7 @@ export class TraceWatcher extends vscode.Disposable {
384389
override dispose(): void {
385390
this.activeSessionWatcher?.close();
386391
this.eventsWatcher?.close();
387-
if (this.pollTimer) { clearTimeout(this.pollTimer); }
392+
if (this.pollTimer) { clearInterval(this.pollTimer); }
388393
this._onSessionStart.dispose();
389394
this._onSessionEnd.dispose();
390395
this._onEvent.dispose();

0 commit comments

Comments
 (0)