Skip to content

Commit bd40f59

Browse files
committed
Smaller app size
1 parent c075cc3 commit bd40f59

10 files changed

Lines changed: 1103 additions & 94 deletions

File tree

.github/workflows/release-macos-arm64.yml

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ on:
1010

1111
permissions:
1212
contents: write
13+
pages: write
14+
id-token: write
1315

1416
jobs:
1517
build-macos-arm64:
@@ -90,14 +92,12 @@ jobs:
9092
APP_BIN="${APP_PATH}/Contents/MacOS/Zero"
9193
RESOURCES_DIR="${APP_PATH}/Contents/Resources"
9294
CODEX_BIN="${RESOURCES_DIR}/app.asar.unpacked/node_modules/@zed-industries/codex-acp-darwin-arm64/bin/codex-acp"
93-
CLAUDE_ENTRY="${RESOURCES_DIR}/app.asar.unpacked/node_modules/@zed-industries/claude-agent-acp/dist/index.js"
9495
NODE_PTY_BIN="${RESOURCES_DIR}/app.asar.unpacked/node_modules/node-pty/build/Release/pty.node"
9596
9697
REQUIRED_PATHS=(
9798
"${APP_BIN}"
9899
"${RESOURCES_DIR}/app.asar"
99100
"${CODEX_BIN}"
100-
"${CLAUDE_ENTRY}"
101101
"${NODE_PTY_BIN}"
102102
)
103103
@@ -116,10 +116,13 @@ jobs:
116116
echo "Codex ACP binary is not executable: ${CODEX_BIN}" >&2
117117
exit 1
118118
fi
119+
if [[ -e "${RESOURCES_DIR}/app.asar.unpacked/node_modules/@zed-industries/claude-agent-acp" ]]; then
120+
echo "Bundled Claude ACP payload should not be present in packaged app." >&2
121+
exit 1
122+
fi
119123
120124
"${CODEX_BIN}" --help >/dev/null
121125
ELECTRON_RUN_AS_NODE=1 "${APP_BIN}" -e "console.log('smoke-node-ok')" | grep -q "smoke-node-ok"
122-
ELECTRON_RUN_AS_NODE=1 "${APP_BIN}" "${CLAUDE_ENTRY}" --help >/dev/null
123126
124127
if [[ -n "${APPLE_SIGNING_IDENTITY:-}" ]]; then
125128
codesign --verify --deep --strict --verbose=2 "${APP_PATH}"
@@ -171,26 +174,41 @@ jobs:
171174
172175
RELEASE_DIR="out/release-assets"
173176
mkdir -p "${RELEASE_DIR}"
174-
STABLE_ZIP="${RELEASE_DIR}/Zero-darwin-arm64.zip"
175177
STABLE_DMG="${RELEASE_DIR}/Zero-darwin-arm64.dmg"
176-
cp "${ZIP_PATH}" "${STABLE_ZIP}"
177178
cp "${DMG_PATH}" "${STABLE_DMG}"
178179
180+
UPDATE_SITE_DIR="out/update-site"
181+
UPDATE_FEED_DIR="${UPDATE_SITE_DIR}/updates/darwin/arm64"
182+
mkdir -p "${UPDATE_FEED_DIR}"
183+
STABLE_ZIP="${UPDATE_FEED_DIR}/Zero-darwin-arm64.zip"
184+
cp "${ZIP_PATH}" "${STABLE_ZIP}"
185+
179186
VERSION="$(node -p "require('./package.json').version")"
180-
node scripts/generate-latest-mac-yml.mjs "${STABLE_ZIP}" "${VERSION}" latest-mac.yml
187+
node scripts/generate-latest-mac-yml.mjs "${STABLE_ZIP}" "${VERSION}" "${UPDATE_FEED_DIR}/latest-mac.yml"
181188
182189
echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
183-
echo "zip_file=${STABLE_ZIP}" >> "${GITHUB_OUTPUT}"
184190
echo "dmg_file=${STABLE_DMG}" >> "${GITHUB_OUTPUT}"
185-
echo "update_file=${RELEASE_DIR}/latest-mac.yml" >> "${GITHUB_OUTPUT}"
191+
echo "update_site_dir=${UPDATE_SITE_DIR}" >> "${GITHUB_OUTPUT}"
186192
187193
- name: Upload workflow artifacts
188194
uses: actions/upload-artifact@v4
189195
with:
190196
name: zero-macos-arm64
191-
path: out/release-assets
197+
path: |
198+
out/release-assets
199+
out/update-site
192200
if-no-files-found: error
193201

202+
- name: Configure GitHub Pages
203+
if: startsWith(github.ref, 'refs/tags/v')
204+
uses: actions/configure-pages@v5
205+
206+
- name: Upload update feed artifact
207+
if: startsWith(github.ref, 'refs/tags/v')
208+
uses: actions/upload-pages-artifact@v3
209+
with:
210+
path: ${{ steps.prepare.outputs.update_site_dir }}
211+
194212
- name: Publish GitHub release assets
195213
if: startsWith(github.ref, 'refs/tags/v')
196214
uses: softprops/action-gh-release@v2
@@ -204,5 +222,18 @@ jobs:
204222
target_commitish: ${{ github.sha }}
205223
files: |
206224
${{ steps.prepare.outputs.dmg_file }}
207-
${{ steps.prepare.outputs.zip_file }}
208-
${{ steps.prepare.outputs.update_file }}
225+
226+
deploy-update-feed:
227+
if: startsWith(github.ref, 'refs/tags/v')
228+
needs: build-macos-arm64
229+
runs-on: ubuntu-latest
230+
permissions:
231+
pages: write
232+
id-token: write
233+
environment:
234+
name: github-pages
235+
url: ${{ steps.deployment.outputs.page_url }}
236+
steps:
237+
- name: Deploy update feed
238+
id: deployment
239+
uses: actions/deploy-pages@v4

forge.config.ts

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,87 @@ const appleSigningIdentity = process.env.APPLE_SIGNING_IDENTITY?.trim();
1313
const appleId = process.env.APPLE_ID?.trim();
1414
const appleAppSpecificPassword = process.env.APPLE_APP_SPECIFIC_PASSWORD?.trim();
1515
const appleTeamId = process.env.APPLE_TEAM_ID?.trim();
16+
const buildPlatform = process.env.npm_config_platform?.trim() || process.platform;
17+
const buildArch = process.env.npm_config_arch?.trim() || process.arch;
18+
19+
const resolveCodexPlatformPackagePath = (): string | null => {
20+
if (buildPlatform === 'darwin') {
21+
if (buildArch === 'arm64') {
22+
return '/node_modules/@zed-industries/codex-acp-darwin-arm64';
23+
}
24+
if (buildArch === 'x64') {
25+
return '/node_modules/@zed-industries/codex-acp-darwin-x64';
26+
}
27+
return null;
28+
}
29+
30+
if (buildPlatform === 'linux') {
31+
if (buildArch === 'arm64') {
32+
return '/node_modules/@zed-industries/codex-acp-linux-arm64';
33+
}
34+
if (buildArch === 'x64') {
35+
return '/node_modules/@zed-industries/codex-acp-linux-x64';
36+
}
37+
return null;
38+
}
39+
40+
if (buildPlatform === 'win32') {
41+
if (buildArch === 'arm64') {
42+
return '/node_modules/@zed-industries/codex-acp-win32-arm64';
43+
}
44+
if (buildArch === 'x64') {
45+
return '/node_modules/@zed-industries/codex-acp-win32-x64';
46+
}
47+
return null;
48+
}
49+
50+
return null;
51+
};
52+
53+
const packagedRuntimePathPrefixes = [
54+
'/.vite',
55+
'/package.json',
56+
'/node_modules/node-pty/package.json',
57+
'/node_modules/node-pty/lib',
58+
'/node_modules/node-pty/build/Release',
59+
`/node_modules/node-pty/prebuilds/${buildPlatform}-${buildArch}`,
60+
'/node_modules/@zed-industries/codex-acp',
61+
]
62+
.concat(resolveCodexPlatformPackagePath() ?? [])
63+
.filter((value, index, entries) => entries.indexOf(value) === index);
64+
65+
const normalizePackagedPath = (file: string): string => {
66+
if (!file) {
67+
return '/';
68+
}
69+
70+
const normalized = file.replaceAll('\\', '/');
71+
if (normalized === '/') {
72+
return normalized;
73+
}
74+
75+
return normalized.endsWith('/') ? normalized.slice(0, -1) : normalized;
76+
};
77+
78+
const isAllowedPackagedPath = (file: string): boolean => {
79+
const normalizedFile = normalizePackagedPath(file);
80+
return packagedRuntimePathPrefixes.some((prefix) => {
81+
const normalizedPrefix = normalizePackagedPath(prefix);
82+
return (
83+
normalizedFile === normalizedPrefix ||
84+
normalizedFile.startsWith(`${normalizedPrefix}/`) ||
85+
normalizedPrefix.startsWith(`${normalizedFile}/`)
86+
);
87+
});
88+
};
1689

1790
const shouldIgnorePackagedFile = (file: string): boolean => {
1891
if (!file) {
1992
return false;
2093
}
2194

22-
// Include Vite bundles, package metadata, and production dependencies.
23-
// ACP adapters (including scoped packages) and native modules must be present at runtime.
24-
if (
25-
file.startsWith('/.vite') ||
26-
file === '/package.json' ||
27-
file.startsWith('/node_modules')
28-
) {
95+
// Keep only the built app bundle plus dynamic runtime modules that cannot be statically bundled.
96+
if (isAllowedPackagedPath(file)) {
2997
return false;
3098
}
3199

0 commit comments

Comments
 (0)