codex-wrapped-noyrlimit 1.0.0
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 +141 -0
- package/assets/images/codex-logo.base64.txt +1 -0
- package/assets/images/codex-logo.png +0 -0
- package/assets/images/demo-wrapped.png +0 -0
- package/bin/codex-wrapped-noyrlimit +79 -0
- package/package.json +43 -0
- package/postinstall.mjs +244 -0
package/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# codex-wrapped-noyrlimit
|
|
4
|
+
|
|
5
|
+
**Your year in code, beautifully visualized.**
|
|
6
|
+
|
|
7
|
+
<p>
|
|
8
|
+
<strong>Credit:</strong> Built on top of
|
|
9
|
+
<a href="https://github.com/moddi3/opencode-wrapped">opencode-wrapped</a>
|
|
10
|
+
by moddi3 (<a href="https://x.com/moddi3io">@moddi3io</a>).
|
|
11
|
+
</p>
|
|
12
|
+
<p>
|
|
13
|
+
Found this useful? Follow <a href="https://x.com/nummanali">@nummanali</a> for more AI tooling!
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
Generate a personalized "Spotify Wrapped"-style summary of your [Codex](https://openai.com/codex) usage.
|
|
17
|
+
|
|
18
|
+
[](LICENSE)
|
|
19
|
+
[](https://bun.sh)
|
|
20
|
+
|
|
21
|
+
<img src="./assets/images/demo-wrapped.png" alt="Codex Wrapped Example" width="600" />
|
|
22
|
+
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
### Quick Start
|
|
30
|
+
|
|
31
|
+
Run directly without installing:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx codex-wrapped-noyrlimit # or bunx, or yarn/pnpm dlx
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Global Install
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install -g codex-wrapped-noyrlimit # or bun/yarn/pnpm
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Then run anywhere:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
codex-wrapped-noyrlimit
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Usage Options
|
|
50
|
+
|
|
51
|
+
| Option | Description |
|
|
52
|
+
| --------------- | ------------------------------------ |
|
|
53
|
+
| `--year, -y` | Generate wrapped for a specific year |
|
|
54
|
+
| `--help, -h` | Show help message |
|
|
55
|
+
| `--version, -v` | Show version number |
|
|
56
|
+
|
|
57
|
+
## Features
|
|
58
|
+
|
|
59
|
+
- Sessions, messages, tokens, projects, and streaks
|
|
60
|
+
- GitHub-style activity heatmap
|
|
61
|
+
- Top models and providers breakdown
|
|
62
|
+
- Usage cost (when available)
|
|
63
|
+
- Shareable PNG image
|
|
64
|
+
- Inline image display (Ghostty, Kitty, iTerm2, WezTerm, Konsole)
|
|
65
|
+
- Auto-copy to clipboard
|
|
66
|
+
|
|
67
|
+
## Terminal Support
|
|
68
|
+
|
|
69
|
+
The wrapped image displays natively in terminals that support inline images:
|
|
70
|
+
|
|
71
|
+
| Terminal | Protocol | Status |
|
|
72
|
+
| ------------------------------------------ | -------------- | --------------------------- |
|
|
73
|
+
| [Ghostty](https://ghostty.org) | Kitty Graphics | Full support |
|
|
74
|
+
| [Kitty](https://sw.kovidgoyal.net/kitty/) | Kitty Graphics | Full support |
|
|
75
|
+
| [WezTerm](https://wezfurlong.org/wezterm/) | Kitty + iTerm2 | Full support |
|
|
76
|
+
| [iTerm2](https://iterm2.com) | iTerm2 Inline | Full support |
|
|
77
|
+
| [Konsole](https://konsole.kde.org) | Kitty Graphics | Full support |
|
|
78
|
+
| Other terminals | — | Image saved to file only |
|
|
79
|
+
|
|
80
|
+
## Output
|
|
81
|
+
|
|
82
|
+
The tool generates:
|
|
83
|
+
|
|
84
|
+
1. **Terminal Summary** — Quick stats overview in your terminal
|
|
85
|
+
2. **PNG Image** — A beautiful, shareable wrapped card saved to your home directory
|
|
86
|
+
3. **Clipboard** — Automatically copies the image to your clipboard
|
|
87
|
+
|
|
88
|
+
## Data Source
|
|
89
|
+
|
|
90
|
+
Codex Wrapped reads data from your local Codex CLI installation:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
~/.codex/ (history.jsonl, sessions, logs)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
No data is sent anywhere. Everything is processed locally.
|
|
97
|
+
|
|
98
|
+
## Building
|
|
99
|
+
|
|
100
|
+
### Development
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Run in development mode with hot reload
|
|
104
|
+
bun run dev
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Production Build
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# Build for all platforms
|
|
111
|
+
bun run build
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Releasing
|
|
115
|
+
|
|
116
|
+
Releases are automated via [semantic-release](https://semantic-release.gitbook.io). Merging PRs with [conventional commits](https://www.conventionalcommits.org) to `main` triggers a release.
|
|
117
|
+
|
|
118
|
+
## Tech Stack
|
|
119
|
+
|
|
120
|
+
- **Runtime**: [Bun](https://bun.sh)
|
|
121
|
+
- **Image Generation**: [Satori](https://github.com/vercel/satori) + [Resvg](https://github.com/nicolo-ribaudo/resvg-js)
|
|
122
|
+
- **CLI UI**: [@clack/prompts](https://github.com/natemoo-re/clack)
|
|
123
|
+
- **Font**: IBM Plex Mono
|
|
124
|
+
|
|
125
|
+
## Contributing
|
|
126
|
+
|
|
127
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
<div align="center">
|
|
136
|
+
|
|
137
|
+
Built for the Codex community
|
|
138
|
+
|
|
139
|
+
Credit: <a href="https://github.com/ryoppippi/ccusage">ccusage</a>
|
|
140
|
+
|
|
141
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
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EREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREUll+n+9jCCOzonctAAAAABJRU5ErkJggg==
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
6
|
+
import { platform as osPlatform, arch as osArch } from "node:os";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
11
|
+
|
|
12
|
+
function run(target) {
|
|
13
|
+
const result = spawnSync(target, process.argv.slice(2), {
|
|
14
|
+
stdio: "inherit",
|
|
15
|
+
});
|
|
16
|
+
if (result.error) {
|
|
17
|
+
console.error(result.error.message);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
const code = typeof result.status === "number" ? result.status : 0;
|
|
21
|
+
process.exit(code);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const platformMap = {
|
|
25
|
+
darwin: "darwin",
|
|
26
|
+
linux: "linux",
|
|
27
|
+
win32: "windows",
|
|
28
|
+
};
|
|
29
|
+
const archMap = {
|
|
30
|
+
x64: "x64",
|
|
31
|
+
arm64: "arm64",
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
let platform = platformMap[osPlatform()];
|
|
35
|
+
if (!platform) {
|
|
36
|
+
platform = osPlatform();
|
|
37
|
+
}
|
|
38
|
+
let arch = archMap[osArch()];
|
|
39
|
+
if (!arch) {
|
|
40
|
+
arch = osArch();
|
|
41
|
+
}
|
|
42
|
+
const base = "codex-wrapped-noyrlimit-" + platform + "-" + arch;
|
|
43
|
+
const binary = platform === "windows" ? "codex-wrapped-noyrlimit.exe" : "codex-wrapped-noyrlimit";
|
|
44
|
+
|
|
45
|
+
function findBinary(startDir) {
|
|
46
|
+
let current = startDir;
|
|
47
|
+
for (;;) {
|
|
48
|
+
const modules = join(current, "node_modules");
|
|
49
|
+
if (fs.existsSync(modules)) {
|
|
50
|
+
const entries = fs.readdirSync(modules);
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
if (!entry.startsWith(base)) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const candidate = join(modules, entry, "bin", binary);
|
|
56
|
+
if (fs.existsSync(candidate)) {
|
|
57
|
+
return candidate;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const parent = dirname(current);
|
|
62
|
+
if (parent === current) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
current = parent;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const resolved = findBinary(__dirname);
|
|
70
|
+
if (!resolved) {
|
|
71
|
+
console.error(
|
|
72
|
+
'It seems that your package manager failed to install the right version of codex-wrapped-noyrlimit CLI for your platform. You can try manually installing "' +
|
|
73
|
+
base +
|
|
74
|
+
'" package'
|
|
75
|
+
);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
run(resolved);
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "codex-wrapped-noyrlimit",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Generate a personalized Spotify Wrapped-style summary of your Codex usage",
|
|
5
|
+
"bin": {
|
|
6
|
+
"codex-wrapped-noyrlimit": "bin/codex-wrapped-noyrlimit"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"postinstall": "node ./postinstall.mjs"
|
|
10
|
+
},
|
|
11
|
+
"optionalDependencies": {
|
|
12
|
+
"codex-wrapped-noyrlimit-linux-arm64": "1.0.0",
|
|
13
|
+
"codex-wrapped-noyrlimit-linux-x64": "1.0.0",
|
|
14
|
+
"codex-wrapped-noyrlimit-linux-x64-baseline": "1.0.0",
|
|
15
|
+
"codex-wrapped-noyrlimit-linux-arm64-musl": "1.0.0",
|
|
16
|
+
"codex-wrapped-noyrlimit-linux-x64-musl": "1.0.0",
|
|
17
|
+
"codex-wrapped-noyrlimit-linux-x64-baseline-musl": "1.0.0",
|
|
18
|
+
"codex-wrapped-noyrlimit-darwin-arm64": "1.0.0",
|
|
19
|
+
"codex-wrapped-noyrlimit-darwin-x64": "1.0.0",
|
|
20
|
+
"codex-wrapped-noyrlimit-darwin-x64-baseline": "1.0.0",
|
|
21
|
+
"codex-wrapped-noyrlimit-windows-x64": "1.0.0",
|
|
22
|
+
"codex-wrapped-noyrlimit-windows-x64-baseline": "1.0.0"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/numman-ali/codex-wrapped.git"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/numman-ali/codex-wrapped",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/numman-ali/codex-wrapped/issues"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"codex",
|
|
34
|
+
"openai",
|
|
35
|
+
"wrapped",
|
|
36
|
+
"codex-wrapped"
|
|
37
|
+
],
|
|
38
|
+
"author": {
|
|
39
|
+
"name": "Numman Ali",
|
|
40
|
+
"email": "numman.ali@gmail.com"
|
|
41
|
+
},
|
|
42
|
+
"license": "MIT"
|
|
43
|
+
}
|
package/postinstall.mjs
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Postinstall script for codex-wrapped-noyrlimit
|
|
5
|
+
*
|
|
6
|
+
* This script runs after npm install and symlinks the correct platform-specific
|
|
7
|
+
* binary to the bin directory. It auto-detects:
|
|
8
|
+
* - Platform (darwin, linux, windows)
|
|
9
|
+
* - Architecture (arm64, x64)
|
|
10
|
+
* - Libc (glibc, musl) for Linux
|
|
11
|
+
* - AVX2 support (baseline vs optimized) for x64
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import fs from "fs";
|
|
15
|
+
import path from "path";
|
|
16
|
+
import os from "os";
|
|
17
|
+
import { execSync } from "child_process";
|
|
18
|
+
import { fileURLToPath } from "url";
|
|
19
|
+
import { createRequire } from "module";
|
|
20
|
+
|
|
21
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
22
|
+
const require = createRequire(import.meta.url);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Detect if the system uses musl libc (Alpine Linux, etc.)
|
|
26
|
+
*/
|
|
27
|
+
function detectMusl() {
|
|
28
|
+
if (os.platform() !== "linux") return false;
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
// Method 1: Check ldd output
|
|
32
|
+
const lddOutput = execSync("ldd --version 2>&1 || true", { encoding: "utf8" });
|
|
33
|
+
if (lddOutput.toLowerCase().includes("musl")) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Method 2: Check for musl loader
|
|
38
|
+
const files = fs.readdirSync("/lib").filter((f) => f.startsWith("ld-musl-"));
|
|
39
|
+
if (files.length > 0) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
} catch {
|
|
43
|
+
// Ignore errors
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Detect if the CPU supports AVX2 instructions
|
|
51
|
+
*/
|
|
52
|
+
function detectAVX2() {
|
|
53
|
+
if (os.arch() !== "x64") return true; // Only relevant for x64
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
if (os.platform() === "linux") {
|
|
57
|
+
const cpuinfo = fs.readFileSync("/proc/cpuinfo", "utf8");
|
|
58
|
+
return cpuinfo.toLowerCase().includes("avx2");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (os.platform() === "darwin") {
|
|
62
|
+
const output = execSync("sysctl -n machdep.cpu.features 2>/dev/null || true", {
|
|
63
|
+
encoding: "utf8",
|
|
64
|
+
});
|
|
65
|
+
return output.toLowerCase().includes("avx2");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (os.platform() === "win32") {
|
|
69
|
+
// Windows: Assume AVX2 support on modern systems
|
|
70
|
+
// A more robust check would require native code
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
// If we can't detect, assume AVX2 is supported
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get the platform-specific package name
|
|
82
|
+
*/
|
|
83
|
+
function getPackageName() {
|
|
84
|
+
let platform;
|
|
85
|
+
switch (os.platform()) {
|
|
86
|
+
case "darwin":
|
|
87
|
+
platform = "darwin";
|
|
88
|
+
break;
|
|
89
|
+
case "linux":
|
|
90
|
+
platform = "linux";
|
|
91
|
+
break;
|
|
92
|
+
case "win32":
|
|
93
|
+
platform = "windows";
|
|
94
|
+
break;
|
|
95
|
+
default:
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let arch;
|
|
100
|
+
switch (os.arch()) {
|
|
101
|
+
case "x64":
|
|
102
|
+
arch = "x64";
|
|
103
|
+
break;
|
|
104
|
+
case "arm64":
|
|
105
|
+
arch = "arm64";
|
|
106
|
+
break;
|
|
107
|
+
default:
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Build package name parts
|
|
112
|
+
const parts = ["codex-wrapped-noyrlimit", platform, arch];
|
|
113
|
+
|
|
114
|
+
// Add baseline suffix for x64 without AVX2
|
|
115
|
+
if (arch === "x64" && !detectAVX2()) {
|
|
116
|
+
parts.push("baseline");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Add musl suffix for Linux with musl libc
|
|
120
|
+
if (platform === "linux" && detectMusl()) {
|
|
121
|
+
parts.push("musl");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return parts.join("-");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Find the binary from the platform package
|
|
129
|
+
*/
|
|
130
|
+
function findBinary(packageName) {
|
|
131
|
+
const binaryName =
|
|
132
|
+
os.platform() === "win32" ? "codex-wrapped-noyrlimit.exe" : "codex-wrapped-noyrlimit";
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
const packageJsonPath = require.resolve(`${packageName}/package.json`);
|
|
136
|
+
const packageDir = path.dirname(packageJsonPath);
|
|
137
|
+
const binaryPath = path.join(packageDir, "bin", binaryName);
|
|
138
|
+
|
|
139
|
+
if (fs.existsSync(binaryPath)) {
|
|
140
|
+
return { binaryPath, binaryName };
|
|
141
|
+
}
|
|
142
|
+
} catch {
|
|
143
|
+
// Package not found via require.resolve
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Fallback: try common paths
|
|
147
|
+
const fallbackPaths = [
|
|
148
|
+
path.join(__dirname, "..", packageName, "bin", binaryName),
|
|
149
|
+
path.join(__dirname, "node_modules", packageName, "bin", binaryName),
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
for (const p of fallbackPaths) {
|
|
153
|
+
if (fs.existsSync(p)) {
|
|
154
|
+
return { binaryPath: p, binaryName };
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Prepare the bin directory
|
|
163
|
+
*/
|
|
164
|
+
function prepareBinDirectory(binaryName) {
|
|
165
|
+
const binDir = path.join(__dirname, "bin");
|
|
166
|
+
const targetPath = path.join(binDir, binaryName);
|
|
167
|
+
|
|
168
|
+
// Ensure bin directory exists
|
|
169
|
+
if (!fs.existsSync(binDir)) {
|
|
170
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Remove existing binary/symlink if it exists
|
|
174
|
+
if (fs.existsSync(targetPath)) {
|
|
175
|
+
fs.unlinkSync(targetPath);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return { binDir, targetPath };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Create symlink (or copy on Windows)
|
|
183
|
+
*/
|
|
184
|
+
function linkBinary(sourcePath, binaryName) {
|
|
185
|
+
const { targetPath } = prepareBinDirectory(binaryName);
|
|
186
|
+
|
|
187
|
+
if (os.platform() === "win32") {
|
|
188
|
+
// Windows: copy instead of symlink (symlinks require admin)
|
|
189
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
190
|
+
} else {
|
|
191
|
+
fs.symlinkSync(sourcePath, targetPath);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Verify the file exists
|
|
195
|
+
if (!fs.existsSync(targetPath)) {
|
|
196
|
+
throw new Error(`Failed to create binary at ${targetPath}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async function main() {
|
|
201
|
+
try {
|
|
202
|
+
const packageName = getPackageName();
|
|
203
|
+
|
|
204
|
+
if (!packageName) {
|
|
205
|
+
console.error(`codex-wrapped-noyrlimit: Unsupported platform: ${os.platform()}-${os.arch()}`);
|
|
206
|
+
console.error("Please download the binary manually from:");
|
|
207
|
+
console.error("https://github.com/numman-ali/codex-wrapped/releases");
|
|
208
|
+
process.exit(0); // Exit gracefully
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
console.log(`codex-wrapped-noyrlimit: Detected platform package: ${packageName}`);
|
|
212
|
+
|
|
213
|
+
const result = findBinary(packageName);
|
|
214
|
+
|
|
215
|
+
if (!result) {
|
|
216
|
+
// Try fallback without baseline/musl
|
|
217
|
+
const baseParts = packageName.split("-").slice(0, 3);
|
|
218
|
+
const basePackage = baseParts.join("-");
|
|
219
|
+
|
|
220
|
+
if (basePackage !== packageName) {
|
|
221
|
+
console.log(`codex-wrapped-noyrlimit: Trying fallback package: ${basePackage}`);
|
|
222
|
+
const fallbackResult = findBinary(basePackage);
|
|
223
|
+
|
|
224
|
+
if (fallbackResult) {
|
|
225
|
+
linkBinary(fallbackResult.binaryPath, fallbackResult.binaryName);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
console.error(`codex-wrapped-noyrlimit: Could not find binary for ${packageName}`);
|
|
231
|
+
console.error("The optional dependency may have failed to install.");
|
|
232
|
+
console.error("Please download the binary manually from:");
|
|
233
|
+
console.error("https://github.com/numman-ali/codex-wrapped/releases");
|
|
234
|
+
process.exit(0);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
linkBinary(result.binaryPath, result.binaryName);
|
|
238
|
+
} catch (error) {
|
|
239
|
+
console.error("codex-wrapped-noyrlimit: Postinstall error:", error.message);
|
|
240
|
+
process.exit(0); // Exit gracefully to not break npm install
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
main();
|