import os import logging from pathlib import Path from flask import Flask from datetime import datetime # Local imports from app.utils.settings import get_settings from app.logging_setup import wire_logging_once, get_app_logger from app.app_settings import AppSettings from app.blueprints.main import bp as main_bp # ui blueprint from app.blueprints.api import api_bp as api_bp # api blueprint from app.blueprints.roadmap import bp as roadmap_bp # roadmap from app.blueprints.changelog import bp as changelog_bp # changelog def create_app() -> Flask: """ Create and configure the Flask application instance. Returns: Flask: The configured Flask app. """ # Basic app object app = Flask(__name__, template_folder="templates", static_folder="static") # logging setup wire_logging_once(app) app_logger = get_app_logger() # Load settings (safe fallback to defaults if file missing) settings = get_settings() # Secret key loaded from env (warn if missing) app.secret_key = os.getenv("SECRET_KEY") if not app.secret_key: app_logger.warning("[init] SECRET_KEY is not set; sessions may be insecure in production.") # version version = f"v{AppSettings.version_major}.{AppSettings.version_minor}" # allow branding for name if they don't match our name branded_name = settings.branding.name if branded_name == AppSettings.name: public_name = AppSettings.name footer = f"{AppSettings.copyright} {public_name} {version} - {AppSettings.tagline}" else: public_name = f"{branded_name}" link = f'{AppSettings.name}' footer = f"{AppSettings.copyright} {public_name} powered by {link} {version} - {AppSettings.tagline}" # web header / footer header = f"{public_name}" # App metadata available to templates app.config["APP_NAME"] = public_name app.config["APP_VERSION"] = version app.config["WEB_HEADER"] = header app.config["WEB_FOOTER"] = footer # roadmap file app.config["ROADMAP_FILE"] = str(Path(app.root_path) / "docs" / "roadmap.yaml") app.config["CHANGELOG_FILE"] = str(Path(app.root_path) / "docs" / "changelog.yaml") # Configure storage directory (bind-mount is still handled by sandbox.sh) sandbox_storage_default = Path("/data") app.config["SANDBOX_STORAGE"] = str(sandbox_storage_default) # Register blueprints app.register_blueprint(main_bp) app.register_blueprint(api_bp) app.register_blueprint(roadmap_bp) app.register_blueprint(changelog_bp) app_logger = get_app_logger() # Example log lines so we know we booted cleanly app_logger.info(f"SneakyScope started: {app.config['APP_NAME']} {app.config['APP_VERSION']}") app_logger.info(f"SANDBOX_STORAGE: {app.config['SANDBOX_STORAGE']}") return app