diff --git a/extension/package.json b/extension/package.json index c134f48..228b803 100644 --- a/extension/package.json +++ b/extension/package.json @@ -2,7 +2,7 @@ "name": "gravity-bridge", "displayName": "Gravity Bridge", "description": "Antigravity ↔ Discord 브리지 연동 확장", - "version": "0.3.7", + "version": "0.3.8", "publisher": "variet", "engines": { "vscode": "^1.100.0" diff --git a/extension/src/extension.ts b/extension/src/extension.ts index 740fbe5..779d661 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -38,6 +38,7 @@ let sdk: any; let statusBar: vscode.StatusBarItem; let bridgePath: string; let projectName: string; +let workspaceUri: string = ''; // filesystem path of the workspace folder (for session filtering) let isActive = false; let deterministicPort = 0; // derived from projectName, consistent across restarts let watcher: fs.FSWatcher | null = null; @@ -1448,23 +1449,41 @@ function setupMonitor() { } // ── Filter to sessions owned by THIS window ── - // Each window claims sessions it sees first via writeRegistration(). - // Only process sessions registered to THIS projectName (or unclaimed ones). + // PRIMARY: Use trajectoryMetadata.workspaces URI to match sessions to this workspace. + // FALLBACK: Use bridge/register/ files for sessions without metadata. + // This prevents cross-window session grabbing when multiple AG instances run. let bestSession: any = null; let bestSessionId = ''; let bestModTime = ''; const regDir = path.join(bridgePath, 'register'); + const normalizedWorkspace = workspaceUri.replace(/\\/g, '/').toLowerCase(); for (const [sid, data] of Object.entries(allTraj.trajectorySummaries) as [string, any][]) { - // Check if this session is claimed by another project - const regFile = path.join(regDir, `${sid}.json`); - if (fs.existsSync(regFile)) { - try { - const reg = JSON.parse(fs.readFileSync(regFile, 'utf-8')); - if (reg.project_name && reg.project_name !== projectName) { - // Session belongs to another window — skip - continue; - } - } catch { } + // PRIMARY FILTER: Check workspace URI from trajectoryMetadata + const trajMeta = data.trajectoryMetadata; + if (trajMeta?.workspaces?.length > 0 && normalizedWorkspace) { + const sessionWorkspaceRaw = trajMeta.workspaces[0]?.workspaceFolderAbsoluteUri || ''; + // Convert file:///c:/Users/... URI to c:/Users/... path for comparison + const sessionWorkspace = sessionWorkspaceRaw + .replace(/^file:\/\/\//, '') + .replace(/%3A/gi, ':') + .replace(/\\/g, '/') + .toLowerCase(); + if (sessionWorkspace && !sessionWorkspace.includes(normalizedWorkspace) && !normalizedWorkspace.includes(sessionWorkspace)) { + // Session belongs to a different workspace — skip + continue; + } + } else { + // FALLBACK: Check registration file (for sessions without metadata) + const regFile = path.join(regDir, `${sid}.json`); + if (fs.existsSync(regFile)) { + try { + const reg = JSON.parse(fs.readFileSync(regFile, 'utf-8')); + if (reg.project_name && reg.project_name !== projectName) { + // Session belongs to another window — skip + continue; + } + } catch { } + } } const modTime = data.lastModifiedTime || ''; @@ -2669,7 +2688,10 @@ export async function activate(context: vscode.ExtensionContext) { // Project detection projectName = detectProjectName(); - console.log(`Gravity Bridge: project "${projectName}"`); + // Store workspace folder path for session filtering (prevents cross-window session grabbing) + const folders = vscode.workspace.workspaceFolders; + workspaceUri = folders && folders.length > 0 ? folders[0].uri.fsPath : ''; + console.log(`Gravity Bridge: project "${projectName}" workspace="${workspaceUri}"`); // Bridge path const config = vscode.workspace.getConfiguration('gravityBridge');