fix about:blank gray icon and add auto-recovery after extension replacement

This commit is contained in:
Tommy D. Rossi
2025-12-22 19:29:25 +01:00
parent b8b2b468d2
commit 150ad47307
6 changed files with 41 additions and 3 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Playwriter MCP",
"version": "0.0.54",
"version": "0.0.55",
"description": "Automate your Browser using Cursor, Claude, VS Code. More capable and context efficient than Playwright MCP.",
"permissions": ["debugger", "tabGroups"],
"host_permissions": ["<all_urls>"],
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "mcp-extension",
"version": "0.0.54",
"version": "0.0.55",
"description": "Playwright MCP Browser Extension",
"private": true,
"repository": {
+27
View File
@@ -14,6 +14,7 @@ let childSessions: Map<string, number> = new Map()
let nextSessionId = 1
let playwriterGroupId: number | null = null
let syncTabGroupQueue: Promise<void> = Promise.resolve()
let replacedRetryInterval: ReturnType<typeof setInterval> | null = null
const store = createStore<ExtensionState>(() => ({
tabs: new Map(),
@@ -450,6 +451,31 @@ function closeConnection(reason: string): void {
}
}
function startReplacedRetryLoop(): void {
if (replacedRetryInterval) return
logger.debug('Starting replaced retry loop (every 3 seconds)')
replacedRetryInterval = setInterval(async () => {
if (ws?.readyState === WebSocket.OPEN || store.getState().connectionState !== 'error') {
clearInterval(replacedRetryInterval!)
replacedRetryInterval = null
logger.debug('Stopped replaced retry loop')
return
}
try {
const response = await fetch('http://localhost:19988/extension/status')
const data = await response.json()
if (!data.connected) {
store.setState({ connectionState: 'disconnected', errorText: undefined })
logger.debug('Extension slot is free, cleared error state')
} else {
logger.debug('Extension slot still taken, will retry...')
}
} catch {
logger.debug('Server not available, will retry...')
}
}, 3000)
}
function handleConnectionClose(reason: string, code: number): void {
logger.debug('Connection closed:', { reason, code })
@@ -474,6 +500,7 @@ function handleConnectionClose(reason: string, code: number): void {
connectionState: 'error',
errorText: 'Disconnected: Replaced by another extension',
})
startReplacedRetryLoop()
return
}
+7
View File
@@ -1,5 +1,12 @@
# Changelog
## 0.0.27
### Patch Changes
- **Fixed gray icon on about:blank pages**: `about:blank` pages now show the black (clickable) icon instead of gray (restricted). Chrome returns `undefined` for `tab.url` on blank pages, which was incorrectly treated as restricted.
- **Auto-recovery after extension replacement**: When another extension instance takes over the connection, the replaced extension now polls `/extension/status` every 3 seconds. When the slot becomes free, it clears the error state so the user can click to reconnect.
## 0.0.26
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "playwriter",
"description": "",
"version": "0.0.26",
"version": "0.0.27",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
+4
View File
@@ -281,6 +281,10 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
return c.json({ version: VERSION })
})
app.get('/extension/status', (c) => {
return c.json({ connected: extensionWs !== null })
})
app.post('/mcp-log', async (c) => {
try {
const { level, args } = await c.req.json()