export PYTHONPATH := $(CURDIR)/src:$(CURDIR)/工具 # 用例与库层直接用仓内解释器:uv run 在嵌套检出里会解析到外层 agent-example/.venv, # 那个环境没有 psycopg_pool,库层会以导入失败告终。工具链目标仍走 uv run。 仓内解释器 := $(CURDIR)/.venv/bin/python # Muse 安装、生成、检查、测试和构建入口。 # 每个声明命令都必须真实可执行(见 .agent/rules/文档与资源生成.md)。 .PHONY: 迁移 前端旅程 快检 索引生成 包验收 安装 格式 格式写入 类型 模块边界 检查 测试 数据库测试 数据库分片 验收数据库 浏览器测试 宿主测试 真实模型测试 前端安装 前端检查 前端测试 生成 构建 资源核对 # 安装:建立并锁定 Python 依赖环境 安装: uv sync --group dev 前端安装: pnpm --dir web install --frozen-lockfile 前端检查: pnpm --dir web run lint pnpm --dir web run typecheck pnpm --dir web exec tsc --noEmit --module esnext --moduleResolution bundler --target es2022 --skipLibCheck --typeRoots node_modules/@types --types node ../src/muse/基础设施/宿主/Pi工具桥.ts 前端测试: pnpm --dir web run test # 浏览器旅程需调用者明确选择真实后端与浏览器;不属于默认离线层。 前端旅程: @test -n "$$MUSE_WORKBENCH_URL" -a -n "$$MUSE_BROWSER_EXECUTABLE" || { echo "缺少明确的 MUSE_WORKBENCH_URL / MUSE_BROWSER_EXECUTABLE" >&2; exit 1; } @test -x "$$MUSE_BROWSER_EXECUTABLE" || { echo "MUSE_BROWSER_EXECUTABLE 不是可执行浏览器路径" >&2; exit 1; } @test "$$MUSE_ISOLATED_TEST_ENVIRONMENT" = "1" || { echo "缺 MUSE_ISOLATED_TEST_ENVIRONMENT=1(旅程环境在配置加载期强校验)" >&2; exit 1; } @test -n "$$MUSE_AUTHOR_PASSWORD_FILE" -a -f "$$MUSE_AUTHOR_PASSWORD_FILE" || { echo "MUSE_AUTHOR_PASSWORD_FILE 必须是可读的绝对路径" >&2; exit 1; } pnpm --dir web run test:journey $(参数) # 格式:静态检查(ruff lint + 格式校验) 格式: uv run --no-sync ruff check src tests 工具 uv run --no-sync ruff format --check src tests 工具 # 格式写入:按项目规则实际格式化 格式写入: uv run --no-sync ruff check --fix src tests 工具 uv run --no-sync ruff format src tests 工具 $(MAKE) 生成 # 类型:pyright 类型检查 类型: uv run --no-sync pyright # 模块边界:固定执行架构门禁,不继承调用者的 pytest 筛选条件。 模块边界: PYTEST_ADDOPTS= $(仓内解释器) -m pytest tests/架构/test_模块依赖.py -m "not 安装包" -q # 检查:格式 + 类型 + 模块边界 + 索引核对的统一入口 检查: 格式 类型 模块边界 uv run --no-sync python 工具/维护索引.py --检查 # 测试:默认离线(按标记剔除外部环境用例;未标记用例在 socket 防护下运行) # 用法:make 测试 全部离线用例 # make 测试 用例=TC-a5c7d4adafe3 按稳定用例 ID 选择 测试: $(仓内解释器) -m pytest -m "not 数据库 and not 网络 and not 真实模型 and not 浏览器 and not 宿主 and not 安装包" $(范围) $(if $(用例),--case $(用例),) # 验收数据库:全量数据库验收门禁,先生成、再门禁、最后跑库;排除标记为慢的用例(浏览器旅程等走对应显式目标)。 验收数据库: @test -n "$$MUSE_TEST_DATABASE_URL" || { echo "缺少 MUSE_TEST_DATABASE_URL(隔离库连接串);拒绝先付生成与门禁成本再失败" >&2; exit 1; } $(MAKE) 生成 $(MAKE) 检查 $(仓内解释器) -m pytest --外部环境 -m "数据库 and not 慢 and not 宿主 and not 真实模型 and not 浏览器 and not 网络" $(范围) # 数据库分片:发现与修复期用分片并行;默认排除慢用例 数据库分片: $(仓内解释器) 工具/并行数据库测试.py --片数 $(if $(片数),$(片数),3) $(范围) # 数据库测试:需要 MUSE_TEST_DATABASE_URL。 # 默认排除慢用例、浏览器、网络、宿主、真实模型。 数据库测试: @test -n "$$MUSE_TEST_DATABASE_URL" || { echo "缺少 MUSE_TEST_DATABASE_URL(隔离库连接串);拒绝静默跳过" >&2; exit 1; } $(仓内解释器) -m pytest --外部环境 -m "数据库 and not 慢 and not 宿主 and not 真实模型 and not 浏览器 and not 网络" $(范围) $(if $(用例),--case $(用例),) # 浏览器测试:需要隔离库与显式浏览器路径;11 个 数据库+浏览器 用例的唯一入口。 # MUSE_ISOLATED_TEST_ENVIRONMENT 由本目标声明:Playwright 配置加载期就要求它,缺了连 spec 都跑不到。 浏览器测试: @test -n "$$MUSE_TEST_DATABASE_URL" -a -n "$$MUSE_BROWSER_EXECUTABLE" || { echo "缺少隔离库或 MUSE_BROWSER_EXECUTABLE" >&2; exit 1; } MUSE_RUN_BROWSER=1 MUSE_ISOLATED_TEST_ENVIRONMENT=1 $(仓内解释器) -m pytest --外部环境 -m "浏览器 and not 宿主 and not 真实模型" $(范围) 真实模型测试: @test -n "$$MUSE_TEST_DATABASE_URL" -a -n "$$MUSE_REAL_MODEL_URL" -a -n "$$MUSE_REAL_MODEL_KEY_FILE" || { echo "缺少隔离库或真实模型地址/凭据文件"; exit 1; } $(仓内解释器) -m pytest --外部环境 -m 真实模型 --timeout=300 宿主测试: @test -n "$$MUSE_TEST_DATABASE_URL" -a -n "$$MUSE_PI_NODE" -a -n "$$MUSE_PI_PACKAGE" || { echo "缺少隔离库或固定Pi/Node路径"; exit 1; } $(仓内解释器) -m pytest --外部环境 -m 宿主 # 迁移:对配置指向的目标库执行显式迁移(维护命令,不在启动时自动执行) 迁移: uv run --no-sync python -m muse 迁移 $(配置) # 快检只检查指定Python源码/测试;不构建资源或前端。 # 范围写成具体路径(如 `范围=src/muse/元数据`、`范围=tests/单元`): # 含非测试路径就跑类型门,含测试路径才跑用例门;范围缺省时按源码 + 单元/契约用例。 快检: uv run --no-sync ruff check $(if $(范围),$(范围),src tests 工具) uv run --no-sync ruff format --check $(if $(范围),$(范围),src tests 工具) $(if $(范围),$(if $(filter-out tests/%,$(范围)),uv run --no-sync pyright,:),uv run --no-sync pyright) $(if $(filter tests/%,$(范围)),$(仓内解释器) -m pytest -m "not 数据库 and not 网络 and not 真实模型 and not 浏览器 and not 宿主 and not 安装包" $(filter tests/%,$(范围)) $(if $(用例),--case $(用例),),$(if $(范围),:,$(仓内解释器) -m pytest -m "not 数据库 and not 网络 and not 真实模型 and not 浏览器 and not 宿主 and not 安装包" tests/单元 tests/契约 $(if $(用例),--case $(用例),))) 索引生成: uv run --no-sync python 工具/维护索引.py --写入 # 聚合入口按内容哈希增量执行;wheel必须与同次资源输入绑定。 生成: uv run --no-sync python 工具/构建编排.py 构建: uv run --no-sync python 工具/构建编排.py --wheel 包验收: uv run --no-sync python 工具/验收安装包.py $(包) # 资源核对:安装包内资源与清单哈希一致 资源核对: uv run --no-sync python -c "from muse.资源加载 import 核对资源; m = 核对资源(); print('资源清单发布身份:', m['发布身份'], '条目数:', len(m['资源']))"