| from __future__ import annotations |
|
|
| import argparse |
| import ctypes |
| import os |
| import shutil |
| import sys |
| from pathlib import Path |
|
|
| from PySide6.QtCore import QTimer |
| from PySide6.QtGui import QIcon |
| from PySide6.QtWidgets import QApplication |
|
|
| from adam.app import build_application |
|
|
|
|
| WINDOWS_APP_ID = "ADAM.Desktop.Orchestrator" |
|
|
|
|
| def application_paths() -> tuple[Path, Path]: |
| """Return the writable app folder and bundled read-only resource folder.""" |
| source_root = Path(__file__).resolve().parent |
| if getattr(sys, "frozen", False): |
| return Path(sys.executable).resolve().parent, Path( |
| getattr(sys, "_MEIPASS", source_root) |
| ).resolve() |
| return source_root, source_root |
|
|
|
|
| def prepare_portable_config(app_root: Path, resource_root: Path) -> None: |
| """Seed a packaged copy with its default registry without overwriting user edits.""" |
| if app_root == resource_root: |
| return |
| config_dir = app_root / "config" |
| config_dir.mkdir(parents=True, exist_ok=True) |
| bundled_config = resource_root / "config" |
| for name in ("tools.json", "settings.json", "external_tools.json"): |
| source = bundled_config / name |
| destination = config_dir / name |
| if source.is_file() and not destination.exists(): |
| shutil.copy2(source, destination) |
|
|
|
|
| def set_windows_app_identity() -> None: |
| """Give Windows a stable identity instead of grouping ADAM under Python.""" |
| if sys.platform != "win32": |
| return |
| try: |
| ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(WINDOWS_APP_ID) |
| except (AttributeError, OSError): |
| pass |
|
|
|
|
| def parse_args() -> argparse.Namespace: |
| parser = argparse.ArgumentParser(description="ADAM desktop orchestrator") |
| parser.add_argument( |
| "--screenshot", |
| type=Path, |
| help="Save a launch screenshot and exit (used for visual smoke tests).", |
| ) |
| return parser.parse_args() |
|
|
|
|
| def main() -> int: |
| args = parse_args() |
| project_root, resource_root = application_paths() |
| prepare_portable_config(project_root, resource_root) |
| set_windows_app_identity() |
|
|
| if args.screenshot and not os.environ.get("QT_QPA_PLATFORM"): |
| os.environ["QT_QPA_PLATFORM"] = "offscreen" |
|
|
| qt_app = QApplication(sys.argv) |
| qt_app.setApplicationName("ADAM") |
| qt_app.setOrganizationName("ADAM") |
| qt_app.setStyle("Fusion") |
|
|
| icon_path = resource_root / "assets" / "adam_atom.png" |
| if icon_path.exists(): |
| qt_app.setWindowIcon(QIcon(str(icon_path))) |
|
|
| window, services = build_application(project_root) |
| window.show() |
|
|
| if args.screenshot: |
| destination = args.screenshot.resolve() |
|
|
| def capture() -> None: |
| destination.parent.mkdir(parents=True, exist_ok=True) |
| window.grab().save(str(destination)) |
| services.shutdown() |
| qt_app.quit() |
|
|
| QTimer.singleShot(1200, capture) |
|
|
| exit_code = qt_app.exec() |
| services.shutdown() |
| return exit_code |
|
|
|
|
| if __name__ == "__main__": |
| raise SystemExit(main()) |
|
|