# FlintTrade Makefile # Usage: make help # # ============================================================================ # Shell # ============================================================================ # This Makefile is the POSIX *alias* surface; scripts/ft.py is the cross-platform # entry point and is what Windows users run (it needs no shell at all). # # GNU Make defaults to /bin/sh, which is dash on Debian/Ubuntu. dash has no # `set -o pipefail` (the shell errors and aborts the recipe) and its `echo` has # no `-e` (the escape prefix is printed literally). The retained POSIX recipes # below — sync-check, logs-clear, ticks-test — use both, so bash is # pinned here. Removing this line silently breaks retained shell recipes on the # primary CI/dev platform. SHELL := /usr/bin/env bash # ============================================================================ # Platform support # ============================================================================ # Most recipes are thin delegators to scripts/ft.py, the stdlib-only task runner # that behaves identically on every OS. If you have no make (or no bash), call # it directly and get the same behaviour: # # python scripts/ft.py # # After install, the shim makes this available as: flinttrade # # `make` itself needs bash (see the Shell section above) and GNU coreutils, so on # Windows use scripts/ft.py — or WSL2 if you specifically want make. The grouping # below is about the underlying WORK, not about where `make` runs: # # 1. Works everywhere (Windows 10/11, macOS, Linux) # Via scripts/ft.py: # setup, start, start-gateway, stop, restart, status, dev, test, test-fast, # check, lint, clean, version, help, desktop-test, desktop-build, desktop-package, # desktop-dev # Plain Python/uv recipes (no shell builtins): # check-python, full-check, desktop-icons, update, version-check, audit, # broker-sdk-sync, broker-reference-check # # 2. POSIX only (the recipe body itself needs bash and GNU coreutils) # health, ticks-test, sync-check, # logs-clear, install-docker, install-server-native, install-native, # backup, restore # # 3. Needs Docker # docker-up, docker-up-monitoring, docker-down, docker-build # ============================================================================ # uv creates .venv/Scripts/python.exe on Windows and .venv/bin/python on POSIX. # Checking only the POSIX layout is what made `make` fall through to the # Microsoft Store python3 alias stub (which exits 49 without running anything). # # The Windows branch below is for an MSYS/Git-Bash make on Windows (the only way # to run this Makefile there). Its path is absolute and forward-slashed on # purpose: an MSYS shell eats the backslashes of a '.venv\Scripts\python.exe', # and a relative forward-slash command is not resolvable either. ifeq ($(OS),Windows_NT) PYTHON := $(if $(wildcard .venv/Scripts/python.exe),$(CURDIR)/.venv/Scripts/python.exe,python) else PYTHON := $(if $(wildcard .venv/bin/python),.venv/bin/python,$(shell which python3 2>/dev/null || which python 2>/dev/null)) endif FLINTTRADE_PYTHONPATH := packages/core/core/src # Colors GREEN := \033[32m RED := \033[31m YELLOW := \033[33m CYAN := \033[36m RESET := \033[0m # Source .env if it exists ifneq (,$(wildcard .env)) include .env export endif # Exported to scripts/ft.py, which reads them from the environment. FLINTTRADE_BACKEND_PORT ?= 5100 FLINTTRADE_BACKEND_HOST ?= 127.0.0.1 .PHONY: setup check-python start start-gateway stop restart status test test-fast check ticks-test lint clean update dev docker-up docker-up-monitoring docker-down docker-build version version-check site-url-check health help audit sync-check broker-sdk-sync broker-reference-check full-check install-docker install-native install-server-native backup restore logs-clear desktop-icons desktop-test desktop-build desktop-package desktop-dev # ====================================================================== # Setup # ====================================================================== setup: check-python ## First-time setup — install all dependencies @"$(PYTHON)" scripts/ft.py setup # Single-command check: no shell `||`, no subshell, no `echo -e`. sys.exit(str) # prints to stderr and exits 1, so the message survives whatever shell runs it. check-python: ## Verify Python >= 3.11 (required for StrEnum) @"$(PYTHON)" -c "import sys; sys.exit(0 if sys.version_info >= (3, 11) else 'Error: Python 3.11+ required (StrEnum support). Found: ' + sys.version.split()[0])" # ====================================================================== # Service management # ====================================================================== start: ## Start FlintTrade backend API @# delegates: PYTHONPATH=$(FLINTTRADE_PYTHONPATH) $(PYTHON) -m flinttrade_core.app @# ft.py joins PYTHONPATH with os.pathsep, so it is ';' on Windows and ':' on POSIX. @"$(PYTHON)" scripts/ft.py start # --- Native gateway mode — single process --- start-gateway: start ## Alias for start (standalone FlintTrade backend) stop: ## Stop FlintTrade backend API if it is listening on FLINTTRADE_BACKEND_PORT @"$(PYTHON)" scripts/ft.py stop restart: ## Restart FlintTrade backend @"$(PYTHON)" scripts/ft.py restart status: ## Show service status @"$(PYTHON)" scripts/ft.py status health: ## Run health check @FLINTTRADE_HEALTH_STRICT=0 bash infra/scripts/health-check.sh dev: ## Start terminal dev server + FlintTrade backend @# delegates: PYTHONPATH=$(FLINTTRADE_PYTHONPATH) $(PYTHON) -m flinttrade_core.app @# plus the terminal Vite dev server, both supervised by ft.py. @"$(PYTHON)" scripts/ft.py dev # ====================================================================== # Testing and quality # ====================================================================== test: ## Run all tests (Python + Rust ticks crate) @# ft.py expands packages/*/*/tests in Python (no shell glob) and runs the @# Rust ticks crate afterwards when cargo is present. @"$(PYTHON)" scripts/ft.py test ticks-test: ## Run the Rust ticks-crate tests (skipped when cargo is absent) @# Portable manifest path (cargo accepts forward slashes on Windows too); @# guarded on cargo presence so a Python-only contributor's `make test` @# does not hard-fail. A real test failure still propagates (no `|| echo`). @if command -v cargo >/dev/null 2>&1; then \ cargo test --manifest-path packages/core/ticks/Cargo.toml; \ else \ echo "cargo not found — skipping Rust ticks tests"; \ fi test-fast: ## Run tests, stop on first failure @"$(PYTHON)" scripts/ft.py test-fast lint: ## Run linters (ruff + the terminal's react-hooks gate) @"$(PYTHON)" scripts/ft.py lint # ====================================================================== # Native desktop app (Electron shell + first-run source bootstrap) # ====================================================================== # Produces the macOS DMG, Windows NSIS and Linux AppImage shell installers. # Each target builds for the CURRENT OS/arch; the full cross-platform matrix is # produced by .github/workflows/desktop-release.yml. See docs/DESKTOP.md. desktop-icons: ## Regenerate the desktop app icons from the brand mark @"$(PYTHON)" packaging/make-icons.py desktop-test: ## Typecheck and test the Electron shell @"$(PYTHON)" scripts/ft.py desktop-test desktop-build: ## Verify and bundle the Electron shell @"$(PYTHON)" scripts/ft.py desktop-build desktop-package: ## Package and verify the Electron installer for this OS/arch @# ft.py builds first, then picks pack:win / pack:mac / pack:linux:x64 / @# pack:linux:arm64 from the host OS and architecture. @"$(PYTHON)" scripts/ft.py desktop-package desktop-dev: ## Run the Electron shell against its managed source bootstrap @"$(PYTHON)" scripts/ft.py desktop-dev # ====================================================================== # Maintenance # ====================================================================== update: ## Update Python dependencies (external test-deps live in .local/external/, update them yourself) @# Unquoted, metacharacter-free echoes: plain echo, never echo -e, so the text @# is identical whichever POSIX shell ends up running the recipe. @echo Updating Python dependencies... @# Regenerate the HASHED uv.lock to newest compatible versions, then install @# it. Stays inside the SC-07 hash-verified path (never an unhashed @# requirements install), which the no-unhashed-install gate now enforces on @# this Makefile too. @uv lock --upgrade @uv sync --frozen --all-packages @echo Updated @echo Note: external test-deps under .local/external/ are not git submodules anymore. clean: ## Remove build artifacts (with confirmation) @# ft.py deletes the trees with shutil.rmtree (no find/rm -rf). @"$(PYTHON)" scripts/ft.py clean # ====================================================================== # Docker # ====================================================================== docker-up: ## Start the Docker app stack (backend + terminal build + Nginx UI origin) docker compose up docker-up-monitoring: ## Start the app stack plus the observability profile (needs real GlitchTip secrets in .env) docker compose --profile monitoring up docker-down: ## Stop Docker services (all profiles) docker compose --profile monitoring down docker-build: ## Rebuild Docker images docker compose build # ====================================================================== # Management # ====================================================================== check: ## Run checks for committed and working-tree changes @"$(PYTHON)" scripts/ft.py check full-check: ## Run the exhaustive local pre-push gate @"$(PYTHON)" scripts/ft.py check --full audit: ## Check repo absorption status @"$(PYTHON)" scripts/audit_repos.py version-check: ## Verify all release-version metadata is aligned @"$(PYTHON)" scripts/check-version-consistency.py site-url-check: ## Verify every tracked mention of the public site URL matches flint.toml @"$(PYTHON)" scripts/check-site-url-consistency.py sync-check: ## Check upstream drift on external test-deps under .local/external/ @echo -e "$(CYAN)=== External Test-Deps Sync Check ===$(RESET)" @if [ -d .local/external/openclaw/.git ]; then \ (cd .local/external/openclaw && git fetch origin --quiet 2>/dev/null && echo "openclaw: $$(git rev-list HEAD..origin/main --count 2>/dev/null || echo '?') commits behind"); \ else \ echo -e "$(YELLOW)openclaw: not present at .local/external/openclaw $(RESET)"; \ fi broker-sdk-sync: ## Refresh repo-local broker SDK refs and fail on upstream drift @uv run python scripts/sync_broker_sdk_refs.py --fail-on-drift broker-reference-check: ## Validate local broker MCP/API reference captures under .local @uv run python scripts/check_broker_reference_inventory.py logs-clear: ## Truncate runtime .log files under .local/dev-logs/ @echo -e "$(CYAN)=== Clearing runtime logs ===$(RESET)" @mkdir -p .local/dev-logs @for f in .local/dev-logs/*.log; do \ [ -e "$$f" ] || continue; \ size=$$(du -h "$$f" 2>/dev/null | cut -f1); \ : > "$$f"; \ echo " truncated $$f ($$size -> 0)"; \ done @touch .local/dev-logs/.gitkeep @echo -e "$(GREEN)=== Logs cleared ===$(RESET)" # ====================================================================== # Installation and backup # ====================================================================== install-docker: ## Install FlintTrade with Docker (production) @bash infra/install/install-docker.sh install-server-native: ## Advanced: install FlintTrade as bare-metal Ubuntu/Debian server services @bash infra/install/install-native.sh install-native: install-server-native ## Deprecated alias for install-server-native; desktop app users want desktop-build backup: ## Run restic backup of FlintTrade data @bash infra/backup/backup.sh restore: ## Restore FlintTrade data from restic backup @bash infra/backup/restore.sh # ====================================================================== # Info # ====================================================================== version: ## Show version @"$(PYTHON)" scripts/ft.py version help: ## Show this help @# ft.py parses the `target: ## description` table out of this Makefile in @# Python, replacing the grep|sort|awk pipeline that Windows does not have. @"$(PYTHON)" scripts/ft.py help .DEFAULT_GOAL := help