From 42ca175b68d2613be73a2abe2330936aa00c0026 Mon Sep 17 00:00:00 2001 From: Matthew Bernardo Date: Fri, 17 Apr 2026 21:12:39 +0200 Subject: [PATCH 1/2] Improve server startup --- cli/src/stacksync_cli/commands/dev.py | 17 ++++++++++++++--- .../stacksync_cli/generator_files/app_router.py | 14 ++++++++++++++ templates/connector/requirements.txt | 2 ++ 3 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 templates/connector/requirements.txt diff --git a/cli/src/stacksync_cli/commands/dev.py b/cli/src/stacksync_cli/commands/dev.py index ca15a7d..4b8b134 100644 --- a/cli/src/stacksync_cli/commands/dev.py +++ b/cli/src/stacksync_cli/commands/dev.py @@ -16,13 +16,24 @@ def dev(api_key: str, stacksync_yml: dict) -> None: and uses the local bridge to route traffic to the application. """ click.echo("Creating build folder...") - build_dir = _create_build_folder(stacksync_yml) - click.echo("Build folder created.") + build_dir = _create_build_folder() + click.echo("Build folder created. Installing dependencies...") + result = subprocess.run( + [sys.executable, "-m", "pip", "install", "-r", "requirements.txt"], + cwd=build_dir, + capture_output=True, + text=True, + ) + if result.returncode != 0: + detail = (result.stderr or result.stdout or "").strip() + raise click.ClickException( + "pip install failed:\n" + detail if detail else "pip install failed." + ) click.echo("Starting application on http://127.0.0.1:2323 (Ctrl+C to stop)") _start_application(build_dir) -def _create_build_folder(stacksync_yml: dict) -> str: +def _create_build_folder() -> str: """ Generates a .stacksync_build folder in the current working directory. """ diff --git a/cli/src/stacksync_cli/generator_files/app_router.py b/cli/src/stacksync_cli/generator_files/app_router.py index 36949cb..2ac14f1 100644 --- a/cli/src/stacksync_cli/generator_files/app_router.py +++ b/cli/src/stacksync_cli/generator_files/app_router.py @@ -37,6 +37,20 @@ def import_module_from_path(module_name: str, file_path: str): def create_app() -> Flask: + + print( + "\033[36m" + + r""" _ _ _ _ + | | | | | | | + ___| |_ __ _ ___| | _____ _ _ _ __ ___ ___ __| | | __ + / __| __/ _` |/ __| |/ / __| | | | '_ \ / __| / __/ _` | |/ / + \__ \ || (_| | (__| <\__ \ |_| | | | | (__ | (_| (_| | < + |___/\__\__,_|\___|_|\_\___/\__, |_| |_|\___| \___\__,_|_|\_\ + __/ | + |___/ + """ + + "\033[0m", + ) if not logging.root.handlers: logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s: %(message)s") diff --git a/templates/connector/requirements.txt b/templates/connector/requirements.txt new file mode 100644 index 0000000..7b2457d --- /dev/null +++ b/templates/connector/requirements.txt @@ -0,0 +1,2 @@ +git+https://github.com/stacksyncdata/cdk.git@prod#subdirectory=lib +requests>=2.31.0 \ No newline at end of file From 8f1ddc890f51b7f4824d50ba6a5ca5f3e34b0431 Mon Sep 17 00:00:00 2001 From: Matthew Bernardo Date: Fri, 17 Apr 2026 21:12:59 +0200 Subject: [PATCH 2/2] Small linting fixes --- .../generator_files/app_router.py | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/cli/src/stacksync_cli/generator_files/app_router.py b/cli/src/stacksync_cli/generator_files/app_router.py index 2ac14f1..0cf7383 100644 --- a/cli/src/stacksync_cli/generator_files/app_router.py +++ b/cli/src/stacksync_cli/generator_files/app_router.py @@ -19,7 +19,6 @@ MODULES_DIR = os.path.join(ROOT, "modules") - def load_stacksync_yml() -> dict[str, Any]: path = os.path.join(ROOT, "stacksync.yml") with open(path, "r", encoding="utf-8") as f: @@ -37,7 +36,6 @@ def import_module_from_path(module_name: str, file_path: str): def create_app() -> Flask: - print( "\033[36m" + r""" _ _ _ _ @@ -52,7 +50,9 @@ def create_app() -> Flask: + "\033[0m", ) if not logging.root.handlers: - logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s: %(message)s") + logging.basicConfig( + level=logging.INFO, format="%(levelname)s %(name)s: %(message)s" + ) app = Flask(__name__) app.logger.info("Initializing connector (root=%s)", ROOT) @@ -72,7 +72,9 @@ def create_app() -> Flask: for module_id, module_meta in modules_cfg.items(): package_dir = os.path.join(MODULES_DIR, module_id) if not os.path.isdir(package_dir): - app.logger.warning("Skipping module %r: no directory at %s", module_id, package_dir) + app.logger.warning( + "Skipping module %r: no directory at %s", module_id, package_dir + ) continue prefix = f"/modules/{module_id}" @@ -95,7 +97,9 @@ def schema_route( credentials = payload.get("credentials") result = _smod.schema_handler(form_data, credentials) # schema_handler may return a Schema (dict subclass) or plain dict - return jsonify({"schema": dict(result) if hasattr(result, "keys") else result}) + return jsonify( + {"schema": dict(result) if hasattr(result, "keys") else result} + ) registered.append("schema") @@ -106,7 +110,9 @@ def schema_route( @app.route(f"{prefix}/content", methods=["POST"]) def content_route(_cmod=cmod, _module_id=module_id): - current_app.logger.info("Content handler called (module=%s)", _module_id) + current_app.logger.info( + "Content handler called (module=%s)", _module_id + ) payload = request.get_json(silent=True) or {} form_data = payload.get("form_data") or {} credentials = payload.get("credentials") @@ -123,7 +129,9 @@ def content_route(_cmod=cmod, _module_id=module_id): @app.route(f"{prefix}/execute", methods=["POST"]) def execute_route(_emod=emod, _module_id=module_id): - current_app.logger.info("Execute handler called (module=%s)", _module_id) + current_app.logger.info( + "Execute handler called (module=%s)", _module_id + ) payload = request.get_json(silent=True) or {} data = payload.get("data") or {} credentials = payload.get("credentials") or {} @@ -155,4 +163,4 @@ def health(): app = create_app() if __name__ == "__main__": - app.run(host="127.0.0.1", port=5000, debug=True) \ No newline at end of file + app.run(host="127.0.0.1", port=5000, debug=True)