fix(cli): improve port-check error handling

- isPortAvailable 只将 EADDRINUSE 映射为 false,其他错误(EACCES/
  EADDRNOTAVAIL 等)通过 reject 抛出,避免误报"端口被占用"
- 将端口预检移入 startup try/catch 块内,确保所有绑定错误都走
  统一的 "Startup failed" 报错路径,不产生未处理的 Promise rejection

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
diguaandClaude Sonnet 4.6 committed 2026-05-31 16:56:08 +08:00
1 parent 1b596d664f
commit 9853c33e0b
2 files changed
+16 -8

No files matched your search

+8 -6
View File
@@ -304,12 +304,6 @@ program
const { startHttpServer } = await import('./http')
const port = parseInt(options.port, 10)
// 启动前预检端口,快速失败,避免无谓的初始化后再报 EADDRINUSE
if (!(await isPortAvailable(port, options.host))) {
console.error(formatPortInUseError(port))
process.exit(1)
}
let webRoot: string | undefined
if (!options.headless) {
const webDir = resolveCliPath('dist-web')
@@ -321,6 +315,14 @@ program
}
try {
// 启动前预检端口,快速失败,避免无谓的初始化后再报 EADDRINUSE;
// 置于 try 内确保非 EADDRINUSE 错误(EACCES/EADDRNOTAVAIL 等)
// 也能走到统一的 Startup failed 错误处理路径。
if (!(await isPortAvailable(port, options.host))) {
console.error(formatPortInUseError(port))
process.exit(1)
}
const info = await startHttpServer({
port,
host: options.host,
+8 -2
View File
@@ -9,9 +9,15 @@ import * as net from 'net'
* 使用 net.createServer() 试探性绑定,无副作用(成功后立即释放)。
*/
export function isPortAvailable(port: number, host: string): Promise<boolean> {
return new Promise((resolve) => {
return new Promise((resolve, reject) => {
const server = net.createServer()
server.once('error', () => resolve(false))
server.once('error', (err: NodeJS.ErrnoException) => {
if (err.code === 'EADDRINUSE') {
resolve(false)
} else {
reject(err)
}
})
server.once('listening', () => server.close(() => resolve(true)))
server.listen(port, host)
})