diff --git a/src/PixelAgentsViewProvider.ts b/src/PixelAgentsViewProvider.ts index 3cc0c459..14f05cee 100644 --- a/src/PixelAgentsViewProvider.ts +++ b/src/PixelAgentsViewProvider.ts @@ -160,6 +160,34 @@ export class PixelAgentsViewProvider implements vscode.WebviewViewProvider { this.persistAgents, ); + // In multi-root workspaces, also scan project dirs for all other folders + // so agents running in any workspace folder are discovered + const wsFolders = vscode.workspace.workspaceFolders; + if (wsFolders && wsFolders.length > 1) { + for (const folder of wsFolders) { + const folderProjectDir = getProjectDirPath(folder.uri.fsPath); + if (folderProjectDir && folderProjectDir !== projectDir) { + console.log( + `[Pixel Agents] Registering additional project dir: ${folderProjectDir}`, + ); + ensureProjectScan( + folderProjectDir, + this.knownJsonlFiles, + this.projectScanTimer, + this.activeAgentId, + this.nextAgentId, + this.agents, + this.fileWatchers, + this.pollingTimers, + this.waitingTimers, + this.permissionTimers, + this.webview, + this.persistAgents, + ); + } + } + } + // Load furniture assets BEFORE sending layout (async () => { try { diff --git a/src/fileWatcher.ts b/src/fileWatcher.ts index f2a60dfd..b233feaf 100644 --- a/src/fileWatcher.ts +++ b/src/fileWatcher.ts @@ -95,6 +95,14 @@ export function readNewLines( } } +// Track all project directories to scan (supports multi-root workspaces) +const trackedProjectDirs = new Set(); + +/** + * Seed a project directory's known files and register it for periodic scanning. + * Can be called multiple times with different directories — all will be scanned + * by the single shared interval timer. + */ export function ensureProjectScan( projectDir: string, knownJsonlFiles: Set, @@ -109,34 +117,55 @@ export function ensureProjectScan( webview: vscode.Webview | undefined, persistAgents: () => void, ): void { - if (projectScanTimerRef.current) return; - // Seed with all existing JSONL files so we only react to truly new ones + // Always seed this directory's existing JSONL files (even if timer is already running) + // so we only react to truly new ones. Skip recently active files (large + recently + // modified) so they can still be picked up by terminal scanning during the current session. try { + const now = Date.now(); const files = fs .readdirSync(projectDir) .filter((f) => f.endsWith('.jsonl')) .map((f) => path.join(projectDir, f)); for (const f of files) { + try { + const stat = fs.statSync(f); + const isRecentlyActive = now - stat.mtimeMs < 600_000 && stat.size >= 3000; + if (isRecentlyActive) { + console.log( + `[Pixel Agents] Skipping pre-register of active JSONL: ${path.basename(f)}`, + ); + continue; + } + } catch { + /* stat failed — pre-register to be safe */ + } knownJsonlFiles.add(f); } } catch { /* dir may not exist yet */ } + // Register for periodic scanning + trackedProjectDirs.add(projectDir); + + // Start the shared timer only once + if (projectScanTimerRef.current) return; projectScanTimerRef.current = setInterval(() => { - scanForNewJsonlFiles( - projectDir, - knownJsonlFiles, - activeAgentIdRef, - nextAgentIdRef, - agents, - fileWatchers, - pollingTimers, - waitingTimers, - permissionTimers, - webview, - persistAgents, - ); + for (const dir of trackedProjectDirs) { + scanForNewJsonlFiles( + dir, + knownJsonlFiles, + activeAgentIdRef, + nextAgentIdRef, + agents, + fileWatchers, + pollingTimers, + waitingTimers, + permissionTimers, + webview, + persistAgents, + ); + } }, PROJECT_SCAN_INTERVAL_MS); } @@ -183,19 +212,19 @@ function scanForNewJsonlFiles( persistAgents, ); } else { - // No active agent → try to adopt the focused terminal - const activeTerminal = vscode.window.activeTerminal; - if (activeTerminal) { + // No active agent → scan all terminals (not just the focused one) + // to find an untracked Claude terminal that may own this JSONL file + for (const terminal of vscode.window.terminals) { let owned = false; for (const agent of agents.values()) { - if (agent.terminalRef === activeTerminal) { + if (agent.terminalRef === terminal) { owned = true; break; } } if (!owned) { adoptTerminalForFile( - activeTerminal, + terminal, file, projectDir, nextAgentIdRef, @@ -208,6 +237,7 @@ function scanForNewJsonlFiles( webview, persistAgents, ); + break; } } }