@just-every/code 0.1.2 → 0.1.4

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.
@@ -56,7 +56,26 @@ if (!targetTriple) {
56
56
  throw new Error(`Unsupported platform: ${platform} (${arch})`);
57
57
  }
58
58
 
59
- const binaryPath = path.join(__dirname, "..", "bin", `code-${targetTriple}`);
59
+ const binaryPath = path.join(__dirname, "..", "bin", `coder-${targetTriple}`);
60
+
61
+ // Check if binary exists and try to fix permissions if needed
62
+ import { existsSync, chmodSync } from "fs";
63
+ if (existsSync(binaryPath)) {
64
+ try {
65
+ // Ensure binary is executable on Unix-like systems
66
+ if (platform !== "win32") {
67
+ chmodSync(binaryPath, 0o755);
68
+ }
69
+ } catch (e) {
70
+ // Ignore permission errors, will be caught below if it's a real problem
71
+ }
72
+ } else {
73
+ console.error(`Binary not found: ${binaryPath}`);
74
+ console.error(`Please try reinstalling the package:`);
75
+ console.error(` npm uninstall -g @just-every/code`);
76
+ console.error(` npm install -g @just-every/code`);
77
+ process.exit(1);
78
+ }
60
79
 
61
80
  // Use an asynchronous spawn instead of spawnSync so that Node is able to
62
81
  // respond to signals (e.g. Ctrl-C / SIGINT) while the native binary is
@@ -67,15 +86,18 @@ const { spawn } = await import("child_process");
67
86
 
68
87
  const child = spawn(binaryPath, process.argv.slice(2), {
69
88
  stdio: "inherit",
70
- env: { ...process.env, CODE_MANAGED_BY_NPM: "1", CODEX_MANAGED_BY_NPM: "1" },
89
+ env: { ...process.env, CODER_MANAGED_BY_NPM: "1", CODEX_MANAGED_BY_NPM: "1" },
71
90
  });
72
91
 
73
92
  child.on("error", (err) => {
74
93
  // Typically triggered when the binary is missing or not executable.
75
- // Re-throwing here will terminate the parent with a non-zero exit code
76
- // while still printing a helpful stack trace.
77
- // eslint-disable-next-line no-console
78
- console.error(err);
94
+ if (err.code === 'EACCES') {
95
+ console.error(`Permission denied: ${binaryPath}`);
96
+ console.error(`Try running: chmod +x "${binaryPath}"`);
97
+ console.error(`Or reinstall the package with: npm install -g @just-every/code`);
98
+ } else {
99
+ console.error(err);
100
+ }
79
101
  process.exit(1);
80
102
  });
81
103
 
@@ -120,4 +142,3 @@ if (childResult.type === "signal") {
120
142
  } else {
121
143
  process.exit(childResult.exitCode);
122
144
  }
123
-
package/bin/codex.js CHANGED
@@ -43,7 +43,7 @@ switch (platform) {
43
43
  targetTriple = "x86_64-pc-windows-msvc.exe";
44
44
  break;
45
45
  case "arm64":
46
- // We do not build this today, fall through...
46
+ // We do not build this today, fall through...
47
47
  default:
48
48
  break;
49
49
  }
@@ -65,9 +65,43 @@ const binaryPath = path.join(__dirname, "..", "bin", `codex-${targetTriple}`);
65
65
  // receives a fatal signal, both processes exit in a predictable manner.
66
66
  const { spawn } = await import("child_process");
67
67
 
68
+ async function tryImport(moduleName) {
69
+ try {
70
+ // eslint-disable-next-line node/no-unsupported-features/es-syntax
71
+ return await import(moduleName);
72
+ } catch (err) {
73
+ return null;
74
+ }
75
+ }
76
+
77
+ async function resolveRgDir() {
78
+ const ripgrep = await tryImport("@vscode/ripgrep");
79
+ if (!ripgrep?.rgPath) {
80
+ return null;
81
+ }
82
+ return path.dirname(ripgrep.rgPath);
83
+ }
84
+
85
+ function getUpdatedPath(newDirs) {
86
+ const pathSep = process.platform === "win32" ? ";" : ":";
87
+ const existingPath = process.env.PATH || "";
88
+ const updatedPath = [
89
+ ...newDirs,
90
+ ...existingPath.split(pathSep).filter(Boolean),
91
+ ].join(pathSep);
92
+ return updatedPath;
93
+ }
94
+
95
+ const additionalDirs = [];
96
+ const rgDir = await resolveRgDir();
97
+ if (rgDir) {
98
+ additionalDirs.push(rgDir);
99
+ }
100
+ const updatedPath = getUpdatedPath(additionalDirs);
101
+
68
102
  const child = spawn(binaryPath, process.argv.slice(2), {
69
103
  stdio: "inherit",
70
- env: { ...process.env, CODEX_MANAGED_BY_NPM: "1" },
104
+ env: { ...process.env, PATH: updatedPath, CODEX_MANAGED_BY_NPM: "1" },
71
105
  });
72
106
 
73
107
  child.on("error", (err) => {
@@ -120,4 +154,3 @@ if (childResult.type === "signal") {
120
154
  } else {
121
155
  process.exit(childResult.exitCode);
122
156
  }
123
-
package/package.json CHANGED
@@ -1,24 +1,35 @@
1
1
  {
2
2
  "name": "@just-every/code",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Lightweight coding agent that runs in your terminal - fork of OpenAI Codex",
6
6
  "bin": {
7
- "code": "bin/code.js"
7
+ "code": "bin/coder.js"
8
8
  },
9
9
  "type": "module",
10
10
  "engines": {
11
11
  "node": ">=20"
12
12
  },
13
13
  "files": [
14
- "bin",
14
+ "bin/coder.js",
15
+ "bin/codex.js",
16
+ "postinstall.js",
15
17
  "dist"
16
18
  ],
19
+ "scripts": {
20
+ "postinstall": "node postinstall.js"
21
+ },
17
22
  "repository": {
18
23
  "type": "git",
19
24
  "url": "git+https://github.com/just-every/code.git"
20
25
  },
21
26
  "publishConfig": {
22
27
  "access": "public"
28
+ },
29
+ "dependencies": {
30
+ "@vscode/ripgrep": "^1.15.14"
31
+ },
32
+ "devDependencies": {
33
+ "prettier": "^3.3.3"
23
34
  }
24
35
  }
package/postinstall.js ADDED
@@ -0,0 +1,221 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { existsSync, mkdirSync, createWriteStream, chmodSync, readFileSync, readSync, writeFileSync } from 'fs';
4
+ import { join, dirname } from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import { get } from 'https';
7
+ import { platform, arch } from 'os';
8
+ import { execSync } from 'child_process';
9
+
10
+ const __dirname = dirname(fileURLToPath(import.meta.url));
11
+
12
+ // Map Node.js platform/arch to Rust target triples
13
+ function getTargetTriple() {
14
+ const platformMap = {
15
+ 'darwin': 'apple-darwin',
16
+ 'linux': 'unknown-linux-musl', // Default to musl for better compatibility
17
+ 'win32': 'pc-windows-msvc'
18
+ };
19
+
20
+ const archMap = {
21
+ 'x64': 'x86_64',
22
+ 'arm64': 'aarch64'
23
+ };
24
+
25
+ const rustArch = archMap[arch()] || arch();
26
+ const rustPlatform = platformMap[platform()] || platform();
27
+
28
+ return `${rustArch}-${rustPlatform}`;
29
+ }
30
+
31
+ async function downloadBinary(url, dest) {
32
+ return new Promise((resolve, reject) => {
33
+ const file = createWriteStream(dest);
34
+
35
+ get(url, (response) => {
36
+ if (response.statusCode === 302 || response.statusCode === 301) {
37
+ // Follow redirect
38
+ get(response.headers.location, (redirectResponse) => {
39
+ redirectResponse.pipe(file);
40
+ file.on('finish', () => {
41
+ file.close();
42
+ resolve();
43
+ });
44
+ }).on('error', reject);
45
+ } else if (response.statusCode === 200) {
46
+ response.pipe(file);
47
+ file.on('finish', () => {
48
+ file.close();
49
+ resolve();
50
+ });
51
+ } else {
52
+ reject(new Error(`Failed to download: ${response.statusCode}`));
53
+ }
54
+ }).on('error', reject);
55
+ });
56
+ }
57
+
58
+ async function main() {
59
+ const targetTriple = getTargetTriple();
60
+ const isWindows = platform() === 'win32';
61
+ const binaryExt = isWindows ? '.exe' : '';
62
+
63
+ const binDir = join(__dirname, 'bin');
64
+ if (!existsSync(binDir)) {
65
+ mkdirSync(binDir, { recursive: true });
66
+ }
67
+
68
+ // Get package version - use readFileSync for compatibility
69
+ const packageJson = JSON.parse(readFileSync(join(__dirname, 'package.json'), 'utf8'));
70
+ const version = packageJson.version;
71
+
72
+ // Binary names to download (Rust artifacts remain named 'coder*')
73
+ const binaries = ['coder', 'coder-tui', 'coder-exec'];
74
+
75
+ console.log(`Installing @just-every/code v${version} for ${targetTriple}...`);
76
+
77
+ for (const binary of binaries) {
78
+ const binaryName = `${binary}-${targetTriple}${binaryExt}`;
79
+ const localPath = join(binDir, binaryName);
80
+
81
+ // Skip if already exists and has correct permissions
82
+ if (existsSync(localPath)) {
83
+ // Always try to fix permissions on Unix-like systems
84
+ if (!isWindows) {
85
+ try {
86
+ chmodSync(localPath, 0o755);
87
+ console.log(`✓ ${binaryName} already exists (permissions fixed)`);
88
+ } catch (e) {
89
+ console.log(`✓ ${binaryName} already exists`);
90
+ }
91
+ } else {
92
+ console.log(`✓ ${binaryName} already exists`);
93
+ }
94
+ continue;
95
+ }
96
+
97
+ const downloadUrl = `https://github.com/just-every/code/releases/download/v${version}/${binaryName}`;
98
+
99
+ console.log(`Downloading ${binaryName}...`);
100
+ try {
101
+ await downloadBinary(downloadUrl, localPath);
102
+
103
+ // Make executable on Unix-like systems
104
+ if (!isWindows) {
105
+ chmodSync(localPath, 0o755);
106
+ }
107
+
108
+ console.log(`✓ Downloaded ${binaryName}`);
109
+ } catch (error) {
110
+ console.error(`✗ Failed to download ${binaryName}: ${error.message}`);
111
+ console.error(` URL: ${downloadUrl}`);
112
+ // Continue with other binaries even if one fails
113
+ }
114
+ }
115
+
116
+ // Create platform-specific symlink/copy for main binary
117
+ const mainBinary = `coder-${targetTriple}${binaryExt}`;
118
+ const mainBinaryPath = join(binDir, mainBinary);
119
+
120
+ if (existsSync(mainBinaryPath)) {
121
+ console.log('Setting up main coder binary...');
122
+
123
+ // On Windows, we can't use symlinks easily, so update the JS wrapper
124
+ // On Unix, the JS wrapper will find the correct binary
125
+ console.log('✓ Installation complete!');
126
+ } else {
127
+ console.warn('⚠ Main coder binary not found. You may need to build from source.');
128
+ }
129
+
130
+ // With bin name = 'code', handle collisions with existing 'code' (e.g., VS Code)
131
+ try {
132
+ const isTTY = process.stdout && process.stdout.isTTY;
133
+ const isWindows = platform() === 'win32';
134
+
135
+ let globalBin = '';
136
+ try {
137
+ globalBin = execSync('npm bin -g', { stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
138
+ } catch {}
139
+
140
+ const ourShim = join(globalBin || '', isWindows ? 'code.cmd' : 'code');
141
+
142
+ // Resolve which 'code' is currently on PATH
143
+ const resolveOnPath = (cmd) => {
144
+ try {
145
+ if (isWindows) {
146
+ const out = execSync(`where ${cmd}`, { stdio: ['ignore', 'pipe', 'ignore'] }).toString().split(/\r?\n/)[0]?.trim();
147
+ return out || '';
148
+ } else {
149
+ return execSync(`command -v ${cmd}`, { stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
150
+ }
151
+ } catch { return ''; }
152
+ };
153
+
154
+ const codeResolved = resolveOnPath('code');
155
+ const collision = codeResolved && ourShim && codeResolved !== ourShim;
156
+
157
+ if (collision) {
158
+ console.log('⚠ Detected an existing `code` command on your PATH (likely VS Code).');
159
+ if (globalBin) {
160
+ // Create a 'coder' shim that forwards to our installed 'code' in the same dir
161
+ try {
162
+ const coderShim = join(globalBin, isWindows ? 'coder.cmd' : 'coder');
163
+ if (isWindows) {
164
+ const content = `@echo off\r\n"%~dp0code" %*\r\n`;
165
+ writeFileSync(coderShim, content);
166
+ } else {
167
+ const content = `#!/bin/sh\nexec "$(dirname \"$0\")/code" "$@"\n`;
168
+ writeFileSync(coderShim, content);
169
+ chmodSync(coderShim, 0o755);
170
+ }
171
+ console.log(`✓ Created fallback command \`coder\` -> our \`code\``);
172
+ } catch (e) {
173
+ console.log(`⚠ Failed to create 'coder' fallback: ${e.message}`);
174
+ }
175
+
176
+ // Offer to create a 'vscode' alias that points to the existing system VS Code
177
+ if (isTTY && codeResolved) {
178
+ const prompt = (msg) => {
179
+ process.stdout.write(msg);
180
+ try {
181
+ const buf = Buffer.alloc(1024);
182
+ const bytes = readSync(0, buf, 0, 1024, null);
183
+ const ans = buf.slice(0, bytes).toString('utf8').trim().toLowerCase();
184
+ return ans;
185
+ } catch { return 'n'; }
186
+ };
187
+ const ans = prompt('Create a `vscode` alias for your existing editor? [y/N] ');
188
+ if (ans === 'y' || ans === 'yes') {
189
+ try {
190
+ const vscodeShim = join(globalBin, isWindows ? 'vscode.cmd' : 'vscode');
191
+ if (isWindows) {
192
+ const content = `@echo off\r\n"${codeResolved}" %*\r\n`;
193
+ writeFileSync(vscodeShim, content);
194
+ } else {
195
+ const content = `#!/bin/sh\nexec "${codeResolved}" "$@"\n`;
196
+ writeFileSync(vscodeShim, content);
197
+ chmodSync(vscodeShim, 0o755);
198
+ }
199
+ console.log('✓ Created `vscode` alias for your editor');
200
+ } catch (e) {
201
+ console.log(`⚠ Failed to create 'vscode' alias: ${e.message}`);
202
+ }
203
+ } else {
204
+ console.log('Skipping creation of `vscode` alias.');
205
+ }
206
+ }
207
+
208
+ console.log('→ Use `coder` to run this tool, and `vscode` (if created) for your editor.');
209
+ } else {
210
+ console.log('Note: could not determine npm global bin; skipping alias creation.');
211
+ }
212
+ }
213
+ } catch {
214
+ // non-fatal
215
+ }
216
+ }
217
+
218
+ main().catch(error => {
219
+ console.error('Installation failed:', error);
220
+ process.exit(1);
221
+ });
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file