get-codex-lost-world 1.0.3 → 1.0.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Get Codex Lost World - Codex for Desktop
2
2
 
3
- Bring Codex to **Intel Mac** and **Windows** with a simple CLI workflow for build, download, and packaging. 🚀
3
+ Bring Codex to **Intel Mac** with a simple CLI workflow for build, download, and packaging. 🚀
4
4
 
5
5
  [![Build](https://img.shields.io/badge/build-passing-brightgreen)](https://github.com/0x0a0d/get-codex-lost-world)
6
6
  [![Version](https://img.shields.io/badge/version-1.0.3-blue)](https://github.com/0x0a0d/get-codex-lost-world)
@@ -14,15 +14,16 @@ Bring Codex to **Intel Mac** and **Windows** with a simple CLI workflow for buil
14
14
  **Get Codex** is a desktop-focused toolchain that helps users on platforms often left behind by official releases:
15
15
 
16
16
  - macOS Intel (`.dmg`)
17
- - Windows x64 / arm64 (`.zip`)
18
17
 
19
18
  It automates artifact resolution, local build flow, and optional signing steps.
20
19
 
20
+ > [!NOTE]
21
+ > Windows support in this repository was removed because OpenAI now provides an official Codex app for Windows via Microsoft Store: https://apps.microsoft.com/detail/9plm9xgg6vks?hl=en-US&gl=EG
22
+
21
23
  ## Features
22
24
 
23
- - ⚡ Build mode for Intel Mac and Windows targets
25
+ - ⚡ Build mode for Intel Mac target
24
26
  - 📦 Cache/download mode for latest release artifacts
25
- - 🪟 Windows ZIP output (x64, arm64)
26
27
  - 🍎 macOS Intel DMG output
27
28
  - 🔐 Optional signing flow for macOS artifacts
28
29
  - 🧩 Simple CLI flags for platform, arch, format, and workdir
@@ -32,7 +33,7 @@ It automates artifact resolution, local build flow, and optional signing steps.
32
33
  - **Runtime:** Node.js
33
34
  - **Language:** JavaScript (CommonJS)
34
35
  - **Testing:** Node.js built-in test runner (`node --test`)
35
- - **Packaging Scripts:** Custom Node scripts for macOS/Windows build artifacts
36
+ - **Packaging Scripts:** Custom Node scripts for macOS build artifacts
36
37
 
37
38
  ## Installation
38
39
 
@@ -69,16 +70,10 @@ npx get-codex-lost-world
69
70
  npx get-codex-lost-world --build --workdir /absolute/path/to/workdir
70
71
  ```
71
72
 
72
- ### Build for Windows arm64 ZIP
73
-
74
- ```bash
75
- npx get-codex-lost-world --build --platform windows --arch arm64 --format zip --workdir /absolute/path/to/workdir
76
- ```
77
-
78
73
  ### Cache/download mode
79
74
 
80
75
  ```bash
81
- npx get-codex-lost-world --cache --platform windows --arch x64 --format zip
76
+ npx get-codex-lost-world --cache --platform mac --arch x64 --format dmg
82
77
  ```
83
78
 
84
79
  ### Sign mode
@@ -6,7 +6,6 @@ const { spawnSync } = require('node:child_process');
6
6
 
7
7
  function createLocalBuilder(overrides = {}) {
8
8
  const builderEntry = overrides.builderEntry || path.resolve(__dirname, '../../scripts/build-intel-dmg.js');
9
- const windowsBuilderEntry = overrides.windowsBuilderEntry || path.resolve(__dirname, '../../scripts/build-windows-zip.js');
10
9
  const fsApi = overrides.fsApi || fs;
11
10
  const spawnSyncFn = overrides.spawnSync || spawnSync;
12
11
  const nodeExecPath = overrides.nodeExecPath || process.execPath;
@@ -26,8 +25,7 @@ function createLocalBuilder(overrides = {}) {
26
25
  if (!normalizedOutputName) {
27
26
  throw new Error('build output filename is required');
28
27
  }
29
- const platform = String(target && target.platform ? target.platform : 'mac').trim().toLowerCase();
30
- const selectedEntry = platform === 'windows' ? windowsBuilderEntry : builderEntry;
28
+ const selectedEntry = builderEntry;
31
29
 
32
30
  if (!fsApi.existsSync(selectedEntry)) {
33
31
  throw new Error(`Local builder entrypoint (${path.basename(selectedEntry)}) was not found`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "get-codex-lost-world",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "CLI to download/build Codex Mac Intel DMG and Windows ZIP artifacts from upstream Codex.dmg.",
5
5
  "main": "lib/get-codex-lost-world/main.js",
6
6
  "bin": {
@@ -1,341 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const fs = require('node:fs');
5
- const path = require('node:path');
6
- const os = require('node:os');
7
- const { spawnSync } = require('node:child_process');
8
-
9
- function die(message) {
10
- process.stderr.write(`${message}\n`);
11
- process.exit(1);
12
- }
13
-
14
- function parseArgs(argv = process.argv.slice(2)) {
15
- let outputPath = '';
16
- let arch = process.env.BUILD_ARCH || 'x64';
17
- let payloadDir = '';
18
- let installerOutputPath = '';
19
- let projectDir = '';
20
-
21
- for (let i = 0; i < argv.length; i += 1) {
22
- const arg = argv[i];
23
- if (arg === '--output' || arg === '-o') {
24
- const candidate = argv[i + 1];
25
- if (!candidate || candidate.startsWith('-')) {
26
- die('--output requires a file path');
27
- }
28
- outputPath = candidate;
29
- i += 1;
30
- continue;
31
- }
32
-
33
- if (arg === '--arch') {
34
- const candidate = argv[i + 1];
35
- if (!candidate || candidate.startsWith('-')) {
36
- die('--arch requires a value');
37
- }
38
- arch = candidate;
39
- i += 1;
40
- continue;
41
- }
42
-
43
- if (arg === '--payload-dir') {
44
- const candidate = argv[i + 1];
45
- if (!candidate || candidate.startsWith('-')) {
46
- die('--payload-dir requires a path');
47
- }
48
- payloadDir = candidate;
49
- i += 1;
50
- continue;
51
- }
52
-
53
- if (arg === '--installer-output') {
54
- const candidate = argv[i + 1];
55
- if (!candidate || candidate.startsWith('-')) {
56
- die('--installer-output requires a file path');
57
- }
58
- installerOutputPath = candidate;
59
- i += 1;
60
- continue;
61
- }
62
-
63
- if (arg === '--project-dir') {
64
- const candidate = argv[i + 1];
65
- if (!candidate || candidate.startsWith('-')) {
66
- die('--project-dir requires a path');
67
- }
68
- projectDir = candidate;
69
- i += 1;
70
- continue;
71
- }
72
-
73
- if (arg.startsWith('-')) {
74
- die(`Unknown option: ${arg}`);
75
- }
76
- }
77
-
78
- if (!outputPath) {
79
- die('--output is required');
80
- }
81
-
82
- if (!payloadDir) {
83
- die('--payload-dir is required');
84
- }
85
-
86
- if (!projectDir) {
87
- die('--project-dir is required');
88
- }
89
-
90
- return {
91
- outputPath: path.resolve(outputPath),
92
- payloadDir: path.resolve(payloadDir),
93
- installerOutputPath: installerOutputPath ? path.resolve(installerOutputPath) : '',
94
- projectDir: path.resolve(projectDir),
95
- arch: String(arch).trim().toLowerCase(),
96
- };
97
- }
98
-
99
- function build() {
100
- const { outputPath, payloadDir, installerOutputPath, projectDir, arch } = parseArgs();
101
- const outputDir = path.dirname(outputPath);
102
- fs.mkdirSync(outputDir, { recursive: true });
103
- if (installerOutputPath) {
104
- fs.mkdirSync(path.dirname(installerOutputPath), { recursive: true });
105
- }
106
-
107
- const metadataPath = path.join(payloadDir, 'payload-metadata.json');
108
- const resourcesPath = path.join(payloadDir, 'payload', 'Resources');
109
- if (!fs.existsSync(metadataPath)) {
110
- die(`payload metadata not found: ${metadataPath}`);
111
- }
112
- if (!fs.existsSync(resourcesPath)) {
113
- die(`payload resources not found: ${resourcesPath}`);
114
- }
115
-
116
- const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
117
- const electronVersion = String(metadata.electronVersion || '').trim();
118
- const betterSqlite3Version = String(metadata.betterSqlite3Version || '').trim();
119
- const nodePtyVersion = String(metadata.nodePtyVersion || '').trim();
120
- if (!electronVersion) {
121
- die('electronVersion missing in payload-metadata.json');
122
- }
123
- if (!betterSqlite3Version || !nodePtyVersion) {
124
- die('native module versions missing in payload-metadata.json');
125
- }
126
-
127
- function runCommand(command, args, opts = {}) {
128
- const result = spawnSync(command, args, {
129
- stdio: 'inherit',
130
- shell: true,
131
- ...opts,
132
- });
133
- if (result.status !== 0) {
134
- die(`command failed: ${command} ${args.join(' ')}`);
135
- }
136
- }
137
-
138
- function assertPeMachine(filePath, expectedMachine) {
139
- const buffer = fs.readFileSync(filePath);
140
- const peOffset = buffer.readUInt32LE(0x3c);
141
- const peSig = buffer.toString('ascii', peOffset, peOffset + 4);
142
- if (peSig !== 'PE\u0000\u0000') {
143
- die(`invalid PE signature: ${filePath}`);
144
- }
145
-
146
- const machine = buffer.readUInt16LE(peOffset + 4);
147
- if (machine !== expectedMachine) {
148
- die(`unexpected machine type for ${filePath}: got 0x${machine.toString(16)}, expected 0x${expectedMachine.toString(16)}`);
149
- }
150
- }
151
-
152
- const stagingDir = fs.mkdtempSync(path.join(os.tmpdir(), `codex-windows-${arch}-`));
153
- try {
154
- const appDir = path.join(stagingDir, 'Codex');
155
- fs.mkdirSync(appDir, { recursive: true });
156
-
157
- const npmArch = arch === 'arm64' ? 'arm64' : 'x64';
158
-
159
- const projectPackagePath = path.join(projectDir, 'package.json');
160
- if (!fs.existsSync(projectPackagePath)) {
161
- die(`project package.json not found: ${projectPackagePath}`);
162
- }
163
-
164
- const projectNodeModules = path.join(projectDir, 'node_modules');
165
- if (!fs.existsSync(projectNodeModules)) {
166
- die(`project node_modules not found: ${projectNodeModules}. Run npm install in a separate CI step first.`);
167
- }
168
-
169
- runCommand('npx', [
170
- '--yes',
171
- '@electron/rebuild',
172
- '-f',
173
- '-w',
174
- 'better-sqlite3,node-pty',
175
- '--arch',
176
- npmArch,
177
- '--version',
178
- electronVersion,
179
- '-m',
180
- projectDir,
181
- ], { cwd: projectDir });
182
-
183
- const electronDist = path.join(projectDir, 'node_modules', 'electron', 'dist');
184
- if (!fs.existsSync(electronDist)) {
185
- die('electron dist folder not found after npm install');
186
- }
187
-
188
- fs.cpSync(electronDist, appDir, { recursive: true });
189
-
190
- const electronExe = path.join(appDir, 'electron.exe');
191
- const codexExePath = path.join(appDir, 'Codex.exe');
192
- if (fs.existsSync(electronExe)) {
193
- fs.renameSync(electronExe, codexExePath);
194
- } else {
195
- die('electron.exe not found in electron dist output');
196
- }
197
-
198
- const appResources = path.join(appDir, 'resources');
199
- if (fs.existsSync(appResources)) {
200
- fs.rmSync(appResources, { recursive: true, force: true });
201
- }
202
- fs.cpSync(resourcesPath, appResources, { recursive: true });
203
-
204
- const targetUnpacked = path.join(appResources, 'app.asar.unpacked');
205
- if (!fs.existsSync(targetUnpacked)) {
206
- die('target app.asar.unpacked not found in payload resources');
207
- }
208
-
209
- const srcBetterSqlite3 = path.join(projectDir, 'node_modules', 'better-sqlite3');
210
- const srcNodePty = path.join(projectDir, 'node_modules', 'node-pty');
211
- const dstBetterSqlite3 = path.join(targetUnpacked, 'node_modules', 'better-sqlite3');
212
- const dstNodePty = path.join(targetUnpacked, 'node_modules', 'node-pty');
213
-
214
- fs.rmSync(dstBetterSqlite3, { recursive: true, force: true });
215
- fs.rmSync(dstNodePty, { recursive: true, force: true });
216
- fs.cpSync(srcBetterSqlite3, dstBetterSqlite3, { recursive: true });
217
- fs.cpSync(srcNodePty, dstNodePty, { recursive: true });
218
-
219
- const sqliteNode = path.join(dstBetterSqlite3, 'build', 'Release', 'better_sqlite3.node');
220
- const ptyNode = path.join(dstNodePty, 'build', 'Release', 'pty.node');
221
- if (!fs.existsSync(sqliteNode) || !fs.existsSync(ptyNode)) {
222
- die('rebuilt native binaries are missing after module replacement');
223
- }
224
-
225
- const expectedMachine = npmArch === 'arm64' ? 0xaa64 : 0x8664;
226
- assertPeMachine(sqliteNode, expectedMachine);
227
- assertPeMachine(ptyNode, expectedMachine);
228
-
229
- // Replace codex/rg binaries with Windows-target ones when found.
230
- const vendorRoot = path.join(projectDir, 'node_modules');
231
- const walk = (dir, out = []) => {
232
- if (!fs.existsSync(dir)) {
233
- return out;
234
- }
235
- for (const item of fs.readdirSync(dir, { withFileTypes: true })) {
236
- const full = path.join(dir, item.name);
237
- if (item.isDirectory()) {
238
- walk(full, out);
239
- } else {
240
- out.push(full);
241
- }
242
- }
243
- return out;
244
- };
245
- const files = walk(vendorRoot, []);
246
- const codexExe = files.find((f) => /codex\.exe$/i.test(f) && /win32/i.test(f));
247
- const rgExe = files.find((f) => /rg\.exe$/i.test(f) && /win32/i.test(f));
248
- const icoCandidates = files.filter((f) => /\.ico$/i.test(f) && /(codex|icon|logo)/i.test(path.basename(f)));
249
- if (codexExe) {
250
- fs.copyFileSync(codexExe, path.join(appResources, 'codex.exe'));
251
- fs.copyFileSync(codexExe, path.join(targetUnpacked, 'codex.exe'));
252
- } else {
253
- die('failed to locate windows codex.exe from installed dependencies');
254
- }
255
- if (rgExe) {
256
- fs.copyFileSync(rgExe, path.join(appResources, 'rg.exe'));
257
- } else {
258
- die('failed to locate windows rg.exe from installed dependencies');
259
- }
260
-
261
- const iconPath = icoCandidates.length > 0 ? icoCandidates[0] : '';
262
- if (iconPath) {
263
- runCommand('npx', ['--yes', 'rcedit', codexExePath, '--set-icon', iconPath], { cwd: projectDir });
264
- }
265
-
266
- fs.writeFileSync(path.join(appDir, 'build-info.txt'), [
267
- 'Codex Windows portable package',
268
- `arch=${arch}`,
269
- `version=${metadata.version || ''}`,
270
- `electron=${electronVersion}`,
271
- `generated=${new Date().toISOString()}`,
272
- ].join('\n'));
273
-
274
- const result = spawnSync('powershell', [
275
- '-NoProfile',
276
- '-Command',
277
- `Compress-Archive -Path "${appDir}\\*" -DestinationPath "${outputPath}" -Force`,
278
- ], { stdio: 'inherit' });
279
-
280
- if (result.status !== 0) {
281
- die('failed to create windows zip artifact');
282
- }
283
-
284
- if (installerOutputPath) {
285
- const buildVersion = String(metadata.version || '0.0.0').replace(/[^0-9.]/g, '.') || '0.0.0';
286
- const installerConfigPath = path.join(projectDir, 'electron-builder.json');
287
- fs.writeFileSync(installerConfigPath, JSON.stringify({
288
- appId: 'com.openai.codex',
289
- productName: 'Codex',
290
- directories: {
291
- output: path.dirname(installerOutputPath),
292
- },
293
- artifactName: path.basename(installerOutputPath),
294
- win: {
295
- target: [
296
- {
297
- target: 'nsis',
298
- arch: [npmArch],
299
- },
300
- ],
301
- icon: iconPath || undefined,
302
- },
303
- nsis: {
304
- oneClick: false,
305
- perMachine: false,
306
- allowToChangeInstallationDirectory: true,
307
- createDesktopShortcut: true,
308
- shortcutName: 'Codex',
309
- },
310
- }, null, 2));
311
-
312
- runCommand('npx', [
313
- '--yes',
314
- 'electron-builder',
315
- '--win',
316
- 'nsis',
317
- '--publish',
318
- 'never',
319
- `--${npmArch}`,
320
- '--prepackaged',
321
- appDir,
322
- '--config',
323
- installerConfigPath,
324
- '--projectDir',
325
- projectDir,
326
- '--config.extraMetadata.version',
327
- buildVersion,
328
- ], { cwd: projectDir });
329
-
330
- if (!fs.existsSync(installerOutputPath)) {
331
- die(`expected installer was not created: ${installerOutputPath}`);
332
- }
333
- }
334
- } finally {
335
- fs.rmSync(stagingDir, { recursive: true, force: true });
336
- }
337
-
338
- process.stdout.write(`Output ZIP: ${outputPath}\n`);
339
- }
340
-
341
- build();
@@ -1,148 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const fs = require('node:fs');
5
- const os = require('node:os');
6
- const path = require('node:path');
7
- const { spawnSync } = require('node:child_process');
8
-
9
- function fail(message) {
10
- process.stderr.write(`${message}\n`);
11
- process.exit(1);
12
- }
13
-
14
- function parseArgs(argv = process.argv.slice(2)) {
15
- let sourceDmgPath = '';
16
- let outputDir = '';
17
-
18
- for (let i = 0; i < argv.length; i += 1) {
19
- const arg = argv[i];
20
- if (arg === '--source') {
21
- sourceDmgPath = argv[i + 1] || '';
22
- i += 1;
23
- continue;
24
- }
25
- if (arg === '--output-dir') {
26
- outputDir = argv[i + 1] || '';
27
- i += 1;
28
- continue;
29
- }
30
- }
31
-
32
- if (!sourceDmgPath) {
33
- fail('--source is required');
34
- }
35
-
36
- if (!outputDir) {
37
- fail('--output-dir is required');
38
- }
39
-
40
- return {
41
- sourceDmgPath: path.resolve(sourceDmgPath),
42
- outputDir: path.resolve(outputDir),
43
- };
44
- }
45
-
46
- function run() {
47
- const { sourceDmgPath, outputDir } = parseArgs();
48
- fs.mkdirSync(outputDir, { recursive: true });
49
-
50
- function runCommand(cmd, args, opts = {}) {
51
- const result = spawnSync(cmd, args, {
52
- stdio: 'pipe',
53
- ...opts,
54
- });
55
- if (result.status !== 0) {
56
- const stderr = result.stderr ? result.stderr.toString().trim() : '';
57
- fail(`${cmd} failed${stderr ? `: ${stderr}` : ''}`);
58
- }
59
- return result.stdout ? result.stdout.toString().trim() : '';
60
- }
61
-
62
- const mountBase = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-payload-'));
63
- const mountPoint = path.join(mountBase, 'mount');
64
- fs.mkdirSync(mountPoint, { recursive: true });
65
-
66
- const attach = spawnSync('hdiutil', [
67
- 'attach',
68
- '-readonly',
69
- '-nobrowse',
70
- '-mountpoint',
71
- mountPoint,
72
- sourceDmgPath,
73
- ], { stdio: 'pipe' });
74
-
75
- if (attach.status !== 0) {
76
- fail('unable to mount source dmg for payload extraction');
77
- }
78
-
79
- try {
80
- const codexApp = path.join(mountPoint, 'Codex.app');
81
- const infoPlist = path.join(codexApp, 'Contents', 'Info.plist');
82
- const frameworkInfo = path.join(
83
- codexApp,
84
- 'Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/Info.plist'
85
- );
86
-
87
- const resourcesSrc = path.join(codexApp, 'Contents/Resources');
88
- if (!fs.existsSync(resourcesSrc)) {
89
- fail('Resources directory was not found in mounted Codex.app');
90
- }
91
-
92
- const payloadRoot = path.join(outputDir, 'payload');
93
- const resourcesDst = path.join(payloadRoot, 'Resources');
94
- fs.mkdirSync(payloadRoot, { recursive: true });
95
- fs.cpSync(resourcesSrc, resourcesDst, { recursive: true });
96
-
97
- let version = '';
98
- const shortVersion = spawnSync('/usr/libexec/PlistBuddy', ['-c', 'Print :CFBundleShortVersionString', infoPlist], { stdio: 'pipe' });
99
- if (shortVersion.status === 0) {
100
- version = shortVersion.stdout.toString().trim();
101
- }
102
- if (!version) {
103
- const fallbackVersion = spawnSync('/usr/libexec/PlistBuddy', ['-c', 'Print :CFBundleVersion', infoPlist], { stdio: 'pipe' });
104
- version = fallbackVersion.status === 0 ? fallbackVersion.stdout.toString().trim() : '';
105
- }
106
-
107
- const electronVersion = runCommand('/usr/libexec/PlistBuddy', ['-c', 'Print :CFBundleVersion', frameworkInfo]);
108
-
109
- const asarFile = path.join(resourcesSrc, 'app.asar');
110
- const asarMetaDir = path.join(outputDir, 'asar-meta');
111
- fs.mkdirSync(asarMetaDir, { recursive: true });
112
-
113
- runCommand('npx', ['--yes', '@electron/asar', 'extract-file', asarFile, 'node_modules/better-sqlite3/package.json'], { cwd: asarMetaDir });
114
- if (fs.existsSync(path.join(asarMetaDir, 'package.json'))) {
115
- fs.renameSync(path.join(asarMetaDir, 'package.json'), path.join(asarMetaDir, 'better-sqlite3.package.json'));
116
- }
117
-
118
- runCommand('npx', ['--yes', '@electron/asar', 'extract-file', asarFile, 'node_modules/node-pty/package.json'], { cwd: asarMetaDir });
119
- if (fs.existsSync(path.join(asarMetaDir, 'package.json'))) {
120
- fs.renameSync(path.join(asarMetaDir, 'package.json'), path.join(asarMetaDir, 'node-pty.package.json'));
121
- }
122
-
123
- const bsPkgPath = path.join(asarMetaDir, 'better-sqlite3.package.json');
124
- const npPkgPath = path.join(asarMetaDir, 'node-pty.package.json');
125
- const betterSqlite3Version = fs.existsSync(bsPkgPath)
126
- ? JSON.parse(fs.readFileSync(bsPkgPath, 'utf8')).version || ''
127
- : '';
128
- const nodePtyVersion = fs.existsSync(npPkgPath)
129
- ? JSON.parse(fs.readFileSync(npPkgPath, 'utf8')).version || ''
130
- : '';
131
-
132
- fs.writeFileSync(path.join(outputDir, 'payload-metadata.json'), JSON.stringify({
133
- sourceDmgPath,
134
- version,
135
- electronVersion,
136
- betterSqlite3Version,
137
- nodePtyVersion,
138
- extractedAt: new Date().toISOString(),
139
- }, null, 2));
140
- } finally {
141
- spawnSync('hdiutil', ['detach', mountPoint], { stdio: 'pipe' });
142
- fs.rmSync(mountBase, { recursive: true, force: true });
143
- }
144
-
145
- process.stdout.write(`Payload extracted to ${outputDir}\n`);
146
- }
147
-
148
- run();