fix CLI relay server startup and extension reconnection
- detect source vs compiled via __filename.endsWith('.ts') instead of env var
- add waitForExtension() to poll for extension connection after server start
- CLI waits up to 10s for extension to reconnect before executing commands
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { cac } from '@xmorse/cac'
|
import { cac } from '@xmorse/cac'
|
||||||
import { VERSION, LOG_FILE_PATH } from './utils.js'
|
import { VERSION, LOG_FILE_PATH } from './utils.js'
|
||||||
import { ensureRelayServer, RELAY_PORT } from './relay-client.js'
|
import { ensureRelayServer, RELAY_PORT, waitForExtension } from './relay-client.js'
|
||||||
|
|
||||||
const cliRelayEnv = { PLAYWRITER_AUTO_ENABLE: '1' }
|
const cliRelayEnv = { PLAYWRITER_AUTO_ENABLE: '1' }
|
||||||
|
|
||||||
@@ -57,6 +57,11 @@ async function executeCode(options: {
|
|||||||
// Ensure relay server is running (only for local)
|
// Ensure relay server is running (only for local)
|
||||||
if (!host && !process.env.PLAYWRITER_HOST) {
|
if (!host && !process.env.PLAYWRITER_HOST) {
|
||||||
await ensureRelayServer({ logger: console, env: cliRelayEnv })
|
await ensureRelayServer({ logger: console, env: cliRelayEnv })
|
||||||
|
// Wait for extension to reconnect after server (re)start
|
||||||
|
const connected = await waitForExtension({ logger: console, timeoutMs: 10000 })
|
||||||
|
if (!connected) {
|
||||||
|
console.error('Warning: Extension not connected. Commands may fail.')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Session is required
|
// Session is required
|
||||||
|
|||||||
@@ -29,6 +29,47 @@ export async function getRelayServerVersion(port: number = RELAY_PORT): Promise<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getExtensionStatus(port: number = RELAY_PORT): Promise<{ connected: boolean; activeTargets: number } | null> {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`http://127.0.0.1:${port}/extension/status`, {
|
||||||
|
signal: AbortSignal.timeout(500),
|
||||||
|
})
|
||||||
|
if (!response.ok) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return await response.json() as { connected: boolean; activeTargets: number }
|
||||||
|
} catch {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for the extension to connect to the relay server.
|
||||||
|
* Returns true if connected within timeout, false otherwise.
|
||||||
|
*/
|
||||||
|
export async function waitForExtension(options: {
|
||||||
|
port?: number
|
||||||
|
timeoutMs?: number
|
||||||
|
logger?: { log: (...args: any[]) => void }
|
||||||
|
} = {}): Promise<boolean> {
|
||||||
|
const { port = RELAY_PORT, timeoutMs = 5000, logger } = options
|
||||||
|
const startTime = Date.now()
|
||||||
|
|
||||||
|
logger?.log('Waiting for extension to connect...')
|
||||||
|
|
||||||
|
while (Date.now() - startTime < timeoutMs) {
|
||||||
|
const status = await getExtensionStatus(port)
|
||||||
|
if (status?.connected) {
|
||||||
|
logger?.log('Extension connected')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
await sleep(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger?.log('Extension did not connect within timeout')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
async function killRelayServer(port: number): Promise<void> {
|
async function killRelayServer(port: number): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await killPortProcess(port)
|
await killPortProcess(port)
|
||||||
@@ -95,12 +136,14 @@ export async function ensureRelayServer(options: EnsureRelayServerOptions = {}):
|
|||||||
logger?.log('CDP relay server not running, starting it...')
|
logger?.log('CDP relay server not running, starting it...')
|
||||||
}
|
}
|
||||||
|
|
||||||
const dev = process.env.PLAYWRITER_NODE_ENV === 'development'
|
// Detect if we're running from source (.ts) or compiled (.js)
|
||||||
const scriptPath = dev
|
// This handles: tsx, vite-node, ts-node, or direct node on compiled output
|
||||||
? path.resolve(__dirname, '../src/start-relay-server.ts')
|
const isRunningFromSource = __filename.endsWith('.ts')
|
||||||
|
const scriptPath = isRunningFromSource
|
||||||
|
? path.resolve(__dirname, './start-relay-server.ts')
|
||||||
: path.resolve(__dirname, './start-relay-server.js')
|
: path.resolve(__dirname, './start-relay-server.js')
|
||||||
|
|
||||||
const serverProcess = spawn(dev ? 'tsx' : process.execPath, [scriptPath], {
|
const serverProcess = spawn(isRunningFromSource ? 'tsx' : process.execPath, [scriptPath], {
|
||||||
detached: true,
|
detached: true,
|
||||||
stdio: 'ignore',
|
stdio: 'ignore',
|
||||||
env: { ...process.env, ...additionalEnv },
|
env: { ...process.env, ...additionalEnv },
|
||||||
@@ -108,14 +151,19 @@ export async function ensureRelayServer(options: EnsureRelayServerOptions = {}):
|
|||||||
|
|
||||||
serverProcess.unref()
|
serverProcess.unref()
|
||||||
|
|
||||||
|
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
await sleep(500)
|
await sleep(500)
|
||||||
const newVersion = await getRelayServerVersion(RELAY_PORT)
|
const newVersion = await getRelayServerVersion(RELAY_PORT)
|
||||||
if (newVersion) {
|
if (newVersion) {
|
||||||
logger?.log('CDP relay server started successfully')
|
logger?.log('CDP relay server started successfully')
|
||||||
|
await sleep(1000)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
throw new Error(`Failed to start CDP relay server after 5 seconds. Check logs at: ${LOG_FILE_PATH}`)
|
throw new Error(`Failed to start CDP relay server after 5 seconds. Check logs at: ${LOG_FILE_PATH}`)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user