feat(ext): handcraft the whole ext from scratch

AI coding doesn't work for MV3 extensions.
Threading was an unfixable mess.
Removed everything and rebuilt by hand.
This commit is contained in:
Simon
2026-01-27 17:21:32 +08:00
parent 8efa8e18c1
commit fdc3cf4e6d
18 changed files with 797 additions and 1749 deletions

View File

@@ -1,114 +1,44 @@
/**
* Background Script (Service Worker) - Stateless Message Relay
*
* Completely stateless. Only two responsibilities:
* 1. Relay AGENT_TO_PAGE messages from SidePanel to ContentScript
* 2. Broadcast TAB_CHANGE events to all extension pages
*/
import {
type AgentToPageMessage,
type TabChangeMessage,
isExtensionMessage,
} from '../agent/protocol'
import { handlePageControlMessage } from '@/agent/RemotePageController.background'
import { handleTabControlMessage } from '@/agent/TabsController.background'
// ============================================================================
// Message Relay
// ============================================================================
function handleUtilsMessage(
message: { type: 'UTILS'; action: string; payload: any },
sender: chrome.runtime.MessageSender,
sendResponse: (response: unknown) => void
): boolean {
const { action, payload } = message
chrome.runtime.onMessage.addListener(
(
message: unknown,
_sender: chrome.runtime.MessageSender,
sendResponse: (response?: unknown) => void
): boolean => {
if (!isExtensionMessage(message)) {
switch (action) {
case 'get_tab_info': {
chrome.tabs
.get(payload.tabId)
.then((tab) => {
const result = { title: tab.title || '', url: tab.url || '' }
sendResponse(result)
})
.catch((error) => {
sendResponse({ error: error instanceof Error ? error.message : String(error) })
})
return true // async response
}
default:
sendResponse({ error: `Unknown TAB_CONTROL action: ${action}` })
return false
}
if (message.type === 'AGENT_TO_PAGE') {
handleAgentToPage(message as AgentToPageMessage, sendResponse)
return true // Async response
}
}
}
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'TAB_CONTROL') {
return handleTabControlMessage(message, sender, sendResponse)
} else if (message.type === 'PAGE_CONTROL') {
return handlePageControlMessage(message, sender, sendResponse)
} else if (message.type !== 'UTILS') {
return handleUtilsMessage(message, sender, sendResponse)
} else {
sendResponse({ error: 'Unknown message type' })
return false
}
)
/**
* Forward RPC call from SidePanel to ContentScript
*/
async function handleAgentToPage(
msg: AgentToPageMessage,
sendResponse: (response: { success: boolean; result?: unknown; error?: string }) => void
): Promise<void> {
const { tabId, method, args } = msg
try {
// Forward directly to content script, same message format
const result = await chrome.tabs.sendMessage(tabId, msg)
sendResponse({ success: true, result })
} catch (error) {
sendResponse({
success: false,
error: error instanceof Error ? error.message : String(error),
})
}
}
// ============================================================================
// Tab Event Broadcasting
// ============================================================================
function broadcastTabChange(message: TabChangeMessage): void {
chrome.runtime.sendMessage(message).catch(() => {
// No listeners (sidepanel not open)
})
}
chrome.tabs.onRemoved.addListener((tabId) => {
broadcastTabChange({
type: 'TAB_CHANGE',
eventType: 'removed',
tabId,
})
})
chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
if (!changeInfo.status) return
broadcastTabChange({
type: 'TAB_CHANGE',
eventType: 'updated',
tabId,
data: {
status: changeInfo.status,
url: changeInfo.url,
},
})
})
chrome.tabs.onActivated.addListener((activeInfo) => {
broadcastTabChange({
type: 'TAB_CHANGE',
eventType: 'activated',
tabId: activeInfo.tabId,
data: {
windowId: activeInfo.windowId,
},
})
})
chrome.windows.onFocusChanged.addListener((windowId) => {
const focused = windowId !== chrome.windows.WINDOW_ID_NONE
broadcastTabChange({
type: 'TAB_CHANGE',
eventType: 'windowFocusChanged',
tabId: -1,
data: {
windowId: focused ? windowId : undefined,
focused,
},
})
})
// ============================================================================