@phystack/cli 5.2.1 → 6.1.0
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/index.js +148 -4
- package/package.json +9 -7
package/bin/index.js
CHANGED
|
@@ -3,9 +3,50 @@ const { spawnSync } = require('child_process');
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
|
|
5
5
|
const BINARY = 'phy';
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
// On Linux, distinguish glibc vs musl so we resolve the right per-platform
|
|
8
|
+
// package. `process.report.getReport().header.glibcVersionRuntime` is set on
|
|
9
|
+
// glibc systems and undefined on musl (Alpine). All other platforms ignore
|
|
10
|
+
// the libc suffix.
|
|
11
|
+
//
|
|
12
|
+
// No optional chaining on `process.report` itself: we WANT a missing
|
|
13
|
+
// `process.report` to throw and land in the catch (returning null = "unknown"
|
|
14
|
+
// = same behavior as the pre-musl shim, which is safer on glibc Linux than
|
|
15
|
+
// guessing musl).
|
|
16
|
+
function detectLibc() {
|
|
17
|
+
if (process.platform !== 'linux') return null;
|
|
18
|
+
try {
|
|
19
|
+
const runtime = process.report.getReport().header.glibcVersionRuntime;
|
|
20
|
+
return runtime ? 'glibc' : 'musl';
|
|
21
|
+
} catch (err) {
|
|
22
|
+
console.error(
|
|
23
|
+
`phy: libc detection via process.report failed (${err?.message || err}); ` +
|
|
24
|
+
`falling back to the platform-default package.`,
|
|
25
|
+
);
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// `JSON.stringify` can throw on circular refs or BigInts.
|
|
31
|
+
function safeStringify(value) {
|
|
32
|
+
try {
|
|
33
|
+
return JSON.stringify(value);
|
|
34
|
+
} catch (err) {
|
|
35
|
+
return `[unserializable: ${err?.message || err}]`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const libc = detectLibc();
|
|
40
|
+
const isMusl = libc === 'musl';
|
|
41
|
+
const libcSuffix = isMusl ? '-musl' : '';
|
|
42
|
+
const key = `${process.platform}-${process.arch}${libcSuffix}`;
|
|
7
43
|
const pkg = `@phystack/${BINARY}-${key}`;
|
|
8
44
|
const ext = process.platform === 'win32' ? '.exe' : '';
|
|
45
|
+
const runtimeTag = `${process.platform}-${process.arch}${libc ? ` (libc=${libc})` : ''}`;
|
|
46
|
+
|
|
47
|
+
// Reused across diagnostic branches so the message format stays consistent.
|
|
48
|
+
const runtimeLine = `Runtime: ${runtimeTag}\n`;
|
|
49
|
+
const muslHint = `You're on musl (Alpine). Ensure ${pkg} is installed (the musl variant).`;
|
|
9
50
|
|
|
10
51
|
let binPath;
|
|
11
52
|
try {
|
|
@@ -17,12 +58,115 @@ try {
|
|
|
17
58
|
} catch {
|
|
18
59
|
console.error(
|
|
19
60
|
`Unsupported or missing platform package: ${pkg}\n` +
|
|
20
|
-
|
|
21
|
-
`
|
|
22
|
-
`Or
|
|
61
|
+
`${runtimeLine}\n` +
|
|
62
|
+
`Fix: npm install ${pkg}\n` +
|
|
63
|
+
`Or: bunx ${pkg}`,
|
|
23
64
|
);
|
|
24
65
|
process.exit(1);
|
|
25
66
|
}
|
|
26
67
|
|
|
27
68
|
const result = spawnSync(binPath, process.argv.slice(2), { stdio: 'inherit' });
|
|
69
|
+
|
|
70
|
+
// `spawnSync` collapses many failure modes into status === null (with `error`
|
|
71
|
+
// or `signal` set instead) — see explainSpawnFailureIfAny for the full taxonomy.
|
|
72
|
+
// Must run BEFORE process.exit, which never returns.
|
|
73
|
+
explainSpawnFailureIfAny(result);
|
|
28
74
|
process.exit(result.status ?? 1);
|
|
75
|
+
|
|
76
|
+
function explainSpawnFailureIfAny(result) {
|
|
77
|
+
const willDiagnose =
|
|
78
|
+
result.error || result.signal || result.status === 127 || result.status === 126;
|
|
79
|
+
if (!willDiagnose) return;
|
|
80
|
+
|
|
81
|
+
// Raw dump first — gives a future debugger the full spawnSync result even
|
|
82
|
+
// if our specific branches misclassify the failure mode.
|
|
83
|
+
console.error(
|
|
84
|
+
`\nphy: spawnSync result: ${safeStringify({
|
|
85
|
+
error: result.error
|
|
86
|
+
? { code: result.error.code, message: result.error.message }
|
|
87
|
+
: null,
|
|
88
|
+
signal: result.signal,
|
|
89
|
+
status: result.status,
|
|
90
|
+
})}`,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
// 1. Spawn itself failed — kernel never started the binary, or rejected the format.
|
|
94
|
+
if (result.error) {
|
|
95
|
+
const code = result.error.code;
|
|
96
|
+
if (code === 'ENOENT') {
|
|
97
|
+
console.error(
|
|
98
|
+
`\nphy: binary not found at ${binPath}\n` +
|
|
99
|
+
runtimeLine +
|
|
100
|
+
`Cause: the platform package ${pkg} wasn't installed. Most common reasons:\n` +
|
|
101
|
+
` - npm/yarn ran with --omit=optional or --no-optional\n` +
|
|
102
|
+
` - your platform (${key}) isn't published\n` +
|
|
103
|
+
`Fix: npm install ${pkg}`,
|
|
104
|
+
);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (code === 'EACCES') {
|
|
108
|
+
console.error(
|
|
109
|
+
`\nphy: binary at ${binPath} is not executable\n` +
|
|
110
|
+
runtimeLine +
|
|
111
|
+
`Fix: chmod +x ${binPath} (or reinstall: npm install --force ${pkg})`,
|
|
112
|
+
);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (code === 'ENOEXEC') {
|
|
116
|
+
console.error(
|
|
117
|
+
`\nphy: binary at ${binPath} is not a valid executable for this platform\n` +
|
|
118
|
+
runtimeLine +
|
|
119
|
+
`Cause: architecture or libc mismatch.\n` +
|
|
120
|
+
`Fix: file ${binPath} (inspect the actual format)`,
|
|
121
|
+
);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
console.error(`\nphy: spawn failed — ${result.error.message} (${code})`);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 2. Killed by signal — exec succeeded but the process died before normal exit.
|
|
129
|
+
if (result.signal) {
|
|
130
|
+
const sig = result.signal;
|
|
131
|
+
if (sig === 'SIGSEGV' || sig === 'SIGABRT') {
|
|
132
|
+
console.error(
|
|
133
|
+
`\nphy: binary crashed (${sig})\n` +
|
|
134
|
+
runtimeLine +
|
|
135
|
+
`Cause: glibc/musl mismatch or glibc too old.\n` +
|
|
136
|
+
(isMusl ? `Fix: ${muslHint}` : `Fix: ldd --version (check glibc version)`),
|
|
137
|
+
);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (sig === 'SIGILL') {
|
|
141
|
+
console.error(
|
|
142
|
+
`\nphy: SIGILL — your CPU is missing a required instruction set. ` +
|
|
143
|
+
`(We ship the linux-x64-baseline build; this should be rare.)`,
|
|
144
|
+
);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (sig === 'SIGKILL') {
|
|
148
|
+
console.error(
|
|
149
|
+
`\nphy: SIGKILL — likely OOM killer or external kill. Check memory limits.`,
|
|
150
|
+
);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
console.error(`\nphy: killed by signal ${sig}`);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// 3. Loader-stage exit codes — process exec'd but the dynamic linker failed.
|
|
158
|
+
if (result.status === 127) {
|
|
159
|
+
console.error(
|
|
160
|
+
`\nphy: exited 127 — dynamic linker could not load the binary\n` +
|
|
161
|
+
runtimeLine +
|
|
162
|
+
(isMusl
|
|
163
|
+
? `Fix: ${muslHint}`
|
|
164
|
+
: `Fix: LD_DEBUG=libs ${binPath} ... (see which library failed to load)`),
|
|
165
|
+
);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (result.status === 126) {
|
|
169
|
+
console.error(`\nphy: exited 126 — binary found but not executable.`);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phystack/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.1.0",
|
|
4
4
|
"description": "Phygrid CLI.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"homepage": "./",
|
|
@@ -37,11 +37,13 @@
|
|
|
37
37
|
},
|
|
38
38
|
"gitHead": "4b0803f6728ceb0665bd999b88ecbb31f8ea025c",
|
|
39
39
|
"optionalDependencies": {
|
|
40
|
-
"@phystack/phy-darwin-arm64": "
|
|
41
|
-
"@phystack/phy-darwin-x64": "
|
|
42
|
-
"@phystack/phy-linux-arm64": "
|
|
43
|
-
"@phystack/phy-linux-x64": "
|
|
44
|
-
"@phystack/phy-win32-x64": "
|
|
45
|
-
"@phystack/phy-win32-arm64": "
|
|
40
|
+
"@phystack/phy-darwin-arm64": "6.1.0",
|
|
41
|
+
"@phystack/phy-darwin-x64": "6.1.0",
|
|
42
|
+
"@phystack/phy-linux-arm64": "6.1.0",
|
|
43
|
+
"@phystack/phy-linux-x64": "6.1.0",
|
|
44
|
+
"@phystack/phy-win32-x64": "6.1.0",
|
|
45
|
+
"@phystack/phy-win32-arm64": "6.1.0",
|
|
46
|
+
"@phystack/phy-linux-x64-musl": "6.1.0",
|
|
47
|
+
"@phystack/phy-linux-arm64-musl": "6.1.0"
|
|
46
48
|
}
|
|
47
49
|
}
|