zelari-code 1.0.2 → 1.0.3
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/dist/cli/main.bundled.js +365 -64
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +10 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/slashHandlers/updater.js +77 -6
- package/dist/cli/slashHandlers/updater.js.map +1 -1
- package/dist/cli/utils/doctor.js +287 -0
- package/dist/cli/utils/doctor.js.map +1 -0
- package/package.json +4 -2
- package/scripts/postinstall.mjs +186 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* postinstall.mjs — Shim health check for global installs.
|
|
4
|
+
*
|
|
5
|
+
* Why this exists:
|
|
6
|
+
* On Windows + npm 10/11, `npm install -g zelari-code@<x>` sometimes
|
|
7
|
+
* fails to (re)create the bin shim `zelari-code.cmd` after an upgrade
|
|
8
|
+
* (e.g. 0.7.x → 1.0.x). The package is correctly installed in
|
|
9
|
+
* `<prefix>/node_modules/zelari-code/`, but `<prefix>/zelari-code.cmd`
|
|
10
|
+
* is missing, so `zelari-code` returns "command not found" on the
|
|
11
|
+
* next shell open. This script runs as `postinstall` and:
|
|
12
|
+
*
|
|
13
|
+
* 1. Detects global installs only (skips local installs to avoid noise).
|
|
14
|
+
* 2. Verifies the expected shim path exists and is current.
|
|
15
|
+
* 3. If missing or stale, prints a clear, actionable warning with the
|
|
16
|
+
* exact fix command. It does NOT auto-repair the shim — auto-repair
|
|
17
|
+
* is risky (shim is a privileged file in the global prefix and a
|
|
18
|
+
* misdirected symlink can shadow other tools).
|
|
19
|
+
* 4. Also warns if the npm global prefix is not on the current PATH,
|
|
20
|
+
* which is a separate-but-related failure mode (npm install
|
|
21
|
+
* succeeds, the shim exists, but the user can't run the command
|
|
22
|
+
* because the prefix isn't reachable from their shell).
|
|
23
|
+
*
|
|
24
|
+
* All output goes to stderr so it doesn't pollute the install log on
|
|
25
|
+
* success. The script is fail-safe: any error here is swallowed and
|
|
26
|
+
* logged, never thrown — a broken postinstall must NEVER fail the
|
|
27
|
+
* install itself.
|
|
28
|
+
*
|
|
29
|
+
* @see scripts/diagnose-path.ps1 — interactive Windows diagnostic
|
|
30
|
+
* @see scripts/fix-path.ps1 — adds npm prefix to user PATH
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { execSync } from 'node:child_process';
|
|
34
|
+
import {
|
|
35
|
+
existsSync,
|
|
36
|
+
readFileSync,
|
|
37
|
+
readlinkSync,
|
|
38
|
+
statSync,
|
|
39
|
+
} from 'node:fs';
|
|
40
|
+
import { fileURLToPath } from 'node:url';
|
|
41
|
+
import path from 'node:path';
|
|
42
|
+
|
|
43
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
44
|
+
const pkgRoot = path.resolve(__dirname, '..');
|
|
45
|
+
|
|
46
|
+
const warn = (msg) => {
|
|
47
|
+
// eslint-disable-next-line no-console
|
|
48
|
+
console.warn(`[zelari-code postinstall] ${msg}`);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const note = (msg) => {
|
|
52
|
+
// eslint-disable-next-line no-console
|
|
53
|
+
console.warn(`[zelari-code postinstall] ${msg}`);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
// 0. Only run for global installs. Local installs (`npm install zelari-code`)
|
|
58
|
+
// create a `node_modules/.bin/zelari-code` symlink that npm handles
|
|
59
|
+
// correctly, and the user runs the command via `npx` or package.json
|
|
60
|
+
// scripts — so the global-prefix shim is irrelevant.
|
|
61
|
+
//
|
|
62
|
+
// npm sets `npm_config_global=true` for `npm install -g` and for
|
|
63
|
+
// `npm install -g <pkg>` invocations. Some npm versions also set
|
|
64
|
+
// `npm_install_global` — check both for safety.
|
|
65
|
+
const isGlobal =
|
|
66
|
+
process.env.npm_config_global === 'true' ||
|
|
67
|
+
process.env.npm_install_global === 'true' ||
|
|
68
|
+
process.env.NPM_CONFIG_GLOBAL === 'true';
|
|
69
|
+
|
|
70
|
+
if (!isGlobal) {
|
|
71
|
+
process.exit(0);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 1. Resolve the global prefix. Prefer the env var (set by npm), fall
|
|
75
|
+
// back to `npm prefix -g`. If both fail, bail silently — we can't
|
|
76
|
+
// diagnose without knowing where to look.
|
|
77
|
+
let prefix = (process.env.npm_config_prefix || process.env.NPM_CONFIG_PREFIX || '').trim();
|
|
78
|
+
if (!prefix) {
|
|
79
|
+
try {
|
|
80
|
+
prefix = execSync('npm prefix -g', { encoding: 'utf8' }).trim();
|
|
81
|
+
} catch {
|
|
82
|
+
// npm not on PATH, or this is a weirdly-sandboxed install.
|
|
83
|
+
// Either way, we can't help further.
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const pkgName = process.env.npm_package_name || 'zelari-code';
|
|
89
|
+
const pkgVersion = process.env.npm_package_version || 'unknown';
|
|
90
|
+
const expectedBinScript = path.join(pkgRoot, 'bin', 'zelari-code.js');
|
|
91
|
+
const isWin = process.platform === 'win32';
|
|
92
|
+
const shimName = isWin ? 'zelari-code.cmd' : 'zelari-code';
|
|
93
|
+
const shimPath = path.join(prefix, shimName);
|
|
94
|
+
const expectedNodeModulesShim = isWin
|
|
95
|
+
? `%~dp0\\node_modules\\${pkgName}\\bin\\zelari-code.js`
|
|
96
|
+
: path.join(prefix, 'node_modules', pkgName, 'bin', 'zelari-code.js');
|
|
97
|
+
|
|
98
|
+
// 2. Check the shim.
|
|
99
|
+
let shimOk = false;
|
|
100
|
+
let shimReason = '';
|
|
101
|
+
|
|
102
|
+
if (!existsSync(shimPath)) {
|
|
103
|
+
shimReason = `shim file not found at ${shimPath}`;
|
|
104
|
+
} else {
|
|
105
|
+
try {
|
|
106
|
+
const st = statSync(shimPath);
|
|
107
|
+
if (isWin) {
|
|
108
|
+
// Windows: .cmd shim. Validate the content references the current
|
|
109
|
+
// package name + bin path. The exact text varies slightly across
|
|
110
|
+
// npm versions, so we just check for the package name + the
|
|
111
|
+
// bin/zelari-code.js substring.
|
|
112
|
+
const content = readFileSync(shimPath, 'utf8');
|
|
113
|
+
if (content.includes(`${pkgName}\\bin\\zelari-code.js`) || content.includes(`${pkgName}/bin/zelari-code.js`)) {
|
|
114
|
+
shimOk = true;
|
|
115
|
+
} else {
|
|
116
|
+
shimReason = `shim at ${shimPath} does not reference ${pkgName}/bin/zelari-code.js — it may belong to a different install`;
|
|
117
|
+
}
|
|
118
|
+
} else {
|
|
119
|
+
// POSIX: symlink (or hardlink). readlinkSync throws for non-symlinks.
|
|
120
|
+
let target;
|
|
121
|
+
try {
|
|
122
|
+
target = readlinkSync(shimPath);
|
|
123
|
+
} catch {
|
|
124
|
+
// Not a symlink — could be a hardlink or a copied file. In
|
|
125
|
+
// either case, npm shouldn't have done that. Treat as broken.
|
|
126
|
+
shimReason = `shim at ${shimPath} is not a symlink (npm should create a symlink for global installs on POSIX)`;
|
|
127
|
+
shimOk = false;
|
|
128
|
+
}
|
|
129
|
+
if (target) {
|
|
130
|
+
const resolved = path.resolve(path.dirname(shimPath), target);
|
|
131
|
+
if (resolved === expectedNodeModulesShim) {
|
|
132
|
+
shimOk = true;
|
|
133
|
+
} else {
|
|
134
|
+
shimReason = `shim at ${shimPath} points to ${resolved}, expected ${expectedNodeModulesShim}`;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// If we reach here with shimOk still false and shimReason still empty,
|
|
139
|
+
// it's a non-symlink non-cmd file — leave shimReason empty so the
|
|
140
|
+
// generic message is shown.
|
|
141
|
+
if (!shimOk && !shimReason) {
|
|
142
|
+
shimReason = `shim at ${shimPath} is not a regular file or symlink (mode=${st.mode})`;
|
|
143
|
+
}
|
|
144
|
+
} catch (err) {
|
|
145
|
+
shimReason = `could not inspect shim at ${shimPath}: ${err.message}`;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (shimOk) {
|
|
150
|
+
note(`shim OK: ${shimPath}`);
|
|
151
|
+
process.exit(0);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 3. Shim is broken or missing. Emit a clear, actionable warning.
|
|
155
|
+
warn('==============================================================');
|
|
156
|
+
warn(' npm install completed, but the `zelari-code` shim is broken.');
|
|
157
|
+
warn('==============================================================');
|
|
158
|
+
warn(` Reason: ${shimReason}`);
|
|
159
|
+
warn('');
|
|
160
|
+
warn(' The package itself is correctly installed in:');
|
|
161
|
+
warn(` ${path.join(prefix, 'node_modules', pkgName)}`);
|
|
162
|
+
warn(' But the bin shim is not where npm should have created it:');
|
|
163
|
+
warn(` ${shimPath}`);
|
|
164
|
+
warn('');
|
|
165
|
+
warn(' Symptom: `zelari-code` returns "command not found" in your');
|
|
166
|
+
warn(' shell, even though `npm ls -g` lists the package.');
|
|
167
|
+
warn('');
|
|
168
|
+
warn(' Fix (try in order, run as Administrator on Windows if needed):');
|
|
169
|
+
warn('');
|
|
170
|
+
warn(` npm install -g ${pkgName}@${pkgVersion} --force`);
|
|
171
|
+
warn('');
|
|
172
|
+
warn(' If the command is still not found after that, your npm');
|
|
173
|
+
warn(' global prefix may not be on your shell PATH. Run:');
|
|
174
|
+
warn('');
|
|
175
|
+
warn(' npm bin -g # shows the expected shim dir');
|
|
176
|
+
warn(' echo "$PATH" # check if it is included');
|
|
177
|
+
warn('');
|
|
178
|
+
warn(' On Windows, scripts/diagnose-path.ps1 and scripts/fix-path.ps1');
|
|
179
|
+
warn(' in the repo can inspect and repair PATH for you.');
|
|
180
|
+
warn('==============================================================');
|
|
181
|
+
process.exit(0); // Never fail the install.
|
|
182
|
+
} catch (err) {
|
|
183
|
+
// Last-resort safety net: log and exit 0.
|
|
184
|
+
warn(`unexpected error (install is not affected): ${err.message}`);
|
|
185
|
+
process.exit(0);
|
|
186
|
+
}
|