@just-every/code 0.2.119 → 0.2.120
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/package.json +9 -6
- package/postinstall.js +128 -32
- package/scripts/preinstall.js +69 -0
- package/scripts/windows-cleanup.ps1 +32 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@just-every/code",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.120",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Lightweight coding agent that runs in your terminal - fork of OpenAI Codex",
|
|
6
6
|
"bin": {
|
|
@@ -14,9 +14,12 @@
|
|
|
14
14
|
"bin/coder.js",
|
|
15
15
|
"bin/codex.js",
|
|
16
16
|
"postinstall.js",
|
|
17
|
+
"scripts/preinstall.js",
|
|
18
|
+
"scripts/windows-cleanup.ps1",
|
|
17
19
|
"dist"
|
|
18
20
|
],
|
|
19
21
|
"scripts": {
|
|
22
|
+
"preinstall": "node scripts/preinstall.js",
|
|
20
23
|
"postinstall": "node postinstall.js",
|
|
21
24
|
"prepublishOnly": "node -e \"const fs=require('fs'),path=require('path'); const repoGit=path.join(__dirname,'..','.git'); const inCi=process.env.GITHUB_ACTIONS==='true'||process.env.CI==='true'; if(fs.existsSync(repoGit) && !inCi){ console.error('Refusing to publish from codex-cli. Use codex-cli/scripts/stage_release.sh to stage a release.'); process.exit(1);} else { console.log(inCi ? 'CI publish detected.' : 'Publishing staged package...'); }\""
|
|
22
25
|
},
|
|
@@ -32,10 +35,10 @@
|
|
|
32
35
|
"prettier": "^3.3.3"
|
|
33
36
|
},
|
|
34
37
|
"optionalDependencies": {
|
|
35
|
-
"@just-every/code-darwin-arm64": "0.2.
|
|
36
|
-
"@just-every/code-darwin-x64": "0.2.
|
|
37
|
-
"@just-every/code-linux-x64-musl": "0.2.
|
|
38
|
-
"@just-every/code-linux-arm64-musl": "0.2.
|
|
39
|
-
"@just-every/code-win32-x64": "0.2.
|
|
38
|
+
"@just-every/code-darwin-arm64": "0.2.120",
|
|
39
|
+
"@just-every/code-darwin-x64": "0.2.120",
|
|
40
|
+
"@just-every/code-linux-x64-musl": "0.2.120",
|
|
41
|
+
"@just-every/code-linux-arm64-musl": "0.2.120",
|
|
42
|
+
"@just-every/code-win32-x64": "0.2.120"
|
|
40
43
|
}
|
|
41
44
|
}
|
package/postinstall.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// Non-functional change to trigger release workflow
|
|
3
3
|
|
|
4
|
-
import { existsSync, mkdirSync, createWriteStream, chmodSync, readFileSync, readSync, writeFileSync, unlinkSync, statSync, openSync, closeSync, copyFileSync } from 'fs';
|
|
4
|
+
import { existsSync, mkdirSync, createWriteStream, chmodSync, readFileSync, readSync, writeFileSync, unlinkSync, statSync, openSync, closeSync, copyFileSync, fsyncSync, renameSync, realpathSync } from 'fs';
|
|
5
5
|
import { join, dirname } from 'path';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
7
|
import { get } from 'https';
|
|
8
|
-
import { platform, arch } from 'os';
|
|
8
|
+
import { platform, arch, tmpdir } from 'os';
|
|
9
9
|
import { execSync } from 'child_process';
|
|
10
10
|
import { createRequire } from 'module';
|
|
11
11
|
|
|
@@ -54,6 +54,56 @@ function getCachedBinaryPath(version, targetTriple, isWindows) {
|
|
|
54
54
|
return join(cacheDir, `code-${targetTriple}${ext}`);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
function isWSL() {
|
|
58
|
+
if (platform() !== 'linux') return false;
|
|
59
|
+
try {
|
|
60
|
+
const ver = readFileSync('/proc/version', 'utf8').toLowerCase();
|
|
61
|
+
return ver.includes('microsoft') || !!process.env.WSL_DISTRO_NAME;
|
|
62
|
+
} catch { return false; }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function isPathOnWindowsFs(p) {
|
|
66
|
+
try {
|
|
67
|
+
const mounts = readFileSync('/proc/mounts', 'utf8').split(/\n/).filter(Boolean);
|
|
68
|
+
let best = { mount: '/', type: 'unknown', len: 1 };
|
|
69
|
+
for (const line of mounts) {
|
|
70
|
+
const parts = line.split(' ');
|
|
71
|
+
if (parts.length < 3) continue;
|
|
72
|
+
const mnt = parts[1];
|
|
73
|
+
const typ = parts[2];
|
|
74
|
+
if (p.startsWith(mnt) && mnt.length > best.len) best = { mount: mnt, type: typ, len: mnt.length };
|
|
75
|
+
}
|
|
76
|
+
return best.type === 'drvfs' || best.type === 'cifs';
|
|
77
|
+
} catch { return false; }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function writeCacheAtomic(srcPath, cachePath) {
|
|
81
|
+
try {
|
|
82
|
+
if (existsSync(cachePath)) {
|
|
83
|
+
const ok = validateDownloadedBinary(cachePath).ok;
|
|
84
|
+
if (ok) return;
|
|
85
|
+
}
|
|
86
|
+
} catch {}
|
|
87
|
+
const dir = dirname(cachePath);
|
|
88
|
+
if (!existsSync(dir)) { try { mkdirSync(dir, { recursive: true }); } catch {} }
|
|
89
|
+
const tmp = cachePath + '.tmp-' + Math.random().toString(36).slice(2, 8);
|
|
90
|
+
copyFileSync(srcPath, tmp);
|
|
91
|
+
try { const fd = openSync(tmp, 'r'); try { fsyncSync(fd); } finally { closeSync(fd); } } catch {}
|
|
92
|
+
// Retry with exponential backoff up to ~1.6s total
|
|
93
|
+
const delays = [100, 200, 400, 800, 1200, 1600];
|
|
94
|
+
for (let i = 0; i < delays.length; i++) {
|
|
95
|
+
try {
|
|
96
|
+
if (existsSync(cachePath)) { try { unlinkSync(cachePath); } catch {} }
|
|
97
|
+
renameSync(tmp, cachePath);
|
|
98
|
+
return;
|
|
99
|
+
} catch {
|
|
100
|
+
await new Promise(r => setTimeout(r, delays[i]));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (existsSync(cachePath)) { try { unlinkSync(cachePath); } catch {} }
|
|
104
|
+
renameSync(tmp, cachePath);
|
|
105
|
+
}
|
|
106
|
+
|
|
57
107
|
async function downloadBinary(url, dest, maxRedirects = 5, maxRetries = 3) {
|
|
58
108
|
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
|
59
109
|
|
|
@@ -238,8 +288,11 @@ async function main() {
|
|
|
238
288
|
if (existsSync(cachePath)) {
|
|
239
289
|
const valid = validateDownloadedBinary(cachePath);
|
|
240
290
|
if (valid.ok) {
|
|
241
|
-
|
|
242
|
-
|
|
291
|
+
// Avoid mirroring into node_modules on Windows or WSL-on-NTFS.
|
|
292
|
+
const wsl = isWSL();
|
|
293
|
+
const binDirReal = (() => { try { return realpathSync(binDir); } catch { return binDir; } })();
|
|
294
|
+
const mirrorToLocal = !(isWindows || (wsl && isPathOnWindowsFs(binDirReal)));
|
|
295
|
+
if (mirrorToLocal) {
|
|
243
296
|
copyFileSync(cachePath, localPath);
|
|
244
297
|
try { chmodSync(localPath, 0o755); } catch {}
|
|
245
298
|
}
|
|
@@ -281,10 +334,13 @@ async function main() {
|
|
|
281
334
|
if (!existsSync(src)) {
|
|
282
335
|
throw new Error(`platform package missing binary: ${platformPkg.name}`);
|
|
283
336
|
}
|
|
284
|
-
// Populate cache first (canonical location)
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
337
|
+
// Populate cache first (canonical location) atomically
|
|
338
|
+
await writeCacheAtomic(src, cachePath);
|
|
339
|
+
// Mirror into local bin only on Unix-like filesystems (not Windows/WSL-on-NTFS)
|
|
340
|
+
const wsl = isWSL();
|
|
341
|
+
const binDirReal = (() => { try { return realpathSync(binDir); } catch { return binDir; } })();
|
|
342
|
+
const mirrorToLocal = !(isWindows || (wsl && isPathOnWindowsFs(binDirReal)));
|
|
343
|
+
if (mirrorToLocal) {
|
|
288
344
|
copyFileSync(cachePath, localPath);
|
|
289
345
|
try { chmodSync(localPath, 0o755); } catch {}
|
|
290
346
|
}
|
|
@@ -299,6 +355,15 @@ async function main() {
|
|
|
299
355
|
// - Windows: .zip
|
|
300
356
|
// - macOS/Linux: prefer .zst if `zstd` CLI is available; otherwise use .tar.gz
|
|
301
357
|
const isWin = isWindows;
|
|
358
|
+
const isWSL = (() => {
|
|
359
|
+
if (platform() !== 'linux') return false;
|
|
360
|
+
try {
|
|
361
|
+
const ver = readFileSync('/proc/version', 'utf8').toLowerCase();
|
|
362
|
+
return ver.includes('microsoft') || !!process.env.WSL_DISTRO_NAME;
|
|
363
|
+
} catch { return false; }
|
|
364
|
+
})();
|
|
365
|
+
const binDirReal = (() => { try { return realpathSync(binDir); } catch { return binDir; } })();
|
|
366
|
+
const mirrorToLocal = !(isWin || (isWSL && isPathOnWindowsFs(binDirReal)));
|
|
302
367
|
let useZst = false;
|
|
303
368
|
if (!isWin) {
|
|
304
369
|
try {
|
|
@@ -313,24 +378,57 @@ async function main() {
|
|
|
313
378
|
|
|
314
379
|
console.log(`Downloading ${archiveName}...`);
|
|
315
380
|
try {
|
|
316
|
-
const
|
|
381
|
+
const needsIsolation = isWin || (!isWin && !mirrorToLocal); // Windows or WSL-on-NTFS
|
|
382
|
+
let safeTempDir = needsIsolation ? join(tmpdir(), 'just-every', 'code', version) : binDir;
|
|
383
|
+
// Ensure staging dir exists; if tmp fails (permissions/space), fall back to user cache.
|
|
384
|
+
if (needsIsolation) {
|
|
385
|
+
try {
|
|
386
|
+
if (!existsSync(safeTempDir)) mkdirSync(safeTempDir, { recursive: true });
|
|
387
|
+
} catch {
|
|
388
|
+
try {
|
|
389
|
+
safeTempDir = getCacheDir(version);
|
|
390
|
+
if (!existsSync(safeTempDir)) mkdirSync(safeTempDir, { recursive: true });
|
|
391
|
+
} catch {}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
const tmpPath = join(needsIsolation ? safeTempDir : binDir, `.${archiveName}.part`);
|
|
317
395
|
await downloadBinary(downloadUrl, tmpPath);
|
|
318
396
|
|
|
319
397
|
if (isWin) {
|
|
320
|
-
// Unzip
|
|
398
|
+
// Unzip to a temp directory, then move into the per-user cache.
|
|
399
|
+
const unzipDest = safeTempDir;
|
|
321
400
|
try {
|
|
322
|
-
const
|
|
323
|
-
|
|
401
|
+
const sysRoot = process.env.SystemRoot || process.env.windir || 'C:\\Windows';
|
|
402
|
+
const psFull = join(sysRoot, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
|
|
403
|
+
const psCmd = `Expand-Archive -Path '${tmpPath}' -DestinationPath '${unzipDest}' -Force`;
|
|
404
|
+
let ok = false;
|
|
405
|
+
// Attempt full-path powershell.exe
|
|
406
|
+
try { execSync(`"${psFull}" -NoProfile -NonInteractive -Command "${psCmd}"`, { stdio: 'ignore' }); ok = true; } catch {}
|
|
407
|
+
// Fallback to powershell in PATH
|
|
408
|
+
if (!ok) { try { execSync(`powershell -NoProfile -NonInteractive -Command "${psCmd}"`, { stdio: 'ignore' }); ok = true; } catch {} }
|
|
409
|
+
// Fallback to pwsh (PowerShell 7)
|
|
410
|
+
if (!ok) { try { execSync(`pwsh -NoProfile -NonInteractive -Command "${psCmd}"`, { stdio: 'ignore' }); ok = true; } catch {} }
|
|
411
|
+
// Final fallback: bsdtar can extract .zip
|
|
412
|
+
if (!ok) { execSync(`tar -xf "${tmpPath}" -C "${unzipDest}"`, { stdio: 'ignore', shell: true }); }
|
|
324
413
|
} catch (e) {
|
|
325
414
|
throw new Error(`failed to unzip archive: ${e.message}`);
|
|
326
415
|
} finally {
|
|
327
416
|
try { unlinkSync(tmpPath); } catch {}
|
|
328
417
|
}
|
|
418
|
+
// Move the extracted file from temp to cache; do not leave a copy in node_modules
|
|
419
|
+
try {
|
|
420
|
+
const extractedPath = join(unzipDest, binaryName);
|
|
421
|
+
await writeCacheAtomic(extractedPath, cachePath);
|
|
422
|
+
try { unlinkSync(extractedPath); } catch {}
|
|
423
|
+
} catch (e) {
|
|
424
|
+
throw new Error(`failed to move binary to cache: ${e.message}`);
|
|
425
|
+
}
|
|
329
426
|
} else {
|
|
330
427
|
if (useZst) {
|
|
331
428
|
// Decompress .zst via system zstd
|
|
332
429
|
try {
|
|
333
|
-
|
|
430
|
+
const outPath = mirrorToLocal ? localPath : join(safeTempDir, binaryName);
|
|
431
|
+
execSync(`zstd -d '${tmpPath}' -o '${outPath}'`, { stdio: 'ignore', shell: true });
|
|
334
432
|
} catch (e) {
|
|
335
433
|
try { unlinkSync(tmpPath); } catch {}
|
|
336
434
|
throw new Error(`failed to decompress .zst (need zstd CLI): ${e.message}`);
|
|
@@ -339,44 +437,42 @@ async function main() {
|
|
|
339
437
|
} else {
|
|
340
438
|
// Extract .tar.gz using system tar
|
|
341
439
|
try {
|
|
342
|
-
|
|
440
|
+
const dest = mirrorToLocal ? binDir : safeTempDir;
|
|
441
|
+
execSync(`tar -xzf '${tmpPath}' -C '${dest}'`, { stdio: 'ignore', shell: true });
|
|
343
442
|
} catch (e) {
|
|
344
443
|
try { unlinkSync(tmpPath); } catch {}
|
|
345
444
|
throw new Error(`failed to extract .tar.gz: ${e.message}`);
|
|
346
445
|
}
|
|
347
446
|
try { unlinkSync(tmpPath); } catch {}
|
|
348
447
|
}
|
|
448
|
+
if (!mirrorToLocal) {
|
|
449
|
+
try {
|
|
450
|
+
const extractedPath = join(safeTempDir, binaryName);
|
|
451
|
+
await writeCacheAtomic(extractedPath, cachePath);
|
|
452
|
+
try { unlinkSync(extractedPath); } catch {}
|
|
453
|
+
} catch (e) {
|
|
454
|
+
throw new Error(`failed to move binary to cache: ${e.message}`);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
349
457
|
}
|
|
350
458
|
|
|
351
459
|
// Validate header to avoid corrupt binaries causing spawn EFTYPE/ENOEXEC
|
|
352
|
-
// On Windows, archive extraction writes to binDir; move the result to cache
|
|
353
|
-
// and remove the copy from node_modules to avoid future locks. On Unix,
|
|
354
|
-
// we keep a copy in binDir and also ensure cache is populated.
|
|
355
|
-
if (isWindows) {
|
|
356
|
-
try {
|
|
357
|
-
// Ensure the extracted file is at localPath; then move it to cachePath
|
|
358
|
-
copyFileSync(localPath, cachePath);
|
|
359
|
-
try { unlinkSync(localPath); } catch {}
|
|
360
|
-
} catch (e) {
|
|
361
|
-
throw new Error(`failed to move binary to cache: ${e.message}`);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
460
|
|
|
365
|
-
const valid = validateDownloadedBinary(
|
|
461
|
+
const valid = validateDownloadedBinary(isWin ? cachePath : (mirrorToLocal ? localPath : cachePath));
|
|
366
462
|
if (!valid.ok) {
|
|
367
|
-
try {
|
|
463
|
+
try { (isWin || !mirrorToLocal) ? unlinkSync(cachePath) : unlinkSync(localPath); } catch {}
|
|
368
464
|
throw new Error(`invalid binary (${valid.reason})`);
|
|
369
465
|
}
|
|
370
466
|
|
|
371
467
|
// Make executable on Unix-like systems
|
|
372
|
-
if (!
|
|
468
|
+
if (!isWin && mirrorToLocal) {
|
|
373
469
|
chmodSync(localPath, 0o755);
|
|
374
470
|
}
|
|
375
471
|
|
|
376
|
-
console.log(`✓ Installed ${binaryName}${
|
|
472
|
+
console.log(`✓ Installed ${binaryName}${(isWin || !mirrorToLocal) ? ' (cached)' : ''}`);
|
|
377
473
|
// Ensure persistent cache holds the binary (already true for Windows path)
|
|
378
|
-
if (!
|
|
379
|
-
try {
|
|
474
|
+
if (!isWin && mirrorToLocal) {
|
|
475
|
+
try { await writeCacheAtomic(localPath, cachePath); } catch {}
|
|
380
476
|
}
|
|
381
477
|
} catch (error) {
|
|
382
478
|
console.error(`✗ Failed to install ${binaryName}: ${error.message}`);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Windows-friendly preinstall: proactively free file locks from prior installs
|
|
3
|
+
// so npm/yarn/pnpm can stage the new package. No-ops on non-Windows.
|
|
4
|
+
|
|
5
|
+
import { platform } from 'os';
|
|
6
|
+
import { execSync } from 'child_process';
|
|
7
|
+
import { existsSync, readdirSync, rmSync, readFileSync, statSync } from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
|
|
11
|
+
function isWSL() {
|
|
12
|
+
if (platform() !== 'linux') return false;
|
|
13
|
+
try {
|
|
14
|
+
const rel = readFileSync('/proc/version', 'utf8').toLowerCase();
|
|
15
|
+
return rel.includes('microsoft') || !!process.env.WSL_DISTRO_NAME;
|
|
16
|
+
} catch { return false; }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const isWin = platform() === 'win32';
|
|
20
|
+
const wsl = isWSL();
|
|
21
|
+
const isWinLike = isWin || wsl;
|
|
22
|
+
|
|
23
|
+
// Scope: only run for global installs, unless explicitly forced. Allow opt-out.
|
|
24
|
+
const isGlobal = process.env.npm_config_global === 'true';
|
|
25
|
+
const force = process.env.CODE_FORCE_PREINSTALL === '1';
|
|
26
|
+
const skip = process.env.CODE_SKIP_PREINSTALL === '1';
|
|
27
|
+
if (!isWinLike || skip || (!isGlobal && !force)) process.exit(0);
|
|
28
|
+
|
|
29
|
+
function tryExec(cmd, opts = {}) {
|
|
30
|
+
try { execSync(cmd, { stdio: ['ignore', 'ignore', 'ignore'], shell: true, ...opts }); } catch { /* ignore */ }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 1) Stop our native binary if it is holding locks. Avoid killing unrelated tools.
|
|
34
|
+
// Only available on native Windows; skip entirely on WSL to avoid noise.
|
|
35
|
+
if (isWin) {
|
|
36
|
+
tryExec('taskkill /IM code-x86_64-pc-windows-msvc.exe /F');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 2) Remove stale staging dirs from previous failed installs under the global
|
|
40
|
+
// @just-every scope, which npm will reuse (e.g., .code-XXXXX). Remove only
|
|
41
|
+
// old entries and never the current staging or live package.
|
|
42
|
+
try {
|
|
43
|
+
let scopeDir = '';
|
|
44
|
+
try {
|
|
45
|
+
const root = execSync('npm root -g', { stdio: ['ignore', 'pipe', 'ignore'], shell: true }).toString().trim();
|
|
46
|
+
scopeDir = path.join(root, '@just-every');
|
|
47
|
+
} catch {
|
|
48
|
+
// Fall back to guessing from this script location: <staging>\..\..\
|
|
49
|
+
const here = path.resolve(path.dirname(fileURLToPath(import.meta.url)));
|
|
50
|
+
scopeDir = path.resolve(here, '..');
|
|
51
|
+
}
|
|
52
|
+
if (existsSync(scopeDir)) {
|
|
53
|
+
const now = Date.now();
|
|
54
|
+
const maxAgeMs = 2 * 60 * 60 * 1000; // 2 hours
|
|
55
|
+
const currentDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
56
|
+
for (const name of readdirSync(scopeDir)) {
|
|
57
|
+
if (!name.startsWith('.code-')) continue;
|
|
58
|
+
const p = path.join(scopeDir, name);
|
|
59
|
+
if (path.resolve(p) === currentDir) continue; // never remove our current dir
|
|
60
|
+
try {
|
|
61
|
+
const st = statSync(p);
|
|
62
|
+
const age = now - st.mtimeMs;
|
|
63
|
+
if (age > maxAgeMs) rmSync(p, { recursive: true, force: true });
|
|
64
|
+
} catch { /* ignore */ }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
} catch { /* ignore */ }
|
|
68
|
+
|
|
69
|
+
process.exit(0);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<#
|
|
2
|
+
Helper to recover from EBUSY/EPERM during global npm upgrades on Windows.
|
|
3
|
+
Closes running processes and removes stale package folders.
|
|
4
|
+
|
|
5
|
+
Usage (PowerShell):
|
|
6
|
+
Set-ExecutionPolicy -Scope Process Bypass -Force
|
|
7
|
+
./codex-cli/scripts/windows-cleanup.ps1
|
|
8
|
+
#>
|
|
9
|
+
|
|
10
|
+
$ErrorActionPreference = 'SilentlyContinue'
|
|
11
|
+
|
|
12
|
+
Write-Host "Stopping running Code/Coder processes..."
|
|
13
|
+
taskkill /IM code-x86_64-pc-windows-msvc.exe /F 2>$null | Out-Null
|
|
14
|
+
taskkill /IM code.exe /F 2>$null | Out-Null
|
|
15
|
+
taskkill /IM coder.exe /F 2>$null | Out-Null
|
|
16
|
+
|
|
17
|
+
Write-Host "Removing old global package (if present)..."
|
|
18
|
+
$npmRoot = (& npm root -g).Trim()
|
|
19
|
+
$pkgPath = Join-Path $npmRoot "@just-every\code"
|
|
20
|
+
if (Test-Path $pkgPath) {
|
|
21
|
+
try { Remove-Item -LiteralPath $pkgPath -Recurse -Force -ErrorAction Stop } catch {}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
Write-Host "Removing temp staging directories (if present)..."
|
|
25
|
+
Get-ChildItem -LiteralPath (Join-Path $npmRoot "@just-every") -Force -ErrorAction SilentlyContinue |
|
|
26
|
+
Where-Object { $_.Name -like '.code-*' } |
|
|
27
|
+
ForEach-Object {
|
|
28
|
+
try { Remove-Item -LiteralPath $_.FullName -Recurse -Force -ErrorAction Stop } catch {}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
Write-Host "Cleanup complete. You can now run: npm install -g @just-every/code@latest"
|
|
32
|
+
|