forked from zestones/Aria
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
245 lines (194 loc) · 10.9 KB
/
Copy pathMakefile
File metadata and controls
245 lines (194 loc) · 10.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# ============================================================
# ARIA — Project orchestration
# ============================================================
# Run `make help` for the full list of targets.
# ============================================================
# Use bash for sane shell semantics
SHELL := /bin/bash
.SHELLFLAGS := -eu -o pipefail -c
.DEFAULT_GOAL := help
# ---- Config -------------------------------------------------
COMPOSE ?= docker compose
BACKEND_DIR := backend
FRONTEND_DIR := frontend
VENV := $(BACKEND_DIR)/.venv
VENV_BIN := $(abspath $(VENV))/bin
PY := $(VENV_BIN)/python
PIP := $(VENV_BIN)/pip
# Pretty colors
C_RESET := \033[0m
C_BOLD := \033[1m
C_CYAN := \033[36m
C_GREEN := \033[32m
C_YELLOW := \033[33m
# ---- Help ---------------------------------------------------
.PHONY: help
help: ## Show this help message
@printf "$(C_BOLD)ARIA$(C_RESET) — make targets\n\n"
@awk 'BEGIN {FS = ":.*##"} /^[a-zA-Z_.-]+:.*##/ {printf " $(C_CYAN)%-22s$(C_RESET) %s\n", $$1, $$2}' $(MAKEFILE_LIST)
@printf "\n$(C_BOLD)Quickstart$(C_RESET): make install && make up\n\n"
# ============================================================
# Install / setup
# ============================================================
.PHONY: install install.backend install.frontend install.hooks
install: install.backend install.frontend ## Install host deps for backend (.venv) + frontend (node_modules)
@printf "$(C_GREEN)✓ All host deps installed$(C_RESET)\n"
install.backend: ## Create backend venv and install requirements + dev tools
@printf "$(C_CYAN)→ Backend venv$(C_RESET)\n"
@test -d $(VENV) || python3 -m venv $(VENV)
@$(PIP) install --upgrade pip --quiet
@$(PIP) install -r $(BACKEND_DIR)/requirements.txt --quiet
@$(PIP) install -r $(BACKEND_DIR)/requirements-dev.txt --quiet
@printf "$(C_GREEN) ✓ $(VENV) ready (point VS Code Python interpreter here)$(C_RESET)\n"
install.frontend: ## Install frontend npm deps locally (so VS Code can resolve types)
@printf "$(C_CYAN)→ Frontend npm install$(C_RESET)\n"
@cd $(FRONTEND_DIR) && npm install --no-audit --no-fund
# ============================================================
# Dev — Docker stack with hot reload
# ============================================================
.PHONY: up up.backend up.frontend up.tunnel deploy down restart logs ps build rebuild doctor doctor.backend doctor.frontend
up: ## Start all services (db, migrate, simulator, backend, frontend) — hot reload enabled
$(COMPOSE) up -d --build
@printf "\n$(C_GREEN)✓ Stack up$(C_RESET)\n"
@printf " • Frontend $(C_CYAN)http://localhost:5173$(C_RESET)\n"
@printf " • Backend $(C_CYAN)http://localhost:8000$(C_RESET) (docs: /docs)\n"
up.tunnel: ## Start the Cloudflare tunnel (profile: tunnel) — exposes /mcp/<secret> for hosted-MCP (#103)
$(COMPOSE) --profile tunnel up -d tunnel
@printf "\n$(C_GREEN)✓ Tunnel up$(C_RESET) — $(C_CYAN)https://aria.vgtray.fr$(C_RESET) → frontend:5173\n"
@printf "\n$(C_GREEN)✓ Tunnel up$(C_RESET) — $(C_CYAN)https://aria-backend.vgtray.fr$(C_RESET) → backend:8000\n"
@printf " Check: $(C_CYAN)docker logs aria-cloudflared --tail 20$(C_RESET)\n"
deploy: up up.tunnel ## Start full stack + Cloudflare tunnel (all services + hosted-MCP exposure)
up.backend: ## Start only db + migrate + backend (no simulator/frontend)
$(COMPOSE) up -d --build timescaledb migrate backend
up.frontend: ## Start only the frontend container
$(COMPOSE) up -d --build frontend
down: ## Stop all services (including tunnel if running)
$(COMPOSE) --profile tunnel down
restart: ## Restart all services
$(COMPOSE) restart
logs: ## Tail logs from all services (Ctrl-C to stop)
$(COMPOSE) logs -f --tail=50
ps: ## Show service status
$(COMPOSE) ps
build: ## Build all docker images
$(COMPOSE) build
rebuild: ## Force rebuild without cache
$(COMPOSE) build --no-cache
# ---- Doctor — detect dependency drift between manifests and running containers ----
doctor: doctor.backend doctor.frontend ## Check both containers for dependency drift
doctor.backend: ## Compare backend/requirements.txt against pip freeze inside aria-backend
@printf "$(C_CYAN)→ Backend drift check (requirements.txt vs aria-backend)$(C_RESET)\n"
@if ! docker ps --format '{{.Names}}' | grep -qx aria-backend; then \
printf " $(C_YELLOW)! aria-backend not running — start with: make up$(C_RESET)\n"; exit 1; \
fi
@docker exec aria-backend pip freeze 2>/dev/null > /tmp/aria_doctor_pip.txt
@drift=0; missing=0; \
while IFS= read -r line; do \
case "$$line" in ''|\#*) continue;; esac; \
pkg=$$(echo "$$line" | sed -E 's/[[:space:]]*#.*$$//' | tr -d '[:space:]'); \
[ -z "$$pkg" ] && continue; \
name=$$(echo "$$pkg" | sed -E 's/([A-Za-z0-9._-]+).*/\1/'); \
want=$$(echo "$$pkg" | sed -nE 's/^[A-Za-z0-9._-]+==(.+)$$/\1/p'); \
got=$$(grep -iE "^$$name==" /tmp/aria_doctor_pip.txt 2>/dev/null | head -1 | sed -E 's/^[^=]+==//' || true); \
if [ -z "$$got" ]; then \
printf " $(C_RED)✗ MISSING$(C_RESET) %-30s (required: %s)\n" "$$name" "$${want:-any}"; \
missing=$$((missing+1)); \
elif [ -n "$$want" ] && [ "$$want" != "$$got" ]; then \
printf " $(C_YELLOW)~ DRIFT$(C_RESET) %-30s want=%s got=%s\n" "$$name" "$$want" "$$got"; \
drift=$$((drift+1)); \
fi; \
done < $(BACKEND_DIR)/requirements.txt; \
rm -f /tmp/aria_doctor_pip.txt; \
if [ $$missing -gt 0 ]; then \
printf " $(C_RED)✗ $$missing missing package(s) — run: make up (rebuilds image)$(C_RESET)\n"; exit 1; \
elif [ $$drift -gt 0 ]; then \
printf " $(C_YELLOW)! $$drift version drift(s) — run: $(COMPOSE) build --no-cache backend && make up$(C_RESET)\n"; exit 1; \
else \
printf " $(C_GREEN)✓ Backend deps in sync$(C_RESET)\n"; \
fi
doctor.frontend: ## Compare frontend/package.json against installed node_modules in aria-frontend
@printf "$(C_CYAN)→ Frontend drift check (package.json vs aria-frontend)$(C_RESET)\n"
@if ! docker ps --format '{{.Names}}' | grep -qx aria-frontend; then \
printf " $(C_YELLOW)! aria-frontend not running — start with: make up$(C_RESET)\n"; exit 1; \
fi
@out=$$(docker exec aria-frontend sh -c 'cd /app && npm ls --depth=0 --all 2>&1' || true); \
missing=$$(echo "$$out" | grep -cE 'UNMET|missing:|invalid:' || true); \
if [ "$$missing" -gt 0 ]; then \
echo "$$out" | grep -E 'UNMET|missing:|invalid:' | sed 's/^/ /'; \
printf " $(C_RED)✗ $$missing drift/missing entr(ies) — run: docker compose exec frontend npm install$(C_RESET)\n"; \
exit 1; \
else \
printf " $(C_GREEN)✓ Frontend deps in sync$(C_RESET)\n"; \
fi
# ============================================================
# Database
# ============================================================
.PHONY: db.shell db.reset migrate db.seed
db.shell: ## Open a psql shell into the database
$(COMPOSE) exec timescaledb psql -U $${POSTGRES_USER:-aria} -d $${POSTGRES_DB:-aria}
db.reset: ## ⚠️ Drop the database volume and re-run migrations + seeds (destroys all data)
@printf "$(C_YELLOW)This will destroy all data. Press Ctrl-C to abort or Enter to continue.$(C_RESET)\n"
@read _
$(COMPOSE) down -v
$(COMPOSE) up -d timescaledb
$(COMPOSE) up migrate
migrate: ## Re-run database migrations + idempotent demo seeds
$(COMPOSE) up migrate
db.seed: ## Re-apply the demo seeds (KB + human context + 24h history) without re-running migrations
@printf "$(C_CYAN)→ Re-applying demo seeds$(C_RESET)\n"
@$(COMPOSE) exec -T timescaledb psql -U $${POSTGRES_USER:-aria} -d $${POSTGRES_DB:-aria} \
< $(BACKEND_DIR)/infrastructure/database/seeds/01_demo_kb.sql
@$(COMPOSE) exec -T timescaledb psql -U $${POSTGRES_USER:-aria} -d $${POSTGRES_DB:-aria} \
< $(BACKEND_DIR)/infrastructure/database/seeds/02_demo_human_context.sql
@$(COMPOSE) exec -T timescaledb psql -U $${POSTGRES_USER:-aria} -d $${POSTGRES_DB:-aria} \
< $(BACKEND_DIR)/infrastructure/database/seeds/03_demo_history.sql
@printf "$(C_GREEN) ✓ Demo seeds applied$(C_RESET)\n"
# ============================================================
# Backend quality gates
# ============================================================
.PHONY: backend.format backend.format.check backend.lint backend.typecheck backend.test backend.check
backend.format: ## Auto-format backend with black
cd $(BACKEND_DIR) && $(VENV_BIN)/black --config pyproject.toml .
backend.format.check: ## Check backend formatting (CI mode)
cd $(BACKEND_DIR) && $(VENV_BIN)/black --check --config pyproject.toml .
backend.lint: ## Lint backend with flake8
cd $(BACKEND_DIR) && $(VENV_BIN)/flake8 .
backend.typecheck: ## Type-check backend with pyright
cd $(BACKEND_DIR) && $(VENV_BIN)/pyright
backend.test: ## Run backend pytest suite
cd $(BACKEND_DIR) && PYTHONPATH=. $(VENV_BIN)/pytest -m "not e2e and not integration"
backend.check: backend.format.check backend.lint backend.typecheck ## Run all backend checks
# ============================================================
# Frontend quality gates
# ============================================================
.PHONY: frontend.format frontend.lint frontend.check frontend.typecheck frontend.test frontend.build
frontend.format: ## Auto-format frontend with biome
cd $(FRONTEND_DIR) && npm run format
frontend.lint: ## Lint frontend with biome
cd $(FRONTEND_DIR) && npm run lint
frontend.check: ## Run biome check (lint + format) and auto-fix
cd $(FRONTEND_DIR) && npm run check:fix
frontend.typecheck: ## Type-check frontend with tsc
cd $(FRONTEND_DIR) && npm run typecheck
frontend.build: ## Production build (vite)
cd $(FRONTEND_DIR) && npm run build
# ============================================================
# Combined targets
# ============================================================
.PHONY: format lint typecheck check test e2e clean backend.smoke.mcp backend.smoke.kb_upload
format: backend.format frontend.format ## Auto-format both backend and frontend
lint: backend.lint frontend.lint ## Lint both backend and frontend
typecheck: backend.typecheck frontend.typecheck ## Type-check both backend and frontend
check: backend.check frontend.check frontend.typecheck ## Run all quality gates (CI parity)
test: backend.test ## Run all unit tests
@printf "$(C_YELLOW)Note: frontend has no test suite yet$(C_RESET)\n"
e2e: ## Run backend E2E smoke test (requires stack to be up)
bash $(BACKEND_DIR)/tests/e2e_smoke.sh
backend.smoke.mcp: ## Run MCP server E2E smoke (requires stack + canonical KB; see issue #69)
cd $(BACKEND_DIR) && PYTHONPATH=. $(VENV_BIN)/python tests/e2e/aria_mcp_smoke.py
backend.smoke.kb_upload: ## M3.2: PDF upload + Opus vision smoke (requires stack + ANTHROPIC_API_KEY; skips if key missing)
cd $(BACKEND_DIR) && PYTHONPATH=. $(VENV_BIN)/python tests/e2e/kb_upload_smoke.py
clean: ## Remove caches and build artifacts
@find . -type d \( -name __pycache__ -o -name .pytest_cache -o -name .mypy_cache -o -name .ruff_cache \) -prune -exec rm -rf {} +
@rm -rf $(BACKEND_DIR)/coverage.xml $(BACKEND_DIR)/htmlcov $(FRONTEND_DIR)/dist
@printf "$(C_GREEN)✓ Cleaned$(C_RESET)\n"