cicy-code 2.1.47 → 2.1.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cicy-code.js +84 -13
- package/package.json +1 -1
package/bin/cicy-code.js
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
3
|
-
// platform-specific optionalDependency (cicy-code-<os>-<cpu>) and execs
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
|
|
2
|
+
// Launcher for the npm distribution. Resolves the prebuilt binary that ships
|
|
3
|
+
// in the platform-specific optionalDependency (cicy-code-<os>-<cpu>) and execs
|
|
4
|
+
// it — no network, no postinstall download.
|
|
5
|
+
//
|
|
6
|
+
// Before exec it mirrors dev.py's startup: if PORT (default 8008) is already
|
|
7
|
+
// held by a *cicy-code* process it kills it and waits, so a stale instance
|
|
8
|
+
// never blocks the new one. A non-cicy occupant is left alone and we abort
|
|
9
|
+
// with a clear message (don't clobber someone else's server).
|
|
10
|
+
const { spawn, execSync } = require('child_process');
|
|
8
11
|
const fs = require('fs');
|
|
9
12
|
|
|
10
|
-
const
|
|
13
|
+
const PORT = process.env.PORT || '8008';
|
|
11
14
|
|
|
15
|
+
const platformPkg = `cicy-code-${process.platform}-${process.arch}`;
|
|
12
16
|
let binPath;
|
|
13
17
|
try {
|
|
14
|
-
// require.resolve finds the binary inside the installed sub-package,
|
|
15
|
-
// wherever the package manager hoisted it.
|
|
16
18
|
binPath = require.resolve(`${platformPkg}/cicy-code`);
|
|
17
19
|
} catch {
|
|
18
20
|
console.error(`cicy-code: no prebuilt binary for ${process.platform}-${process.arch}.`);
|
|
@@ -22,12 +24,81 @@ try {
|
|
|
22
24
|
` (in China add --registry=https://registry.npmmirror.com)`);
|
|
23
25
|
process.exit(1);
|
|
24
26
|
}
|
|
25
|
-
|
|
26
|
-
// npm restores the 0755 mode from the tarball, but chmod defensively in case
|
|
27
|
-
// a mirror or extraction stripped the exec bit.
|
|
28
27
|
try { fs.chmodSync(binPath, 0o755); } catch {}
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
// --- dev.py-style port hygiene on PORT (default 8008) ----------------------
|
|
30
|
+
|
|
31
|
+
function pidOnPort(port) {
|
|
32
|
+
// lsof first (macOS + Linux), then ss (Linux without lsof).
|
|
33
|
+
try {
|
|
34
|
+
const out = execSync(`lsof -ti TCP:${port} -sTCP:LISTEN`, {
|
|
35
|
+
encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'],
|
|
36
|
+
}).trim();
|
|
37
|
+
if (out) return out.split('\n')[0].trim();
|
|
38
|
+
} catch {}
|
|
39
|
+
try {
|
|
40
|
+
const out = execSync(`ss -tlnp 'sport = :${port}'`, {
|
|
41
|
+
encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'],
|
|
42
|
+
});
|
|
43
|
+
const m = out.match(/pid=(\d+)/);
|
|
44
|
+
if (m) return m[1];
|
|
45
|
+
} catch {}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function processCommand(pid) {
|
|
50
|
+
try {
|
|
51
|
+
return execSync(`ps -p ${pid} -o command=`, {
|
|
52
|
+
encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'],
|
|
53
|
+
}).trim();
|
|
54
|
+
} catch { return ''; }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isAlive(pid) {
|
|
58
|
+
try { process.kill(Number(pid), 0); return true; }
|
|
59
|
+
catch (e) { return e.code === 'EPERM'; }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function waitExit(pid, timeoutMs) {
|
|
63
|
+
const start = Date.now();
|
|
64
|
+
while (Date.now() - start < timeoutMs) {
|
|
65
|
+
if (!isAlive(pid)) return true;
|
|
66
|
+
try { execSync('sleep 0.2'); } catch {}
|
|
67
|
+
}
|
|
68
|
+
return !isAlive(pid);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function killPid(pid) {
|
|
72
|
+
try { process.kill(Number(pid), 'SIGTERM'); }
|
|
73
|
+
catch (e) { if (e.code === 'ESRCH') return true; }
|
|
74
|
+
if (waitExit(pid, 6000)) return true;
|
|
75
|
+
try { process.kill(Number(pid), 'SIGKILL'); }
|
|
76
|
+
catch (e) { if (e.code === 'ESRCH') return true; }
|
|
77
|
+
return waitExit(pid, 2000);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const existing = pidOnPort(PORT);
|
|
81
|
+
if (existing) {
|
|
82
|
+
const cmd = processCommand(existing);
|
|
83
|
+
if (/cicy-code/.test(cmd)) {
|
|
84
|
+
console.log(`cicy-code: stopping existing instance on :${PORT} (pid=${existing})`);
|
|
85
|
+
if (!killPid(existing) || pidOnPort(PORT)) {
|
|
86
|
+
console.error(`cicy-code: port ${PORT} still in use after kill — aborting`);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
console.error(`cicy-code: port ${PORT} is held by a non-cicy process (pid=${existing}): ${cmd}`);
|
|
91
|
+
console.error(`cicy-code: free it or set PORT=<other> — aborting`);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// --- launch ----------------------------------------------------------------
|
|
97
|
+
|
|
98
|
+
const child = spawn(binPath, process.argv.slice(2), {
|
|
99
|
+
stdio: 'inherit',
|
|
100
|
+
env: { ...process.env, PORT },
|
|
101
|
+
});
|
|
31
102
|
child.on('exit', (code, signal) => {
|
|
32
103
|
if (signal) process.kill(process.pid, signal);
|
|
33
104
|
else process.exit(code == null ? 0 : code);
|