Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
name: Build & Release (Manual)
name: Build Artifacts

on:
push:
branches: [master, main]
tags: ["v*"]
paths-ignore:
- "**/*.md"
- "docs/**"
workflow_dispatch:
inputs:
platform:
description: "Target platform"
required: false
default: "all"
required: true
type: choice
options: [all, mac, windows, linux]

permissions:
contents: read

concurrency:
group: build-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
NODE_VERSION: "24"

jobs:
build-mac:
if: inputs.platform == 'all' || inputs.platform == 'mac'
if: ${{ github.event_name != 'workflow_dispatch' || inputs.platform == 'all' || inputs.platform == 'mac' }}
runs-on: macos-latest
strategy:
fail-fast: false
Expand All @@ -40,7 +52,7 @@ jobs:
path: out/*.dmg

build-windows:
if: inputs.platform == 'all' || inputs.platform == 'windows'
if: ${{ github.event_name != 'workflow_dispatch' || inputs.platform == 'all' || inputs.platform == 'windows' }}
runs-on: windows-latest
steps:
- uses: actions/checkout@v6
Expand All @@ -65,7 +77,7 @@ jobs:
path: out/*.zip

build-linux:
if: inputs.platform == 'all' || inputs.platform == 'linux'
if: ${{ github.event_name != 'workflow_dispatch' || inputs.platform == 'all' || inputs.platform == 'linux' }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand All @@ -81,7 +93,7 @@ jobs:
npm ci
- run: |
sudo apt-get update
sudo apt-get install -y rpm fakeroot dpkg 7zip
sudo apt-get install -y rpm fakeroot dpkg 7zip unzip
- run: node scripts/sync-upstream.js --force --skip-win
- run: node scripts/patch-all.js mac-${{ matrix.arch }}
- run: npm run build:linux-${{ matrix.arch }}
Expand Down
59 changes: 46 additions & 13 deletions .github/workflows/sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,23 @@ on:
force:
description: "Force sync even without version change"
type: boolean
default: false

env:
NODE_VERSION: "24"

permissions:
contents: read

concurrency:
group: sync-upstream-${{ github.ref }}
cancel-in-progress: false

jobs:
check:
runs-on: ubuntu-latest
outputs:
has_update: ${{ steps.detect.outputs.has_update }}
latest_version: ${{ steps.detect.outputs.latest_version }}
steps:
- name: Checkout
uses: actions/checkout@v6
Expand All @@ -34,18 +41,39 @@ jobs:
- name: Check upstream versions
id: detect
run: |
set +e
node scripts/check-update.js --json --force 2>&1
exit_code=$?
set -e

if [ "${{ inputs.force }}" = "true" ]; then
RESULT="$(node scripts/check-update.js --json --force)"
echo "$RESULT" > /tmp/codex-version-check.json

LATEST_VERSION="$(node -e "
const fs = require('fs');
const result = JSON.parse(fs.readFileSync('/tmp/codex-version-check.json', 'utf8'));
const platforms = Object.values(result.platforms || {});
const first = platforms.find((p) => p && p.version);
process.stdout.write(first?.version || '');
")"

HAS_UPDATE="$(node -e "
const fs = require('fs');
const result = JSON.parse(fs.readFileSync('/tmp/codex-version-check.json', 'utf8'));
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
const normalize = (version) => String(version || '').replace(/\\.0$/, '');
const current = normalize(pkg.version);
const platforms = Object.values(result.platforms || {});
const versions = platforms.map((p) => normalize(p.version)).filter(Boolean);
process.stdout.write(versions.some((v) => v !== current) ? 'true' : 'false');
")"

echo "latest_version=$LATEST_VERSION" >> "$GITHUB_OUTPUT"

if [ "${{ github.event_name == 'workflow_dispatch' && inputs.force }}" = "true" ]; then
echo "has_update=true" >> "$GITHUB_OUTPUT"
elif [ $exit_code -eq 0 ]; then
echo "Manual force sync requested."
elif [ "$HAS_UPDATE" = "true" ]; then
echo "has_update=true" >> "$GITHUB_OUTPUT"
echo "Upstream update detected: ${LATEST_VERSION}"
else
echo "has_update=false" >> "$GITHUB_OUTPUT"
echo "No upstream update detected."
echo "No upstream update detected. Current package.json version already matches upstream."
fi

# ──────────────────────────────────────────────
Expand Down Expand Up @@ -158,7 +186,7 @@ jobs:
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y rpm fakeroot dpkg 7zip
sudo apt-get install -y rpm fakeroot dpkg 7zip unzip

- name: Install dependencies
run: |
Expand Down Expand Up @@ -187,8 +215,13 @@ jobs:
# Bump version + tag + release
# ──────────────────────────────────────────────
release:
needs: [build-mac, build-windows, build-linux]
if: always() && needs.check.result == 'success'
needs: [check, build-mac, build-windows, build-linux]
if: >-
always() &&
needs.check.result == 'success' &&
needs.check.outputs.has_update == 'true' &&
!contains(needs.*.result, 'failure') &&
!contains(needs.*.result, 'cancelled')
runs-on: ubuntu-latest
permissions:
contents: write
Expand Down Expand Up @@ -266,6 +299,6 @@ jobs:
artifacts/**/*.deb
artifacts/**/*.rpm
artifacts/**/*.exe
draft: true
draft: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ npm run dev
## CI/CD

GitHub Actions automatically builds on:
- Push to `master`
- Tag `v*` → Creates draft release
- Push to `master` / `main` and tag `v*` → build artifacts
- Daily upstream sync workflow → downloads upstream, reapplies patches, builds, and creates a draft release when a newer upstream version is detected

## Credits

Expand Down
41 changes: 37 additions & 4 deletions forge.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@ const { FuseV1Options, FuseVersion } = require("@electron/fuses");
const path = require("path");
const fs = require("fs");

const githubRepository = process.env.GITHUB_REPOSITORY || "";
const githubRefName = process.env.GITHUB_REF_NAME || "master";
const repositoryUrl =
process.env.CODEX_REPOSITORY_URL ||
(githubRepository ? `https://github.com/${githubRepository}` : undefined);
const remoteIconUrl =
process.env.CODEX_ICON_URL ||
(githubRepository
? `https://raw.githubusercontent.com/${githubRepository}/${githubRefName}/resources/electron.ico`
: undefined);

function withRepositoryHomepage(options) {
return repositoryUrl ? { ...options, homepage: repositoryUrl } : options;
}

module.exports = {
packagerConfig: {
name: "Codex",
Expand Down Expand Up @@ -64,17 +79,17 @@ module.exports = {
authors: "OpenAI, Cometix Space",
description: "Codex Desktop App",
setupIcon: "./resources/electron.ico",
iconUrl: "https://raw.githubusercontent.com/Haleclipse/CodexDesktop-Rebuild/master/resources/electron.ico",
...(remoteIconUrl ? { iconUrl: remoteIconUrl } : {}),
},
},
{ name: "@electron-forge/maker-zip", platforms: ["win32"] },
{
name: "@electron-forge/maker-deb",
config: { options: { name: "codex", productName: "Codex", genericName: "AI Coding Assistant", categories: ["Development", "Utility"], bin: "Codex", maintainer: "Cometix Space", homepage: "https://github.com/Haleclipse/CodexDesktop-Rebuild", icon: "./resources/electron.png" } },
config: { options: withRepositoryHomepage({ name: "codex", productName: "Codex", genericName: "AI Coding Assistant", categories: ["Development", "Utility"], bin: "Codex", maintainer: "Cometix Space", icon: "./resources/electron.png" }) },
},
{
name: "@electron-forge/maker-rpm",
config: { options: { name: "codex", productName: "Codex", genericName: "AI Coding Assistant", categories: ["Development", "Utility"], bin: "Codex", license: "Apache-2.0", homepage: "https://github.com/Haleclipse/CodexDesktop-Rebuild", icon: "./resources/electron.png" } },
config: { options: withRepositoryHomepage({ name: "codex", productName: "Codex", genericName: "AI Coding Assistant", categories: ["Development", "Utility"], bin: "Codex", license: "Apache-2.0", icon: "./resources/electron.png" }) },
},
{ name: "@electron-forge/maker-zip", platforms: ["linux"] },
],
Expand Down Expand Up @@ -129,13 +144,29 @@ module.exports = {
for (const d of MACOS_ONLY_DIRS) skip.add(d);
}
let copied = 0;
let skippedForeignArch = 0;

// @oai/sky ships Linux binaries for multiple CPU architectures.
// rpm's brp-strip runs target-arch strip over every executable in the package;
// leaving the foreign one inside the RPM makes linux-x64 fail on sky_linux_arm64
// (and vice versa for arm64).
const shouldSkipForeignLinuxBinary = (name) => {
if (!isLinux) return false;
if (arch === "x64" && name === "sky_linux_arm64") return true;
if (arch === "arm64" && name === "sky_linux_x64") return true;
return false;
};

const copyDir = (s, d) => {
fs.mkdirSync(d, { recursive: true });
for (const e of fs.readdirSync(s, { withFileTypes: true })) {
const sp = path.join(s, e.name), dp = path.join(d, e.name);
if (e.isDirectory()) copyDir(sp, dp);
else if (!e.isSymbolicLink()) { fs.copyFileSync(sp, dp); copied++; }
else if (!e.isSymbolicLink()) {
if (shouldSkipForeignLinuxBinary(e.name)) { skippedForeignArch++; continue; }
fs.copyFileSync(sp, dp);
copied++;
}
}
};

Expand All @@ -149,13 +180,15 @@ module.exports = {
if (entry.isDirectory()) {
copyDir(srcPath, destPath);
} else if (!entry.isSymbolicLink()) {
if (shouldSkipForeignLinuxBinary(entry.name)) { skippedForeignArch++; continue; }
fs.copyFileSync(srcPath, destPath);
try { fs.chmodSync(destPath, 0o755); } catch {}
copied++;
}
}

console.log(` [ok] ${copied} files (app.asar + unpacked + resources)`);
if (skippedForeignArch) console.log(` [ok] skipped ${skippedForeignArch} foreign-arch Linux binaries`);
},
},
};
12 changes: 7 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "codex-rebuild",
"productName": "Codex",
"version": "26.623.81905",
"version": "26.623.101652",
"description": "Codex Electron App - Cross-platform Build",
"main": "src/.vite/build/bootstrap.js",
"scripts": {
Expand All @@ -12,7 +12,7 @@
"patch:win": "node scripts/patch-all.js win",
"forge:package": "electron-forge package",
"forge:make": "electron-forge make",
"build": "npm run build:mac-arm64",
"build": "node scripts/build-current.js",
"build:mac-arm64": "node scripts/build-from-upstream.js --platform mac-arm64",
"build:mac-x64": "node scripts/build-from-upstream.js --platform mac-x64",
"build:mac": "npm run build:mac-arm64 && npm run build:mac-x64",
Expand Down Expand Up @@ -46,7 +46,7 @@
"dependencies": {
"@sentry/electron": "^7.5.0",
"@sentry/node": "10.29.0",
"better-sqlite3": "^12.4.6",
"better-sqlite3": "^12.11.1",
"electron-context-menu": "^4.1.1",
"electron-squirrel-startup": "^1.0.1",
"encoding": "^0.1.13",
Expand Down
Loading