mirror of
https://github.com/trycua/computer.git
synced 2026-01-01 02:50:15 -06:00
166 lines
5.7 KiB
Python
Executable File
166 lines
5.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Build script for CUA Desktop Extension (.mcpb file)
|
|
|
|
This script:
|
|
1. Creates a temporary build directory
|
|
2. Copies necessary files from mcp_server/ to the build directory
|
|
3. Copies manifest and other static files
|
|
4. Creates a .mcpb (zip) file
|
|
5. Cleans up the temporary directory
|
|
|
|
Usage:
|
|
python build-extension.py
|
|
"""
|
|
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import zipfile
|
|
from pathlib import Path
|
|
|
|
|
|
def main():
|
|
"""Build the desktop extension."""
|
|
# Get the script directory (libs/python/mcp-server)
|
|
script_dir = Path(__file__).parent
|
|
repo_root = script_dir.parent.parent.parent
|
|
|
|
# Define paths
|
|
output_dir = script_dir / "desktop-extension"
|
|
output_file = output_dir / "cua-extension.mcpb"
|
|
|
|
# Source directories
|
|
mcp_server_dir = script_dir / "mcp_server"
|
|
|
|
# Required files to copy
|
|
files_to_copy = {
|
|
"manifest.json": output_dir / "manifest.json",
|
|
"desktop_extension.png": output_dir / "desktop_extension.png",
|
|
"requirements.txt": output_dir / "requirements.txt",
|
|
"run_server.sh": output_dir / "run_server.sh",
|
|
"setup.py": output_dir / "setup.py",
|
|
}
|
|
|
|
# MCP server files to copy
|
|
mcp_server_files = [
|
|
"server.py",
|
|
"session_manager.py",
|
|
]
|
|
|
|
print("Building CUA Desktop Extension...")
|
|
print(f" Output: {output_file}")
|
|
|
|
# Create temporary build directory
|
|
with tempfile.TemporaryDirectory(prefix="cua-extension-build-") as build_dir:
|
|
build_path = Path(build_dir)
|
|
|
|
# Copy MCP server files
|
|
print(" Copying MCP server files...")
|
|
for filename in mcp_server_files:
|
|
src = mcp_server_dir / filename
|
|
dst = build_path / filename
|
|
if src.exists():
|
|
shutil.copy2(src, dst)
|
|
print(f" ✓ {filename}")
|
|
else:
|
|
print(f" ✗ {filename} (not found)")
|
|
sys.exit(1)
|
|
|
|
# Copy static files from desktop-extension directory
|
|
print(" Copying static files...")
|
|
for src_name, src_path in files_to_copy.items():
|
|
if src_path.exists():
|
|
dst = build_path / src_name
|
|
# Special handling for shell script - ensure executable
|
|
shutil.copy2(src_path, dst)
|
|
if src_name.endswith(".sh"):
|
|
os.chmod(dst, 0o755)
|
|
print(f" ✓ {src_name}")
|
|
else:
|
|
print(f" ✗ {src_name} (not found)")
|
|
sys.exit(1)
|
|
|
|
# Validate manifest.json exists
|
|
manifest_path = build_path / "manifest.json"
|
|
if not manifest_path.exists():
|
|
print(" ✗ manifest.json not found in build directory")
|
|
sys.exit(1)
|
|
|
|
# Create the .mcpb file (zip archive)
|
|
print(" Creating .mcpb archive...")
|
|
with zipfile.ZipFile(output_file, "w", zipfile.ZIP_DEFLATED) as zipf:
|
|
# Add all files from build directory to the zip
|
|
for root, dirs, files in os.walk(build_path):
|
|
# Skip __pycache__ and other unwanted directories
|
|
dirs[:] = [d for d in dirs if d not in ["__pycache__", ".git"]]
|
|
|
|
for file in files:
|
|
file_path = Path(root) / file
|
|
# Use relative path from build directory as archive name
|
|
arcname = file_path.relative_to(build_path)
|
|
zipf.write(file_path, arcname)
|
|
print(f" ✓ Added {arcname}")
|
|
|
|
print(f"✓ Build complete: {output_file}")
|
|
print(f" Archive size: {output_file.stat().st_size / 1024:.1f} KB")
|
|
|
|
# Set custom file icon based on platform
|
|
icon_file = output_dir / "desktop_extension.png"
|
|
if sys.platform == "darwin":
|
|
_set_icon_macos(output_file, icon_file)
|
|
elif sys.platform == "win32":
|
|
_set_icon_windows(output_file, icon_file)
|
|
elif sys.platform.startswith("linux"):
|
|
_set_icon_linux(output_file, icon_file)
|
|
|
|
|
|
def _set_icon_macos(output_file: Path, icon_file: Path):
|
|
"""Set custom file icon on macOS."""
|
|
try:
|
|
# Check if fileicon is installed
|
|
result = subprocess.run(["which", "fileicon"], capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
# Use the logo as the file icon
|
|
if icon_file.exists():
|
|
print(" Setting custom file icon (macOS)...")
|
|
subprocess.run(
|
|
["fileicon", "set", str(output_file), str(icon_file)],
|
|
check=False,
|
|
capture_output=True,
|
|
)
|
|
print(" ✓ File icon set")
|
|
else:
|
|
print(f" ⚠ Icon file not found: {icon_file}")
|
|
else:
|
|
print(" ⚠ fileicon not installed (optional - for custom file icon)")
|
|
print(" Install with: brew install fileicon")
|
|
except Exception as e:
|
|
print(f" ⚠ Could not set file icon: {e}")
|
|
|
|
|
|
def _set_icon_windows(output_file: Path, icon_file: Path):
|
|
"""Set custom file icon on Windows."""
|
|
try:
|
|
# Windows uses a desktop.ini approach, which is complex
|
|
# For simplicity, we'll skip this for now
|
|
print(" ⚠ Custom file icons not supported on Windows yet")
|
|
except Exception as e:
|
|
print(f" ⚠ Could not set file icon: {e}")
|
|
|
|
|
|
def _set_icon_linux(output_file: Path, icon_file: Path):
|
|
"""Set custom file icon on Linux."""
|
|
try:
|
|
# Linux uses .desktop files and thumbnail generation
|
|
# This is complex and depends on the desktop environment
|
|
print(" ⚠ Custom file icons not supported on Linux yet")
|
|
except Exception as e:
|
|
print(f" ⚠ Could not set file icon: {e}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|