[eric] DMG/EXE slim ~445 MB: drop legacy onboarding videos, per-arch node + lipo-thin uv, electronLanguages=[en], exclude backend/data + uv-bin

from bundle rsync (closes dev auth.token / install_id leak), strip pip + Tcl/Tk + pydoc_data + _pyrepl, both platforms
This commit is contained in:
ciregenz
2026-05-18 04:28:13 -07:00
parent 05f6897b40
commit d51ff66552
10 changed files with 89 additions and 10 deletions
+10 -2
View File
@@ -28,6 +28,7 @@
"build": {
"appId": "com.clusterlabs.openswarm",
"productName": "OpenSwarm",
"electronLanguages": ["en"],
"electronDownload": {
"mirror": "https://github.com/castlabs/electron-releases/releases/download/v"
},
@@ -125,8 +126,15 @@
]
},
{
"from": "build-staging/node",
"to": "node",
"from": "build-staging/node/${arch}",
"to": "node/${arch}",
"filter": [
"**/*"
]
},
{
"from": "build-staging/uv-bin/${arch}",
"to": "backend/uv-bin",
"filter": [
"**/*"
]
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+15 -2
View File
@@ -327,7 +327,13 @@ function Copy-Excluded($Source, $Dest, $Exclude) {
Copy-Excluded `
(Join-Path $ProjectRoot 'backend') (Join-Path $Staging 'backend') `
@{ Dirs = @('__pycache__','.venv','tools','tests'); Files = @('*.pyc','.env','.env.*') }
@{ Dirs = @('__pycache__','.venv','data','uv-bin','tests'); Files = @('*.pyc','.env','.env.*') }
# data: backend/config/paths.py points DATA_ROOT at %APPDATA%/OpenSwarm/data in
# packaged mode and no code seeds from the bundle, so the entire shipped
# backend/data/ tree was dead weight (and was leaking the dev machine's
# auth.token + install_id + dev session artifacts).
# uv-bin: source dir holds the binary so dev works; staged separately below
# so extraResources can substitute ${arch} (matches the mac build).
# Production .env: OAuth helper base URL + Google credentials. See
# scripts/build-app.sh for the rationale; v1.0.29 cloud-proxied the OAuth flow,
@@ -353,7 +359,14 @@ New-Item -ItemType Directory -Force -Path (Split-Path $ShipEnvPath -Parent) | Ou
"GOOGLE_OAUTH_CLIENT_SECRET=$GoogleClientSecretShip"
) | Set-Content -Path $ShipEnvPath
Write-Host "Staged production .env"
New-Item -ItemType Directory -Force -Path (Join-Path $Staging 'backend\data\tools') | Out-Null
# Stage uv-bin into per-arch staging so package.json extraResources can
# substitute ${arch} and ship only the matching slice. Windows is x64-only
# today; matches the mac build's per-arch staging shape.
$UvStageX64 = Join-Path $Staging 'uv-bin\x64'
New-Item -ItemType Directory -Force -Path $UvStageX64 | Out-Null
Copy-Item -Force (Join-Path $UvBinDir 'uv.exe') (Join-Path $UvStageX64 'uv.exe')
Copy-Item -Force (Join-Path $UvBinDir 'uvx.exe') (Join-Path $UvStageX64 'uvx.exe')
Copy-Excluded `
(Join-Path $ProjectRoot 'debugger') (Join-Path $Staging 'debugger') `
+22 -5
View File
@@ -366,13 +366,18 @@ echo "[4/5] Snapshotting source directories..."
rsync -a \
--exclude='__pycache__' --exclude='**/__pycache__' \
--exclude='*.pyc' --exclude='.venv' \
--exclude='data/tools' \
--exclude='data/outputs_workspace' \
--exclude='data/agent_history' --exclude='data/sessions' \
--exclude='/data' \
--exclude='/uv-bin' \
--exclude='apps/outputs/webapp_template_cache' \
--exclude='tests' --exclude='**/tests' \
--exclude='/.env' --exclude='/.env.*' \
"$PROJECT_ROOT/backend/" "$STAGING_DIR/backend/"
# /data: backend/config/paths.py points DATA_ROOT at ~/Library/Application Support/OpenSwarm/data
# in packaged mode and no code seeds from the bundle, so the entire shipped
# backend/data/ tree was dead weight (and was leaking the dev machine's
# auth.token + install_id + dev session artifacts).
# /uv-bin: source dir holds the universal binary so `bash run.sh` works on either
# host arch; we stage per-arch thin slices below so each DMG ships only its slice.
# webapp_template_cache: a pre-built node_modules.tar.gz that gets shipped
# to speed up first-app-create. Apple notarization extracts it and rejects
# the build because upstream native binaries inside (esbuild, fsevents, etc.)
@@ -411,8 +416,20 @@ GOOGLE_OAUTH_CLIENT_ID=${GOOGLE_CLIENT_ID_SHIP}
GOOGLE_OAUTH_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET_SHIP}
EOF
echo "Staged production .env"
# Create empty tools directory so the app has a place to write
mkdir -p "$STAGING_DIR/backend/data/tools"
# Per-arch slice of the universal uv/uvx for shipping. The source-tree uv-bin/
# stays universal so dev (`bash run.sh`) works on either host arch; thinning
# into staging means each per-arch DMG ships only its slice (~48 MB savings
# vs the 97 MB universal binary the build used to put in both DMGs).
echo "Slicing uv per-arch into staging..."
for arch in arm64 x64; do
lipo_arch=$arch
[[ "$arch" == "x64" ]] && lipo_arch=x86_64
mkdir -p "$STAGING_DIR/uv-bin/$arch"
lipo "$UV_BIN_DIR/uv" -thin "$lipo_arch" -output "$STAGING_DIR/uv-bin/$arch/uv"
lipo "$UV_BIN_DIR/uvx" -thin "$lipo_arch" -output "$STAGING_DIR/uv-bin/$arch/uvx"
chmod +x "$STAGING_DIR/uv-bin/$arch/uv" "$STAGING_DIR/uv-bin/$arch/uvx"
done
rsync -a \
--exclude='__pycache__' --exclude='**/__pycache__' \
+16 -1
View File
@@ -98,16 +98,31 @@ $ToStrip = @(
(Join-Path $PythonEnvDir 'lib\python3.13\tkinter'), # Tk GUI toolkit, same
(Join-Path $PythonEnvDir 'lib\python3.13\ensurepip'), # Pip bootstrap, backend never installs at runtime
(Join-Path $PythonEnvDir 'lib\python3.13\turtledemo'), # Educational drawing examples
(Join-Path $PythonEnvDir 'lib\python3.13\pydoc_data'), # pydoc topics/keywords; only `help()` reads them
(Join-Path $PythonEnvDir 'lib\python3.13\_pyrepl'), # Python 3.13 interactive REPL, never started in packaged app
(Join-Path $PythonEnvDir 'share') # Man pages / desktop integration
)
foreach ($p in $ToStrip) {
if (Test-Path $p) { Remove-Item -Recurse -Force $p -ErrorAction SilentlyContinue }
}
$Sp = Join-Path $PythonEnvDir 'lib\python3.13\site-packages'
# pip itself: nothing in the packaged backend invokes it. uvx (used by
# MCPs) is a self-contained installer; the App Builder picks SYSTEM
# python via shutil.which (view_builder_templates.py:382), never this
# bundled one; backend code only mentions "pip install" in error strings.
Remove-Item -Recurse -Force (Join-Path $Sp 'pip') -ErrorAction SilentlyContinue
Get-ChildItem -Path $Sp -Directory -Filter 'pip-*.dist-info' -ErrorAction SilentlyContinue `
| Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
# Launcher .exe shims for the now-removed tools. Windows installs them under
# Scripts\; ignore missing.
foreach ($exe in @('pip.exe','pip3.exe','pip3.13.exe','idle3.exe','idle3.13.exe','pydoc3.exe','pydoc3.13.exe')) {
$p = Join-Path $PythonEnvDir "Scripts\$exe"
if (Test-Path $p) { Remove-Item -Force $p -ErrorAction SilentlyContinue }
}
# ----- Babel locale-data trim (~30 MB / ~900 files) -----
# Babel ships 1,084 CLDR locale .dat files. Trafilatura's transitive dep
# courlan/filters.py:184 calls Locale.parse(seg) on URL path segments. UnknownLocaleError IS caught at line 188, so stripped locales just skip language-filtering for that URL.
$Sp = Join-Path $PythonEnvDir 'lib\python3.13\site-packages'
$LocaleDir = Join-Path $Sp 'babel\locale-data'
if (Test-Path $LocaleDir) {
Write-Host "Trimming babel/locale-data..."
+26
View File
@@ -127,6 +127,32 @@ rm -rf "$PYTHON_ENV_DIR/lib/python3.13/ensurepip"
rm -rf "$PYTHON_ENV_DIR/lib/python3.13/turtledemo"
# Man pages / desktop integration files.
rm -rf "$PYTHON_ENV_DIR/share"
# pip itself + launcher shims. Verified the packaged backend never invokes
# pip: uvx (used by MCPs) is a self-contained installer; the App Builder's
# view_builder_templates.py:382 picks SYSTEM python via shutil.which, never
# this bundled one; backend code only mentions "pip install" in error-message
# strings. `python -m venv` from this bundled env is also dead (ensurepip
# already stripped above) but nothing calls it.
rm -rf "$PYTHON_ENV_DIR/lib/python3.13/site-packages/pip" \
"$PYTHON_ENV_DIR/lib/python3.13/site-packages"/pip-*.dist-info
rm -f "$PYTHON_ENV_DIR/bin/pip" "$PYTHON_ENV_DIR/bin/pip3" "$PYTHON_ENV_DIR/bin/pip3.13" \
"$PYTHON_ENV_DIR/bin/idle3" "$PYTHON_ENV_DIR/bin/idle3.13" \
"$PYTHON_ENV_DIR/bin/pydoc3" "$PYTHON_ENV_DIR/bin/pydoc3.13"
# pydoc_data: keyword/topic tables consumed only by stdlib `pydoc` / `help()`.
# Backend never starts a REPL or calls help().
rm -rf "$PYTHON_ENV_DIR/lib/python3.13/pydoc_data"
# _pyrepl: Python 3.13's new interactive REPL implementation. We never
# spawn an interactive shell from the packaged build.
rm -rf "$PYTHON_ENV_DIR/lib/python3.13/_pyrepl"
# Tcl/Tk runtime shared libraries. python-build-standalone install_only_stripped
# ships these even after the `tkinter` Python package is stripped. With the
# `_tkinter` C extension absent (lib-dynload/ is empty in this build variant;
# verified `find python-env -name '_tkinter*.so'` returns nothing), no code
# path can load these libraries. PIL.ImageTk would import them but backend
# only does `from PIL import Image`, never ImageTk.
rm -rf "$PYTHON_ENV_DIR/lib/tcl8.6" "$PYTHON_ENV_DIR/lib/tk8.6" \
"$PYTHON_ENV_DIR/lib/itcl4.2.4" "$PYTHON_ENV_DIR/lib/thread2.8.9" \
"$PYTHON_ENV_DIR/lib/tcl8"
# ----- Babel locale-data trim (~30 MB / ~900 files) -----
# Babel ships 1,084 CLDR locale .dat files (~30 MB). Our backend doesn't use