kimi-code / apps /vis /scripts /dev.mjs
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
5710dd0 verified
Raw
History Blame Contribute Delete
2.17 kB
#!/usr/bin/env node
// Wraps `concurrently` so the vis-server (API) and vite (web) each pick a
// free port and agree on each other's, even when the defaults are taken by
// a previous dev session or another local app.
import { spawn } from 'node:child_process';
import net from 'node:net';
const DEFAULT_API_PORT = 5174;
const DEFAULT_WEB_PORT = 5173;
const MAX_PROBE = 50;
async function isFree(port) {
return new Promise((resolve) => {
const srv = net.createServer();
srv.unref();
srv.once('error', () => {
resolve(false);
});
srv.once('listening', () => {
srv.close(() => {
resolve(true);
});
});
srv.listen({ port, host: '127.0.0.1', exclusive: true });
});
}
async function pickPort(startPort, exclude = new Set()) {
for (let port = startPort; port < startPort + MAX_PROBE; port += 1) {
if (exclude.has(port)) continue;
// eslint-disable-next-line no-await-in-loop
if (await isFree(port)) return port;
}
throw new Error(
`no free port in [${startPort}, ${startPort + MAX_PROBE}); something is hogging the range`,
);
}
const requestedApi = Number(process.env.PORT) || DEFAULT_API_PORT;
const apiPort = await pickPort(requestedApi);
if (apiPort !== requestedApi) {
process.stdout.write(`[vis] api port ${requestedApi} busy, using ${apiPort} instead\n`);
}
const requestedWeb = Number(process.env.WEB_PORT) || DEFAULT_WEB_PORT;
const webPort = await pickPort(requestedWeb, new Set([apiPort]));
if (webPort !== requestedWeb) {
process.stdout.write(`[vis] web port ${requestedWeb} busy, using ${webPort} instead\n`);
}
process.stdout.write(`[vis] web → http://localhost:${webPort} (api on ${apiPort})\n`);
const env = { ...process.env, PORT: String(apiPort), WEB_PORT: String(webPort) };
const child = spawn(
'concurrently',
[
'-k',
'-n', 'server,web',
'-c', 'cyan,magenta',
'pnpm --filter @moonshot-ai/vis-server dev',
'pnpm --filter @moonshot-ai/vis-web dev',
],
{ stdio: 'inherit', env, shell: false },
);
child.on('exit', (code, signal) => {
if (signal !== null) process.kill(process.pid, signal);
else process.exit(code ?? 0);
});