diff --git a/package-lock.json b/package-lock.json index 2a4f8c7..a4df233 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11333,7 +11333,7 @@ }, "packages/extension": { "name": "@page-agent/ext", - "version": "0.1.0-beta.1", + "version": "0.1.0-b.2", "hasInstallScript": true, "dependencies": { "@page-agent/core": "1.0.0", diff --git a/packages/extension/package.json b/packages/extension/package.json index c363e82..a25a2c8 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/ext", "private": true, - "version": "0.1.0-beta.1", + "version": "0.1.0-b.2", "type": "module", "scripts": { "dev": "wxt", diff --git a/packages/extension/src/agent/TabsController.ts b/packages/extension/src/agent/TabsController.ts index fcbaeee..d889b79 100644 --- a/packages/extension/src/agent/TabsController.ts +++ b/packages/extension/src/agent/TabsController.ts @@ -3,7 +3,7 @@ * - live in the agent env (extension page or content script) * - no chrome apis. call sw for tab operations */ -export class TabsController { +export class TabsController extends EventTarget { currentTabId: number | null = null private tabs: TabMeta[] = [] @@ -38,6 +38,42 @@ export class TabsController { } await this.updateCurrentTabId(this.currentTabId) + + const tabChangeHandler = (message: any) => { + if (message.type !== 'TAB_CHANGE') + throw new Error(`[TabsController]: Invalid message type: ${message.type}`) + + if (message.action === 'created') { + const tab = message.payload.tab as chrome.tabs.Tab + if (tab.groupId === this.tabGroupId && tab.id != null) { + // Tab created in our controlled group + if (!this.tabs.find((t) => t.id === tab.id)) { + this.tabs.push({ id: tab.id, isInitial: false }) + } + this.switchToTab(tab.id) + } + } else if (message.action === 'removed') { + const { tabId } = message.payload as { tabId: number } + const targetTab = this.tabs.find((t) => t.id === tabId) + if (targetTab) { + this.tabs = this.tabs.filter((t) => t.id !== tabId) + if (this.currentTabId === tabId) { + const newCurrentTab = this.tabs[this.tabs.length - 1] || null + if (newCurrentTab) { + this.switchToTab(newCurrentTab.id) + } else { + this.updateCurrentTabId(null) + } + } + } + } + } + + chrome.runtime.onMessage.addListener(tabChangeHandler) + + this.addEventListener('dispose', () => { + chrome.runtime.onMessage.removeListener(tabChangeHandler) + }) } async openNewTab(url: string): Promise<{ success: boolean; tabId: number; message: string }> { @@ -194,6 +230,10 @@ export class TabsController { } return summaries.join('\n') } + + dispose() { + this.dispatchEvent(new Event('dispose')) + } } export type TabAction = diff --git a/packages/extension/src/entrypoints/background.ts b/packages/extension/src/entrypoints/background.ts index cf2d705..434d0f5 100644 --- a/packages/extension/src/entrypoints/background.ts +++ b/packages/extension/src/entrypoints/background.ts @@ -19,6 +19,8 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { export default defineBackground(() => { console.log('[Background] Service Worker started') + // generate user auth token + chrome.storage.local.get('PageAgentExtUserAuthToken').then((result) => { if (result.PageAgentExtUserAuthToken) return @@ -26,5 +28,21 @@ export default defineBackground(() => { chrome.storage.local.set({ PageAgentExtUserAuthToken: userAuthToken }) }) + // setup + chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true }).catch(() => {}) + + // Tab change events + + chrome.tabs.onCreated.addListener((tab) => { + chrome.runtime.sendMessage({ type: 'TAB_CHANGE', action: 'created', payload: { tab } }) + }) + + chrome.tabs.onRemoved.addListener((tabId, removeInfo) => { + chrome.runtime.sendMessage({ + type: 'TAB_CHANGE', + action: 'removed', + payload: { tabId, removeInfo }, + }) + }) })