shadowbrain / shadow_brain_core /build_agent_macos.command
taemin1980's picture
๐Ÿ”ฑ Imperial Deployment: Shadow Brain Core ignition (part 2)
2be4d92 verified
Raw History Blame Contribute Delete
6.57 kB
#!/bin/zsh
# ============================================================
# ๐Ÿ”ฑ [Taemini CLI] macOS Local Agent Build (PyInstaller)
# ============================================================
# build_agent.bat ์˜ macOS ๋Œ€์‘ํŒ. venv Python์œผ๋กœ PyInstaller --windowed
# ์‹คํ–‰ํ•ด dist/TaeminiCLI.app ์„ ๋งŒ๋“ ๋‹ค. ์ฝ”๋“œ์„œ๋ช…/๊ณต์ฆ/dmg๋Š” ์ƒ์œ„
# BUILD_TAEMINI_CLI_MACOS.command ๊ฐ€ ๋‹ด๋‹นํ•œ๋‹ค(์ด ์Šคํฌ๋ฆฝํŠธ๋Š” ์ˆœ์ˆ˜ ๋นŒ๋“œ๋งŒ).
# ============================================================
set -uo pipefail
ROOT="$(cd "$(dirname "$0")" && pwd)"
cd "$ROOT"
echo "[Taemini CLI] Starting Local Agent Build (macOS)..."
# venv Python ๊ฒฝ๋กœ: ์™ธ๋ถ€(BUILD_TAEMINI_CLI_MACOS.command)์—์„œ ์ฃผ์ž…๋˜๊ฑฐ๋‚˜ ์ž๋™ ํƒ์ƒ‰
if [ -z "${SHADOW_VENV_PYTHON:-}" ]; then
if [ -x "$ROOT/venv/bin/python3" ]; then
SHADOW_VENV_PYTHON="$ROOT/venv/bin/python3"
else
SHADOW_VENV_PYTHON="python3"
fi
fi
echo "[*] Using Python: $SHADOW_VENV_PYTHON"
# 0. Kill existing TaeminiCLI process to prevent file lock
echo "[Step 0] Stopping existing TaeminiCLI process..."
pkill -f "dist/TaeminiCLI.app/Contents/MacOS/TaeminiCLI" 2>/dev/null || true
sleep 1
# 1. Check and install dependencies
echo "[Step 1] Installing dependencies..."
"$SHADOW_VENV_PYTHON" -m pip install --upgrade pip
"$SHADOW_VENV_PYTHON" -m pip install pyinstaller
"$SHADOW_VENV_PYTHON" -m pip install -r requirements.txt
# 2. Clean previous builds
echo "[Step 2] Cleaning previous builds..."
rm -rf build dist TaeminiCLI.spec taemini.spec
# 3. Package with PyInstaller (macOS: --windowed โ†’ .app ๋ฒˆ๋“ค, GUI/์ฝ˜์†” ์—†์Œ)
echo ""
echo "[Step 3] Packaging into .app bundle..."
"$SHADOW_VENV_PYTHON" -m PyInstaller --name "TaeminiCLI" --windowed -y \
--icon "resources/app_icon.icns" \
--osx-bundle-identifier com.taemingames.shadowbrain \
--add-data "config:config" \
--hidden-import=flask --hidden-import=flask_cors --hidden-import=flask_sock \
--hidden-import=requests --hidden-import=dotenv --hidden-import=psycopg2 \
--hidden-import=google.genai --hidden-import=tkinter --hidden-import=mcp \
--hidden-import=yaml --hidden-import=PIL --hidden-import=psutil \
--hidden-import=pyautogui --hidden-import=pyperclip --hidden-import=boto3 \
--hidden-import=soundfile --hidden-import=cffi --hidden-import=discord \
--hidden-import=sqlite3 --hidden-import=_sqlite3 --hidden-import=obsidian_index \
--hidden-import=rumps \
--collect-submodules=keyring.backends --hidden-import=jwt --hidden-import=cryptography \
--add-data "packs:packs" --hidden-import=addon_packs --hidden-import=mlx_engine_fetch \
`# ๐Ÿงฉ ์ถ”๊ฐ€ ํŒฉ โ€” ๋ฐฐํฌํŒ์— ๋„ฃ์ง€ ์•Š๊ณ  ์ฒ˜์Œ ์“ธ ๋•Œ ๋ฐ›๋Š”๋‹ค(addon_packs.py ยท packs/*.lock, 2026-10-13)` \
`# ๋ณด์ปฌ ๋ถ„๋ฆฌ(Demucs): torchยทsympyยทmpmathยทdemucsยทjuliusยทeinopsยทlameenc (์•ฝ 0.5GB)` \
--exclude-module torch --exclude-module torchaudio --exclude-module torchvision \
--exclude-module demucs --exclude-module julius --exclude-module einops --exclude-module lameenc \
--exclude-module sympy --exclude-module mpmath \
--paths ../jarvis_django --paths ../scripts/tools local_launcher.py
echo ""
echo "[COMPLETE] Please check the dist/TaeminiCLI.app bundle."
# 3.1. Dock/Finder ํ‘œ์‹œ ์ด๋ฆ„์„ "Taemini CLI"(๊ณต๋ฐฑ)๋กœ ์ง€์ •.
# ๋ฒˆ๋“ค/๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” TaeminiCLI(๊ณต๋ฐฑ ์—†์Œ)์ง€๋งŒ, ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์ด๋Š” ์ด๋ฆ„์€
# CFBundleDisplayName ์œผ๋กœ "Taemini CLI"๋ฅผ ๋…ธ์ถœํ•œ๋‹ค.
if [ -d "dist/TaeminiCLI.app" ]; then
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName Taemini CLI" \
"dist/TaeminiCLI.app/Contents/Info.plist" 2>/dev/null \
|| /usr/libexec/PlistBuddy -c "Add :CFBundleDisplayName string Taemini CLI" \
"dist/TaeminiCLI.app/Contents/Info.plist"
echo "[+] CFBundleDisplayName set to 'Taemini CLI'."
fi
# 3.5. taemini CLI ๋‹จ์ผ ์‹คํ–‰ํŒŒ์ผ ๋นŒ๋“œ โ†’ .app ์•ˆ์— ๋™๋ด‰
# Contents/MacOS/ ์— ๋‘๋Š” ์ด์œ : --deep ์ฝ”๋“œ์„œ๋ช…์ด '์ค‘์ฒฉ ์ฝ”๋“œ'๋กœ ์ธ์‹ํ•ด ํ•จ๊ป˜
# ์„œ๋ช…ยท๊ณต์ฆ๋˜๋Š” ์œ„์น˜๋‹ค (Resources์— ๋‘๋ฉด ์„œ๋ช… ์•ˆ ๋œ Mach-O๋กœ ๊ณต์ฆ ๊ฑฐ๋ถ€๋จ).
# PATH ๋“ฑ๋ก์€ ์•ฑ์ด ๋ถ€ํŒ… ์‹œ ์Šค์Šค๋กœ ํ•œ๋‹ค (local_launcher._ensure_taemini_cli_on_path).
echo ""
echo "[Step 3.5] Building taemini CLI (onefile console)..."
"$SHADOW_VENV_PYTHON" -m PyInstaller --name "taemini" --onefile -y \
--hidden-import=prompt_toolkit taemini_cli.py
if [ -f "dist/taemini" ] && [ -d "dist/TaeminiCLI.app" ]; then
cp "dist/taemini" "dist/TaeminiCLI.app/Contents/MacOS/taemini"
chmod +x "dist/TaeminiCLI.app/Contents/MacOS/taemini"
echo "[+] taemini CLI bundled into TaeminiCLI.app/Contents/MacOS/"
else
echo "[!] taemini CLI build failed - app will ship without the CLI."
fi
# 4. Copy config files to dist (mcp_servers.json, Supertonic ์†Œ์Šค vendoring)
# ๐Ÿ”ฑ local_settings.json์€ dist์— ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค. ์•ฑ์ด ~/Library/Application Support ์—์„œ
# ์ฝ๊ณ  ์ตœ์ดˆ ์‹คํ–‰ ์‹œ ์ž๋™ ์ƒ์„ฑํ•˜๋ฏ€๋กœ, ์•ˆ ์ฝํžˆ๋Š” ์‚ฌ๋ณธ์€ ํ˜ผ๋ž€๋งŒ ์ค€๋‹ค.
echo "[Step 4] Copying config files to dist..."
RESOURCES_DIR="dist/TaeminiCLI.app/Contents/Resources"
if [ -d "dist/TaeminiCLI.app" ]; then
if [ -f "mcp_servers.json" ]; then
cp "mcp_servers.json" "$RESOURCES_DIR/mcp_servers.json"
echo "[+] mcp_servers.json copied."
fi
if [ -d "config" ]; then
mkdir -p "$RESOURCES_DIR/config"
cp -R config/* "$RESOURCES_DIR/config/"
echo "[+] config directory copied."
fi
# [Supertonic] vendoring๋œ ์†Œ์Šค๋ฅผ ์•ฑ ๋ฆฌ์†Œ์Šค ์•ˆ์œผ๋กœ ๋ณต์‚ฌ
# ๋ชจ๋ธ ๊ฐ€์ค‘์น˜(ONNX)๋Š” ์ตœ์ดˆ ์‹คํ–‰ ์‹œ HF์—์„œ ์ž๋™ ๋‹ค์šด๋กœ๋“œ๋จ
if [ -d "../vendor/supertonic" ]; then
mkdir -p "$RESOURCES_DIR/vendor"
cp -R "../vendor/supertonic" "$RESOURCES_DIR/vendor/supertonic"
echo "[+] Supertonic source vendored into dist (Resources/vendor/supertonic)"
else
echo "[!] vendor/supertonic not found - Supertonic engine will be unavailable in this build."
fi
# 4.5. [MLX Serve] ๐ŸŽ Apple Silicon ๋„ค์ดํ‹ฐ๋ธŒ ์„œ๋น™ ๋Ÿฐํƒ€์ž„ ๋ฒˆ๋“ค๋ง (Zero-Setup Metal ๊ฐ€์†)
echo ""
echo "[Step 4.5] Bundling MLX Serve native runtime into TaeminiCLI.app..."
# ๋ฐฐํฌํŒ์—๋Š” ๋„ฃ์ง€ ์•Š๋Š”๋‹ค โ€” ์•ฑ์ด ์ฒ˜์Œ ์“ธ ๋•Œ ๊ณต์‹ GitHub ๋ฆด๋ฆฌ์Šค์—์„œ ๋ฐ›๋Š”๋‹ค(shadow_brain_core/mlx_engine_fetch.py).
# ์˜ˆ์ „์—” ์—ฌ๊ธฐ์„œ ์—”์ง„๊ณผ ๊ฐ™์€ 174MB metallib ๋ฅผ ๋‹ค์„ฏ ๊ตฐ๋ฐ ๋ณต์‚ฌํ•ด ์•ฑ์ด 870MB ๋ถ€ํ’€์—ˆ๋‹ค(2026-10-13 ์ธก์ •).
echo "[=] MLX Serve: ๋ฒˆ๋“ค ์•ˆ ํ•จ โ€” ์ฒ˜์Œ ์“ธ ๋•Œ github.com/ddalcu/mlx-serve ์—์„œ ๋ฐ›๋Š”๋‹ค(์•ฝ 79MB)"
fi
if [ "${1:-}" = "--no-pause" ]; then
exit 0
fi
read -r "?Press Enter to continue..."