Add system tray, dual-exe build, and installer scripts
- core/tray.py: System tray icon with Start/Stop/Restart/Open Dashboard/Exit - autarch_web.py: Windowless web launcher entry point (Win32GUI, no console) - core/paths.py: Frozen build support — dual-directory pattern for PyInstaller - core/menu.py: Module loading scans both bundled and user module directories - web/app.py: Template/static paths resolve correctly in frozen builds - autarch.py: --no-tray flag, tray integration for --web mode - autarch_public.spec: Dual-exe PyInstaller spec with MERGE/COLLECT - setup_msi.py: Dual executables, LocalAppData install, model inclusion - installer.iss: Inno Setup script (model stored uncompressed to avoid OOM) - installer.nsi: NSIS installer script with MUI2 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
150f58f57a
commit
4a721a73b4
19
autarch.py
19
autarch.py
@ -210,6 +210,11 @@ def create_parser():
|
|||||||
metavar='PORT',
|
metavar='PORT',
|
||||||
help='Web dashboard port (default: 8181)'
|
help='Web dashboard port (default: 8181)'
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--no-tray',
|
||||||
|
action='store_true',
|
||||||
|
help='Disable system tray icon (run web server in foreground only)'
|
||||||
|
)
|
||||||
|
|
||||||
# Web service management
|
# Web service management
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@ -680,6 +685,20 @@ def main():
|
|||||||
proto = 'http'
|
proto = 'http'
|
||||||
|
|
||||||
print(f"{Colors.GREEN}[+] Starting AUTARCH Web Dashboard on {proto}://{host}:{port}{Colors.RESET}")
|
print(f"{Colors.GREEN}[+] Starting AUTARCH Web Dashboard on {proto}://{host}:{port}{Colors.RESET}")
|
||||||
|
|
||||||
|
# System tray mode (default on desktop environments)
|
||||||
|
if not args.no_tray:
|
||||||
|
try:
|
||||||
|
from core.tray import TrayManager, TRAY_AVAILABLE
|
||||||
|
if TRAY_AVAILABLE:
|
||||||
|
print(f"{Colors.DIM} System tray icon active — right-click to control{Colors.RESET}")
|
||||||
|
tray = TrayManager(app, host, port, ssl_context=ssl_ctx)
|
||||||
|
tray.run() # Blocks until Exit
|
||||||
|
sys.exit(0)
|
||||||
|
except Exception:
|
||||||
|
pass # Fall through to normal mode
|
||||||
|
|
||||||
|
# Fallback: run Flask directly (headless / --no-tray)
|
||||||
app.run(host=host, port=port, debug=False, ssl_context=ssl_ctx)
|
app.run(host=host, port=port, debug=False, ssl_context=ssl_ctx)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
# -*- mode: python ; coding: utf-8 -*-
|
# -*- mode: python ; coding: utf-8 -*-
|
||||||
# PyInstaller spec for AUTARCH Public Release
|
# PyInstaller spec for AUTARCH Public Release
|
||||||
# Build: pyinstaller autarch_public.spec
|
#
|
||||||
# Output: dist/autarch_public.exe (single-file executable)
|
# Build: pyinstaller autarch_public.spec
|
||||||
|
# Output: dist/autarch/
|
||||||
|
# ├── autarch.exe (CLI — full framework, console window)
|
||||||
|
# └── autarch_web.exe (Web — double-click to launch dashboard + tray icon, no console)
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -11,25 +14,31 @@ SRC = Path(SPECPATH)
|
|||||||
block_cipher = None
|
block_cipher = None
|
||||||
|
|
||||||
# ── Data files (non-Python assets to bundle) ─────────────────────────────────
|
# ── Data files (non-Python assets to bundle) ─────────────────────────────────
|
||||||
added_files = [
|
# Only include files that actually exist to prevent build failures
|
||||||
|
_candidate_files = [
|
||||||
# Web assets
|
# Web assets
|
||||||
(str(SRC / 'web' / 'templates'), 'web/templates'),
|
(SRC / 'web' / 'templates', 'web/templates'),
|
||||||
(str(SRC / 'web' / 'static'), 'web/static'),
|
(SRC / 'web' / 'static', 'web/static'),
|
||||||
|
|
||||||
# Data (SQLite DBs, site lists, config defaults)
|
# Data (SQLite DBs, site lists, config defaults)
|
||||||
(str(SRC / 'data'), 'data'),
|
(SRC / 'data', 'data'),
|
||||||
|
|
||||||
# Modules directory (dynamically loaded)
|
# Modules directory (dynamically loaded at runtime)
|
||||||
(str(SRC / 'modules'), 'modules'),
|
(SRC / 'modules', 'modules'),
|
||||||
|
|
||||||
|
# LLM model
|
||||||
|
(SRC / 'models' / 'Hal_v2.gguf', 'models'),
|
||||||
|
|
||||||
# Root-level config and docs
|
# Root-level config and docs
|
||||||
(str(SRC / 'autarch_settings.conf'), '.'),
|
(SRC / 'autarch_settings.conf', '.'),
|
||||||
(str(SRC / 'user_manual.md'), '.'),
|
(SRC / 'user_manual.md', '.'),
|
||||||
(str(SRC / 'windows_manual.md'), '.'),
|
(SRC / 'windows_manual.md', '.'),
|
||||||
(str(SRC / 'custom_sites.inf'), '.'),
|
(SRC / 'custom_sites.inf', '.'),
|
||||||
(str(SRC / 'custom_adultsites.json'), '.'),
|
(SRC / 'custom_adultsites.json', '.'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
added_files = [(str(src), dst) for src, dst in _candidate_files if src.exists()]
|
||||||
|
|
||||||
# ── Hidden imports ────────────────────────────────────────────────────────────
|
# ── Hidden imports ────────────────────────────────────────────────────────────
|
||||||
hidden_imports = [
|
hidden_imports = [
|
||||||
# Flask ecosystem
|
# Flask ecosystem
|
||||||
@ -39,10 +48,13 @@ hidden_imports = [
|
|||||||
|
|
||||||
# Core libraries
|
# Core libraries
|
||||||
'bcrypt', 'requests', 'msgpack', 'pyserial', 'qrcode', 'PIL',
|
'bcrypt', 'requests', 'msgpack', 'pyserial', 'qrcode', 'PIL',
|
||||||
'PIL.Image', 'PIL.ImageDraw', 'cryptography',
|
'PIL.Image', 'PIL.ImageDraw', 'PIL.ImageFont', 'cryptography',
|
||||||
|
|
||||||
|
# System tray
|
||||||
|
'pystray', 'pystray._win32',
|
||||||
|
|
||||||
# AUTARCH core modules
|
# AUTARCH core modules
|
||||||
'core.config', 'core.paths', 'core.banner', 'core.menu',
|
'core.config', 'core.paths', 'core.banner', 'core.menu', 'core.tray',
|
||||||
'core.llm', 'core.agent', 'core.tools',
|
'core.llm', 'core.agent', 'core.tools',
|
||||||
'core.msf', 'core.msf_interface',
|
'core.msf', 'core.msf_interface',
|
||||||
'core.hardware', 'core.android_protect',
|
'core.hardware', 'core.android_protect',
|
||||||
@ -74,6 +86,7 @@ hidden_imports = [
|
|||||||
'web.routes.chat',
|
'web.routes.chat',
|
||||||
'web.routes.targets',
|
'web.routes.targets',
|
||||||
'web.routes.encmodules',
|
'web.routes.encmodules',
|
||||||
|
'web.routes.llm_trainer',
|
||||||
|
|
||||||
# Standard library (sometimes missed on Windows)
|
# Standard library (sometimes missed on Windows)
|
||||||
'email.mime.text', 'email.mime.multipart',
|
'email.mime.text', 'email.mime.multipart',
|
||||||
@ -82,9 +95,30 @@ hidden_imports = [
|
|||||||
'threading', 'queue', 'uuid', 'hashlib', 'zlib',
|
'threading', 'queue', 'uuid', 'hashlib', 'zlib',
|
||||||
'configparser', 'platform', 'socket', 'shutil',
|
'configparser', 'platform', 'socket', 'shutil',
|
||||||
'importlib', 'importlib.util', 'importlib.metadata',
|
'importlib', 'importlib.util', 'importlib.metadata',
|
||||||
|
'webbrowser', 'ssl',
|
||||||
]
|
]
|
||||||
|
|
||||||
a = Analysis(
|
excludes = [
|
||||||
|
# Exclude heavy optional deps not needed at runtime
|
||||||
|
'torch', 'transformers', 'llama_cpp', 'llama_cpp_python', 'anthropic',
|
||||||
|
'tkinter', 'matplotlib', 'numpy',
|
||||||
|
# CUDA / quantization libraries
|
||||||
|
'bitsandbytes',
|
||||||
|
# HuggingFace ecosystem
|
||||||
|
'huggingface_hub', 'safetensors', 'tokenizers',
|
||||||
|
# MCP/uvicorn/starlette
|
||||||
|
'mcp', 'uvicorn', 'starlette', 'anyio', 'httpx', 'httpx_sse',
|
||||||
|
'httpcore', 'h11', 'h2', 'hpack', 'hyperframe',
|
||||||
|
# Pydantic
|
||||||
|
'pydantic', 'pydantic_core', 'pydantic_settings',
|
||||||
|
# Other heavy packages
|
||||||
|
'scipy', 'pandas', 'tensorflow', 'keras',
|
||||||
|
'IPython', 'notebook', 'jupyterlab',
|
||||||
|
'fsspec', 'rich', 'typer',
|
||||||
|
]
|
||||||
|
|
||||||
|
# ── Analysis for CLI entry point ─────────────────────────────────────────────
|
||||||
|
a_cli = Analysis(
|
||||||
['autarch.py'],
|
['autarch.py'],
|
||||||
pathex=[str(SRC)],
|
pathex=[str(SRC)],
|
||||||
binaries=[],
|
binaries=[],
|
||||||
@ -93,38 +127,40 @@ a = Analysis(
|
|||||||
hookspath=[],
|
hookspath=[],
|
||||||
hooksconfig={},
|
hooksconfig={},
|
||||||
runtime_hooks=[],
|
runtime_hooks=[],
|
||||||
excludes=[
|
excludes=excludes,
|
||||||
# Exclude heavy optional deps not needed at runtime
|
|
||||||
'torch', 'transformers', 'llama_cpp', 'llama_cpp_python', 'anthropic',
|
|
||||||
'tkinter', 'matplotlib', 'numpy',
|
|
||||||
# CUDA / quantization libraries (bitsandbytes ships 169MB of CUDA DLLs)
|
|
||||||
'bitsandbytes',
|
|
||||||
# HuggingFace ecosystem (pulled in by llama_cpp_python)
|
|
||||||
'huggingface_hub', 'safetensors', 'tokenizers',
|
|
||||||
# MCP/uvicorn/starlette (heavy server stack not needed in frozen exe)
|
|
||||||
'mcp', 'uvicorn', 'starlette', 'anyio', 'httpx', 'httpx_sse',
|
|
||||||
'httpcore', 'h11', 'h2', 'hpack', 'hyperframe',
|
|
||||||
# Pydantic (pulled in by MCP/huggingface)
|
|
||||||
'pydantic', 'pydantic_core', 'pydantic_settings',
|
|
||||||
# Other heavy / unnecessary packages
|
|
||||||
'scipy', 'pandas', 'tensorflow', 'keras',
|
|
||||||
'IPython', 'notebook', 'jupyterlab',
|
|
||||||
'fsspec', 'rich', 'typer',
|
|
||||||
],
|
|
||||||
noarchive=False,
|
noarchive=False,
|
||||||
optimize=0,
|
optimize=0,
|
||||||
)
|
)
|
||||||
|
|
||||||
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
# ── Analysis for Web entry point ─────────────────────────────────────────────
|
||||||
|
a_web = Analysis(
|
||||||
|
['autarch_web.py'],
|
||||||
|
pathex=[str(SRC)],
|
||||||
|
binaries=[],
|
||||||
|
datas=added_files,
|
||||||
|
hiddenimports=hidden_imports,
|
||||||
|
hookspath=[],
|
||||||
|
hooksconfig={},
|
||||||
|
runtime_hooks=[],
|
||||||
|
excludes=excludes,
|
||||||
|
noarchive=False,
|
||||||
|
optimize=0,
|
||||||
|
)
|
||||||
|
|
||||||
# ── Single-file executable ───────────────────────────────────────────────────
|
# ── Merge analyses (shared libraries only stored once) ───────────────────────
|
||||||
exe = EXE(
|
MERGE(
|
||||||
pyz,
|
(a_cli, 'autarch', 'autarch'),
|
||||||
a.scripts,
|
(a_web, 'autarch_web', 'autarch_web'),
|
||||||
a.binaries,
|
)
|
||||||
a.datas,
|
|
||||||
|
# ── CLI executable (console window) ─────────────────────────────────────────
|
||||||
|
pyz_cli = PYZ(a_cli.pure, a_cli.zipped_data, cipher=block_cipher)
|
||||||
|
exe_cli = EXE(
|
||||||
|
pyz_cli,
|
||||||
|
a_cli.scripts,
|
||||||
[],
|
[],
|
||||||
name='autarch_public',
|
exclude_binaries=True,
|
||||||
|
name='autarch',
|
||||||
debug=False,
|
debug=False,
|
||||||
bootloader_ignore_signals=False,
|
bootloader_ignore_signals=False,
|
||||||
strip=False,
|
strip=False,
|
||||||
@ -137,3 +173,38 @@ exe = EXE(
|
|||||||
entitlements_file=None,
|
entitlements_file=None,
|
||||||
icon=None,
|
icon=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# ── Web executable (NO console window — tray icon only) ─────────────────────
|
||||||
|
pyz_web = PYZ(a_web.pure, a_web.zipped_data, cipher=block_cipher)
|
||||||
|
exe_web = EXE(
|
||||||
|
pyz_web,
|
||||||
|
a_web.scripts,
|
||||||
|
[],
|
||||||
|
exclude_binaries=True,
|
||||||
|
name='autarch_web',
|
||||||
|
debug=False,
|
||||||
|
bootloader_ignore_signals=False,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
console=False, # <-- No console window
|
||||||
|
disable_windowed_traceback=False,
|
||||||
|
argv_emulation=False,
|
||||||
|
target_arch=None,
|
||||||
|
codesign_identity=None,
|
||||||
|
entitlements_file=None,
|
||||||
|
icon=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
# ── Collect everything into one directory ────────────────────────────────────
|
||||||
|
coll = COLLECT(
|
||||||
|
exe_cli,
|
||||||
|
a_cli.binaries,
|
||||||
|
a_cli.datas,
|
||||||
|
exe_web,
|
||||||
|
a_web.binaries,
|
||||||
|
a_web.datas,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
upx_exclude=[],
|
||||||
|
name='autarch',
|
||||||
|
)
|
||||||
|
|||||||
66
autarch_web.py
Normal file
66
autarch_web.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
"""AUTARCH Web Launcher — double-click to start the web dashboard with system tray.
|
||||||
|
|
||||||
|
This is the entry point for autarch_web.exe (no console window).
|
||||||
|
It starts the Flask web server and shows a system tray icon for control.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Ensure framework is importable
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
FRAMEWORK_DIR = Path(sys._MEIPASS)
|
||||||
|
else:
|
||||||
|
FRAMEWORK_DIR = Path(__file__).parent
|
||||||
|
sys.path.insert(0, str(FRAMEWORK_DIR))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
from web.app import create_app
|
||||||
|
from core.config import get_config
|
||||||
|
from core.paths import get_data_dir
|
||||||
|
|
||||||
|
config = get_config()
|
||||||
|
app = create_app()
|
||||||
|
host = config.get('web', 'host', fallback='0.0.0.0')
|
||||||
|
port = config.get_int('web', 'port', fallback=8181)
|
||||||
|
|
||||||
|
# Auto-generate self-signed TLS cert
|
||||||
|
ssl_ctx = None
|
||||||
|
use_https = config.get('web', 'https', fallback='true').lower() != 'false'
|
||||||
|
if use_https:
|
||||||
|
import subprocess
|
||||||
|
cert_dir = os.path.join(get_data_dir(), 'certs')
|
||||||
|
os.makedirs(cert_dir, exist_ok=True)
|
||||||
|
cert_path = os.path.join(cert_dir, 'autarch.crt')
|
||||||
|
key_path = os.path.join(cert_dir, 'autarch.key')
|
||||||
|
if not os.path.exists(cert_path) or not os.path.exists(key_path):
|
||||||
|
try:
|
||||||
|
subprocess.run([
|
||||||
|
'openssl', 'req', '-x509', '-newkey', 'rsa:2048',
|
||||||
|
'-keyout', key_path, '-out', cert_path,
|
||||||
|
'-days', '3650', '-nodes',
|
||||||
|
'-subj', '/CN=AUTARCH/O=darkHal',
|
||||||
|
], check=True, capture_output=True)
|
||||||
|
except Exception:
|
||||||
|
use_https = False
|
||||||
|
if use_https:
|
||||||
|
ssl_ctx = (cert_path, key_path)
|
||||||
|
|
||||||
|
# Try system tray mode (preferred — no console window needed)
|
||||||
|
try:
|
||||||
|
from core.tray import TrayManager, TRAY_AVAILABLE
|
||||||
|
if TRAY_AVAILABLE:
|
||||||
|
tray = TrayManager(app, host, port, ssl_context=ssl_ctx)
|
||||||
|
tray.run()
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Fallback: run Flask directly
|
||||||
|
app.run(host=host, port=port, debug=False, ssl_context=ssl_ctx)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
33
core/menu.py
33
core/menu.py
@ -100,29 +100,36 @@ class MainMenu:
|
|||||||
print(f"{color}[{symbol}] {message}{Colors.RESET}")
|
print(f"{color}[{symbol}] {message}{Colors.RESET}")
|
||||||
|
|
||||||
def load_modules(self):
|
def load_modules(self):
|
||||||
"""Load all available modules from the modules directory."""
|
"""Load all available modules from the modules directory.
|
||||||
modules_path = self._app_dir / self.config.get('autarch', 'modules_path', 'modules')
|
|
||||||
|
|
||||||
if not modules_path.exists():
|
In a frozen (PyInstaller) build, scans both the bundled modules inside
|
||||||
self.print_status(f"Modules directory not found: {modules_path}", "warning")
|
_MEIPASS and the user modules directory next to the exe. User modules
|
||||||
return
|
override bundled modules with the same name.
|
||||||
|
"""
|
||||||
|
from core.paths import get_modules_dir, get_user_modules_dir, is_frozen
|
||||||
|
|
||||||
for module_file in modules_path.glob("*.py"):
|
# Collect module files — bundled first, then user (user overrides)
|
||||||
if module_file.name.startswith("_"):
|
module_files: dict[str, Path] = {}
|
||||||
continue
|
|
||||||
|
|
||||||
module_name = module_file.stem
|
bundled = get_modules_dir()
|
||||||
|
if bundled.exists():
|
||||||
|
for f in bundled.glob("*.py"):
|
||||||
|
if not f.name.startswith("_") and f.stem != "setup":
|
||||||
|
module_files[f.stem] = f
|
||||||
|
|
||||||
# Skip the setup module from regular listing
|
if is_frozen():
|
||||||
if module_name == "setup":
|
user_dir = get_user_modules_dir()
|
||||||
continue
|
if user_dir.exists():
|
||||||
|
for f in user_dir.glob("*.py"):
|
||||||
|
if not f.name.startswith("_") and f.stem != "setup":
|
||||||
|
module_files[f.stem] = f # Override bundled
|
||||||
|
|
||||||
|
for module_name, module_file in module_files.items():
|
||||||
try:
|
try:
|
||||||
spec = importlib.util.spec_from_file_location(module_name, module_file)
|
spec = importlib.util.spec_from_file_location(module_name, module_file)
|
||||||
module = importlib.util.module_from_spec(spec)
|
module = importlib.util.module_from_spec(spec)
|
||||||
spec.loader.exec_module(module)
|
spec.loader.exec_module(module)
|
||||||
|
|
||||||
# Check if module has required 'run' function
|
|
||||||
if hasattr(module, 'run'):
|
if hasattr(module, 'run'):
|
||||||
self.modules[module_name] = ModuleInfo(module_name, module_file, module)
|
self.modules[module_name] = ModuleInfo(module_name, module_file, module)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -14,22 +14,60 @@ from typing import Optional, List
|
|||||||
|
|
||||||
|
|
||||||
# ── Application Root ────────────────────────────────────────────────
|
# ── Application Root ────────────────────────────────────────────────
|
||||||
|
#
|
||||||
|
# Two directories matter:
|
||||||
|
# _BUNDLE_DIR — read-only bundled assets (templates, static, default modules)
|
||||||
|
# Points to sys._MEIPASS in a frozen PyInstaller build,
|
||||||
|
# otherwise same as _APP_DIR.
|
||||||
|
# _APP_DIR — writable application root (config, data, results, user modules)
|
||||||
|
# Points to the .exe's parent directory in a frozen build,
|
||||||
|
# otherwise the project root (parent of core/).
|
||||||
|
|
||||||
# Computed once: the autarch project root (parent of core/)
|
import sys as _sys
|
||||||
_APP_DIR = Path(__file__).resolve().parent.parent
|
|
||||||
|
_FROZEN = getattr(_sys, 'frozen', False)
|
||||||
|
|
||||||
|
if _FROZEN:
|
||||||
|
# PyInstaller frozen build
|
||||||
|
_BUNDLE_DIR = Path(_sys._MEIPASS)
|
||||||
|
_APP_DIR = Path(_sys.executable).resolve().parent
|
||||||
|
else:
|
||||||
|
# Normal Python execution
|
||||||
|
_APP_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
_BUNDLE_DIR = _APP_DIR
|
||||||
|
|
||||||
|
|
||||||
|
def is_frozen() -> bool:
|
||||||
|
"""Return True if running from a PyInstaller bundle."""
|
||||||
|
return _FROZEN
|
||||||
|
|
||||||
|
|
||||||
def get_app_dir() -> Path:
|
def get_app_dir() -> Path:
|
||||||
"""Return the AUTARCH application root directory."""
|
"""Return the writable application root directory."""
|
||||||
return _APP_DIR
|
return _APP_DIR
|
||||||
|
|
||||||
|
|
||||||
|
def get_bundle_dir() -> Path:
|
||||||
|
"""Return the bundle directory (read-only assets: templates, static, default modules)."""
|
||||||
|
return _BUNDLE_DIR
|
||||||
|
|
||||||
|
|
||||||
def get_core_dir() -> Path:
|
def get_core_dir() -> Path:
|
||||||
return _APP_DIR / 'core'
|
return _BUNDLE_DIR / 'core'
|
||||||
|
|
||||||
|
|
||||||
def get_modules_dir() -> Path:
|
def get_modules_dir() -> Path:
|
||||||
return _APP_DIR / 'modules'
|
"""Return the bundled modules directory (read-only in frozen mode)."""
|
||||||
|
return _BUNDLE_DIR / 'modules'
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_modules_dir() -> Path:
|
||||||
|
"""Return the user modules directory (writable, next to exe).
|
||||||
|
New or modified modules go here; scanned in addition to bundled modules."""
|
||||||
|
d = _APP_DIR / 'modules'
|
||||||
|
if _FROZEN:
|
||||||
|
d.mkdir(parents=True, exist_ok=True)
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
def get_data_dir() -> Path:
|
def get_data_dir() -> Path:
|
||||||
@ -39,7 +77,15 @@ def get_data_dir() -> Path:
|
|||||||
|
|
||||||
|
|
||||||
def get_config_path() -> Path:
|
def get_config_path() -> Path:
|
||||||
return _APP_DIR / 'autarch_settings.conf'
|
"""Return config path. Writable copy lives next to the exe;
|
||||||
|
falls back to the bundled default if the writable copy doesn't exist yet."""
|
||||||
|
writable = _APP_DIR / 'autarch_settings.conf'
|
||||||
|
if not writable.exists() and _FROZEN:
|
||||||
|
bundled = _BUNDLE_DIR / 'autarch_settings.conf'
|
||||||
|
if bundled.exists():
|
||||||
|
import shutil as _sh
|
||||||
|
_sh.copy2(str(bundled), str(writable))
|
||||||
|
return writable
|
||||||
|
|
||||||
|
|
||||||
def get_results_dir() -> Path:
|
def get_results_dir() -> Path:
|
||||||
|
|||||||
130
core/tray.py
Normal file
130
core/tray.py
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
"""AUTARCH System Tray Icon
|
||||||
|
|
||||||
|
Provides a taskbar/system tray icon with Start, Stop, Restart, Open Dashboard,
|
||||||
|
and Exit controls for the web dashboard.
|
||||||
|
|
||||||
|
Requires: pystray, Pillow
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import threading
|
||||||
|
import webbrowser
|
||||||
|
|
||||||
|
try:
|
||||||
|
import pystray
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
TRAY_AVAILABLE = True
|
||||||
|
except ImportError:
|
||||||
|
TRAY_AVAILABLE = False
|
||||||
|
|
||||||
|
|
||||||
|
def create_icon_image(size=64):
|
||||||
|
"""Create AUTARCH tray icon programmatically — dark circle with cyan 'A'."""
|
||||||
|
img = Image.new('RGBA', (size, size), (0, 0, 0, 0))
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
|
||||||
|
# Dark background circle with cyan border
|
||||||
|
draw.ellipse([1, 1, size - 2, size - 2], fill=(15, 15, 25, 255),
|
||||||
|
outline=(0, 180, 255, 255), width=2)
|
||||||
|
|
||||||
|
# Letter "A" centered
|
||||||
|
try:
|
||||||
|
font = ImageFont.truetype("arial.ttf", int(size * 0.5))
|
||||||
|
except OSError:
|
||||||
|
font = ImageFont.load_default()
|
||||||
|
|
||||||
|
bbox = draw.textbbox((0, 0), "A", font=font)
|
||||||
|
tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1]
|
||||||
|
x = (size - tw) // 2
|
||||||
|
y = (size - th) // 2 - bbox[1]
|
||||||
|
draw.text((x, y), "A", fill=(0, 200, 255, 255), font=font)
|
||||||
|
|
||||||
|
return img
|
||||||
|
|
||||||
|
|
||||||
|
class TrayManager:
|
||||||
|
"""Manages the system tray icon and Flask server lifecycle."""
|
||||||
|
|
||||||
|
def __init__(self, app, host, port, ssl_context=None):
|
||||||
|
self.app = app
|
||||||
|
self.host = host
|
||||||
|
self.port = port
|
||||||
|
self.ssl_context = ssl_context
|
||||||
|
self._server = None
|
||||||
|
self._thread = None
|
||||||
|
self.running = False
|
||||||
|
self._icon = None
|
||||||
|
self._proto = 'https' if ssl_context else 'http'
|
||||||
|
|
||||||
|
def start_server(self):
|
||||||
|
"""Start the Flask web server in a background thread."""
|
||||||
|
if self.running:
|
||||||
|
return
|
||||||
|
|
||||||
|
from werkzeug.serving import make_server
|
||||||
|
self._server = make_server(self.host, self.port, self.app, threaded=True)
|
||||||
|
|
||||||
|
if self.ssl_context:
|
||||||
|
import ssl
|
||||||
|
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||||
|
ctx.load_cert_chain(self.ssl_context[0], self.ssl_context[1])
|
||||||
|
self._server.socket = ctx.wrap_socket(self._server.socket, server_side=True)
|
||||||
|
|
||||||
|
self.running = True
|
||||||
|
self._thread = threading.Thread(target=self._server.serve_forever, daemon=True)
|
||||||
|
self._thread.start()
|
||||||
|
|
||||||
|
def stop_server(self):
|
||||||
|
"""Stop the Flask web server."""
|
||||||
|
if not self.running or not self._server:
|
||||||
|
return
|
||||||
|
self._server.shutdown()
|
||||||
|
self._server = None
|
||||||
|
self._thread = None
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
def restart_server(self):
|
||||||
|
"""Stop and restart the Flask web server."""
|
||||||
|
self.stop_server()
|
||||||
|
self.start_server()
|
||||||
|
|
||||||
|
def open_browser(self):
|
||||||
|
"""Open the dashboard in the default web browser."""
|
||||||
|
if self.running:
|
||||||
|
host = 'localhost' if self.host in ('0.0.0.0', '::') else self.host
|
||||||
|
webbrowser.open(f"{self._proto}://{host}:{self.port}")
|
||||||
|
|
||||||
|
def quit(self):
|
||||||
|
"""Stop server and exit the tray icon."""
|
||||||
|
self.stop_server()
|
||||||
|
if self._icon:
|
||||||
|
self._icon.stop()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""Start server and show tray icon. Blocks until Exit is clicked."""
|
||||||
|
if not TRAY_AVAILABLE:
|
||||||
|
raise RuntimeError("pystray or Pillow not installed")
|
||||||
|
|
||||||
|
self.start_server()
|
||||||
|
|
||||||
|
image = create_icon_image()
|
||||||
|
menu = pystray.Menu(
|
||||||
|
pystray.MenuItem(
|
||||||
|
lambda item: f"AUTARCH — {'Running' if self.running else 'Stopped'}",
|
||||||
|
None, enabled=False),
|
||||||
|
pystray.Menu.SEPARATOR,
|
||||||
|
pystray.MenuItem("Start", lambda: self.start_server(),
|
||||||
|
enabled=lambda item: not self.running),
|
||||||
|
pystray.MenuItem("Stop", lambda: self.stop_server(),
|
||||||
|
enabled=lambda item: self.running),
|
||||||
|
pystray.MenuItem("Restart", lambda: self.restart_server(),
|
||||||
|
enabled=lambda item: self.running),
|
||||||
|
pystray.Menu.SEPARATOR,
|
||||||
|
pystray.MenuItem("Open Dashboard", lambda: self.open_browser(),
|
||||||
|
enabled=lambda item: self.running, default=True),
|
||||||
|
pystray.Menu.SEPARATOR,
|
||||||
|
pystray.MenuItem("Exit", lambda: self.quit()),
|
||||||
|
)
|
||||||
|
|
||||||
|
self._icon = pystray.Icon("autarch", image, "AUTARCH", menu=menu)
|
||||||
|
self._icon.run() # Blocks until quit()
|
||||||
85
installer.iss
Normal file
85
installer.iss
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
; ============================================================================
|
||||||
|
; AUTARCH Inno Setup Installer Script
|
||||||
|
; ============================================================================
|
||||||
|
;
|
||||||
|
; Prerequisites:
|
||||||
|
; 1. Build PyInstaller first: pyinstaller autarch_public.spec
|
||||||
|
; 2. Install Inno Setup: https://jrsoftware.org/isdl.php
|
||||||
|
; 3. Compile this script: Open in Inno Setup Compiler -> Build -> Compile
|
||||||
|
; Or from CLI: iscc installer.iss
|
||||||
|
;
|
||||||
|
; Output: Output\AUTARCH_Setup.exe
|
||||||
|
; ============================================================================
|
||||||
|
|
||||||
|
[Setup]
|
||||||
|
AppName=AUTARCH
|
||||||
|
AppVersion=1.3
|
||||||
|
AppVerName=AUTARCH 1.3
|
||||||
|
AppPublisher=darkHal Security Group
|
||||||
|
AppPublisherURL=https://github.com/darkhal
|
||||||
|
AppSupportURL=https://github.com/darkhal
|
||||||
|
DefaultDirName={localappdata}\AUTARCH
|
||||||
|
DefaultGroupName=AUTARCH
|
||||||
|
OutputBaseFilename=AUTARCH_Setup
|
||||||
|
Compression=lzma2
|
||||||
|
SolidCompression=no
|
||||||
|
LZMANumBlockThreads=4
|
||||||
|
PrivilegesRequired=lowest
|
||||||
|
ArchitecturesAllowed=x64compatible
|
||||||
|
ArchitecturesInstallIn64BitMode=x64compatible
|
||||||
|
UninstallDisplayName=AUTARCH
|
||||||
|
DisableProgramGroupPage=yes
|
||||||
|
WizardStyle=modern
|
||||||
|
SetupLogging=yes
|
||||||
|
|
||||||
|
; Uncomment and set path if you have a custom icon:
|
||||||
|
; SetupIconFile=assets\autarch.ico
|
||||||
|
|
||||||
|
[Languages]
|
||||||
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||||
|
|
||||||
|
[Tasks]
|
||||||
|
Name: "desktopicon"; Description: "Create a Desktop shortcut"; GroupDescription: "Additional shortcuts:"
|
||||||
|
Name: "startupicon"; Description: "Launch Web Dashboard on Windows startup"; GroupDescription: "Additional shortcuts:"; Flags: unchecked
|
||||||
|
|
||||||
|
[Files]
|
||||||
|
; GGUF model — store uncompressed (3.9GB, barely compressible, avoids OOM)
|
||||||
|
Source: "dist\autarch\_internal\models\Hal_v2.gguf"; DestDir: "{app}\_internal\models"; Flags: ignoreversion nocompression
|
||||||
|
; Everything else from PyInstaller output (compressed with lzma2)
|
||||||
|
Source: "dist\autarch\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Excludes: "_internal\models\Hal_v2.gguf"
|
||||||
|
|
||||||
|
[Icons]
|
||||||
|
; Start Menu
|
||||||
|
Name: "{group}\AUTARCH Web Dashboard"; Filename: "{app}\autarch_web.exe"; Comment: "Launch AUTARCH Web Dashboard with system tray"
|
||||||
|
Name: "{group}\AUTARCH CLI"; Filename: "{app}\autarch.exe"; Comment: "AUTARCH command-line interface"
|
||||||
|
Name: "{group}\Uninstall AUTARCH"; Filename: "{uninstallexe}"
|
||||||
|
|
||||||
|
; Desktop (optional)
|
||||||
|
Name: "{commondesktop}\AUTARCH Web"; Filename: "{app}\autarch_web.exe"; Tasks: desktopicon; Comment: "Launch AUTARCH Web Dashboard"
|
||||||
|
|
||||||
|
; Windows Startup (optional)
|
||||||
|
Name: "{userstartup}\AUTARCH Web"; Filename: "{app}\autarch_web.exe"; Tasks: startupicon
|
||||||
|
|
||||||
|
[Run]
|
||||||
|
; Option to launch after install
|
||||||
|
Filename: "{app}\autarch_web.exe"; Description: "Launch AUTARCH Web Dashboard"; Flags: nowait postinstall skipifsilent
|
||||||
|
|
||||||
|
[UninstallRun]
|
||||||
|
; Kill running instances before uninstall
|
||||||
|
Filename: "taskkill"; Parameters: "/F /IM autarch.exe"; Flags: runhidden
|
||||||
|
Filename: "taskkill"; Parameters: "/F /IM autarch_web.exe"; Flags: runhidden
|
||||||
|
|
||||||
|
[UninstallDelete]
|
||||||
|
; Clean up runtime-generated files
|
||||||
|
Type: filesandordirs; Name: "{app}\data"
|
||||||
|
Type: filesandordirs; Name: "{app}\results"
|
||||||
|
Type: filesandordirs; Name: "{app}\dossiers"
|
||||||
|
Type: filesandordirs; Name: "{app}\backups"
|
||||||
|
Type: files; Name: "{app}\autarch_settings.conf"
|
||||||
|
|
||||||
|
[Code]
|
||||||
|
// Show installed size in wizard
|
||||||
|
function InitializeSetup(): Boolean;
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
end;
|
||||||
144
installer.nsi
Normal file
144
installer.nsi
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
; ============================================================================
|
||||||
|
; AUTARCH NSIS Installer Script
|
||||||
|
; ============================================================================
|
||||||
|
;
|
||||||
|
; Prerequisites:
|
||||||
|
; 1. Build PyInstaller first: pyinstaller autarch_public.spec
|
||||||
|
; 2. Install NSIS: https://nsis.sourceforge.io/Download
|
||||||
|
; 3. Compile this script: makensis installer.nsi
|
||||||
|
; Or right-click installer.nsi -> "Compile NSIS Script"
|
||||||
|
;
|
||||||
|
; Output: AUTARCH_Setup.exe
|
||||||
|
; ============================================================================
|
||||||
|
|
||||||
|
!include "MUI2.nsh"
|
||||||
|
!include "FileFunc.nsh"
|
||||||
|
!include "LogicLib.nsh"
|
||||||
|
|
||||||
|
; ── App metadata ─────────────────────────────────────────────────────────────
|
||||||
|
!define APPNAME "AUTARCH"
|
||||||
|
!define APPVERSION "1.3"
|
||||||
|
!define PUBLISHER "darkHal Security Group"
|
||||||
|
!define DESCRIPTION "Autonomous Tactical Agent for Reconnaissance, Counterintelligence, and Hacking"
|
||||||
|
|
||||||
|
; Source directory — PyInstaller onedir output
|
||||||
|
!define SRCDIR "dist\autarch"
|
||||||
|
|
||||||
|
; ── Installer settings ───────────────────────────────────────────────────────
|
||||||
|
Name "${APPNAME} ${APPVERSION}"
|
||||||
|
OutFile "AUTARCH_Setup.exe"
|
||||||
|
InstallDir "$LOCALAPPDATA\${APPNAME}"
|
||||||
|
InstallDirRegKey HKCU "Software\${APPNAME}" "InstallDir"
|
||||||
|
RequestExecutionLevel user
|
||||||
|
SetCompressor /SOLID lzma
|
||||||
|
SetCompressorDictSize 64
|
||||||
|
Unicode True
|
||||||
|
|
||||||
|
; ── Variables ────────────────────────────────────────────────────────────────
|
||||||
|
Var StartMenuGroup
|
||||||
|
|
||||||
|
; ── MUI configuration ────────────────────────────────────────────────────────
|
||||||
|
!define MUI_ABORTWARNING
|
||||||
|
!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
|
||||||
|
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
|
||||||
|
|
||||||
|
; Welcome page
|
||||||
|
!define MUI_WELCOMEPAGE_TITLE "Welcome to ${APPNAME} Setup"
|
||||||
|
!define MUI_WELCOMEPAGE_TEXT "This wizard will install ${APPNAME} ${APPVERSION} on your computer.$\r$\n$\r$\n${DESCRIPTION}$\r$\n$\r$\nClick Next to continue."
|
||||||
|
|
||||||
|
; Finish page — option to launch
|
||||||
|
!define MUI_FINISHPAGE_RUN "$INSTDIR\autarch_web.exe"
|
||||||
|
!define MUI_FINISHPAGE_RUN_TEXT "Launch ${APPNAME} Web Dashboard"
|
||||||
|
!define MUI_FINISHPAGE_SHOWREADME ""
|
||||||
|
!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED
|
||||||
|
!define MUI_FINISHPAGE_SHOWREADME_TEXT "Create Desktop Shortcut"
|
||||||
|
!define MUI_FINISHPAGE_SHOWREADME_FUNCTION CreateDesktopShortcut
|
||||||
|
|
||||||
|
; ── Pages ────────────────────────────────────────────────────────────────────
|
||||||
|
!insertmacro MUI_PAGE_WELCOME
|
||||||
|
!insertmacro MUI_PAGE_DIRECTORY
|
||||||
|
!insertmacro MUI_PAGE_INSTFILES
|
||||||
|
!insertmacro MUI_PAGE_FINISH
|
||||||
|
|
||||||
|
; Uninstaller pages
|
||||||
|
!insertmacro MUI_UNPAGE_CONFIRM
|
||||||
|
!insertmacro MUI_UNPAGE_INSTFILES
|
||||||
|
|
||||||
|
; Language
|
||||||
|
!insertmacro MUI_LANGUAGE "English"
|
||||||
|
|
||||||
|
; ── Install section ──────────────────────────────────────────────────────────
|
||||||
|
Section "Install" SecInstall
|
||||||
|
SetOutPath "$INSTDIR"
|
||||||
|
|
||||||
|
; Copy everything from the PyInstaller dist/autarch/ directory
|
||||||
|
File /r "${SRCDIR}\*.*"
|
||||||
|
|
||||||
|
; Write uninstaller
|
||||||
|
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||||
|
|
||||||
|
; Registry — install location + Add/Remove Programs entry
|
||||||
|
WriteRegStr HKCU "Software\${APPNAME}" "InstallDir" "$INSTDIR"
|
||||||
|
|
||||||
|
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" \
|
||||||
|
"DisplayName" "${APPNAME}"
|
||||||
|
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" \
|
||||||
|
"DisplayVersion" "${APPVERSION}"
|
||||||
|
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" \
|
||||||
|
"Publisher" "${PUBLISHER}"
|
||||||
|
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" \
|
||||||
|
"UninstallString" '"$INSTDIR\Uninstall.exe"'
|
||||||
|
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" \
|
||||||
|
"InstallLocation" "$INSTDIR"
|
||||||
|
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" \
|
||||||
|
"DisplayIcon" "$INSTDIR\autarch.exe"
|
||||||
|
WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" \
|
||||||
|
"NoModify" 1
|
||||||
|
WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" \
|
||||||
|
"NoRepair" 1
|
||||||
|
|
||||||
|
; Estimate installed size for Add/Remove Programs
|
||||||
|
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
|
||||||
|
IntFmt $0 "0x%08X" $0
|
||||||
|
WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" \
|
||||||
|
"EstimatedSize" "$0"
|
||||||
|
|
||||||
|
; ── Start Menu shortcuts ─────────────────────────────────────────────────
|
||||||
|
CreateDirectory "$SMPROGRAMS\${APPNAME}"
|
||||||
|
|
||||||
|
CreateShortcut "$SMPROGRAMS\${APPNAME}\${APPNAME} Web Dashboard.lnk" \
|
||||||
|
"$INSTDIR\autarch_web.exe" "" "$INSTDIR\autarch_web.exe" 0
|
||||||
|
CreateShortcut "$SMPROGRAMS\${APPNAME}\${APPNAME} CLI.lnk" \
|
||||||
|
"$INSTDIR\autarch.exe" "" "$INSTDIR\autarch.exe" 0
|
||||||
|
CreateShortcut "$SMPROGRAMS\${APPNAME}\Uninstall ${APPNAME}.lnk" \
|
||||||
|
"$INSTDIR\Uninstall.exe" "" "$INSTDIR\Uninstall.exe" 0
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
; ── Desktop shortcut function (called from finish page checkbox) ─────────────
|
||||||
|
Function CreateDesktopShortcut
|
||||||
|
CreateShortcut "$DESKTOP\${APPNAME} Web.lnk" \
|
||||||
|
"$INSTDIR\autarch_web.exe" "" "$INSTDIR\autarch_web.exe" 0
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
; ── Uninstall section ────────────────────────────────────────────────────────
|
||||||
|
Section "Uninstall"
|
||||||
|
|
||||||
|
; Kill running instances
|
||||||
|
nsExec::ExecToLog 'taskkill /F /IM autarch.exe'
|
||||||
|
nsExec::ExecToLog 'taskkill /F /IM autarch_web.exe'
|
||||||
|
|
||||||
|
; Remove Start Menu
|
||||||
|
RMDir /r "$SMPROGRAMS\${APPNAME}"
|
||||||
|
|
||||||
|
; Remove Desktop shortcut
|
||||||
|
Delete "$DESKTOP\${APPNAME} Web.lnk"
|
||||||
|
|
||||||
|
; Remove install directory (everything)
|
||||||
|
RMDir /r "$INSTDIR"
|
||||||
|
|
||||||
|
; Remove registry entries
|
||||||
|
DeleteRegKey HKCU "Software\${APPNAME}"
|
||||||
|
DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}"
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
18
setup_msi.py
18
setup_msi.py
@ -16,6 +16,7 @@ include_files = [
|
|||||||
(str(SRC / 'web' / 'static'), 'web/static'),
|
(str(SRC / 'web' / 'static'), 'web/static'),
|
||||||
(str(SRC / 'data'), 'data'),
|
(str(SRC / 'data'), 'data'),
|
||||||
(str(SRC / 'modules'), 'modules'),
|
(str(SRC / 'modules'), 'modules'),
|
||||||
|
(str(SRC / 'models' / 'Hal_v2.gguf'), 'models/Hal_v2.gguf'),
|
||||||
(str(SRC / 'autarch_settings.conf'), 'autarch_settings.conf'),
|
(str(SRC / 'autarch_settings.conf'), 'autarch_settings.conf'),
|
||||||
(str(SRC / 'user_manual.md'), 'user_manual.md'),
|
(str(SRC / 'user_manual.md'), 'user_manual.md'),
|
||||||
(str(SRC / 'windows_manual.md'), 'windows_manual.md'),
|
(str(SRC / 'windows_manual.md'), 'windows_manual.md'),
|
||||||
@ -27,10 +28,11 @@ include_files = [(s, d) for s, d in include_files if Path(s).exists()]
|
|||||||
build_exe_options = {
|
build_exe_options = {
|
||||||
'packages': [
|
'packages': [
|
||||||
'flask', 'jinja2', 'werkzeug', 'markupsafe',
|
'flask', 'jinja2', 'werkzeug', 'markupsafe',
|
||||||
'bcrypt', 'requests', 'core', 'web', 'web.routes', 'modules',
|
'bcrypt', 'requests', 'pystray', 'PIL',
|
||||||
|
'core', 'web', 'web.routes', 'modules',
|
||||||
],
|
],
|
||||||
'includes': [
|
'includes': [
|
||||||
'core.config', 'core.paths', 'core.banner', 'core.menu',
|
'core.config', 'core.paths', 'core.banner', 'core.menu', 'core.tray',
|
||||||
'core.llm', 'core.agent', 'core.tools',
|
'core.llm', 'core.agent', 'core.tools',
|
||||||
'core.msf', 'core.msf_interface',
|
'core.msf', 'core.msf_interface',
|
||||||
'core.hardware', 'core.android_protect',
|
'core.hardware', 'core.android_protect',
|
||||||
@ -49,6 +51,7 @@ build_exe_options = {
|
|||||||
'web.routes.revshell', 'web.routes.archon',
|
'web.routes.revshell', 'web.routes.archon',
|
||||||
'web.routes.msf', 'web.routes.chat',
|
'web.routes.msf', 'web.routes.chat',
|
||||||
'web.routes.targets', 'web.routes.encmodules',
|
'web.routes.targets', 'web.routes.encmodules',
|
||||||
|
'web.routes.llm_trainer',
|
||||||
],
|
],
|
||||||
'excludes': ['torch', 'transformers', 'llama_cpp', 'llama_cpp_python', 'anthropic',
|
'excludes': ['torch', 'transformers', 'llama_cpp', 'llama_cpp_python', 'anthropic',
|
||||||
'tkinter', 'matplotlib', 'numpy',
|
'tkinter', 'matplotlib', 'numpy',
|
||||||
@ -66,7 +69,7 @@ build_exe_options = {
|
|||||||
bdist_msi_options = {
|
bdist_msi_options = {
|
||||||
'upgrade_code': '{A07B3D2E-5F1C-4D8A-9E6B-0C2F7A8D4E1B}',
|
'upgrade_code': '{A07B3D2E-5F1C-4D8A-9E6B-0C2F7A8D4E1B}',
|
||||||
'add_to_path': False,
|
'add_to_path': False,
|
||||||
'initial_target_dir': r'[ProgramFilesFolder]\AUTARCH',
|
'initial_target_dir': r'[LocalAppDataFolder]\AUTARCH',
|
||||||
}
|
}
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
@ -81,8 +84,13 @@ setup(
|
|||||||
executables=[
|
executables=[
|
||||||
Executable(
|
Executable(
|
||||||
'autarch.py',
|
'autarch.py',
|
||||||
target_name='autarch_public',
|
target_name='autarch',
|
||||||
base=None, # console application
|
base=None, # console application (CLI)
|
||||||
|
),
|
||||||
|
Executable(
|
||||||
|
'autarch_web.py',
|
||||||
|
target_name='autarch_web',
|
||||||
|
base='Win32GUI', # no console window (tray icon only)
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
11
web/app.py
11
web/app.py
@ -9,15 +9,20 @@ from pathlib import Path
|
|||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
|
||||||
# Ensure framework is importable
|
# Ensure framework is importable
|
||||||
FRAMEWORK_DIR = Path(__file__).parent.parent
|
if getattr(sys, 'frozen', False):
|
||||||
|
FRAMEWORK_DIR = Path(sys._MEIPASS)
|
||||||
|
else:
|
||||||
|
FRAMEWORK_DIR = Path(__file__).parent.parent
|
||||||
sys.path.insert(0, str(FRAMEWORK_DIR))
|
sys.path.insert(0, str(FRAMEWORK_DIR))
|
||||||
|
|
||||||
|
|
||||||
def create_app():
|
def create_app():
|
||||||
|
# In frozen builds, templates/static are inside _MEIPASS, not next to __file__
|
||||||
|
bundle_web = FRAMEWORK_DIR / 'web'
|
||||||
app = Flask(
|
app = Flask(
|
||||||
__name__,
|
__name__,
|
||||||
template_folder=str(Path(__file__).parent / 'templates'),
|
template_folder=str(bundle_web / 'templates'),
|
||||||
static_folder=str(Path(__file__).parent / 'static')
|
static_folder=str(bundle_web / 'static')
|
||||||
)
|
)
|
||||||
|
|
||||||
# Config
|
# Config
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user