@just-every/code 0.2.4 → 0.2.6
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 +9 -3
- package/bin/coder.js +27 -0
- package/package.json +1 -1
- package/postinstall.js +54 -6
package/README.md
CHANGED
|
@@ -33,14 +33,20 @@
|
|
|
33
33
|
 
|
|
34
34
|
## Quickstart
|
|
35
35
|
|
|
36
|
-
###
|
|
36
|
+
### Run
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npx -y @just-every/code
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Install & Run
|
|
37
43
|
|
|
38
44
|
```bash
|
|
39
45
|
npm install -g @just-every/code
|
|
40
|
-
code
|
|
46
|
+
code // or `coder` if you're using VS Code
|
|
41
47
|
```
|
|
42
48
|
|
|
43
|
-
Note: If another tool already provides a `code` command (e.g
|
|
49
|
+
Note: If another tool already provides a `code` command (e.g. VS Code), our CLI is also installed as `coder`. Use `coder` to avoid conflicts.
|
|
44
50
|
|
|
45
51
|
**Authenticate** (one of the following):
|
|
46
52
|
- **Sign in with ChatGPT** (Plus/Pro/Team; uses models available to your plan)
|
package/bin/coder.js
CHANGED
|
@@ -10,6 +10,20 @@ const __dirname = path.dirname(__filename);
|
|
|
10
10
|
|
|
11
11
|
const { platform, arch } = process;
|
|
12
12
|
|
|
13
|
+
const isWSL = () => {
|
|
14
|
+
if (platform !== "linux") return false;
|
|
15
|
+
try {
|
|
16
|
+
const os = require("os");
|
|
17
|
+
const rel = os.release().toLowerCase();
|
|
18
|
+
if (rel.includes("microsoft")) return true;
|
|
19
|
+
const fs = require("fs");
|
|
20
|
+
const txt = fs.readFileSync("/proc/version", "utf8").toLowerCase();
|
|
21
|
+
return txt.includes("microsoft");
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
13
27
|
let targetTriple = null;
|
|
14
28
|
switch (platform) {
|
|
15
29
|
case "linux":
|
|
@@ -78,6 +92,11 @@ if (existsSync(binaryPath)) {
|
|
|
78
92
|
console.error(`Please try reinstalling the package:`);
|
|
79
93
|
console.error(` npm uninstall -g @just-every/code`);
|
|
80
94
|
console.error(` npm install -g @just-every/code`);
|
|
95
|
+
if (isWSL()) {
|
|
96
|
+
console.error("Detected WSL. Install inside WSL (Ubuntu) separately:");
|
|
97
|
+
console.error(" npx -y @just-every/code@latest (run inside WSL)");
|
|
98
|
+
console.error("If installed globally on Windows, those binaries are not usable from WSL.");
|
|
99
|
+
}
|
|
81
100
|
process.exit(1);
|
|
82
101
|
}
|
|
83
102
|
|
|
@@ -122,6 +141,10 @@ if (!validation.ok) {
|
|
|
122
141
|
console.error("If the issue persists, clear npm cache and disable antivirus temporarily:");
|
|
123
142
|
console.error(" npm cache clean --force");
|
|
124
143
|
}
|
|
144
|
+
if (isWSL()) {
|
|
145
|
+
console.error("Detected WSL. Ensure you install/run inside WSL, not Windows:");
|
|
146
|
+
console.error(" npx -y @just-every/code@latest (inside WSL)");
|
|
147
|
+
}
|
|
125
148
|
process.exit(1);
|
|
126
149
|
}
|
|
127
150
|
|
|
@@ -152,6 +175,10 @@ child.on("error", (err) => {
|
|
|
152
175
|
console.error("On Windows, ensure the .exe downloaded correctly (proxy/AV can interfere).");
|
|
153
176
|
console.error("Try clearing cache: npm cache clean --force");
|
|
154
177
|
}
|
|
178
|
+
if (isWSL()) {
|
|
179
|
+
console.error("Detected WSL. Windows binaries cannot be executed from WSL.");
|
|
180
|
+
console.error("Install inside WSL and run there: npx -y @just-every/code@latest");
|
|
181
|
+
}
|
|
155
182
|
} else {
|
|
156
183
|
console.error(err);
|
|
157
184
|
}
|
package/package.json
CHANGED
package/postinstall.js
CHANGED
|
@@ -29,10 +29,12 @@ function getTargetTriple() {
|
|
|
29
29
|
return `${rustArch}-${rustPlatform}`;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
async function downloadBinary(url, dest, maxRedirects = 5) {
|
|
33
|
-
|
|
32
|
+
async function downloadBinary(url, dest, maxRedirects = 5, maxRetries = 3) {
|
|
33
|
+
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
|
34
|
+
|
|
35
|
+
const doAttempt = () => new Promise((resolve, reject) => {
|
|
34
36
|
const attempt = (currentUrl, redirectsLeft) => {
|
|
35
|
-
get(currentUrl, (response) => {
|
|
37
|
+
const req = get(currentUrl, (response) => {
|
|
36
38
|
const status = response.statusCode || 0;
|
|
37
39
|
const location = response.headers.location;
|
|
38
40
|
|
|
@@ -46,28 +48,74 @@ async function downloadBinary(url, dest, maxRedirects = 5) {
|
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
if (status === 200) {
|
|
49
|
-
|
|
51
|
+
const expected = parseInt(response.headers['content-length'] || '0', 10) || 0;
|
|
52
|
+
let bytes = 0;
|
|
53
|
+
let timer;
|
|
54
|
+
const timeoutMs = 30000; // 30s inactivity timeout
|
|
55
|
+
|
|
56
|
+
const resetTimer = () => {
|
|
57
|
+
if (timer) clearTimeout(timer);
|
|
58
|
+
timer = setTimeout(() => {
|
|
59
|
+
req.destroy(new Error('download stalled'));
|
|
60
|
+
}, timeoutMs);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
resetTimer();
|
|
64
|
+
response.on('data', (chunk) => {
|
|
65
|
+
bytes += chunk.length;
|
|
66
|
+
resetTimer();
|
|
67
|
+
});
|
|
68
|
+
|
|
50
69
|
const file = createWriteStream(dest);
|
|
51
70
|
response.pipe(file);
|
|
52
71
|
file.on('finish', () => {
|
|
72
|
+
if (timer) clearTimeout(timer);
|
|
53
73
|
file.close();
|
|
54
|
-
|
|
74
|
+
if (expected && bytes !== expected) {
|
|
75
|
+
try { unlinkSync(dest); } catch {}
|
|
76
|
+
reject(new Error(`incomplete download: got ${bytes} of ${expected} bytes`));
|
|
77
|
+
} else if (bytes === 0) {
|
|
78
|
+
try { unlinkSync(dest); } catch {}
|
|
79
|
+
reject(new Error('empty download'));
|
|
80
|
+
} else {
|
|
81
|
+
resolve();
|
|
82
|
+
}
|
|
55
83
|
});
|
|
56
84
|
file.on('error', (err) => {
|
|
85
|
+
if (timer) clearTimeout(timer);
|
|
57
86
|
try { unlinkSync(dest); } catch {}
|
|
58
87
|
reject(err);
|
|
59
88
|
});
|
|
60
89
|
} else {
|
|
61
90
|
reject(new Error(`Failed to download: HTTP ${status}`));
|
|
62
91
|
}
|
|
63
|
-
})
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
req.on('error', (err) => {
|
|
64
95
|
try { unlinkSync(dest); } catch {}
|
|
65
96
|
reject(err);
|
|
66
97
|
});
|
|
98
|
+
|
|
99
|
+
// Absolute request timeout to avoid hanging forever
|
|
100
|
+
req.setTimeout(120000, () => {
|
|
101
|
+
req.destroy(new Error('download timed out'));
|
|
102
|
+
});
|
|
67
103
|
};
|
|
68
104
|
|
|
69
105
|
attempt(url, maxRedirects);
|
|
70
106
|
});
|
|
107
|
+
|
|
108
|
+
let attemptNum = 0;
|
|
109
|
+
while (true) {
|
|
110
|
+
try {
|
|
111
|
+
return await doAttempt();
|
|
112
|
+
} catch (e) {
|
|
113
|
+
attemptNum += 1;
|
|
114
|
+
if (attemptNum > maxRetries) throw e;
|
|
115
|
+
const backoff = Math.min(2000, 200 * attemptNum);
|
|
116
|
+
await sleep(backoff);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
71
119
|
}
|
|
72
120
|
|
|
73
121
|
function validateDownloadedBinary(p) {
|