Skip to content

Commit b8cf182

Browse files
committed
chore(dev): 添加开发进程自动清理脚本
- 新增 kill:dev 脚本用于清理占用 18181 端口的进程 - 在 dev:fresh 和 dev:desktop:fresh 前自动执行清理 - 支持跨平台(Windows/Linux/macOS) - 双轮清理策略确保进程完全退出
1 parent 9842a81 commit b8cf182

File tree

2 files changed

+142
-3
lines changed

2 files changed

+142
-3
lines changed

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
"build:desktop-only": "pnpm -F @prompt-optimizer/desktop build",
1919
"build:desktop": "npm-run-all build:core build:ui build:web build:desktop-only",
2020
"dev": "npm-run-all clean:dist build:core build:ui dev:parallel",
21-
"dev:fresh": "npm-run-all clean pnpm-install dev",
21+
"dev:fresh": "npm-run-all kill:dev clean pnpm-install dev",
2222
"dev:parallel": "concurrently -k -p \"[{name}]\" -n \"UI,WEB\" \"pnpm -F @prompt-optimizer/ui build --watch\" \"pnpm -F @prompt-optimizer/web dev\"",
2323
"dev:ext": "pnpm -F @prompt-optimizer/extension dev",
2424
"dev:desktop": "npm-run-all clean:dist build:core build:ui dev:desktop:parallel",
25-
"dev:desktop:fresh": "npm-run-all clean pnpm-install dev:desktop",
25+
"dev:desktop:fresh": "npm-run-all kill:dev clean pnpm-install dev:desktop",
2626
"dev:desktop:parallel": "concurrently -k -p \"[{name}]\" -n \"WEB,DESKTOP\" \"pnpm -F @prompt-optimizer/web dev\" \"pnpm -F @prompt-optimizer/desktop dev\"",
2727
"test": "pnpm -r test --run --passWithNoTests",
2828
"test:e2e": "playwright test",
@@ -45,7 +45,8 @@
4545
"lint:fix": "pnpm -F @prompt-optimizer/ui lint:fix",
4646
"bmad:refresh": "bmad-method install -f -i codex",
4747
"bmad:list": "bmad-method list:agents",
48-
"bmad:validate": "bmad-method validate"
48+
"bmad:validate": "bmad-method validate",
49+
"kill:dev": "node scripts/kill-dev.js"
4950
},
5051
"devDependencies": {
5152
"@intlify/unplugin-vue-i18n": "^6.0.3",

scripts/kill-dev.js

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/**
2+
* kill-dev v2 - Ultimate Safe Process Cleanup Script
3+
*
4+
* Strategy:
5+
* 1. Clean up processes occupying ports (most critical)
6+
* 2. Wait 2 seconds for parent processes to exit naturally
7+
* 3. Check ports again to ensure complete cleanup
8+
*
9+
* About "missed processes":
10+
* - Parent processes (pnpm) usually exit automatically after child processes terminate
11+
* - vite build --watch doesn't occupy ports, exits with parent process
12+
* - Even if missed, they don't occupy ports and won't block new starts
13+
*/
14+
15+
const { execSync } = require('child_process');
16+
const os = require('os');
17+
18+
console.log('🧹 Safely cleaning up project development processes...\n');
19+
20+
// Limit to project-specific ports so we do not kill other apps using defaults like 5173
21+
const PORTS = [18181];
22+
23+
/**
24+
* Cross-platform non-blocking sleep
25+
*/
26+
function wait(ms) {
27+
return new Promise((resolve) => setTimeout(resolve, ms));
28+
}
29+
30+
function killByPorts(round = 1) {
31+
const platform = os.platform();
32+
let killedCount = 0;
33+
const killedPids = new Set();
34+
35+
console.log(`🔍 Round ${round}: Checking port occupation...`);
36+
37+
if (platform === 'win32') {
38+
for (const port of PORTS) {
39+
try {
40+
const output = execSync(`netstat -ano | findstr ":${port}"`, {
41+
encoding: 'utf-8',
42+
stdio: 'pipe'
43+
});
44+
45+
// Windows uses \r\n, so split by \n and trim each line
46+
const lines = output.split('\n').map(line => line.trim()).filter(Boolean);
47+
lines.forEach(line => {
48+
const match = line.match(/LISTENING\s+(\d+)/);
49+
if (match && !killedPids.has(match[1])) {
50+
const pid = match[1];
51+
try {
52+
execSync(`taskkill /F /PID ${pid}`, { stdio: 'pipe' });
53+
console.log(` ✓ Killed process on port ${port} (PID: ${pid})`);
54+
killedPids.add(pid);
55+
killedCount++;
56+
} catch (e) {
57+
// Process may have already exited
58+
}
59+
}
60+
});
61+
} catch (error) {
62+
// Port not occupied or command failed
63+
}
64+
}
65+
} else {
66+
for (const port of PORTS) {
67+
try {
68+
const output = execSync(`lsof -ti :${port}`, {
69+
encoding: 'utf-8',
70+
stdio: 'pipe'
71+
});
72+
73+
const pids = output.split('\n').map(pid => pid.trim()).filter(Boolean);
74+
pids.forEach(pid => {
75+
if (!killedPids.has(pid)) {
76+
try {
77+
execSync(`kill -9 ${pid}`, { stdio: 'pipe' });
78+
console.log(` ✓ Killed process on port ${port} (PID: ${pid})`);
79+
killedPids.add(pid);
80+
killedCount++;
81+
} catch (e) {
82+
// Process may have already exited
83+
}
84+
}
85+
});
86+
} catch (error) {
87+
// Port not occupied or command failed
88+
}
89+
}
90+
}
91+
92+
if (killedCount === 0) {
93+
console.log(' ℹ️ No processes found occupying ports');
94+
}
95+
96+
return killedCount;
97+
}
98+
99+
async function main() {
100+
try {
101+
// First round cleanup
102+
let totalKilled = killByPorts(1);
103+
104+
if (totalKilled > 0) {
105+
// Wait for parent processes to exit naturally (cross-platform)
106+
console.log('\n⏳ Waiting 2 seconds for parent processes to exit naturally...\n');
107+
await wait(2000);
108+
109+
// Second round cleanup (ensure no missed processes)
110+
const round2Killed = killByPorts(2);
111+
totalKilled += round2Killed;
112+
113+
if (round2Killed > 0) {
114+
console.log('\n💡 Found and cleaned up missed processes');
115+
} else {
116+
console.log('\n✅ Confirmed: All processes completely cleaned up');
117+
}
118+
}
119+
120+
console.log(`\n📊 Total cleaned: ${totalKilled} process(es)`);
121+
122+
if (totalKilled > 0) {
123+
console.log('✅ Cleanup complete! You can now run pnpm dev:fresh');
124+
} else {
125+
console.log('ℹ️ No processes found that need cleanup');
126+
}
127+
128+
process.exit(0);
129+
} catch (error) {
130+
console.error('\n❌ Cleanup failed:', error.message);
131+
console.error('\n💡 Please try:');
132+
console.error(' 1. Run this script again');
133+
console.error(' 2. Or manually terminate related processes in Task Manager');
134+
process.exit(1);
135+
}
136+
}
137+
138+
main();

0 commit comments

Comments
 (0)