chore(dev): 添加开发进程自动清理脚本

- 新增 kill:dev 脚本用于清理占用 18181 端口的进程
- 在 dev:fresh 和 dev:desktop:fresh 前自动执行清理
- 支持跨平台(Windows/Linux/macOS)
- 双轮清理策略确保进程完全退出
This commit is contained in:
linshen committed 2025-11-16 13:25:09 +08:00
1 parent 9842a81f84
commit b8cf182154
2 files changed
+142 -3

No files matched your search

+4 -3
View File
@@ -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",
+138
View File
@@ -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();