-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMakefile
More file actions
642 lines (561 loc) Β· 25.5 KB
/
Makefile
File metadata and controls
642 lines (561 loc) Β· 25.5 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
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
# ushadow Makefile
# Quick commands for development and deployment
# All compose operations delegate to setup/run.py for single source of truth
.PHONY: help up down restart logs build clean test test-integration test-tdd test-all \
test-robot test-robot-api test-robot-features test-robot-quick test-robot-critical test-report \
go install status health dev prod \
svc-list svc-restart svc-start svc-stop svc-status \
chronicle-env-export chronicle-build-local chronicle-up-local chronicle-down-local chronicle-dev \
ushadow-push ushadow-push-local chronicle-push mycelia-push openmemory-push \
release env-sync env-sync-apply env-info
# Read .env for display purposes only (actual logic is in run.py)
-include .env
# Default target
help:
@echo "ushadow - AI Orchestration Platform"
@echo ""
@echo "Available commands:"
@echo " make go - Quick start (infrastructure + ushadow)"
@echo " make dev - Development mode (Vite HMR + backend)"
@echo " make prod - Production mode (optimized nginx build)"
@echo " make up - Start ushadow application"
@echo " make down - Stop ushadow application"
@echo " make restart - Restart ushadow application"
@echo " make logs - View application logs"
@echo " make logs-f - Follow application logs"
@echo " make build - Rebuild containers (uses DEV_MODE from .env)"
@echo " make build-with-tailscale - Build with Tailscale socket (Linux only)"
@echo " make clean - Stop everything and remove volumes"
@echo " make status - Show running containers"
@echo " make health - Check service health"
@echo ""
@echo "Infrastructure commands:"
@echo " make infra-up - Start infrastructure (MongoDB, Redis, Qdrant)"
@echo " make infra-down - Stop infrastructure"
@echo " make chronicle-up - Start Chronicle backend"
@echo " make chronicle-down - Stop Chronicle backend"
@echo ""
@echo "Chronicle local development:"
@echo " make chronicle-env-export - Export env vars to .env.chronicle"
@echo " make chronicle-build-local - Build Chronicle from local source"
@echo " make chronicle-up-local - Run Chronicle with local build"
@echo " make chronicle-down-local - Stop local Chronicle"
@echo " make chronicle-dev - Build + run (full dev cycle)"
@echo ""
@echo "Build & Push:"
@echo " make ushadow-push [TAG=latest] - Build and push ushadow to ghcr.io"
@echo " K8S_REGISTRY=host:port make ushadow-push-local - Build and push ushadow to local K8s registry"
@echo " make chronicle-push [TAG=latest] - Build and push Chronicle to ghcr.io"
@echo " make mycelia-push [TAG=latest] - Build and push Mycelia to ghcr.io"
@echo " make openmemory-push [TAG=latest] - Build and push OpenMemory to ghcr.io"
@echo ""
@echo "Service management:"
@echo " make rebuild <service> - Rebuild service from compose/<service>-compose.yml"
@echo " (e.g., make rebuild mycelia, make rebuild chronicle)"
@echo " make svc-list - List all services and their status"
@echo " make restart-<service> - Restart a service (e.g., make restart-chronicle)"
@echo " make svc-start SVC=x - Start a service"
@echo " make svc-stop SVC=x - Stop a service"
@echo ""
@echo "Testing commands (Pyramid approach):"
@echo " Backend (pytest):"
@echo " make test - Fast unit tests (~seconds)"
@echo " make test-integration - Integration tests (need services running)"
@echo " make test-all - All backend tests (unit + integration)"
@echo " make test-tdd - TDD tests (expected failures)"
@echo " Robot Framework (API/E2E):"
@echo " make test-robot-quick - Quick smoke tests (~30s)"
@echo " make test-robot-critical - Critical path tests only"
@echo " make test-robot-api - All API integration tests"
@echo " make test-robot-features - Feature-level tests"
@echo " make test-robot - All Robot tests (full suite)"
@echo " make test-report - View last test report in browser"
@echo ""
@echo "Development commands:"
@echo " make install - Install Python dependencies"
@echo " make lint - Run linters"
@echo " make format - Format code"
@echo ""
@echo "Environment commands:"
@echo " make env-info - Show current environment info"
@echo " make env-sync - Check for missing variables from .env.example"
@echo " make env-sync-apply - Add missing variables to .env"
@echo ""
@echo "Cleanup commands:"
@echo " make clean-logs - Remove log files"
@echo " make clean-cache - Remove Python cache files"
@echo " make reset - Full reset (stop all, remove volumes, clean)"
@echo " make reset-tailscale - Reset Tailscale (container, state, certs)"
@echo ""
@echo "Kubernetes DNS commands:"
@echo " make k8s-add-service-dns SVC=<name> NS=<ns> NAMES=\"<aliases>\" - Add service to DNS"
@echo " make k8s-add-service-dns-interactive - Add service (interactive)"
@echo " make k8s-show-dns - Show current DNS mappings"
@echo " make k8s-test-dns - Test DNS resolution"
@echo ""
@echo "Keycloak realm management:"
@echo " make keycloak-delete-realm - Delete the ushadow realm"
@echo " make keycloak-create-realm - Create realm from realm-export.json"
@echo " make keycloak-reset-realm - Delete and recreate realm"
@echo " make keycloak-fresh-start - Complete fresh setup (stop, clear DB, restart, import)"
@echo ""
@echo "Launcher release:"
@echo " make release VERSION=x.y.z [PLATFORMS=all] [DRAFT=true]"
@echo " - Build, commit, and trigger GitHub release workflow"
# Quick start - runs go.sh
go:
@./go.sh
# Development mode - Vite dev server + backend in Docker
dev:
@./dev.sh --quick --dev --no-admin
# Production mode - Optimized build with nginx
prod:
@echo "π Starting ushadow in production mode..."
@docker network create ushadow-network 2>/dev/null || true
@docker compose -f compose/docker-compose.yml -f compose/docker-compose.prod.yml up -d --build
@echo "β
ushadow running in production mode"
@echo ""
@echo "Access at: http://localhost:$${WEBUI_PORT:-3000}"
# Application commands - delegate to run.py (reads DEV_MODE from .env)
up:
@python3 setup/run.py --up
down:
@python3 setup/run.py --down
restart:
@python3 setup/run.py --restart
build:
@python3 setup/run.py --build
logs:
@docker compose -f docker-compose.yml logs --tail=100
logs-f:
@docker compose -f docker-compose.yml logs -f
build-with-tailscale:
@echo "π¨ Building with Tailscale socket support (Linux only)..."
@echo "β οΈ This requires Tailscale to be running on your Linux host"
@python3 setup/run.py --build
@echo "Note: Tailscale socket mount requires manual compose override"
reset-tailscale:
@./setup/reset-tailscale.sh
# Infrastructure commands
# Note: Services use profiles, so we must specify --profile to include them
INFRA_COMPOSE := docker compose -f compose/docker-compose.infra.yml -p infra --profile infra --profile memory
infra-up:
@echo "ποΈ Starting infrastructure..."
@docker network create infra-network 2>/dev/null || true
@docker network create ushadow-network 2>/dev/null || true
@cd $(shell pwd) && python3 -c "import sys; sys.path.insert(0,'setup'); from start_utils import cleanup_stale_endpoints; cleanup_stale_endpoints()"
@$(INFRA_COMPOSE) up -d
@echo "β
Infrastructure started"
infra-down:
$(INFRA_COMPOSE) down
infra-logs:
$(INFRA_COMPOSE) logs -f
# Chronicle commands
chronicle-up:
@echo "π Starting Chronicle..."
@docker network create ushadow-network 2>/dev/null || true
@docker compose -f deployment/docker-compose.chronicle.yml up -d
@echo "β
Chronicle started"
chronicle-down:
docker compose -f deployment/docker-compose.chronicle.yml down
chronicle-logs:
docker compose -f deployment/docker-compose.chronicle.yml logs -f
# Chronicle local development
# Export env vars from ushadow's config for local Chronicle builds
chronicle-env-export:
@echo "π¦ Exporting Chronicle env vars..."
@python3 scripts/ushadow_client.py service env-export chronicle-backend -o .env.chronicle
@echo "β
Env vars exported to .env.chronicle"
# Build Chronicle from local source
chronicle-build-local:
@echo "π¨ Building Chronicle from local source..."
@docker build -t chronicle-backend-local:latest chronicle/backends/advanced
@docker tag chronicle-backend-local:latest ghcr.io/ushadow-io/chronicle-backend:local
@echo "β
Built and tagged as ghcr.io/ushadow-io/chronicle-backend:local"
# Run Chronicle with local build using exported env vars
chronicle-up-local: chronicle-env-export
@echo "π Starting Chronicle with local build..."
@docker network create infra-network 2>/dev/null || true
@export $$(grep -v '^#' .env.chronicle | xargs) && \
docker run -d --rm \
--name ushadow-chronicle-backend-local \
--network infra-network \
-p $${CHRONICLE_PORT:-8080}:8000 \
--env-file .env.chronicle \
-e PROJECT_ROOT=$(PWD) \
-v $(PWD)/config/config.yml:/app/config.yml:ro \
ghcr.io/ushadow-io/chronicle-backend:local
@echo "β
Chronicle running locally on port $${CHRONICLE_PORT:-8080}"
# Stop local Chronicle
chronicle-down-local:
@echo "π Stopping local Chronicle..."
@docker stop ushadow-chronicle-backend-local 2>/dev/null || true
@echo "β
Chronicle stopped"
# Full local development cycle: build and run
chronicle-dev: chronicle-build-local chronicle-up-local
@echo "π Chronicle dev environment ready"
# =============================================================================
# Build & Push to GHCR
# =============================================================================
# Build and push multi-arch images to GitHub Container Registry
# Requires: docker login ghcr.io -u USERNAME --password-stdin
# ushadow - Build and push backend + frontend to ghcr.io
ushadow-push:
@./scripts/build-push-images.sh ushadow $(TAG)
# ushadow - Build and push to local K8s registry
# Set K8S_REGISTRY environment variable to your registry (e.g., localhost:32000, registry.local:5000)
ushadow-push-local:
@if [ -z "$(K8S_REGISTRY)" ]; then \
echo "β Error: K8S_REGISTRY not set"; \
echo ""; \
echo "Usage: K8S_REGISTRY=localhost:32000 make ushadow-push-local"; \
echo ""; \
echo "Example registries:"; \
echo " - localhost:32000 (microk8s)"; \
echo " - registry.local:5000 (custom registry)"; \
exit 1; \
fi
@echo "ποΈ Building for $(K8S_REGISTRY) (amd64)..."
@docker build --platform linux/amd64 -t $(K8S_REGISTRY)/ushadow-backend:latest -f ushadow/backend/Dockerfile .
@docker build --platform linux/amd64 -t $(K8S_REGISTRY)/ushadow-frontend:latest ushadow/frontend/
@echo "π€ Pushing to $(K8S_REGISTRY)..."
@docker push $(K8S_REGISTRY)/ushadow-backend:latest
@docker push $(K8S_REGISTRY)/ushadow-frontend:latest
@echo "β
Images pushed to $(K8S_REGISTRY)"
@echo ""
@echo "To update K8s deployments:"
@echo " kubectl delete pod -n ushadow -l app.kubernetes.io/name=ushadow-backend"
@echo " kubectl delete pod -n ushadow -l app.kubernetes.io/name=ushadow-frontend"
# Chronicle - Build and push backend + webui
chronicle-push:
@./scripts/build-push-images.sh chronicle $(TAG)
# Mycelia - Build and push backend
mycelia-push:
@./scripts/build-push-images.sh mycelia $(TAG)
# OpenMemory - Build and push server
openmemory-push:
@./scripts/build-push-images.sh openmemory $(TAG)
# =============================================================================
# Service Management (via ushadow API)
# =============================================================================
# These commands use the ushadow API to manage services, ensuring env vars
# are properly resolved and injected by the ushadow backend.
svc-list:
@python3 scripts/ushadow_client.py service list
svc-restart:
@if [ -z "$(SVC)" ]; then echo "Usage: make svc-restart SVC=<service-name>"; exit 1; fi
@python3 scripts/ushadow_client.py service restart $(SVC)
svc-start:
@if [ -z "$(SVC)" ]; then echo "Usage: make svc-start SVC=<service-name>"; exit 1; fi
@python3 scripts/ushadow_client.py service start $(SVC)
svc-stop:
@if [ -z "$(SVC)" ]; then echo "Usage: make svc-stop SVC=<service-name>"; exit 1; fi
@python3 scripts/ushadow_client.py service stop $(SVC)
svc-status:
@if [ -z "$(SVC)" ]; then echo "Usage: make svc-status SVC=<service-name>"; exit 1; fi
@python3 scripts/ushadow_client.py service status $(SVC)
# Generic service restart pattern: make restart-<service>
# e.g., make restart-chronicle, make restart-speaker
restart-%:
@python3 scripts/ushadow_client.py service restart $*
# =============================================================================
# Service Rebuild Command
# =============================================================================
# Rebuild service image: make rebuild <service>
# Usage: make rebuild mycelia, make rebuild chronicle
# Only builds the image, does not stop or start containers
# Assumes compose file exists at: compose/<service>-compose.yml or .yaml
rebuild:
@if [ -z "$(filter-out $@,$(MAKECMDGOALS))" ]; then \
echo "Usage: make rebuild <service>"; \
echo "Example: make rebuild mycelia"; \
exit 1; \
fi
@SERVICE=$(filter-out $@,$(MAKECMDGOALS)); \
if [ -f compose/$$SERVICE-compose.yml ]; then \
echo "π¨ Building $$SERVICE..."; \
docker compose -f compose/$$SERVICE-compose.yml build && \
echo "β
$$SERVICE image built (use 'docker compose -f compose/$$SERVICE-compose.yml up -d' to start)"; \
elif [ -f compose/$$SERVICE-compose.yaml ]; then \
echo "π¨ Building $$SERVICE..."; \
docker compose -f compose/$$SERVICE-compose.yaml build && \
echo "β
$$SERVICE image built (use 'docker compose -f compose/$$SERVICE-compose.yaml up -d' to start)"; \
else \
echo "β Compose file not found: compose/$$SERVICE-compose.yml or compose/$$SERVICE-compose.yaml"; \
echo "Available services:"; \
ls compose/*-compose.y*l 2>/dev/null | xargs -n1 basename | sed 's/-compose\.y.*$$//' | sed 's/^/ - /'; \
exit 1; \
fi
# Allow service name to be passed as argument without error
%:
@:
# Status and health
status:
@echo "=== Docker Containers ==="
@docker ps --filter "name=ushadow" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null || true
@docker ps --filter "name=chronicle" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null || true
@docker ps --filter "name=mongo" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null || true
@docker ps --filter "name=redis" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null || true
@docker ps --filter "name=qdrant" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null || true
health:
@echo "=== Health Checks ==="
@echo -n "ushadow Backend: "
@curl -s http://localhost:$${BACKEND_PORT:-8000}/health | grep -q "healthy" && echo "β
Healthy" || echo "β Unhealthy"
@echo -n "Chronicle: "
@curl -s http://localhost:8000/health | grep -q "ok" && echo "β
Healthy" || echo "β Unhealthy"
@echo -n "MongoDB: "
@docker exec mongo mongosh --quiet --eval "db.adminCommand('ping').ok" 2>/dev/null | grep -q "1" && echo "β
Healthy" || echo "β Unhealthy"
@echo -n "Redis: "
@docker exec redis redis-cli ping 2>/dev/null | grep -q "PONG" && echo "β
Healthy" || echo "β Healthy"
# Development commands
install:
@echo "π¦ Installing dependencies..."
@echo "β οΈ Use 'pixi run install' instead for shared pixi environment"
@echo " Or run: pixi shell, then run make targets"
@exit 1
# =============================================================================
# Backend Tests (pytest) - Test Pyramid Base
# =============================================================================
# Fast unit tests only (no services needed) - should complete in seconds
test:
@echo "π§ͺ Running unit tests..."
@cd ushadow/backend && pytest -m "unit and not tdd" -q --tb=short
# Integration tests (need MongoDB, Redis running)
test-integration:
@echo "π§ͺ Running integration tests..."
@cd ushadow/backend && pytest -m "integration and not tdd" -v --tb=short
# TDD tests (expected to fail - for tracking progress)
test-tdd:
@echo "π§ͺ Running TDD tests (expected failures)..."
@cd ushadow/backend && pytest -m "tdd" -v
# All backend tests (unit + integration, excludes TDD)
test-all:
@echo "π§ͺ Running all backend tests..."
@cd ushadow/backend && pytest -m "not tdd" -v --tb=short
# =============================================================================
# Robot Framework Tests (API/E2E) - Test Pyramid Top
# =============================================================================
# Quick smoke tests - health checks and critical paths (~30 seconds)
test-robot-quick:
@echo "π€ Running quick smoke tests..."
@robot --outputdir robot_results \
--include quick \
robot_tests/api/api_health_check.robot \
robot_tests/api/service_config_scenarios.robot
# Critical path tests only - must-pass scenarios
test-robot-critical:
@echo "π€ Running critical path tests..."
@robot --outputdir robot_results \
--include critical \
robot_tests/api/
# All API integration tests
test-robot-api:
@echo "π€ Running all API tests..."
@robot --outputdir robot_results \
--exclude wip \
robot_tests/api/
# Feature-level tests (memory feedback, etc.)
test-robot-features:
@echo "π€ Running feature tests..."
@robot --outputdir robot_results \
--exclude wip \
robot_tests/features/
# All Robot tests (full suite) - may take several minutes
test-robot:
@echo "π€ Running full Robot test suite..."
@robot --outputdir robot_results \
--exclude wip \
robot_tests/
# View last test report in browser
test-report:
@echo "π Opening test report..."
@open robot_results/report.html 2>/dev/null || xdg-open robot_results/report.html 2>/dev/null || echo "Report at: robot_results/report.html"
lint:
cd ushadow/backend && ruff check .
cd ushadow/frontend && npm run lint
format:
cd ushadow/backend && ruff format .
cd ushadow/frontend && npm run format
# Cleanup commands
clean:
docker compose -f compose/docker-compose.yml down -v
docker compose -f deployment/docker-compose.chronicle.yml down -v
docker compose -f compose/docker-compose.infra.yml down -v
clean-logs:
find . -name "*.log" -type f -delete
clean-cache:
find . -type d -name "__pycache__" -exec rm -rf {} +
find . -type d -name ".pytest_cache" -exec rm -rf {} +
find . -type d -name ".ruff_cache" -exec rm -rf {} +
reset: clean clean-logs clean-cache
@echo "π§Ή Full reset complete"
# Database commands
db-shell:
docker exec -it mongo mongosh ushadow
db-backup:
@mkdir -p backups
docker exec mongo mongodump --db=ushadow --out=/tmp/backup
docker cp mongo:/tmp/backup ./backups/backup-$(shell date +%Y%m%d-%H%M%S)
@echo "β
Database backed up to ./backups/"
db-restore:
@echo "β οΈ This will restore the database. Are you sure? [y/N]"
@read -r response; \
if [ "$$response" = "y" ]; then \
docker exec mongo mongorestore --db=ushadow /tmp/backup/ushadow; \
echo "β
Database restored"; \
fi
# Network commands
network-create:
docker network create ushadow-network 2>/dev/null || true
network-remove:
docker network rm ushadow-network 2>/dev/null || true
# =============================================================================
# Kubernetes DNS Management
# =============================================================================
# Add services to Kubernetes CoreDNS for short-name access via Tailscale
# Example: make k8s-add-service-dns SVC=mycelium NS=ushadow NAMES="mycelium fungi network"
k8s-add-service-dns: ## Add DNS entry for a Kubernetes service (interactive)
@if [ -z "$(SVC)" ] || [ -z "$(NS)" ] || [ -z "$(NAMES)" ]; then \
echo "Usage: make k8s-add-service-dns SVC=<service> NS=<namespace> NAMES=\"<shortname1> [shortname2]...\""; \
echo ""; \
echo "Examples:"; \
echo " make k8s-add-service-dns SVC=mycelium NS=ushadow NAMES=\"mycelium fungi\""; \
echo " make k8s-add-service-dns SVC=neo4j NS=ushadow NAMES=\"neo4j graph\""; \
echo ""; \
echo "Or run interactively:"; \
echo " make k8s-add-service-dns-interactive"; \
exit 1; \
fi
@./k8s/scripts/dns/add-service-dns.sh $(SVC) $(NS) $(NAMES)
k8s-add-service-dns-interactive: ## Add DNS entry (prompts for input)
@echo "π Add Kubernetes Service to DNS"
@echo ""
@read -p "Service name: " service; \
read -p "Namespace: " namespace; \
read -p "Short names (space-separated): " names; \
./k8s/scripts/dns/add-service-dns.sh $$service $$namespace $$names
k8s-show-dns: ## Show current DNS mappings
@echo "π Current DNS Mappings:"
@echo ""
@kubectl get configmap chakra-dns-hosts -n kube-system -o jsonpath='{.data.chakra\.hosts}' 2>/dev/null || \
echo "β DNS ConfigMap not found. Run setup first."
k8s-test-dns: ## Test DNS resolution for ushadow services
@./k8s/scripts/dns/test-ushadow-dns.sh
# Show environment info
env-info:
@echo "=== Environment Information ==="
@echo "ENV_NAME: $${ENV_NAME:-ushadow}"
@echo "BACKEND_PORT: $${BACKEND_PORT:-8000}"
@echo "WEBUI_PORT: $${WEBUI_PORT:-3000}"
@echo "CHRONICLE_PORT: $${CHRONICLE_PORT:-8000}"
@echo "MONGODB_DATABASE: $${MONGODB_DATABASE:-ushadow}"
# Sync .env with .env.example (show missing variables)
env-sync:
@uv run scripts/sync-env.py
# Sync .env with .env.example (apply missing variables)
env-sync-apply:
@uv run scripts/sync-env.py --apply
# Launcher release - triggers GitHub Actions workflow
# Usage: make release VERSION=0.4.2 [PLATFORMS=macos] [DRAFT=true] [RELEASE_NAME="Bug Fixes"]
release:
@if [ -z "$(VERSION)" ]; then \
echo "Error: VERSION is required"; \
echo "Usage: make release VERSION=0.4.2 [PLATFORMS=macos,windows,linux] [DRAFT=true] [RELEASE_NAME='Bug Fixes']"; \
exit 1; \
fi
@echo "π Triggering launcher release workflow..."
@echo " Version: $(VERSION)"
@echo " Platforms: $${PLATFORMS:-all}"
@echo " Draft: $${DRAFT:-false}"
@echo " Release Name: $${RELEASE_NAME:-v$(VERSION)}"
@echo ""
@echo "π¦ Building frontend dist..."
@cd ushadow/launcher && npm run build
@echo "β
Frontend built"
@echo ""
@echo "π Committing dist folder (required for GitHub Actions)..."
@git add -f ushadow/launcher/dist
@git commit -m "chore(launcher): build dist for release v$(VERSION)" || true
@git push origin HEAD
@echo ""
@echo "π¬ Triggering GitHub Actions workflow..."
@gh workflow run launcher-release.yml \
-f version=$(VERSION) \
-f platforms=$${PLATFORMS:-all} \
-f draft=$${DRAFT:-false} \
$${RELEASE_NAME:+-f release_name="$$RELEASE_NAME"}
@echo ""
@echo "β
Release workflow triggered!"
@echo " View progress: gh run list --workflow=launcher-release.yml"
@echo " Or visit: https://github.com/$$(git config --get remote.origin.url | sed 's/.*github.com[:/]\(.*\)\.git/\1/')/actions"
# Keycloak realm management
keycloak-delete-realm:
@echo "ποΈ Deleting Keycloak realm 'ushadow'..."
@docker exec keycloak /opt/keycloak/bin/kcadm.sh config credentials \
--server http://localhost:8080 \
--realm master \
--user admin \
--password admin > /dev/null 2>&1 || \
(echo "β οΈ Keycloak not running" && exit 1)
@docker exec keycloak /opt/keycloak/bin/kcadm.sh delete realms/ushadow 2>/dev/null || \
(echo "β οΈ Realm doesn't exist" && exit 1)
@echo "β
Realm deleted"
keycloak-create-realm:
@echo "π¦ Creating Keycloak realm 'ushadow' from realm-export.json..."
@if [ ! -f config/keycloak/realm-export.json ]; then \
echo "β Error: config/keycloak/realm-export.json not found"; \
exit 1; \
fi
@docker cp config/keycloak/realm-export.json keycloak:/tmp/realm-import.json
@docker exec keycloak /opt/keycloak/bin/kcadm.sh config credentials \
--server http://localhost:8080 \
--realm master \
--user admin \
--password admin
@docker exec keycloak /opt/keycloak/bin/kcadm.sh create realms \
-f /tmp/realm-import.json
@echo "β
Realm created and configured"
keycloak-reset-realm: keycloak-delete-realm keycloak-create-realm
@echo "β
Realm reset complete"
keycloak-fresh-start:
@echo "π Starting fresh Keycloak setup..."
@echo "1. Stopping Keycloak..."
@docker stop keycloak 2>/dev/null || true
@docker rm keycloak 2>/dev/null || true
@echo "2. Clearing Keycloak database..."
@docker exec postgres psql -U ushadow -d ushadow -c "DROP SCHEMA IF EXISTS public CASCADE; CREATE SCHEMA public;" 2>/dev/null || \
echo "β οΈ Database already clean or Postgres not running"
@echo "3. Starting Keycloak (realm will import automatically)..."
@docker-compose -f compose/docker-compose.infra.yml --profile infra up -d keycloak
@echo "4. Waiting for Keycloak health check..."
@for i in {1..60}; do \
printf " Checking health (attempt $$i/60)...\r"; \
if curl -sf http://localhost:$${KEYCLOAK_MGMT_PORT:-9000}/health/ready > /dev/null 2>&1; then \
echo "\n β
Keycloak is healthy "; \
break; \
fi; \
if [ $$i -eq 60 ]; then \
echo "\n β οΈ Keycloak health check timeout - check logs: docker logs keycloak"; \
exit 1; \
fi; \
sleep 2; \
done
@echo "5. Waiting for realm import to complete..."
@for i in {1..30}; do \
printf " Checking realm (attempt $$i/30)...\r"; \
if curl -sf http://localhost:$${KEYCLOAK_PORT:-8081}/realms/ushadow > /dev/null 2>&1; then \
echo "\n β
Realm 'ushadow' is ready "; \
break; \
fi; \
if [ $$i -eq 30 ]; then \
echo "\n β οΈ Realm import timeout - check logs: docker logs keycloak"; \
fi; \
sleep 2; \
done
@echo "6. Restarting backend..."
@docker ps --format "{{.Names}}" | grep -E "^ushadow-.*-backend$$" | grep -v chronicle | grep -v mycelia | head -1 | xargs -r docker restart
@echo "β
Backend restarted"
@echo "β
Fresh Keycloak setup complete"
@echo " Admin console: http://localhost:$${KEYCLOAK_PORT:-8081}"
@echo " Username: admin"
@echo " Password: admin"