mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-09-24 23:10:56 +08:00
125 lines
3.1 KiB
JavaScript
125 lines
3.1 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { execSync } from "node:child_process";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import process from "node:process";
|
|
|
|
const devPort = process.env.LIME_DEV_PORT ?? process.env.PROXYCAST_DEV_PORT ?? "1420";
|
|
const projectRoot = path.resolve(process.cwd());
|
|
const repoRootMarker = path.join(projectRoot, "package.json");
|
|
const nestedRepoRootMarker = path.join(projectRoot, "..", "package.json");
|
|
|
|
const runningInsideSrcTauri =
|
|
path.basename(projectRoot) === "src-tauri" &&
|
|
fs.existsSync(nestedRepoRootMarker);
|
|
|
|
if (runningInsideSrcTauri) {
|
|
console.error("[lime] 检测到在 src-tauri 子目录启动开发脚本。");
|
|
console.error("[lime] 请回到仓库根目录执行:npm run tauri:dev");
|
|
console.error(
|
|
"[lime] 这样可以避免生成 src-tauri/src-tauri/target 目录。",
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
if (!fs.existsSync(repoRootMarker)) {
|
|
console.error(`[lime] 当前目录缺少 package.json: ${projectRoot}`);
|
|
console.error("[lime] 请在 lime 仓库根目录执行开发命令。");
|
|
process.exit(1);
|
|
}
|
|
|
|
function run(command) {
|
|
try {
|
|
return execSync(command, { stdio: ["ignore", "pipe", "pipe"] })
|
|
.toString("utf8")
|
|
.trim();
|
|
} catch {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
function listListenPids(port) {
|
|
const output = run(`lsof -nP -iTCP:${port} -sTCP:LISTEN -t`);
|
|
if (!output) {
|
|
return [];
|
|
}
|
|
return [
|
|
...new Set(
|
|
output
|
|
.split("\n")
|
|
.map((item) => item.trim())
|
|
.filter(Boolean),
|
|
),
|
|
];
|
|
}
|
|
|
|
function readCommand(pid) {
|
|
return run(`ps -p ${pid} -o command=`).trim();
|
|
}
|
|
|
|
function killPid(pid, signal) {
|
|
try {
|
|
process.kill(Number(pid), signal);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (process.platform === "win32") {
|
|
process.exit(0);
|
|
}
|
|
|
|
const occupiedPids = listListenPids(devPort);
|
|
if (occupiedPids.length === 0) {
|
|
process.exit(0);
|
|
}
|
|
|
|
const blockedProcesses = [];
|
|
const targetPids = [];
|
|
|
|
for (const pid of occupiedPids) {
|
|
const command = readCommand(pid);
|
|
const isViteProcess = command.includes("vite");
|
|
const inCurrentProject = command.includes(projectRoot);
|
|
|
|
if (isViteProcess && inCurrentProject) {
|
|
targetPids.push(pid);
|
|
} else {
|
|
blockedProcesses.push({ pid, command: command || "unknown" });
|
|
}
|
|
}
|
|
|
|
if (blockedProcesses.length > 0) {
|
|
console.error(`[lime] 端口 ${devPort} 被其他进程占用,无法自动清理:`);
|
|
for (const item of blockedProcesses) {
|
|
console.error(`- PID ${item.pid}: ${item.command}`);
|
|
}
|
|
console.error("[lime] 请先结束占用进程后再重试启动。");
|
|
process.exit(1);
|
|
}
|
|
|
|
for (const pid of targetPids) {
|
|
killPid(pid, "SIGTERM");
|
|
}
|
|
|
|
const stillOccupied = listListenPids(devPort);
|
|
for (const pid of stillOccupied) {
|
|
if (targetPids.includes(pid)) {
|
|
killPid(pid, "SIGKILL");
|
|
}
|
|
}
|
|
|
|
const unresolved = listListenPids(devPort);
|
|
if (unresolved.length > 0) {
|
|
console.error(`[lime] 端口 ${devPort} 仍被占用,请手动清理后重试。`);
|
|
process.exit(1);
|
|
}
|
|
|
|
if (targetPids.length > 0) {
|
|
console.log(
|
|
`[lime] 已清理 ${targetPids.length} 个残留 vite 进程(端口 ${devPort})。`,
|
|
);
|
|
}
|