From aa1fc468757bf7fdac9dede8fa6b5035672b21f7 Mon Sep 17 00:00:00 2001 From: WJZ_P <110795301+WJZ-P@users.noreply.github.com> Date: Mon, 16 Mar 2026 01:40:49 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E6=B5=8F=E8=A7=88?= =?UTF-8?q?=E5=99=A8=E5=90=AF=E5=8A=A8=E9=94=99=E8=AF=AF=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=EF=BC=8Cdemo=20=E4=B8=AD=E6=96=B0=E5=A2=9E=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=B8=85=E7=90=86=E6=B5=8F=E8=A7=88=E5=99=A8=E8=BF=9B=E7=A8=8B?= =?UTF-8?q?=E9=87=8D=E8=AF=95=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/browser.js | 1 + src/demo.js | 59 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/browser.js b/src/browser.js index 0e832ee..e56f10f 100644 --- a/src/browser.js +++ b/src/browser.js @@ -398,6 +398,7 @@ export async function ensureBrowser(opts = {}) { // 大概率是用户数据目录被正在运行的浏览器锁住了 if (err.message?.includes('EPERM') || err.message?.includes('lock') || err.message?.includes('already')) { throw new Error( + `报错信息:${err.message}\n`+ `[browser] 无法启动浏览器,用户数据目录可能被占用:${userDataDir}\n` + `这通常是因为该浏览器正在运行且锁定了数据目录。\n\n` + `请选择以下任一方式解决:\n` + diff --git a/src/demo.js b/src/demo.js index 8692b5e..e00ce1f 100644 --- a/src/demo.js +++ b/src/demo.js @@ -14,13 +14,68 @@ * * 所有配置项见 .env,可直接编辑或通过命令行设环境变量。 */ +import { execSync } from 'node:child_process'; +import { platform } from 'node:os'; import { createGeminiSession, disconnect } from './index.js'; +// ── Demo 专用:杀掉所有 Chromium 系浏览器进程 ── +function killAllBrowserProcesses() { + const os = platform(); + const commands = os === 'win32' + ? [ + 'taskkill /F /IM msedge.exe /T', + 'taskkill /F /IM chrome.exe /T', + 'taskkill /F /IM chromium.exe /T', + ] + : [ + 'pkill -f msedge || true', + 'pkill -f chrome || true', + 'pkill -f chromium || true', + ]; + + for (const cmd of commands) { + try { + execSync(cmd, { stdio: 'ignore', timeout: 5000 }); + } catch { + // 进程不存在时会报错,忽略 + } + } + console.log('[demo] 已清理所有浏览器进程'); +} + +/** 异步等待 */ +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); + +/** + * 创建会话,如果因浏览器目录被锁而失败,自动杀掉全部浏览器进程后重试一次 + */ +async function createSessionWithRetry() { + try { + return await createGeminiSession(); + } catch (err) { + const msg = err.message || ''; + const isLocked = msg.includes('EPERM') || msg.includes('lock') || msg.includes('already'); + + if (!isLocked) throw err; + + console.warn( + `[demo] 浏览器数据目录被占用,正在清理所有浏览器进程后重试...\n` + + ` 原始错误:${msg}` + ); + + killAllBrowserProcesses(); + await sleep(2000); + + // 重试一次,还失败就直接抛出 + return await createGeminiSession(); + } +} + async function main() { console.log('=== Gemini Skill Demo ===\n'); - // 创建会话(配置自动从环境变量读取,也可以传 opts 覆盖) - const { ops } = await createGeminiSession(); + // 创建会话:自带杀进程重试逻辑 + const { ops } = await createSessionWithRetry(); try { // 1. 探测页面状态