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.
- package/README.md +105 -0
- package/bin/get-codex-lost-world.js +62 -0
- package/lib/ci/state.js +17 -0
- package/lib/get-codex-lost-world/args.js +124 -0
- package/lib/get-codex-lost-world/build.js +31 -0
- package/lib/get-codex-lost-world/cache-download.js +21 -0
- package/lib/get-codex-lost-world/local-builder.js +62 -0
- package/lib/get-codex-lost-world/main.js +496 -0
- package/lib/get-codex-lost-world/release.js +62 -0
- package/lib/get-codex-lost-world/sign.js +15 -0
- package/lib/get-codex-lost-world/targets.js +52 -0
- package/package.json +31 -0
- package/scripts/build-intel-dmg.js +508 -0
- package/scripts/build-windows-zip.js +341 -0
- package/scripts/ci/check-update.js +83 -0
- package/scripts/ci/extract-codex-payload.js +148 -0
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Get Codex Lost World - Codex for Desktop
|
|
2
|
+
|
|
3
|
+
Bring Codex to **Intel Mac** and **Windows** with a simple CLI workflow for build, download, and packaging. 🚀
|
|
4
|
+
|
|
5
|
+
[](https://github.com/0x0a0d/get-codex-lost-world)
|
|
6
|
+
[](https://github.com/0x0a0d/get-codex-lost-world)
|
|
7
|
+
[](./LICENSE)
|
|
8
|
+
[](https://github.com/0x0a0d/get-codex-lost-world)
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
## Introduction
|
|
13
|
+
|
|
14
|
+
**Get Codex** is a desktop-focused toolchain that helps users on platforms often left behind by official releases:
|
|
15
|
+
|
|
16
|
+
- macOS Intel (`.dmg`)
|
|
17
|
+
- Windows x64 / arm64 (`.zip`)
|
|
18
|
+
|
|
19
|
+
It automates artifact resolution, local build flow, and optional signing steps.
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
- ⚡ Build mode for Intel Mac and Windows targets
|
|
24
|
+
- 📦 Cache/download mode for latest release artifacts
|
|
25
|
+
- 🪟 Windows ZIP output (x64, arm64)
|
|
26
|
+
- 🍎 macOS Intel DMG output
|
|
27
|
+
- 🔐 Optional signing flow for macOS artifacts
|
|
28
|
+
- 🧩 Simple CLI flags for platform, arch, format, and workdir
|
|
29
|
+
|
|
30
|
+
## Tech Stack
|
|
31
|
+
|
|
32
|
+
- **Runtime:** Node.js
|
|
33
|
+
- **Language:** JavaScript (CommonJS)
|
|
34
|
+
- **Testing:** Node.js built-in test runner (`node --test`)
|
|
35
|
+
- **Packaging Scripts:** Custom Node scripts for macOS/Windows build artifacts
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
### Option 1: Run directly with NPX
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx get-codex-lost-world --help
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Option 2: Clone and run locally
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
git clone https://github.com/0x0a0d/get-codex-lost-world.git
|
|
49
|
+
cd get-codex-lost-world
|
|
50
|
+
npm install
|
|
51
|
+
npm test
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Usage
|
|
55
|
+
|
|
56
|
+
### Show help
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx get-codex-lost-world --help
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Build mode (default)
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx get-codex-lost-world
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npx get-codex-lost-world --build --workdir /absolute/path/to/workdir
|
|
70
|
+
```
|
|
71
|
+
|
|
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
|
+
### Cache/download mode
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npx get-codex-lost-world --cache --platform windows --arch x64 --format zip
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Sign mode
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx get-codex-lost-world --sign /Applications/Codex.app
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Contributing
|
|
91
|
+
|
|
92
|
+
Contributions are welcome! 🙌
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
git checkout -b feat/your-feature
|
|
96
|
+
npm test
|
|
97
|
+
git commit -m "feat: add your feature"
|
|
98
|
+
git push origin feat/your-feature
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Then open a Pull Request.
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
Licensed under the **ISC** License.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { runMain, usage } = require('../lib/get-codex-lost-world/main');
|
|
5
|
+
|
|
6
|
+
function printTargetShortcuts() {
|
|
7
|
+
const message = [
|
|
8
|
+
'',
|
|
9
|
+
'Target shortcuts:',
|
|
10
|
+
' --mac-silicon Build/download for Apple Silicon Mac (default source: original Codex.dmg on macOS arm64 host)',
|
|
11
|
+
' --mac-intel Build/download for Intel Mac (.dmg)',
|
|
12
|
+
' --windows-x64 Build/download for Windows x64 (.zip)',
|
|
13
|
+
' --windows-arm64 Build/download for Windows arm64 (.zip)',
|
|
14
|
+
'',
|
|
15
|
+
'Example:',
|
|
16
|
+
' npx get-codex-lost-world --windows-x64 --workdir /tmp/codex',
|
|
17
|
+
].join('\n');
|
|
18
|
+
|
|
19
|
+
process.stdout.write(`${message}\n`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function remapShortcutArgs(argv = []) {
|
|
23
|
+
const targetShortcuts = {
|
|
24
|
+
'--mac-silicon': ['--platform', 'mac', '--format', 'dmg'],
|
|
25
|
+
'--mac-intel': ['--platform', 'mac', '--arch', 'x64', '--format', 'dmg'],
|
|
26
|
+
'--windows-x64': ['--platform', 'windows', '--arch', 'x64', '--format', 'zip'],
|
|
27
|
+
'--windows-arm64': ['--platform', 'windows', '--arch', 'arm64', '--format', 'zip'],
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const selectedShortcuts = argv.filter((arg) => Object.prototype.hasOwnProperty.call(targetShortcuts, arg));
|
|
31
|
+
if (selectedShortcuts.length > 1) {
|
|
32
|
+
throw new Error(`Target shortcut conflict: ${selectedShortcuts.join(', ')}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const selected = selectedShortcuts[0];
|
|
36
|
+
const withoutShortcuts = argv.filter((arg) => !Object.prototype.hasOwnProperty.call(targetShortcuts, arg));
|
|
37
|
+
|
|
38
|
+
if (!selected) {
|
|
39
|
+
return withoutShortcuts;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return [...withoutShortcuts, ...targetShortcuts[selected]];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function main() {
|
|
46
|
+
const argv = process.argv.slice(2);
|
|
47
|
+
if (argv.includes('--target-help')) {
|
|
48
|
+
process.stdout.write(`${usage()}\n`);
|
|
49
|
+
printTargetShortcuts();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const remapped = remapShortcutArgs(argv);
|
|
54
|
+
await runMain(remapped);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
main().catch((error) => {
|
|
58
|
+
const message = error && error.message ? error.message : String(error);
|
|
59
|
+
process.stderr.write(`${message}\n\n${usage()}\n`);
|
|
60
|
+
process.stderr.write('Use --target-help to see target shortcuts.\n');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
});
|
package/lib/ci/state.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function shouldBuild({ incomingLastModified, cachedLastModified, force }) {
|
|
4
|
+
if (force === true) {
|
|
5
|
+
return true;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (incomingLastModified === cachedLastModified) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
shouldBuild,
|
|
17
|
+
};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function parseArgs(argv = []) {
|
|
4
|
+
const modeFlags = [];
|
|
5
|
+
let signPath;
|
|
6
|
+
let workdir;
|
|
7
|
+
let platform;
|
|
8
|
+
let arch;
|
|
9
|
+
let format;
|
|
10
|
+
let help = false;
|
|
11
|
+
|
|
12
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
13
|
+
const arg = argv[i];
|
|
14
|
+
|
|
15
|
+
if (arg === '--help' || arg === '-h') {
|
|
16
|
+
help = true;
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (arg === '--cache' || arg === '-c') {
|
|
21
|
+
modeFlags.push('cache');
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (arg === '--build' || arg === '-b') {
|
|
26
|
+
modeFlags.push('build');
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (arg === '--sign' || arg === '-s') {
|
|
31
|
+
modeFlags.push('sign');
|
|
32
|
+
const candidate = argv[i + 1];
|
|
33
|
+
if (typeof candidate !== 'string' || candidate.trim() === '' || candidate.startsWith('-')) {
|
|
34
|
+
throw new Error('--sign requires a path');
|
|
35
|
+
}
|
|
36
|
+
signPath = candidate;
|
|
37
|
+
i += 1;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (arg === '--workdir' || arg === '-w') {
|
|
42
|
+
const candidate = argv[i + 1];
|
|
43
|
+
if (typeof candidate !== 'string' || candidate.trim() === '' || candidate.startsWith('-')) {
|
|
44
|
+
throw new Error('--workdir requires a path');
|
|
45
|
+
}
|
|
46
|
+
workdir = candidate;
|
|
47
|
+
i += 1;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (arg === '--platform') {
|
|
52
|
+
const candidate = argv[i + 1];
|
|
53
|
+
if (typeof candidate !== 'string' || candidate.trim() === '' || candidate.startsWith('-')) {
|
|
54
|
+
throw new Error('--platform requires a value');
|
|
55
|
+
}
|
|
56
|
+
platform = candidate;
|
|
57
|
+
i += 1;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (arg === '--arch') {
|
|
62
|
+
const candidate = argv[i + 1];
|
|
63
|
+
if (typeof candidate !== 'string' || candidate.trim() === '' || candidate.startsWith('-')) {
|
|
64
|
+
throw new Error('--arch requires a value');
|
|
65
|
+
}
|
|
66
|
+
arch = candidate;
|
|
67
|
+
i += 1;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (arg === '--format') {
|
|
72
|
+
const candidate = argv[i + 1];
|
|
73
|
+
if (typeof candidate !== 'string' || candidate.trim() === '' || candidate.startsWith('-')) {
|
|
74
|
+
throw new Error('--format requires a value');
|
|
75
|
+
}
|
|
76
|
+
format = candidate;
|
|
77
|
+
i += 1;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (arg.startsWith('-')) {
|
|
82
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const uniqueModes = [...new Set(modeFlags)];
|
|
87
|
+
if (uniqueModes.length > 1) {
|
|
88
|
+
throw new Error('mode flag conflict');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (help) {
|
|
92
|
+
return { mode: 'help' };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const mode = uniqueModes[0] || 'build';
|
|
96
|
+
const result = { mode };
|
|
97
|
+
|
|
98
|
+
if (typeof platform === 'string') {
|
|
99
|
+
result.platform = platform;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (typeof arch === 'string') {
|
|
103
|
+
result.arch = arch;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (typeof format === 'string') {
|
|
107
|
+
result.format = format;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (typeof workdir === 'string') {
|
|
111
|
+
result.workdir = workdir;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (mode === 'sign') {
|
|
115
|
+
result.signPath = signPath;
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
module.exports = {
|
|
123
|
+
parseArgs,
|
|
124
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function sanitizeVersion(version) {
|
|
4
|
+
return String(version || '')
|
|
5
|
+
.trim()
|
|
6
|
+
.replace(/\s+/g, '-')
|
|
7
|
+
.replace(/[^0-9A-Za-z._-]/g, '-');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function makeOutputName(version) {
|
|
11
|
+
return `CodexIntelMac_${sanitizeVersion(version)}.dmg`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function makeOutputNameForTarget({ version, platform, arch, format }) {
|
|
15
|
+
const safeVersion = sanitizeVersion(version);
|
|
16
|
+
const normalizedPlatform = String(platform || '').trim().toLowerCase();
|
|
17
|
+
const normalizedArch = String(arch || '').trim().toLowerCase();
|
|
18
|
+
const normalizedFormat = String(format || '').trim().toLowerCase();
|
|
19
|
+
|
|
20
|
+
if (normalizedPlatform === 'windows') {
|
|
21
|
+
return `CodexWindows_${normalizedArch || 'x64'}_${safeVersion}.${normalizedFormat || 'zip'}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return `CodexIntelMac_${safeVersion}.${normalizedFormat || 'dmg'}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = {
|
|
28
|
+
sanitizeVersion,
|
|
29
|
+
makeOutputName,
|
|
30
|
+
makeOutputNameForTarget,
|
|
31
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function resolveCacheDownload(location) {
|
|
4
|
+
const normalized = typeof location === 'string' ? location.trim() : '';
|
|
5
|
+
|
|
6
|
+
if (!normalized) {
|
|
7
|
+
return {
|
|
8
|
+
shouldDownload: false,
|
|
9
|
+
location: '',
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
shouldDownload: true,
|
|
15
|
+
location: normalized,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
resolveCacheDownload,
|
|
21
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { spawnSync } = require('node:child_process');
|
|
6
|
+
|
|
7
|
+
function createLocalBuilder(overrides = {}) {
|
|
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
|
+
const fsApi = overrides.fsApi || fs;
|
|
11
|
+
const spawnSyncFn = overrides.spawnSync || spawnSync;
|
|
12
|
+
const nodeExecPath = overrides.nodeExecPath || process.execPath;
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
async run({ location, downloadedPath, outputName, target }) {
|
|
16
|
+
const normalizedLocation = typeof location === 'string' ? location.trim() : '';
|
|
17
|
+
const normalizedSource = typeof downloadedPath === 'string' ? downloadedPath.trim() : '';
|
|
18
|
+
const normalizedOutputName = typeof outputName === 'string' ? outputName.trim() : '';
|
|
19
|
+
|
|
20
|
+
if (!normalizedLocation) {
|
|
21
|
+
throw new Error('build output location is required');
|
|
22
|
+
}
|
|
23
|
+
if (!normalizedSource) {
|
|
24
|
+
throw new Error('source Codex.dmg path is required to run the builder');
|
|
25
|
+
}
|
|
26
|
+
if (!normalizedOutputName) {
|
|
27
|
+
throw new Error('build output filename is required');
|
|
28
|
+
}
|
|
29
|
+
const platform = String(target && target.platform ? target.platform : 'mac').trim().toLowerCase();
|
|
30
|
+
const selectedEntry = platform === 'windows' ? windowsBuilderEntry : builderEntry;
|
|
31
|
+
|
|
32
|
+
if (!fsApi.existsSync(selectedEntry)) {
|
|
33
|
+
throw new Error(`Local builder entrypoint (${path.basename(selectedEntry)}) was not found`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
fsApi.mkdirSync(normalizedLocation, { recursive: true });
|
|
37
|
+
const outputPath = path.join(normalizedLocation, normalizedOutputName);
|
|
38
|
+
const result = spawnSyncFn(nodeExecPath, [
|
|
39
|
+
selectedEntry,
|
|
40
|
+
'--output',
|
|
41
|
+
outputPath,
|
|
42
|
+
normalizedSource,
|
|
43
|
+
], {
|
|
44
|
+
stdio: 'inherit',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
if (result.error) {
|
|
48
|
+
throw result.error;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (result.status !== 0) {
|
|
52
|
+
throw new Error('Local builder failed (see logs above for details)');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return { outputPath };
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = {
|
|
61
|
+
createLocalBuilder,
|
|
62
|
+
};
|