@just-every/code 0.2.42 → 0.2.44
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/coder.js +31 -51
- package/package.json +6 -6
- package/postinstall.js +185 -95
package/bin/coder.js
CHANGED
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
|
|
4
4
|
import path from "path";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
|
-
import { realpathSync, accessSync, constants } from "fs";
|
|
7
|
-
import { spawnSync } from "child_process";
|
|
8
6
|
|
|
9
7
|
// __dirname equivalent in ESM
|
|
10
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -12,55 +10,9 @@ const __dirname = path.dirname(__filename);
|
|
|
12
10
|
|
|
13
11
|
const { platform, arch } = process;
|
|
14
12
|
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
const maybeDelegateToOtherCode = () => {
|
|
19
|
-
try {
|
|
20
|
-
const invoked = process.env._ || "";
|
|
21
|
-
const invokedBase = path.basename(invoked);
|
|
22
|
-
if (invokedBase !== "code") return false;
|
|
23
|
-
|
|
24
|
-
const ourScriptReal = realpathSync(process.argv[1]);
|
|
25
|
-
|
|
26
|
-
const which = spawnSync("bash", ["-lc", "which -a code 2>/dev/null"], {
|
|
27
|
-
encoding: "utf8",
|
|
28
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
29
|
-
});
|
|
30
|
-
if (which.status !== 0 || !which.stdout) return false;
|
|
31
|
-
|
|
32
|
-
const candidates = which.stdout
|
|
33
|
-
.split(/\r?\n/)
|
|
34
|
-
.map((s) => s.trim())
|
|
35
|
-
.filter(Boolean);
|
|
36
|
-
|
|
37
|
-
for (const c of candidates) {
|
|
38
|
-
// Skip the path that was used to invoke us
|
|
39
|
-
if (c === invoked) continue;
|
|
40
|
-
try {
|
|
41
|
-
const real = realpathSync(c);
|
|
42
|
-
// Skip if it resolves to our own script (same file inside our package)
|
|
43
|
-
if (real === ourScriptReal) continue;
|
|
44
|
-
|
|
45
|
-
// Ensure it's executable; if so, exec and mirror exit code
|
|
46
|
-
accessSync(c, constants.X_OK);
|
|
47
|
-
const run = spawnSync(c, process.argv.slice(2), {
|
|
48
|
-
stdio: "inherit",
|
|
49
|
-
});
|
|
50
|
-
// If it executed (even with non-zero), we consider delegation done.
|
|
51
|
-
const code = run.status == null ? 1 : run.status;
|
|
52
|
-
process.exit(code);
|
|
53
|
-
} catch {
|
|
54
|
-
// Try next candidate
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
} catch {
|
|
58
|
-
// Fall through to our own binary
|
|
59
|
-
}
|
|
60
|
-
return false;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
maybeDelegateToOtherCode();
|
|
13
|
+
// Important: Never delegate to another system's `code` binary (e.g., VS Code).
|
|
14
|
+
// When users run via `npx @just-every/code`, we must always execute our
|
|
15
|
+
// packaged native binary by absolute path to avoid PATH collisions.
|
|
64
16
|
|
|
65
17
|
const isWSL = () => {
|
|
66
18
|
if (platform !== "linux") return false;
|
|
@@ -130,6 +82,7 @@ if (!existsSync(binaryPath)) {
|
|
|
130
82
|
|
|
131
83
|
// Check if binary exists and try to fix permissions if needed
|
|
132
84
|
import { existsSync, chmodSync, statSync, openSync, readSync, closeSync } from "fs";
|
|
85
|
+
import { spawnSync } from "child_process";
|
|
133
86
|
if (existsSync(binaryPath)) {
|
|
134
87
|
try {
|
|
135
88
|
// Ensure binary is executable on Unix-like systems
|
|
@@ -200,6 +153,33 @@ if (!validation.ok) {
|
|
|
200
153
|
process.exit(1);
|
|
201
154
|
}
|
|
202
155
|
|
|
156
|
+
// If running under npx/npm, emit a concise notice about which binary path is used
|
|
157
|
+
try {
|
|
158
|
+
const ua = process.env.npm_config_user_agent || "";
|
|
159
|
+
const isNpx = ua.includes("npx");
|
|
160
|
+
if (isNpx && process.stderr && process.stderr.isTTY) {
|
|
161
|
+
// Best-effort discovery of another 'code' on PATH for user clarity
|
|
162
|
+
let otherCode = "";
|
|
163
|
+
try {
|
|
164
|
+
const cmd = process.platform === "win32" ? "where code" : "command -v code || which code || true";
|
|
165
|
+
const out = spawnSync(process.platform === "win32" ? "cmd" : "bash", [
|
|
166
|
+
process.platform === "win32" ? "/c" : "-lc",
|
|
167
|
+
cmd,
|
|
168
|
+
], { encoding: "utf8" });
|
|
169
|
+
const line = (out.stdout || "").split(/\r?\n/).map((s) => s.trim()).filter(Boolean)[0];
|
|
170
|
+
if (line && !line.includes("@just-every/code")) {
|
|
171
|
+
otherCode = line;
|
|
172
|
+
}
|
|
173
|
+
} catch {}
|
|
174
|
+
if (otherCode) {
|
|
175
|
+
console.error(`@just-every/code: running bundled binary -> ${binaryPath}`);
|
|
176
|
+
console.error(`Note: a different 'code' exists at ${otherCode}; not delegating.`);
|
|
177
|
+
} else {
|
|
178
|
+
console.error(`@just-every/code: running bundled binary -> ${binaryPath}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
} catch {}
|
|
182
|
+
|
|
203
183
|
// Use an asynchronous spawn instead of spawnSync so that Node is able to
|
|
204
184
|
// respond to signals (e.g. Ctrl-C / SIGINT) while the native binary is
|
|
205
185
|
// executing. This allows us to forward those signals to the child process
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@just-every/code",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.44",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Lightweight coding agent that runs in your terminal - fork of OpenAI Codex",
|
|
6
6
|
"bin": {
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
"prettier": "^3.3.3"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|
|
38
|
-
"@just-every/code-darwin-arm64": "0.2.
|
|
39
|
-
"@just-every/code-darwin-x64": "0.2.
|
|
40
|
-
"@just-every/code-linux-x64-musl": "0.2.
|
|
41
|
-
"@just-every/code-linux-arm64-musl": "0.2.
|
|
42
|
-
"@just-every/code-win32-x64": "0.2.
|
|
38
|
+
"@just-every/code-darwin-arm64": "0.2.44",
|
|
39
|
+
"@just-every/code-darwin-x64": "0.2.44",
|
|
40
|
+
"@just-every/code-linux-x64-musl": "0.2.44",
|
|
41
|
+
"@just-every/code-linux-arm64-musl": "0.2.44",
|
|
42
|
+
"@just-every/code-win32-x64": "0.2.44"
|
|
43
43
|
}
|
|
44
44
|
}
|
package/postinstall.js
CHANGED
|
@@ -30,6 +30,30 @@ function getTargetTriple() {
|
|
|
30
30
|
return `${rustArch}-${rustPlatform}`;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
// Resolve a persistent user cache directory for binaries so that repeated
|
|
34
|
+
// npx installs can reuse a previously downloaded artifact and skip work.
|
|
35
|
+
function getCacheDir(version) {
|
|
36
|
+
const plt = platform();
|
|
37
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
38
|
+
let base = '';
|
|
39
|
+
if (plt === 'win32') {
|
|
40
|
+
base = process.env.LOCALAPPDATA || join(home, 'AppData', 'Local');
|
|
41
|
+
} else if (plt === 'darwin') {
|
|
42
|
+
base = join(home, 'Library', 'Caches');
|
|
43
|
+
} else {
|
|
44
|
+
base = process.env.XDG_CACHE_HOME || join(home, '.cache');
|
|
45
|
+
}
|
|
46
|
+
const dir = join(base, 'just-every', 'code', version);
|
|
47
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
48
|
+
return dir;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getCachedBinaryPath(version, targetTriple, isWindows) {
|
|
52
|
+
const ext = isWindows ? '.exe' : '';
|
|
53
|
+
const cacheDir = getCacheDir(version);
|
|
54
|
+
return join(cacheDir, `code-${targetTriple}${ext}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
33
57
|
async function downloadBinary(url, dest, maxRedirects = 5, maxRetries = 3) {
|
|
34
58
|
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
|
35
59
|
|
|
@@ -151,27 +175,33 @@ function validateDownloadedBinary(p) {
|
|
|
151
175
|
|
|
152
176
|
async function main() {
|
|
153
177
|
// Detect potential PATH conflict with an existing `code` command (e.g., VS Code)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
178
|
+
// Only relevant for global installs; skip for npx/local installs to keep postinstall fast.
|
|
179
|
+
const ua = process.env.npm_config_user_agent || '';
|
|
180
|
+
const isNpx = ua.includes('npx');
|
|
181
|
+
const isGlobal = process.env.npm_config_global === 'true';
|
|
182
|
+
if (isGlobal && !isNpx) {
|
|
183
|
+
try {
|
|
184
|
+
const whichCmd = process.platform === 'win32' ? 'where code' : 'command -v code || which code || true';
|
|
185
|
+
const resolved = execSync(whichCmd, { stdio: ['ignore', 'pipe', 'ignore'], shell: process.platform !== 'win32' }).toString().split(/\r?\n/).filter(Boolean)[0];
|
|
186
|
+
if (resolved) {
|
|
187
|
+
let contents = '';
|
|
188
|
+
try {
|
|
189
|
+
contents = readFileSync(resolved, 'utf8');
|
|
190
|
+
} catch {
|
|
191
|
+
contents = '';
|
|
192
|
+
}
|
|
193
|
+
const looksLikeOurs = contents.includes('@just-every/code') || contents.includes('bin/coder.js');
|
|
194
|
+
if (!looksLikeOurs) {
|
|
195
|
+
console.warn('[notice] Found an existing `code` on PATH at:');
|
|
196
|
+
console.warn(` ${resolved}`);
|
|
197
|
+
console.warn('[notice] We will still install our CLI, also available as `coder`.');
|
|
198
|
+
console.warn(' If `code` runs another tool, prefer using: coder');
|
|
199
|
+
console.warn(' Or run our CLI explicitly via: npx -y @just-every/code');
|
|
200
|
+
}
|
|
171
201
|
}
|
|
202
|
+
} catch {
|
|
203
|
+
// Ignore detection failures; proceed with install.
|
|
172
204
|
}
|
|
173
|
-
} catch {
|
|
174
|
-
// Ignore detection failures; proceed with install.
|
|
175
205
|
}
|
|
176
206
|
|
|
177
207
|
const targetTriple = getTargetTriple();
|
|
@@ -195,6 +225,7 @@ async function main() {
|
|
|
195
225
|
for (const binary of binaries) {
|
|
196
226
|
const binaryName = `${binary}-${targetTriple}${binaryExt}`;
|
|
197
227
|
const localPath = join(binDir, binaryName);
|
|
228
|
+
const cachePath = getCachedBinaryPath(version, targetTriple, isWindows);
|
|
198
229
|
|
|
199
230
|
// Skip if already exists and has correct permissions
|
|
200
231
|
if (existsSync(localPath)) {
|
|
@@ -211,6 +242,21 @@ async function main() {
|
|
|
211
242
|
}
|
|
212
243
|
continue;
|
|
213
244
|
}
|
|
245
|
+
|
|
246
|
+
// Fast path: if a valid cached binary exists for this version+triple, reuse it.
|
|
247
|
+
try {
|
|
248
|
+
if (existsSync(cachePath)) {
|
|
249
|
+
const valid = validateDownloadedBinary(cachePath);
|
|
250
|
+
if (valid.ok) {
|
|
251
|
+
copyFileSync(cachePath, localPath);
|
|
252
|
+
if (!isWindows) chmodSync(localPath, 0o755);
|
|
253
|
+
console.log(`✓ Installed ${binaryName} from user cache`);
|
|
254
|
+
continue; // next binary
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
} catch {
|
|
258
|
+
// Ignore cache errors and fall through to normal paths
|
|
259
|
+
}
|
|
214
260
|
|
|
215
261
|
// First try platform package via npm optionalDependencies (fast path on npm CDN).
|
|
216
262
|
const require = createRequire(import.meta.url);
|
|
@@ -245,6 +291,12 @@ async function main() {
|
|
|
245
291
|
copyFileSync(src, localPath);
|
|
246
292
|
if (!isWindows) chmodSync(localPath, 0o755);
|
|
247
293
|
console.log(`✓ Installed ${binaryName} from ${platformPkg.name}`);
|
|
294
|
+
// Populate cache for future npx runs
|
|
295
|
+
try {
|
|
296
|
+
if (!existsSync(cachePath)) {
|
|
297
|
+
copyFileSync(localPath, cachePath);
|
|
298
|
+
}
|
|
299
|
+
} catch {}
|
|
248
300
|
continue; // next binary
|
|
249
301
|
} catch (e) {
|
|
250
302
|
console.warn(`⚠ Failed platform package install (${e.message}), falling back to GitHub download`);
|
|
@@ -317,6 +369,10 @@ async function main() {
|
|
|
317
369
|
}
|
|
318
370
|
|
|
319
371
|
console.log(`✓ Installed ${binaryName}`);
|
|
372
|
+
// Save into persistent cache for future fast installs
|
|
373
|
+
try {
|
|
374
|
+
copyFileSync(localPath, cachePath);
|
|
375
|
+
} catch {}
|
|
320
376
|
} catch (error) {
|
|
321
377
|
console.error(`✗ Failed to install ${binaryName}: ${error.message}`);
|
|
322
378
|
console.error(` Downloaded from: ${downloadUrl}`);
|
|
@@ -353,108 +409,142 @@ async function main() {
|
|
|
353
409
|
}
|
|
354
410
|
|
|
355
411
|
// With bin name = 'code', handle collisions (e.g., VS Code) and add legacy wrappers
|
|
356
|
-
|
|
412
|
+
// Only do this for global installs; skip under npx/local to avoid extra work and collisions.
|
|
413
|
+
if (isGlobal && !isNpx) try {
|
|
357
414
|
const isTTY = process.stdout && process.stdout.isTTY;
|
|
358
415
|
const isWindows = platform() === 'win32';
|
|
416
|
+
const ua = process.env.npm_config_user_agent || '';
|
|
417
|
+
const isBun = ua.includes('bun') || !!process.env.BUN_INSTALL;
|
|
359
418
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
globalBin = execSync('npm bin -g', { stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
|
|
363
|
-
} catch {}
|
|
364
|
-
|
|
365
|
-
const ourShim = join(globalBin || '', isWindows ? 'code.cmd' : 'code');
|
|
419
|
+
const installedCmds = new Set(['coder']); // global install always exposes coder via package manager
|
|
420
|
+
const skippedCmds = [];
|
|
366
421
|
|
|
367
|
-
//
|
|
368
|
-
const
|
|
422
|
+
// Helper to resolve all 'code' on PATH
|
|
423
|
+
const resolveAllOnPath = () => {
|
|
369
424
|
try {
|
|
370
425
|
if (isWindows) {
|
|
371
|
-
const out = execSync(
|
|
372
|
-
return out
|
|
373
|
-
} else {
|
|
374
|
-
return execSync(`command -v ${cmd}`, { stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
|
|
426
|
+
const out = execSync('where code', { stdio: ['ignore', 'pipe', 'ignore'] }).toString();
|
|
427
|
+
return out.split(/\r?\n/).map(s => s.trim()).filter(Boolean);
|
|
375
428
|
}
|
|
376
|
-
|
|
429
|
+
let out = '';
|
|
430
|
+
try {
|
|
431
|
+
out = execSync('bash -lc "which -a code 2>/dev/null"', { stdio: ['ignore', 'pipe', 'ignore'] }).toString();
|
|
432
|
+
} catch {
|
|
433
|
+
try {
|
|
434
|
+
out = execSync('command -v code || true', { stdio: ['ignore', 'pipe', 'ignore'] }).toString();
|
|
435
|
+
} catch { out = ''; }
|
|
436
|
+
}
|
|
437
|
+
return out.split(/\r?\n/).map(s => s.trim()).filter(Boolean);
|
|
438
|
+
} catch {
|
|
439
|
+
return [];
|
|
440
|
+
}
|
|
377
441
|
};
|
|
378
442
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
const ensureWrapper = (name, args) => {
|
|
383
|
-
if (!globalBin) return;
|
|
443
|
+
if (isBun) {
|
|
444
|
+
// Bun creates shims for every bin; if another 'code' exists elsewhere on PATH, remove Bun's shim
|
|
445
|
+
let bunBin = '';
|
|
384
446
|
try {
|
|
385
|
-
const
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
447
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
448
|
+
const bunBase = process.env.BUN_INSTALL || join(home, '.bun');
|
|
449
|
+
bunBin = join(bunBase, 'bin');
|
|
450
|
+
} catch {}
|
|
451
|
+
|
|
452
|
+
const bunShim = join(bunBin || '', isWindows ? 'code.cmd' : 'code');
|
|
453
|
+
const candidates = resolveAllOnPath();
|
|
454
|
+
const other = candidates.find(p => p && (!bunBin || !p.startsWith(bunBin)));
|
|
455
|
+
if (other && existsSync(bunShim)) {
|
|
456
|
+
try {
|
|
457
|
+
unlinkSync(bunShim);
|
|
458
|
+
console.log(`✓ Skipped global 'code' shim under Bun (existing: ${other})`);
|
|
459
|
+
skippedCmds.push({ name: 'code', reason: `existing: ${other}` });
|
|
460
|
+
} catch (e) {
|
|
461
|
+
console.log(`⚠ Could not remove Bun shim '${bunShim}': ${e.message}`);
|
|
393
462
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
console.log(`⚠ Failed to create '${name}' wrapper: ${e.message}`);
|
|
463
|
+
} else if (existsSync(bunShim)) {
|
|
464
|
+
installedCmds.add('code');
|
|
397
465
|
}
|
|
398
|
-
};
|
|
399
466
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
467
|
+
// Print summary for Bun
|
|
468
|
+
const list = Array.from(installedCmds).sort().join(', ');
|
|
469
|
+
console.log(`Commands installed (bun): ${list}`);
|
|
470
|
+
if (skippedCmds.length) {
|
|
471
|
+
for (const s of skippedCmds) console.log(`Commands skipped: ${s.name} (${s.reason})`);
|
|
472
|
+
console.log('→ Use `coder` to run this tool.');
|
|
473
|
+
}
|
|
474
|
+
// Final friendly usage hint
|
|
475
|
+
if (installedCmds.has('code')) {
|
|
476
|
+
console.log("Use 'code' to launch Code.");
|
|
477
|
+
} else {
|
|
478
|
+
console.log("Use 'coder' to launch Code.");
|
|
479
|
+
}
|
|
480
|
+
} else {
|
|
481
|
+
// npm/pnpm/yarn path
|
|
482
|
+
let globalBin = '';
|
|
483
|
+
try {
|
|
484
|
+
globalBin = execSync('npm bin -g', { stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
|
|
485
|
+
} catch {}
|
|
486
|
+
|
|
487
|
+
const ourShim = join(globalBin || '', isWindows ? 'code.cmd' : 'code');
|
|
488
|
+
const candidates = resolveAllOnPath();
|
|
489
|
+
const others = candidates.filter(p => p && ourShim && p !== ourShim);
|
|
490
|
+
const collision = others.length > 0;
|
|
403
491
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
if (globalBin) {
|
|
407
|
-
// Create a 'coder' shim that forwards to our installed 'code' in the same dir
|
|
492
|
+
const ensureWrapper = (name, args) => {
|
|
493
|
+
if (!globalBin) return;
|
|
408
494
|
try {
|
|
409
|
-
const
|
|
495
|
+
const wrapperPath = join(globalBin, isWindows ? `${name}.cmd` : name);
|
|
410
496
|
if (isWindows) {
|
|
411
|
-
const content = `@echo off\r\n"%~
|
|
412
|
-
writeFileSync(
|
|
497
|
+
const content = `@echo off\r\n"%~dp0${collision ? 'coder' : 'code'}" ${args} %*\r\n`;
|
|
498
|
+
writeFileSync(wrapperPath, content);
|
|
413
499
|
} else {
|
|
414
|
-
const content = `#!/bin/sh\nexec "$(dirname \"$0\")
|
|
415
|
-
writeFileSync(
|
|
416
|
-
chmodSync(
|
|
500
|
+
const content = `#!/bin/sh\nexec "$(dirname \"$0\")/${collision ? 'coder' : 'code'}" ${args} "$@"\n`;
|
|
501
|
+
writeFileSync(wrapperPath, content);
|
|
502
|
+
chmodSync(wrapperPath, 0o755);
|
|
417
503
|
}
|
|
418
|
-
console.log(`✓ Created
|
|
504
|
+
console.log(`✓ Created wrapper '${name}' -> ${collision ? 'coder' : 'code'} ${args}`);
|
|
505
|
+
installedCmds.add(name);
|
|
419
506
|
} catch (e) {
|
|
420
|
-
console.log(`⚠ Failed to create '
|
|
507
|
+
console.log(`⚠ Failed to create '${name}' wrapper: ${e.message}`);
|
|
421
508
|
}
|
|
509
|
+
};
|
|
422
510
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
try {
|
|
437
|
-
const vscodeShim = join(globalBin, isWindows ? 'vscode.cmd' : 'vscode');
|
|
438
|
-
if (isWindows) {
|
|
439
|
-
const content = `@echo off\r\n"${codeResolved}" %*\r\n`;
|
|
440
|
-
writeFileSync(vscodeShim, content);
|
|
441
|
-
} else {
|
|
442
|
-
const content = `#!/bin/sh\nexec "${codeResolved}" "$@"\n`;
|
|
443
|
-
writeFileSync(vscodeShim, content);
|
|
444
|
-
chmodSync(vscodeShim, 0o755);
|
|
445
|
-
}
|
|
446
|
-
console.log('✓ Created `vscode` alias for your editor');
|
|
447
|
-
} catch (e) {
|
|
448
|
-
console.log(`⚠ Failed to create 'vscode' alias: ${e.message}`);
|
|
511
|
+
// Always create legacy wrappers so existing scripts keep working
|
|
512
|
+
ensureWrapper('code-tui', '');
|
|
513
|
+
ensureWrapper('code-exec', 'exec');
|
|
514
|
+
|
|
515
|
+
if (collision) {
|
|
516
|
+
console.log('⚠ Detected existing `code` on PATH:');
|
|
517
|
+
for (const p of others) console.log(` - ${p}`);
|
|
518
|
+
if (globalBin) {
|
|
519
|
+
try {
|
|
520
|
+
if (existsSync(ourShim)) {
|
|
521
|
+
unlinkSync(ourShim);
|
|
522
|
+
console.log(`✓ Skipped global 'code' shim (removed ${ourShim})`);
|
|
523
|
+
skippedCmds.push({ name: 'code', reason: `existing: ${others[0]}` });
|
|
449
524
|
}
|
|
450
|
-
}
|
|
451
|
-
console.log(
|
|
525
|
+
} catch (e) {
|
|
526
|
+
console.log(`⚠ Could not remove npm shim '${ourShim}': ${e.message}`);
|
|
452
527
|
}
|
|
528
|
+
console.log('→ Use `coder` to run this tool.');
|
|
529
|
+
} else {
|
|
530
|
+
console.log('Note: could not determine npm global bin; skipping alias creation.');
|
|
453
531
|
}
|
|
532
|
+
} else {
|
|
533
|
+
// No collision; npm created a 'code' shim for us.
|
|
534
|
+
if (globalBin && existsSync(ourShim)) installedCmds.add('code');
|
|
535
|
+
}
|
|
454
536
|
|
|
455
|
-
|
|
537
|
+
// Print summary for npm/pnpm/yarn
|
|
538
|
+
const list = Array.from(installedCmds).sort().join(', ');
|
|
539
|
+
console.log(`Commands installed: ${list}`);
|
|
540
|
+
if (skippedCmds.length) {
|
|
541
|
+
for (const s of skippedCmds) console.log(`Commands skipped: ${s.name} (${s.reason})`);
|
|
542
|
+
}
|
|
543
|
+
// Final friendly usage hint
|
|
544
|
+
if (installedCmds.has('code')) {
|
|
545
|
+
console.log("Use 'code' to launch Code.");
|
|
456
546
|
} else {
|
|
457
|
-
console.log('
|
|
547
|
+
console.log("Use 'coder' to launch Code.");
|
|
458
548
|
}
|
|
459
549
|
}
|
|
460
550
|
} catch {
|