@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 CHANGED
@@ -33,14 +33,20 @@
33
33
   
34
34
  ## Quickstart
35
35
 
36
- ### Install Code
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., VS Code), our CLI is also installed as `coder`. Use `coder` to avoid conflicts. Check which command runs with `which -a code` (or `type -a code`). You can also run our CLI explicitly via `npx -y @just-every/code` or `$(npm bin -g)/code`.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@just-every/code",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Lightweight coding agent that runs in your terminal - fork of OpenAI Codex",
6
6
  "bin": {
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
- return new Promise((resolve, reject) => {
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
- // Only create the file stream after we know it's a successful response
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
- resolve();
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
- }).on('error', (err) => {
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) {