# mens 开发任务。所有 Python 入口都用 $(PY) 跟随当前激活的环境（conda py12），
# `make env` 打印实际解析到的 mens / flexllm 路径。

.PHONY: help env start api web build test test-py test-web lint fmt clean

PY       ?= python
# 与 mens chat-web 的默认一致：0.0.0.0，启动信息里会展开成 Local + Network，
# 手机/同网段机器也能连。只想本机可见就 `make start HOST=127.0.0.1`。
HOST     ?= 0.0.0.0
# 开发时后端端口。浏览器开的是 vite（WEB_PORT），不是这个
API_PORT ?= 8080
WEB_PORT ?= 5173
TOOLS    ?= all
# 默认 bypass（工具直接执行）。HOST=0.0.0.0 意味着同网段能连上，
# 在不受信任的网络里应改成 default，写操作会在页面上逐次审批
PERM     ?= bypass

help:
	@echo "make start   前后端一起起，都热更新（改 Python 自动重启，改前端 HMR）"
	@echo "make api     只起后端（自动重启），端口 $(API_PORT)"
	@echo "make web     只起前端 dev server，端口 $(WEB_PORT)"
	@echo "make build   构建前端 → mens/data/chat_web.html（产物要提交）"
	@echo "make test    Python + 前端测试"
	@echo "make lint    ruff check + tsc"
	@echo "make env     打印实际解析到的 python / mens / flexllm"
	@echo ""
	@echo "变量：PY=$(PY) HOST=$(HOST) API_PORT=$(API_PORT) WEB_PORT=$(WEB_PORT)"
	@echo "      TOOLS=$(TOOLS) PERM=$(PERM)"

## 开发主入口。启动信息由 mens chat-web 自己打印（模型/工具/权限只有它知道），
## MENS_DEV_URL 让那份 banner 把 vite 的地址排在最前面。
##
## 前后端各自热更新，中间靠 vite 的 /api 代理连起来（web/vite.config.ts）。
## 浏览器**不要**开 $(API_PORT) —— 那个端口返回的是上次 build 出来的静态产物，
## 看不到你正在改的前端代码。
##
## 退出时要连子孙一起收掉：不收的话 Ctrl+C 只杀掉 make，watchfiles / vite
## 会活下来占着端口，下次 make start 直接 address in use。
##
## kt 按 PID 递归杀子树。**不要用 `kill 0` 或 `kill -- -$$pid`** —— 它们打的是
## 进程组，而 make 的 SHELL 是 dash，dash 在无 tty 时 `set -m` 会静默失败
## （"can't access tty; job control turned off"），后台任务仍留在调用方的进程组，
## 于是那两个写法会把调用方一起杀掉（CI、脚本、各种 wrapper 里都会踩）。
start:
	@kt() { for c in $$(pgrep -P $$1 2>/dev/null); do kt $$c; done; kill $$1 2>/dev/null; }; \
		MENS_DEV_PORT=$(WEB_PORT) $(MAKE) --no-print-directory api & api=$$!; \
		$(MAKE) --no-print-directory web & web=$$!; \
		trap 'kt $$api; kt $$web' EXIT INT TERM; \
		wait

## 后端自动重启。watchfiles 只盯 mens/，改 web/ 不会白重启后端。
## 重启会丢掉内存里的会话，前端拿到 404 后会自动开新会话并在页面上说明。
##
## 用 `$(PY) -m mens` 而不是裸 `mens`：前者跟着 PY 走，换环境时不会悄悄
## 跑到另一套解释器的 console script 上。
api:
	@command -v watchfiles >/dev/null || { \
		echo "缺 watchfiles：pip install -e '.[all,dev]'"; exit 1; }
	watchfiles --filter python \
		"$(PY) -m mens chat-web --tools $(TOOLS) -p $(API_PORT) --host $(HOST) \
		 --permission-mode $(PERM)" mens

## 打印实际解析到的依赖路径。mens 与 flexllm 都该指向 ~/github/…（editable）
env:
	@$(PY) -c "import sys, flexllm, mens; \
print('python  ', sys.executable); \
print('mens    ', mens.__file__); \
print('flexllm ', flexllm.__file__, flexllm.__version__)"

## 必须显式传 --host：vite 默认绑 localhost，双栈机器上只落到 [::1]，
## 用 127.0.0.1 或局域网 IP 都连不上（curl / 手机访问尤其容易踩）。
## MENS_API 走 127.0.0.1 而非 $(HOST)：代理是 vite 进程到本机后端的连接，
## 用回环最短最稳，且 0.0.0.0 作为连接目标本身就不合法。
web:
	@[ -d web/node_modules ] || (cd web && npm install)
	cd web && MENS_API=http://127.0.0.1:$(API_PORT) \
		npm run dev -- --host $(HOST) --port $(WEB_PORT) --strictPort

## 前端产物必须与源码一起提交：发版机器不装 node
build:
	@[ -d web/node_modules ] || (cd web && npm install)
	cd web && npm run build

test: test-py test-web

test-py:
	$(PY) -m pytest -q

test-web:
	cd web && npm test

lint:
	ruff check mens/ tests/
	cd web && npx tsc -b --noEmit

fmt:
	ruff check --fix mens/ tests/

clean:
	rm -rf dist build web/tsconfig.tsbuildinfo
	find . -name __pycache__ -type d -prune -exec rm -rf {} +
