(msg: { tabId?: number; url?: string; title?: string })
| 914 | } |
| 915 | |
| 916 | function handleTabSwitch(msg: { tabId?: number; url?: string; title?: string }): void { |
| 917 | const url = msg.url || ''; |
| 918 | if (!url || url.startsWith('chrome://') || url.startsWith('chrome-extension://')) return; |
| 919 | |
| 920 | const stateDir = path.dirname(STATE_FILE); |
| 921 | const ctxFile = path.join(stateDir, 'active-tab.json'); |
| 922 | const tmp = path.join(stateDir, `.tmp-tab-${process.pid}`); |
| 923 | try { |
| 924 | writeSecureFile(tmp, JSON.stringify({ |
| 925 | tabId: msg.tabId ?? null, |
| 926 | url, |
| 927 | title: msg.title ?? '', |
| 928 | })); |
| 929 | fs.renameSync(tmp, ctxFile); |
| 930 | } catch { |
| 931 | safeUnlink(tmp); |
| 932 | } |
| 933 | |
| 934 | // Best-effort sync to parent server so its activeTabId tracking matches. |
| 935 | // No await; this is fire-and-forget. |
| 936 | if (BROWSE_SERVER_PORT > 0) { |
| 937 | fetch(`http://127.0.0.1:${BROWSE_SERVER_PORT}/command`, { |
| 938 | method: 'POST', |
| 939 | headers: { |
| 940 | 'Content-Type': 'application/json', |
| 941 | 'Authorization': `Bearer ${readBrowseToken()}`, |
| 942 | }, |
| 943 | body: JSON.stringify({ |
| 944 | command: 'tab', |
| 945 | args: [String(msg.tabId ?? ''), '--no-focus'], |
| 946 | }), |
| 947 | }).catch(() => {}); |
| 948 | } |
| 949 | } |
| 950 | |
| 951 | function readBrowseToken(): string { |
| 952 | try { |
no test coverage detected