@dhruv2mars/mdv 0.0.13 → 0.0.15
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/README.md +14 -0
- package/bin/install-lib.js +61 -0
- package/bin/install.js +122 -18
- package/bin/mdv-lib.js +115 -0
- package/bin/mdv.js +12 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ npm i -g @dhruv2mars/mdv
|
|
|
10
10
|
|
|
11
11
|
First run downloads native `mdv` binary.
|
|
12
12
|
Assets are resolved from GitHub Releases for your platform/arch.
|
|
13
|
+
Installer keeps verified cache under `~/.mdv/cache`.
|
|
13
14
|
|
|
14
15
|
## Usage
|
|
15
16
|
|
|
@@ -17,6 +18,13 @@ Assets are resolved from GitHub Releases for your platform/arch.
|
|
|
17
18
|
mdv README.md
|
|
18
19
|
```
|
|
19
20
|
|
|
21
|
+
Manual upgrade:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
mdv update
|
|
25
|
+
```
|
|
26
|
+
Uses detected install manager (bun/pnpm/yarn/npm), prefers original installer metadata.
|
|
27
|
+
|
|
20
28
|
Stream stdin:
|
|
21
29
|
|
|
22
30
|
```bash
|
|
@@ -37,3 +45,9 @@ tail -f notes.md | mdv --stream
|
|
|
37
45
|
- `--no-watch` disable file watch
|
|
38
46
|
- `--stream` read markdown from stdin
|
|
39
47
|
- `--perf` show perf stats
|
|
48
|
+
|
|
49
|
+
## Installer Env
|
|
50
|
+
|
|
51
|
+
- `MDV_INSTALL_DEBUG=1` local installer debug logs
|
|
52
|
+
- `MDV_INSTALL_TIMEOUT_MS` request timeout (default `15000`)
|
|
53
|
+
- `MDV_INSTALL_RETRY_ATTEMPTS` retries (default `3`)
|
package/bin/install-lib.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
|
|
1
3
|
export function assetNameFor(platform = process.platform, arch = process.arch) {
|
|
2
4
|
const ext = platform === 'win32' ? '.exe' : '';
|
|
3
5
|
return `mdv-${platform}-${arch}${ext}`;
|
|
@@ -14,6 +16,65 @@ export function checksumsAssetNameFromBinaryAsset(asset) {
|
|
|
14
16
|
return checksumsAssetNameFor(m[1], m[2]);
|
|
15
17
|
}
|
|
16
18
|
|
|
19
|
+
export function packageManagerHintFromEnv(env = process.env) {
|
|
20
|
+
const execPath = String(env.npm_execpath || '').toLowerCase();
|
|
21
|
+
if (execPath.includes('bun')) return 'bun';
|
|
22
|
+
if (execPath.includes('pnpm')) return 'pnpm';
|
|
23
|
+
if (execPath.includes('yarn')) return 'yarn';
|
|
24
|
+
if (execPath.includes('npm')) return 'npm';
|
|
25
|
+
|
|
26
|
+
const ua = String(env.npm_config_user_agent || '').toLowerCase();
|
|
27
|
+
if (ua.startsWith('bun/')) return 'bun';
|
|
28
|
+
if (ua.startsWith('pnpm/')) return 'pnpm';
|
|
29
|
+
if (ua.startsWith('yarn/')) return 'yarn';
|
|
30
|
+
if (ua.startsWith('npm/')) return 'npm';
|
|
31
|
+
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function parseIntEnv(value, fallback, min, max) {
|
|
36
|
+
const parsed = Number.parseInt(String(value ?? ''), 10);
|
|
37
|
+
if (!Number.isFinite(parsed)) return fallback;
|
|
38
|
+
if (parsed < min) return min;
|
|
39
|
+
if (parsed > max) return max;
|
|
40
|
+
return parsed;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function installTuningFromEnv(env = process.env) {
|
|
44
|
+
return {
|
|
45
|
+
retryAttempts: parseIntEnv(env.MDV_INSTALL_RETRY_ATTEMPTS, 3, 1, 10),
|
|
46
|
+
timeoutMs: parseIntEnv(env.MDV_INSTALL_TIMEOUT_MS, 15000, 1000, 120000),
|
|
47
|
+
backoffMs: parseIntEnv(env.MDV_INSTALL_BACKOFF_MS, 250, 50, 5000),
|
|
48
|
+
backoffJitterMs: parseIntEnv(env.MDV_INSTALL_BACKOFF_JITTER_MS, 100, 0, 2000)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function computeBackoffDelay(attempt, backoffMs, backoffJitterMs, rand = Math.random) {
|
|
53
|
+
const scaled = Math.max(1, attempt) * Math.max(0, backoffMs);
|
|
54
|
+
if (backoffJitterMs <= 0) return scaled;
|
|
55
|
+
const jitter = Math.floor(Math.max(0, rand()) * (backoffJitterMs + 1));
|
|
56
|
+
return scaled + jitter;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function cachePathsFor(installRoot, version, asset, checksumsAsset) {
|
|
60
|
+
const root = join(installRoot, 'cache', `v${version}`);
|
|
61
|
+
return {
|
|
62
|
+
cacheDir: root,
|
|
63
|
+
cacheBinary: join(root, asset),
|
|
64
|
+
cacheChecksums: join(root, checksumsAsset)
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function buildChecksumMismatchHelp({ asset, expected, actual, cachePath }) {
|
|
69
|
+
const shortExpected = String(expected || '').slice(0, 12);
|
|
70
|
+
const shortActual = String(actual || '').slice(0, 12);
|
|
71
|
+
return [
|
|
72
|
+
`checksum mismatch for ${asset}`,
|
|
73
|
+
`expected=${shortExpected}... actual=${shortActual}...`,
|
|
74
|
+
`clear cache and retry: rm -rf ${cachePath}`
|
|
75
|
+
].join('; ');
|
|
76
|
+
}
|
|
77
|
+
|
|
17
78
|
export function findAssetUrl(release, asset) {
|
|
18
79
|
if (!release || !Array.isArray(release.assets)) return null;
|
|
19
80
|
for (const item of release.assets) {
|
package/bin/install.js
CHANGED
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
mkdirSync,
|
|
9
9
|
readFileSync,
|
|
10
10
|
rmSync,
|
|
11
|
-
renameSync
|
|
11
|
+
renameSync,
|
|
12
|
+
writeFileSync
|
|
12
13
|
} from 'node:fs';
|
|
13
14
|
import { createHash } from 'node:crypto';
|
|
14
15
|
import { homedir } from 'node:os';
|
|
@@ -18,7 +19,12 @@ import { spawnSync } from 'node:child_process';
|
|
|
18
19
|
import { fileURLToPath } from 'node:url';
|
|
19
20
|
import {
|
|
20
21
|
assetNameFor,
|
|
22
|
+
buildChecksumMismatchHelp,
|
|
23
|
+
cachePathsFor,
|
|
21
24
|
checksumsAssetNameFor,
|
|
25
|
+
computeBackoffDelay,
|
|
26
|
+
installTuningFromEnv,
|
|
27
|
+
packageManagerHintFromEnv,
|
|
22
28
|
parseChecksumForAsset,
|
|
23
29
|
resolveReleaseAssetBundle,
|
|
24
30
|
shouldUseFallbackUrl
|
|
@@ -28,11 +34,16 @@ const REPO = 'Dhruv2mars/mdv';
|
|
|
28
34
|
|
|
29
35
|
const installRoot = process.env.MDV_INSTALL_ROOT || join(homedir(), '.mdv');
|
|
30
36
|
const binDir = join(installRoot, 'bin');
|
|
37
|
+
const metaPath = join(installRoot, 'install-meta.json');
|
|
31
38
|
const binName = process.platform === 'win32' ? 'mdv.exe' : 'mdv';
|
|
32
39
|
const dest = join(binDir, binName);
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const
|
|
40
|
+
const tuning = installTuningFromEnv(process.env);
|
|
41
|
+
const retryAttempts = tuning.retryAttempts;
|
|
42
|
+
const timeoutMs = tuning.timeoutMs;
|
|
43
|
+
const backoffMs = tuning.backoffMs;
|
|
44
|
+
const backoffJitterMs = tuning.backoffJitterMs;
|
|
45
|
+
const debugEnabled = process.env.MDV_INSTALL_DEBUG === '1';
|
|
46
|
+
const installStartedAt = Date.now();
|
|
36
47
|
|
|
37
48
|
if (process.env.MDV_SKIP_DOWNLOAD === '1') process.exit(0);
|
|
38
49
|
if (existsSync(dest)) process.exit(0);
|
|
@@ -42,26 +53,48 @@ mkdirSync(binDir, { recursive: true });
|
|
|
42
53
|
const version = pkgVersion();
|
|
43
54
|
const asset = assetNameFor();
|
|
44
55
|
const checksumsAsset = checksumsAssetNameFor();
|
|
56
|
+
const cachePaths = cachePathsFor(installRoot, version, asset, checksumsAsset);
|
|
45
57
|
const url = `https://github.com/${REPO}/releases/download/v${version}/${asset}`;
|
|
46
58
|
const checksumsUrl = `https://github.com/${REPO}/releases/download/v${version}/${checksumsAsset}`;
|
|
47
59
|
const tmp = `${dest}.tmp-${Date.now()}`;
|
|
60
|
+
mkdirSync(cachePaths.cacheDir, { recursive: true });
|
|
48
61
|
|
|
49
62
|
try {
|
|
63
|
+
trace(`start retry=${retryAttempts} timeout=${timeoutMs}ms backoff=${backoffMs}ms jitter=${backoffJitterMs}ms`);
|
|
50
64
|
console.error(`mdv: download ${asset} v${version}`);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
65
|
+
let checksumsText = null;
|
|
66
|
+
const restoredFromCache = await installFromCache(cachePaths, asset, tmp);
|
|
67
|
+
if (restoredFromCache) {
|
|
68
|
+
trace('cache-hit');
|
|
69
|
+
} else {
|
|
70
|
+
trace('cache-miss');
|
|
71
|
+
const result = await downloadWithFallback(
|
|
72
|
+
{ binaryUrl: url, checksumsUrl },
|
|
73
|
+
version,
|
|
74
|
+
asset,
|
|
75
|
+
checksumsAsset,
|
|
76
|
+
tmp
|
|
77
|
+
);
|
|
78
|
+
if (result.source === 'primary') {
|
|
79
|
+
checksumsText = result.checksumsText;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
58
82
|
if (process.platform !== 'win32') chmodSync(tmp, 0o755);
|
|
59
83
|
renameSync(tmp, dest);
|
|
84
|
+
if (checksumsText) {
|
|
85
|
+
persistCache(cachePaths, checksumsText, dest);
|
|
86
|
+
trace('cache-store');
|
|
87
|
+
}
|
|
88
|
+
persistInstallMeta();
|
|
89
|
+
trace('success');
|
|
60
90
|
process.exit(0);
|
|
61
91
|
} catch (err) {
|
|
62
92
|
try { rmSync(tmp, { force: true }); } catch {}
|
|
63
|
-
|
|
64
|
-
|
|
93
|
+
if (err && err.code === 'MDV_CHECKSUM_MISMATCH') {
|
|
94
|
+
console.error(`mdv: ${err.message}`);
|
|
95
|
+
} else {
|
|
96
|
+
console.error(`mdv: download failed (${String(err)})`);
|
|
97
|
+
}
|
|
65
98
|
|
|
66
99
|
if (process.env.MDV_ALLOW_CARGO_FALLBACK === '1') {
|
|
67
100
|
if (cargoInstallFallback()) {
|
|
@@ -170,7 +203,7 @@ async function withRetry(label, fn) {
|
|
|
170
203
|
} catch (err) {
|
|
171
204
|
lastErr = err;
|
|
172
205
|
if (attempt >= retryAttempts) break;
|
|
173
|
-
await sleep(backoffMs
|
|
206
|
+
await sleep(computeBackoffDelay(attempt, backoffMs, backoffJitterMs));
|
|
174
207
|
console.error(`mdv: retry ${label} (${attempt + 1}/${retryAttempts})`);
|
|
175
208
|
}
|
|
176
209
|
}
|
|
@@ -201,14 +234,15 @@ async function downloadAndVerify({ binaryUrl, checksumsUrl }, asset, outPath) {
|
|
|
201
234
|
|
|
202
235
|
const actual = await sha256File(outPath);
|
|
203
236
|
if (actual !== expected) {
|
|
204
|
-
throw
|
|
237
|
+
throw checksumMismatchError(asset, expected, actual);
|
|
205
238
|
}
|
|
239
|
+
return { checksumsText };
|
|
206
240
|
}
|
|
207
241
|
|
|
208
242
|
async function downloadWithFallback(primary, version, asset, checksumsAsset, outPath) {
|
|
209
243
|
try {
|
|
210
|
-
await downloadAndVerify(primary, asset, outPath);
|
|
211
|
-
return;
|
|
244
|
+
const primaryVerified = await downloadAndVerify(primary, asset, outPath);
|
|
245
|
+
return { ...primaryVerified, source: 'primary' };
|
|
212
246
|
} catch (primaryErr) {
|
|
213
247
|
const fallback = await resolveReleaseAssetBundle({
|
|
214
248
|
version,
|
|
@@ -222,7 +256,8 @@ async function downloadWithFallback(primary, version, asset, checksumsAsset, out
|
|
|
222
256
|
}
|
|
223
257
|
|
|
224
258
|
console.error(`mdv: fallback download ${fallback.binaryUrl}`);
|
|
225
|
-
await downloadAndVerify(fallback, asset, outPath);
|
|
259
|
+
const fallbackVerified = await downloadAndVerify(fallback, asset, outPath);
|
|
260
|
+
return { ...fallbackVerified, source: 'fallback' };
|
|
226
261
|
}
|
|
227
262
|
}
|
|
228
263
|
|
|
@@ -270,6 +305,75 @@ function requestJson(url) {
|
|
|
270
305
|
});
|
|
271
306
|
}
|
|
272
307
|
|
|
308
|
+
function trace(msg) {
|
|
309
|
+
if (!debugEnabled) return;
|
|
310
|
+
const elapsed = Date.now() - installStartedAt;
|
|
311
|
+
console.error(`mdv:debug +${elapsed}ms ${msg}`);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
async function installFromCache(paths, asset, outPath) {
|
|
315
|
+
if (!existsSync(paths.cacheBinary) || !existsSync(paths.cacheChecksums)) {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
try {
|
|
320
|
+
const checksumsText = readFileSync(paths.cacheChecksums, 'utf8');
|
|
321
|
+
const expected = parseChecksumForAsset(checksumsText, asset);
|
|
322
|
+
if (!expected) {
|
|
323
|
+
trace('cache-invalid-missing-checksum-entry');
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
326
|
+
const actual = await sha256File(paths.cacheBinary);
|
|
327
|
+
if (actual !== expected) {
|
|
328
|
+
trace('cache-invalid-checksum-mismatch');
|
|
329
|
+
try { rmSync(paths.cacheBinary, { force: true }); } catch {}
|
|
330
|
+
try { rmSync(paths.cacheChecksums, { force: true }); } catch {}
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
copyFileSync(paths.cacheBinary, outPath);
|
|
334
|
+
return true;
|
|
335
|
+
} catch {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function persistCache(paths, checksumsText, sourceBinaryPath) {
|
|
341
|
+
try {
|
|
342
|
+
copyFileSync(sourceBinaryPath, paths.cacheBinary);
|
|
343
|
+
writeFileSync(paths.cacheChecksums, checksumsText, 'utf8');
|
|
344
|
+
} catch {
|
|
345
|
+
trace('cache-store-failed');
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function persistInstallMeta() {
|
|
350
|
+
const packageManager = packageManagerHintFromEnv(process.env);
|
|
351
|
+
const meta = {
|
|
352
|
+
packageManager,
|
|
353
|
+
version,
|
|
354
|
+
savedAt: new Date().toISOString()
|
|
355
|
+
};
|
|
356
|
+
try {
|
|
357
|
+
writeFileSync(metaPath, JSON.stringify(meta, null, 2), 'utf8');
|
|
358
|
+
trace(`meta-store pm=${packageManager || 'unknown'}`);
|
|
359
|
+
} catch {
|
|
360
|
+
trace('meta-store-failed');
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function checksumMismatchError(asset, expected, actual) {
|
|
365
|
+
const err = new Error(
|
|
366
|
+
buildChecksumMismatchHelp({
|
|
367
|
+
asset,
|
|
368
|
+
expected,
|
|
369
|
+
actual,
|
|
370
|
+
cachePath: cachePaths.cacheDir
|
|
371
|
+
})
|
|
372
|
+
);
|
|
373
|
+
err.code = 'MDV_CHECKSUM_MISMATCH';
|
|
374
|
+
return err;
|
|
375
|
+
}
|
|
376
|
+
|
|
273
377
|
function cargoInstallFallback() {
|
|
274
378
|
const probe = spawnSync('cargo', ['--version'], { stdio: 'ignore' });
|
|
275
379
|
if (probe.status !== 0) return false;
|
package/bin/mdv-lib.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { packageManagerHintFromEnv } from './install-lib.js';
|
|
6
|
+
|
|
7
|
+
const PACKAGE_NAME = '@dhruv2mars/mdv@latest';
|
|
8
|
+
const SUPPORTED_PMS = new Set(['bun', 'pnpm', 'yarn', 'npm']);
|
|
9
|
+
|
|
10
|
+
export function binNameForPlatform(platform = process.platform) {
|
|
11
|
+
return platform === 'win32' ? 'mdv.exe' : 'mdv';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function resolveInstallRoot(env = process.env, home = homedir()) {
|
|
15
|
+
return env.MDV_INSTALL_ROOT || join(home, '.mdv');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function resolveInstalledBin(env = process.env, platform = process.platform, home = homedir()) {
|
|
19
|
+
const installRoot = resolveInstallRoot(env, home);
|
|
20
|
+
const binName = binNameForPlatform(platform);
|
|
21
|
+
return join(installRoot, 'bin', binName);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function shouldRunUpdateCommand(args) {
|
|
25
|
+
return Array.isArray(args) && args.length > 0 && args[0] === 'update';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function updateArgsFor(pm) {
|
|
29
|
+
if (pm === 'bun') return ['add', '-g', PACKAGE_NAME];
|
|
30
|
+
if (pm === 'pnpm') return ['add', '-g', PACKAGE_NAME];
|
|
31
|
+
if (pm === 'yarn') return ['global', 'add', PACKAGE_NAME];
|
|
32
|
+
return ['install', '-g', PACKAGE_NAME];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function readInstallMeta(installRoot) {
|
|
36
|
+
const path = join(installRoot, 'install-meta.json');
|
|
37
|
+
if (!existsSync(path)) return null;
|
|
38
|
+
try {
|
|
39
|
+
return JSON.parse(readFileSync(path, 'utf8'));
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function isSupportedPm(pm) {
|
|
46
|
+
return typeof pm === 'string' && SUPPORTED_PMS.has(pm);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function defaultProbe(command) {
|
|
50
|
+
const args = command === 'bun'
|
|
51
|
+
? ['pm', 'ls', '-g']
|
|
52
|
+
: command === 'pnpm'
|
|
53
|
+
? ['list', '-g', '--depth=0']
|
|
54
|
+
: command === 'yarn'
|
|
55
|
+
? ['global', 'list', '--depth=0']
|
|
56
|
+
: ['list', '-g', '--depth=0'];
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const res = spawnSync(command, args, { encoding: 'utf8', stdio: 'pipe' });
|
|
60
|
+
return {
|
|
61
|
+
status: res.status ?? 1,
|
|
62
|
+
stdout: String(res.stdout || '')
|
|
63
|
+
};
|
|
64
|
+
} catch {
|
|
65
|
+
return { status: 1, stdout: '' };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function pmSearchOrder(preferred) {
|
|
70
|
+
const base = ['bun', 'pnpm', 'yarn', 'npm'];
|
|
71
|
+
if (!isSupportedPm(preferred)) return base;
|
|
72
|
+
return [preferred, ...base.filter((x) => x !== preferred)];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function detectInstalledPackageManager(probe = defaultProbe, preferred = null) {
|
|
76
|
+
for (const command of pmSearchOrder(preferred)) {
|
|
77
|
+
const out = probe(command);
|
|
78
|
+
if ((out?.status ?? 1) !== 0) continue;
|
|
79
|
+
if (String(out?.stdout || '').includes('@dhruv2mars/mdv')) return command;
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function resolveUpdateCommand(env = process.env) {
|
|
85
|
+
const installRoot = resolveInstallRoot(env);
|
|
86
|
+
const metaPm = readInstallMeta(installRoot)?.packageManager;
|
|
87
|
+
const envPm = packageManagerHintFromEnv(env);
|
|
88
|
+
const hintPm = isSupportedPm(metaPm) ? metaPm : (isSupportedPm(envPm) ? envPm : null);
|
|
89
|
+
const detectedPm = env === process.env && !hintPm
|
|
90
|
+
? detectInstalledPackageManager(defaultProbe, null)
|
|
91
|
+
: null;
|
|
92
|
+
const manager = hintPm || detectedPm || 'npm';
|
|
93
|
+
|
|
94
|
+
if (manager === 'npm') {
|
|
95
|
+
const npmExecPath = env.npm_execpath;
|
|
96
|
+
if (typeof npmExecPath === 'string' && npmExecPath.endsWith('.js')) {
|
|
97
|
+
return {
|
|
98
|
+
command: process.execPath,
|
|
99
|
+
args: [npmExecPath, ...updateArgsFor('npm')]
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (isSupportedPm(manager)) {
|
|
105
|
+
return {
|
|
106
|
+
command: manager,
|
|
107
|
+
args: updateArgsFor(manager)
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
command: 'npm',
|
|
113
|
+
args: updateArgsFor('npm')
|
|
114
|
+
};
|
|
115
|
+
}
|
package/bin/mdv.js
CHANGED
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
|
-
import { homedir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
3
|
import { spawnSync } from 'node:child_process';
|
|
6
4
|
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import {
|
|
6
|
+
resolveInstalledBin,
|
|
7
|
+
resolveUpdateCommand,
|
|
8
|
+
shouldRunUpdateCommand
|
|
9
|
+
} from './mdv-lib.js';
|
|
7
10
|
|
|
8
11
|
const args = process.argv.slice(2);
|
|
9
12
|
|
|
13
|
+
if (shouldRunUpdateCommand(args)) {
|
|
14
|
+
const update = resolveUpdateCommand(process.env);
|
|
15
|
+
const res = spawnSync(update.command, update.args, { stdio: 'inherit', env: process.env });
|
|
16
|
+
process.exit(res.status ?? 1);
|
|
17
|
+
}
|
|
18
|
+
|
|
10
19
|
const envBin = process.env.MDV_BIN;
|
|
11
20
|
if (envBin) run(envBin, args);
|
|
12
21
|
|
|
13
|
-
const
|
|
14
|
-
const binName = process.platform === 'win32' ? 'mdv.exe' : 'mdv';
|
|
15
|
-
const installedBin = join(installRoot, 'bin', binName);
|
|
22
|
+
const installedBin = resolveInstalledBin(process.env, process.platform);
|
|
16
23
|
|
|
17
24
|
if (!existsSync(installedBin)) {
|
|
18
25
|
const here = fileURLToPath(new URL('.', import.meta.url));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dhruv2mars/mdv",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "Terminal-first markdown visualizer/editor",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"mdv": "node bin/mdv.js",
|
|
14
14
|
"postinstall": "node bin/install.js",
|
|
15
15
|
"selftest": "node bin/selftest.js",
|
|
16
|
-
"lint": "node --check bin/mdv.js && node --check bin/install.js && node --check bin/install-lib.js && node --check bin/selftest.js",
|
|
16
|
+
"lint": "node --check bin/mdv.js && node --check bin/mdv-lib.js && node --check bin/install.js && node --check bin/install-lib.js && node --check bin/selftest.js",
|
|
17
17
|
"test": "node scripts/test.js",
|
|
18
18
|
"coverage": "c8 --all --include bin/install-lib.js --reporter text-summary --check-coverage --lines 95 --functions 95 --branches 80 --statements 95 node scripts/test.js"
|
|
19
19
|
},
|