[eric] shrink prod payload another ~125MB: drop unused binary (-97MB), trim babel non-en locale data (-30MB), strip pip-only dist-info

noise (-2MB), move pytest to dev-requirements (-4MB)
This commit is contained in:
ciregenz
2026-04-25 04:35:20 -07:00
parent c67d27976b
commit d8f69bb23d
10 changed files with 123 additions and 4677 deletions
File diff suppressed because it is too large Load Diff
@@ -1,16 +0,0 @@
{
"name": "notionhq-notion-mcp-server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"dependencies": {
"@notionhq/notion-mcp-server": "^2.2.1"
}
}
File diff suppressed because it is too large Load Diff
@@ -1,16 +0,0 @@
{
"name": "softeria-ms-365-mcp-server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"dependencies": {
"@softeria/ms-365-mcp-server": "^0.85.1"
}
}
+11
View File
@@ -0,0 +1,11 @@
# Development-only dependencies. NOT installed by build-python-env.{sh,ps1},
# so these never ship to production users (the embedded electron python-env
# only installs requirements.txt).
#
# To install for local development:
# pip install -r backend/requirements.txt -r backend/requirements-dev.txt
#
# CI test runs should also install both files.
pytest==8.3.4
pytest-asyncio==0.25.2
+4 -3
View File
@@ -5,11 +5,12 @@ fastapi[standard]
pydantic==2.10.5
langchain-core==0.3.51
langchain-openai==0.3.12
pytest==8.3.4
pytest-asyncio==0.25.2
typeguard==4.4.2
python-dotenv==1.1.1
Pillow
posthog
httpx>=0.27.0
trafilatura
trafilatura
# Test deps (pytest, pytest-asyncio) live in requirements-dev.txt — they
# never ship to production users and shaved ~3 MB / ~200 files off the
# Mac DMG when removed from the prod env.
+13 -5
View File
@@ -60,10 +60,18 @@ if ($Sign) {
}
}
# --- Step 0: Bundled uv/uvx (Windows zip) ---
# --- Step 0: Bundled uvx for Windows ---
# We deliberately ship ONLY uvx.exe (~700KB), NOT uv.exe (~30MB). Tools
# only ever invoke uvx; bare uv is a build-time installer/manager. Saves
# ~30MB from the Windows installer. See scripts/build-app.sh for context.
$UvBinDir = Join-Path $ProjectRoot 'backend\uv-bin'
# Defensively drop a stale uv.exe from prior builds.
if (Test-Path (Join-Path $UvBinDir 'uv.exe')) {
Write-Host "[0] Removing legacy uv.exe (we now ship uvx only)..."
Remove-Item -Force (Join-Path $UvBinDir 'uv.exe')
}
if (-not (Test-Path (Join-Path $UvBinDir 'uvx.exe'))) {
Write-Host "[0] Downloading uv/uvx for Windows..."
Write-Host "[0] Downloading uvx for Windows..."
New-Item -ItemType Directory -Force -Path $UvBinDir | Out-Null
$UvUrl = 'https://github.com/astral-sh/uv/releases/latest/download/uv-x86_64-pc-windows-msvc.zip'
$TmpZip = Join-Path $env:TEMP "uv-win-$([guid]::NewGuid()).zip"
@@ -71,15 +79,15 @@ if (-not (Test-Path (Join-Path $UvBinDir 'uvx.exe'))) {
try {
Invoke-WebRequest -Uri $UvUrl -OutFile $TmpZip -UseBasicParsing
Expand-Archive -Path $TmpZip -DestinationPath $TmpExtract -Force
Get-ChildItem -Path $TmpExtract -Recurse -Filter 'uv.exe' | Select-Object -First 1 | ForEach-Object { Copy-Item $_.FullName (Join-Path $UvBinDir 'uv.exe') -Force }
# Only copy uvx.exe — skip uv.exe entirely.
Get-ChildItem -Path $TmpExtract -Recurse -Filter 'uvx.exe' | Select-Object -First 1 | ForEach-Object { Copy-Item $_.FullName (Join-Path $UvBinDir 'uvx.exe') -Force }
Write-Host "uv/uvx downloaded and bundled."
Write-Host "uvx.exe downloaded and bundled."
} finally {
Remove-Item -Force $TmpZip -ErrorAction SilentlyContinue
Remove-Item -Recurse -Force $TmpExtract -ErrorAction SilentlyContinue
}
} else {
Write-Host "[0] uv/uvx binaries already present."
Write-Host "[0] uvx.exe already present."
}
Write-Host ""
+17 -7
View File
@@ -68,22 +68,32 @@ if $SIGN_MODE; then
fi
fi
# Step 0: Ensure bundled uv/uvx binaries exist
# Step 0: Ensure bundled uvx binary exists.
# We deliberately ship ONLY uvx (~681KB universal), NOT uv (~97MB universal).
# tools_lib.py probes for both, but the only tool config that uses either is
# Google Workspace (cmd: "uvx"). Bare `uv` (the package installer/manager) is
# never invoked at runtime by any shipped tool — it's a build-time tool.
# Saves 97MB from the Mac DMG. If a future MCP needs `uv`, this is a one-line
# add-back here.
UV_BIN_DIR="$PROJECT_ROOT/backend/uv-bin"
# Defensively drop a stale `uv` from prior builds so it doesn't ride along.
if [[ -f "$UV_BIN_DIR/uv" ]]; then
echo "[0] Removing legacy uv binary (we now ship uvx only)..."
rm -f "$UV_BIN_DIR/uv"
fi
if [[ ! -f "$UV_BIN_DIR/uvx" ]]; then
echo "[0] Downloading uv/uvx binaries..."
echo "[0] Downloading uvx binary..."
mkdir -p "$UV_BIN_DIR"
TMPDIR_UV=$(mktemp -d)
# Download both architectures and create universal binaries
curl -sL "https://github.com/astral-sh/uv/releases/latest/download/uv-aarch64-apple-darwin.tar.gz" | tar xz -C "$TMPDIR_UV"
curl -sL "https://github.com/astral-sh/uv/releases/latest/download/uv-x86_64-apple-darwin.tar.gz" | tar xz -C "$TMPDIR_UV"
lipo -create "$TMPDIR_UV/uv-aarch64-apple-darwin/uv" "$TMPDIR_UV/uv-x86_64-apple-darwin/uv" -output "$UV_BIN_DIR/uv"
# Only lipo uvx — skip uv entirely.
lipo -create "$TMPDIR_UV/uv-aarch64-apple-darwin/uvx" "$TMPDIR_UV/uv-x86_64-apple-darwin/uvx" -output "$UV_BIN_DIR/uvx"
chmod +x "$UV_BIN_DIR/uv" "$UV_BIN_DIR/uvx"
chmod +x "$UV_BIN_DIR/uvx"
rm -rf "$TMPDIR_UV"
echo "uv/uvx downloaded and bundled."
echo "uvx downloaded and bundled."
else
echo "[0] uv/uvx binaries already present."
echo "[0] uvx binary already present."
fi
echo ""
+35 -3
View File
@@ -92,9 +92,7 @@ Get-ChildItem -Path $PythonEnvDir -Recurse -Force -Filter '*.pyc' `
| Remove-Item -Force -ErrorAction SilentlyContinue
# Strip parts of the Python distribution we provably don't use at runtime.
# Each removal here has been individually verified — conservative on purpose.
# NOT removing pip/, babel/locale-data/, pygments lexers, or PIL — each had
# at least one weak import-evidence trail.
# Each removal here has been individually verified.
Write-Host "Stripping unused Python distribution files..."
$ToStrip = @(
(Join-Path $PythonEnvDir 'include'), # C headers — never used at runtime
@@ -108,6 +106,40 @@ foreach ($p in $ToStrip) {
if (Test-Path $p) { Remove-Item -Recurse -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 (graceful degradation: that URL
# just doesn't get language-filtered). Keeping the 20 most common base
# languages preserves filtering for the URLs we'll actually see.
$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..."
$KeepLangs = @('ar','de','es','fr','it','ja','ko','nl','pl','pt','ru','sv','tr','zh','hi','th','vi','id','da','no','fi','cs','el','he','uk')
Get-ChildItem -Path $LocaleDir -File -ErrorAction SilentlyContinue | ForEach-Object {
$name = $_.Name
$keep = $false
if ($name -eq 'root.dat' -or $name -eq 'LICENSE.unicode') { $keep = $true }
elseif ($name -match '^en($|_)') { $keep = $true }
else {
foreach ($l in $KeepLangs) {
if ($name -eq "$l.dat") { $keep = $true; break }
}
}
if (-not $keep) { Remove-Item -Force $_.FullName -ErrorAction SilentlyContinue }
}
}
# ----- dist-info noise trim (~2 MB / ~280 files) -----
# pip-only metadata. METADATA is kept (some packages call importlib.metadata).
Write-Host "Trimming pip dist-info noise..."
foreach ($pattern in @('RECORD','INSTALLER','WHEEL','top_level.txt','entry_points.txt')) {
Get-ChildItem -Path $Sp -Recurse -Filter $pattern -File -ErrorAction SilentlyContinue `
| Where-Object { $_.FullName -match '\.dist-info[\\/]' } `
| Remove-Item -Force -ErrorAction SilentlyContinue
}
# Pre-compile bytecode so cold backend startup skips parse+compile on
# every imported .py. Worth ~5-10s on Windows under Defender (parsing
# Python source is parser-bound; loading .pyc is just bytes). We cap
+43 -7
View File
@@ -117,13 +117,7 @@ find "$PYTHON_ENV_DIR" -type d -name "tests" -exec rm -rf {} + 2>/dev/null || tr
find "$PYTHON_ENV_DIR" -type d -name "test" -exec rm -rf {} + 2>/dev/null || true
# Strip parts of the Python distribution we provably don't use at runtime.
# Each removal here has been individually verified — see the audit notes in
# the project plan. Doing this BEFORE compileall would also work, but doing
# it after means the dirs are already definitely-not-imported (compileall
# would have surfaced any backend code that touches them).
#
# Conservative on purpose. NOT removing pip/, babel/locale-data/, pygments
# lexers, or PIL — each had at least one weak import-evidence trail.
# Each removal here has been individually verified.
echo "Stripping unused Python distribution files..."
# C headers — only needed when building C extensions, never at runtime.
rm -rf "$PYTHON_ENV_DIR/include"
@@ -137,6 +131,48 @@ rm -rf "$PYTHON_ENV_DIR/lib/python3.13/turtledemo"
# Man pages / desktop-integration files — embedded Python doesn't read these.
rm -rf "$PYTHON_ENV_DIR/share"
# ----- Babel locale-data trim (~30 MB / ~900 files) -----
# Babel ships 1,084 CLDR locale .dat files (~30 MB). Our backend doesn't use
# babel directly, but trafilatura's transitive dep `courlan/filters.py:184`
# calls `Locale.parse(seg)` on URL path segments — if a stripped locale's
# .dat is missing courlan raises `UnknownLocaleError`, which IS caught at
# line 188 (graceful degradation: that URL just doesn't get language-
# filtered). Even so, keeping the most-common 20 base languages preserves
# language detection for the URLs we'll actually see in practice.
SP="$PYTHON_ENV_DIR/lib/python3.13/site-packages"
if [[ -d "$SP/babel/locale-data" ]]; then
echo "Trimming babel/locale-data..."
LOCALE_DIR="$SP/babel/locale-data"
# Keep:
# - root.dat — fallback for unknown locales
# - LICENSE.unicode — required by Unicode/CLDR license
# - en*.dat — every English variant (130 files; small)
# - <lang>.dat for the 20 most common base languages we'd plausibly see
# in URL path segments. Country-suffix variants (fr_CA.dat, de_AT.dat
# etc.) get dropped — courlan only uses .language so the base is enough.
KEEP_LANGS="ar de es fr it ja ko nl pl pt ru sv tr zh hi th vi id da no fi cs el he uk"
# Build a regex of "files to KEEP" so find can delete the rest.
KEEP_RE='^(root\.dat|LICENSE\.unicode|en($|_).*\.dat'
for L in $KEEP_LANGS; do KEEP_RE="$KEEP_RE|${L}\.dat"; done
KEEP_RE="$KEEP_RE)$"
# Find every file in locale-data that DOESN'T match KEEP_RE and delete it.
find "$LOCALE_DIR" -maxdepth 1 -type f \
| awk -v re="$KEEP_RE" 'BEGIN { FS="/" } { if ($NF !~ re) print }' \
| xargs -r -n 50 rm -f
fi
# ----- dist-info noise trim (~2 MB / ~280 files) -----
# pip metadata that's only consulted by pip itself (which we don't run at
# runtime). RECORD/INSTALLER/WHEEL/entry_points.txt/top_level.txt have zero
# runtime readers in our shipped deps. METADATA we KEEP — some packages and
# transitive deps occasionally call importlib.metadata.metadata("pkg").
echo "Trimming pip dist-info noise..."
find "$SP" -path '*.dist-info/RECORD' -delete 2>/dev/null
find "$SP" -path '*.dist-info/INSTALLER' -delete 2>/dev/null
find "$SP" -path '*.dist-info/WHEEL' -delete 2>/dev/null
find "$SP" -path '*.dist-info/top_level.txt' -delete 2>/dev/null
find "$SP" -path '*.dist-info/entry_points.txt' -delete 2>/dev/null
# Pre-compile bytecode so cold backend startup skips the parse+compile
# step on every imported .py. Worth ~5-10s on Windows under Defender
# (parsing Python source is parser-bound; loading .pyc is just bytes).