From b8cf1821543f21bf39b72364ea40acc45e4aee3a Mon Sep 17 00:00:00 2001 From: linshen <32978552+linshenkx@users.noreply.github.com> Date: Sun, 16 Nov 2025 13:25:09 +0800 Subject: [PATCH] =?UTF-8?q?chore(dev):=20=E6=B7=BB=E5=8A=A0=E5=BC=80?= =?UTF-8?q?=E5=8F=91=E8=BF=9B=E7=A8=8B=E8=87=AA=E5=8A=A8=E6=B8=85=E7=90=86?= =?UTF-8?q?=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 kill:dev 脚本用于清理占用 18181 端口的进程 - 在 dev:fresh 和 dev:desktop:fresh 前自动执行清理 - 支持跨平台(Windows/Linux/macOS) - 双轮清理策略确保进程完全退出 --- package.json | 7 ++- scripts/kill-dev.js | 138 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 scripts/kill-dev.js diff --git a/package.json b/package.json index cc31166e..48c9f541 100644 --- a/package.json +++ b/package.json @@ -18,11 +18,11 @@ "build:desktop-only": "pnpm -F @prompt-optimizer/desktop build", "build:desktop": "npm-run-all build:core build:ui build:web build:desktop-only", "dev": "npm-run-all clean:dist build:core build:ui dev:parallel", - "dev:fresh": "npm-run-all clean pnpm-install dev", + "dev:fresh": "npm-run-all kill:dev clean pnpm-install dev", "dev:parallel": "concurrently -k -p \"[{name}]\" -n \"UI,WEB\" \"pnpm -F @prompt-optimizer/ui build --watch\" \"pnpm -F @prompt-optimizer/web dev\"", "dev:ext": "pnpm -F @prompt-optimizer/extension dev", "dev:desktop": "npm-run-all clean:dist build:core build:ui dev:desktop:parallel", - "dev:desktop:fresh": "npm-run-all clean pnpm-install dev:desktop", + "dev:desktop:fresh": "npm-run-all kill:dev clean pnpm-install dev:desktop", "dev:desktop:parallel": "concurrently -k -p \"[{name}]\" -n \"WEB,DESKTOP\" \"pnpm -F @prompt-optimizer/web dev\" \"pnpm -F @prompt-optimizer/desktop dev\"", "test": "pnpm -r test --run --passWithNoTests", "test:e2e": "playwright test", @@ -45,7 +45,8 @@ "lint:fix": "pnpm -F @prompt-optimizer/ui lint:fix", "bmad:refresh": "bmad-method install -f -i codex", "bmad:list": "bmad-method list:agents", - "bmad:validate": "bmad-method validate" + "bmad:validate": "bmad-method validate", + "kill:dev": "node scripts/kill-dev.js" }, "devDependencies": { "@intlify/unplugin-vue-i18n": "^6.0.3", diff --git a/scripts/kill-dev.js b/scripts/kill-dev.js new file mode 100644 index 00000000..a23cc123 --- /dev/null +++ b/scripts/kill-dev.js @@ -0,0 +1,138 @@ +/** + * kill-dev v2 - Ultimate Safe Process Cleanup Script + * + * Strategy: + * 1. Clean up processes occupying ports (most critical) + * 2. Wait 2 seconds for parent processes to exit naturally + * 3. Check ports again to ensure complete cleanup + * + * About "missed processes": + * - Parent processes (pnpm) usually exit automatically after child processes terminate + * - vite build --watch doesn't occupy ports, exits with parent process + * - Even if missed, they don't occupy ports and won't block new starts + */ + +const { execSync } = require('child_process'); +const os = require('os'); + +console.log('🧹 Safely cleaning up project development processes...\n'); + +// Limit to project-specific ports so we do not kill other apps using defaults like 5173 +const PORTS = [18181]; + +/** + * Cross-platform non-blocking sleep + */ +function wait(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +function killByPorts(round = 1) { + const platform = os.platform(); + let killedCount = 0; + const killedPids = new Set(); + + console.log(`🔍 Round ${round}: Checking port occupation...`); + + if (platform === 'win32') { + for (const port of PORTS) { + try { + const output = execSync(`netstat -ano | findstr ":${port}"`, { + encoding: 'utf-8', + stdio: 'pipe' + }); + + // Windows uses \r\n, so split by \n and trim each line + const lines = output.split('\n').map(line => line.trim()).filter(Boolean); + lines.forEach(line => { + const match = line.match(/LISTENING\s+(\d+)/); + if (match && !killedPids.has(match[1])) { + const pid = match[1]; + try { + execSync(`taskkill /F /PID ${pid}`, { stdio: 'pipe' }); + console.log(` ✓ Killed process on port ${port} (PID: ${pid})`); + killedPids.add(pid); + killedCount++; + } catch (e) { + // Process may have already exited + } + } + }); + } catch (error) { + // Port not occupied or command failed + } + } + } else { + for (const port of PORTS) { + try { + const output = execSync(`lsof -ti :${port}`, { + encoding: 'utf-8', + stdio: 'pipe' + }); + + const pids = output.split('\n').map(pid => pid.trim()).filter(Boolean); + pids.forEach(pid => { + if (!killedPids.has(pid)) { + try { + execSync(`kill -9 ${pid}`, { stdio: 'pipe' }); + console.log(` ✓ Killed process on port ${port} (PID: ${pid})`); + killedPids.add(pid); + killedCount++; + } catch (e) { + // Process may have already exited + } + } + }); + } catch (error) { + // Port not occupied or command failed + } + } + } + + if (killedCount === 0) { + console.log(' ℹ️ No processes found occupying ports'); + } + + return killedCount; +} + +async function main() { + try { + // First round cleanup + let totalKilled = killByPorts(1); + + if (totalKilled > 0) { + // Wait for parent processes to exit naturally (cross-platform) + console.log('\n⏳ Waiting 2 seconds for parent processes to exit naturally...\n'); + await wait(2000); + + // Second round cleanup (ensure no missed processes) + const round2Killed = killByPorts(2); + totalKilled += round2Killed; + + if (round2Killed > 0) { + console.log('\n💡 Found and cleaned up missed processes'); + } else { + console.log('\n✅ Confirmed: All processes completely cleaned up'); + } + } + + console.log(`\n📊 Total cleaned: ${totalKilled} process(es)`); + + if (totalKilled > 0) { + console.log('✅ Cleanup complete! You can now run pnpm dev:fresh'); + } else { + console.log('ℹ️ No processes found that need cleanup'); + } + + process.exit(0); + } catch (error) { + console.error('\n❌ Cleanup failed:', error.message); + console.error('\n💡 Please try:'); + console.error(' 1. Run this script again'); + console.error(' 2. Or manually terminate related processes in Task Manager'); + process.exit(1); + } +} + +main();