less resets
This commit is contained in:
+52
-50
@@ -53,11 +53,7 @@ interface VMContext {
|
|||||||
}) => Promise<string>
|
}) => Promise<string>
|
||||||
getLocatorStringForElement: (element: any) => Promise<string>
|
getLocatorStringForElement: (element: any) => Promise<string>
|
||||||
resetPlaywright: () => Promise<{ page: Page; context: BrowserContext }>
|
resetPlaywright: () => Promise<{ page: Page; context: BrowserContext }>
|
||||||
getLatestLogs: (options?: {
|
getLatestLogs: (options?: { page?: Page; count?: number; searchFilter?: string | RegExp }) => Promise<string[]>
|
||||||
page?: Page
|
|
||||||
count?: number
|
|
||||||
searchFilter?: string | RegExp
|
|
||||||
}) => Promise<string[]>
|
|
||||||
clearAllLogs: () => void
|
clearAllLogs: () => void
|
||||||
require: NodeRequire
|
require: NodeRequire
|
||||||
import: (specifier: string) => Promise<any>
|
import: (specifier: string) => Promise<any>
|
||||||
@@ -110,7 +106,7 @@ async function sendLogToRelayServer(level: string, ...args: any[]) {
|
|||||||
async function isPortTaken(port: number): Promise<boolean> {
|
async function isPortTaken(port: number): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`http://localhost:${port}/`, {
|
const response = await fetch(`http://localhost:${port}/`, {
|
||||||
signal: AbortSignal.timeout(100)
|
signal: AbortSignal.timeout(100),
|
||||||
})
|
})
|
||||||
return response.ok
|
return response.ok
|
||||||
} catch {
|
} catch {
|
||||||
@@ -173,7 +169,7 @@ async function ensureConnection(): Promise<{ browser: Browser; page: Page }> {
|
|||||||
const page = pages[0]
|
const page = pages[0]
|
||||||
|
|
||||||
// Set up console listener for all existing pages
|
// Set up console listener for all existing pages
|
||||||
context.pages().forEach(p => setupPageConsoleListener(p))
|
context.pages().forEach((p) => setupPageConsoleListener(p))
|
||||||
|
|
||||||
state.browser = browser
|
state.browser = browser
|
||||||
state.page = page
|
state.page = page
|
||||||
@@ -261,7 +257,7 @@ async function getCurrentPage(timeout = 5000) {
|
|||||||
|
|
||||||
if (pages.length > 0) {
|
if (pages.length > 0) {
|
||||||
const page = pages[0]
|
const page = pages[0]
|
||||||
page.waitForEvent('load', {timeout})
|
page.waitForEvent('load', { timeout })
|
||||||
await page.emulateMedia({ colorScheme: null })
|
await page.emulateMedia({ colorScheme: null })
|
||||||
return page
|
return page
|
||||||
}
|
}
|
||||||
@@ -306,7 +302,7 @@ async function resetConnection(): Promise<{ browser: Browser; page: Page; contex
|
|||||||
const page = pages[0]
|
const page = pages[0]
|
||||||
|
|
||||||
// Set up console listener for all existing pages
|
// Set up console listener for all existing pages
|
||||||
context.pages().forEach(p => setupPageConsoleListener(p))
|
context.pages().forEach((p) => setupPageConsoleListener(p))
|
||||||
|
|
||||||
state.browser = browser
|
state.browser = browser
|
||||||
state.page = page
|
state.page = page
|
||||||
@@ -372,10 +368,7 @@ server.tool(
|
|||||||
const { page: targetPage, searchString, contextLines = 10 } = options
|
const { page: targetPage, searchString, contextLines = 10 } = options
|
||||||
if ((targetPage as any)._snapshotForAI) {
|
if ((targetPage as any)._snapshotForAI) {
|
||||||
const snapshot = await (targetPage as any)._snapshotForAI()
|
const snapshot = await (targetPage as any)._snapshotForAI()
|
||||||
const snapshotStr =
|
const snapshotStr = typeof snapshot === 'string' ? snapshot : JSON.stringify(snapshot, null, 2)
|
||||||
typeof snapshot === 'string'
|
|
||||||
? snapshot
|
|
||||||
: JSON.stringify(snapshot, null, 2)
|
|
||||||
|
|
||||||
if (!searchString) {
|
if (!searchString) {
|
||||||
return snapshotStr
|
return snapshotStr
|
||||||
@@ -416,9 +409,7 @@ server.tool(
|
|||||||
|
|
||||||
const getLocatorStringForElement = async (element: any) => {
|
const getLocatorStringForElement = async (element: any) => {
|
||||||
if (!element || typeof element.evaluate !== 'function') {
|
if (!element || typeof element.evaluate !== 'function') {
|
||||||
throw new Error(
|
throw new Error('getLocatorStringForElement: argument must be a Playwright Locator or ElementHandle')
|
||||||
'getLocatorStringForElement: argument must be a Playwright Locator or ElementHandle',
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return await element.evaluate(async (el: any) => {
|
return await element.evaluate(async (el: any) => {
|
||||||
@@ -433,19 +424,14 @@ server.tool(
|
|||||||
toLocator: module.toLocator,
|
toLocator: module.toLocator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const { createSelectorGenerator, toLocator } =
|
const { createSelectorGenerator, toLocator } = WIN.__selectorGenerator as SelectorGenerator
|
||||||
WIN.__selectorGenerator as SelectorGenerator
|
|
||||||
const generator = createSelectorGenerator(WIN)
|
const generator = createSelectorGenerator(WIN)
|
||||||
const result = generator(el)
|
const result = generator(el)
|
||||||
return toLocator(result.selector, 'javascript')
|
return toLocator(result.selector, 'javascript')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const getLatestLogs = async (options?: {
|
const getLatestLogs = async (options?: { page?: Page; count?: number; searchFilter?: string | RegExp }) => {
|
||||||
page?: Page
|
|
||||||
count?: number
|
|
||||||
searchFilter?: string | RegExp
|
|
||||||
}) => {
|
|
||||||
const { page: filterPage, count, searchFilter } = options || {}
|
const { page: filterPage, count, searchFilter } = options || {}
|
||||||
|
|
||||||
let allLogs: string[] = []
|
let allLogs: string[] = []
|
||||||
@@ -464,7 +450,7 @@ server.tool(
|
|||||||
|
|
||||||
// Filter by search string or regex
|
// Filter by search string or regex
|
||||||
if (searchFilter) {
|
if (searchFilter) {
|
||||||
allLogs = allLogs.filter(log => {
|
allLogs = allLogs.filter((log) => {
|
||||||
if (typeof searchFilter === 'string') {
|
if (typeof searchFilter === 'string') {
|
||||||
return log.includes(searchFilter)
|
return log.includes(searchFilter)
|
||||||
} else if (searchFilter instanceof RegExp) {
|
} else if (searchFilter instanceof RegExp) {
|
||||||
@@ -506,15 +492,15 @@ server.tool(
|
|||||||
resetPlaywright: vmContextObj.resetPlaywright,
|
resetPlaywright: vmContextObj.resetPlaywright,
|
||||||
require,
|
require,
|
||||||
import: vmContextObj.import,
|
import: vmContextObj.import,
|
||||||
...usefulGlobals
|
...usefulGlobals,
|
||||||
}
|
}
|
||||||
Object.keys(vmContextObj).forEach(key => delete (vmContextObj as any)[key])
|
Object.keys(vmContextObj).forEach((key) => delete (vmContextObj as any)[key])
|
||||||
Object.assign(vmContextObj, resetObj)
|
Object.assign(vmContextObj, resetObj)
|
||||||
return { page: newPage, context: newContext }
|
return { page: newPage, context: newContext }
|
||||||
},
|
},
|
||||||
require,
|
require,
|
||||||
import: (specifier: string) => import(specifier),
|
import: (specifier: string) => import(specifier),
|
||||||
...usefulGlobals
|
...usefulGlobals,
|
||||||
}
|
}
|
||||||
|
|
||||||
const vmContext = vm.createContext(vmContextObj)
|
const vmContext = vm.createContext(vmContextObj)
|
||||||
@@ -563,7 +549,9 @@ server.tool(
|
|||||||
const MAX_LENGTH = 6000
|
const MAX_LENGTH = 6000
|
||||||
let finalText = responseText.trim()
|
let finalText = responseText.trim()
|
||||||
if (finalText.length > MAX_LENGTH) {
|
if (finalText.length > MAX_LENGTH) {
|
||||||
finalText = finalText.slice(0, MAX_LENGTH) + `\n\n[Truncated to ${MAX_LENGTH} characters. Better manage your logs or paginate them to read the full logs]`
|
finalText =
|
||||||
|
finalText.slice(0, MAX_LENGTH) +
|
||||||
|
`\n\n[Truncated to ${MAX_LENGTH} characters. Better manage your logs or paginate them to read the full logs]`
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -577,30 +565,44 @@ server.tool(
|
|||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
const errorStack = error.stack || error.message
|
const errorStack = error.stack || error.message
|
||||||
console.error('Error in execute tool, attempting reset:', errorStack)
|
console.error('Error in execute tool, attempting reset:', errorStack)
|
||||||
await sendLogToRelayServer('error', '[MCP] CRITICAL ERROR - Connection reset triggered:', errorStack)
|
if (error.message.includes('duplicate target')) {
|
||||||
|
await sendLogToRelayServer('error', '[MCP] CRITICAL ERROR - Connection reset triggered:', errorStack)
|
||||||
try {
|
try {
|
||||||
await resetConnection()
|
await resetConnection()
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: 'text',
|
||||||
text: `Connection was reset due to error. Please retry your command.\n\nError: ${error.message}`,
|
text: `Connection was reset due to error. Please retry your command.\n\nError: ${error.message}`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
} catch (resetError: any) {
|
} catch (resetError: any) {
|
||||||
await sendLogToRelayServer('error', '[MCP] CRITICAL ERROR - Reset failed:', resetError.stack || resetError.message)
|
await sendLogToRelayServer(
|
||||||
return {
|
'error',
|
||||||
content: [
|
'[MCP] CRITICAL ERROR - Reset failed:',
|
||||||
{
|
resetError.stack || resetError.message,
|
||||||
type: 'text',
|
)
|
||||||
text: `Error executing code: ${error.message}\n${errorStack}`,
|
return {
|
||||||
},
|
content: [
|
||||||
],
|
{
|
||||||
isError: true,
|
type: 'text',
|
||||||
|
text: `Error executing code: ${error.message}\n${errorStack}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: `Error executing code: ${error.message}\n${errorStack}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isError: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user