get-codex-lost-world 1.0.3

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.
@@ -0,0 +1,341 @@
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();
@@ -0,0 +1,83 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const { shouldBuild } = require('../../lib/ci/state');
5
+
6
+ function parseForce(value) {
7
+ const normalized = String(value || '').trim().toLowerCase();
8
+
9
+ if (normalized === 'true' || normalized === '1' || normalized === 'yes') {
10
+ return true;
11
+ }
12
+
13
+ if (normalized === 'false' || normalized === '0' || normalized === 'no') {
14
+ return false;
15
+ }
16
+
17
+ return false;
18
+ }
19
+
20
+ function getReason({ force, build }) {
21
+ if (force) {
22
+ return 'force';
23
+ }
24
+
25
+ return build ? 'changed' : 'unchanged';
26
+ }
27
+
28
+ function appendGithubOutput(filePath, outputs) {
29
+ if (!filePath) {
30
+ return;
31
+ }
32
+
33
+ const lines = [
34
+ `should_build=${outputs.shouldBuild}`,
35
+ `reason=${outputs.reason}`,
36
+ ].join('\n') + '\n';
37
+
38
+ try {
39
+ fs.appendFileSync(filePath, lines, 'utf8');
40
+ } catch (error) {
41
+ process.stdout.write(`Warning: could not write GITHUB_OUTPUT (${error.message})\n`);
42
+ }
43
+ }
44
+
45
+ function run(env = process.env) {
46
+ const incomingLastModified = env.LAST_MODIFIED;
47
+ const cachedLastModified = env.CACHED_LAST_MODIFIED;
48
+ const force = parseForce(env.FORCE);
49
+
50
+ const build = shouldBuild({
51
+ incomingLastModified,
52
+ cachedLastModified,
53
+ force,
54
+ });
55
+
56
+ const reason = getReason({ force, build });
57
+
58
+ process.stdout.write(
59
+ `CI check: should_build=${build} (reason=${reason}, incoming=${incomingLastModified || ''}, cached=${cachedLastModified || ''}, force=${force})\n`
60
+ );
61
+
62
+ appendGithubOutput(env.GITHUB_OUTPUT, {
63
+ shouldBuild: build,
64
+ reason,
65
+ });
66
+
67
+ return {
68
+ shouldBuild: build,
69
+ reason,
70
+ force,
71
+ };
72
+ }
73
+
74
+ if (require.main === module) {
75
+ run(process.env);
76
+ process.exitCode = 0;
77
+ }
78
+
79
+ module.exports = {
80
+ run,
81
+ parseForce,
82
+ getReason,
83
+ };
@@ -0,0 +1,148 @@
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();