build: establish unified project entry
This commit is contained in:
+16
-12
@@ -89,8 +89,8 @@ cmbuyer 是一个自动化采购系统:**采购服务**(网页端,`admin/`
|
||||
|
||||
执行按任务依赖驱动,**不按 Phase 整段串行等待**。当前优先路径:
|
||||
|
||||
1. T-004 核心数据模型正在进行;T-003 统一入口与 T-101 真机环境盘点可开始。
|
||||
2. T-002 已完成,立即推进 **T-101 → T-102 → T-103 真机取证**,并可并行补 T-003 统一入口。
|
||||
1. T-003 统一入口与 T-004 核心数据模型已完成;T-101 真机环境盘点已就绪,但尚未真机验收。
|
||||
2. T-002 已完成,立即推进 **T-101 → T-102 → T-103 真机取证**。
|
||||
3. T-103 结论确认后,才开始依赖真机可读字段的 Phase 2 生产页面;采购服务核心与
|
||||
T-104 → T-107 后续真机安全判据按依赖并行推进。
|
||||
4. Phase 3:双端打通与**第一趟试选**端到端。
|
||||
@@ -172,25 +172,29 @@ cmbuyer 是一个自动化采购系统:**采购服务**(网页端,`admin/`
|
||||
|
||||
## 验证命令
|
||||
|
||||
> 采购服务命令已由 T-001 实际验证;采购工具的离线测试、编译和 wheel 元数据命令已由
|
||||
> Python 3.12 实际验证。当前默认 `python` 是 Python 3.10.11,统一入口尚未正确选择
|
||||
> Python 3.11+,此缺口由 T-003 修复。
|
||||
> Windows 标准入口 `./init.ps1` 已由 T-003 实际验证。它优先使用合规的既有 venv(本机实际为
|
||||
> Python 3.12),仅在 venv 缺失时才从 Python Launcher 自动选择最高的 Python 3.11+,避免回退到
|
||||
> 默认 Python 3.10;通过后会输出两端真实启动命令。
|
||||
|
||||
```powershell
|
||||
# Windows 统一安装、离线验证与启动命令提示
|
||||
.\init.ps1
|
||||
|
||||
# 以下为诊断或单独验证时使用的等价命令
|
||||
# 采购服务 admin/(改了 Go 代码后)
|
||||
cd admin
|
||||
go test ./...
|
||||
go vet ./...
|
||||
go build ./...
|
||||
|
||||
# 采购工具 client/(使用 Python 3.11+;本机已验证 3.12)
|
||||
# 采购工具 client/(由 init.ps1 创建的 Python 3.11+ 虚拟环境)
|
||||
cd client
|
||||
py -3.12 -m unittest discover -s tests -t .
|
||||
py -3.12 -m compileall -q src tests scripts
|
||||
.\.venv\Scripts\python.exe -m unittest discover -s tests -t .
|
||||
.\.venv\Scripts\python.exe -m compileall -q src tests scripts
|
||||
$wheelDir = Join-Path $env:TEMP ('cmbuyer-client-wheel-' + [guid]::NewGuid())
|
||||
New-Item -ItemType Directory -Path $wheelDir | Out-Null
|
||||
py -3.12 -m pip wheel --no-deps . --wheel-dir $wheelDir
|
||||
py -3.12 scripts/verify_wheel_metadata.py (Get-ChildItem $wheelDir -Filter '*.whl').FullName
|
||||
.\.venv\Scripts\python.exe -m pip wheel --no-deps . --wheel-dir $wheelDir
|
||||
.\.venv\Scripts\python.exe scripts/verify_wheel_metadata.py (Get-ChildItem $wheelDir -Filter '*.whl').FullName
|
||||
|
||||
# 跨端契约改动:两端全跑
|
||||
```
|
||||
@@ -198,5 +202,5 @@ py -3.12 scripts/verify_wheel_metadata.py (Get-ChildItem $wheelDir -Filter '*.wh
|
||||
验证层级何时触发见 [`03-tech-stack.md`](03-tech-stack.md) 第六节验证矩阵。
|
||||
`requirements.txt` 是采购工具唯一的运行时依赖来源,`pyproject.toml` 动态读取它写入 wheel
|
||||
元数据。规范安装是 Python 3.11+ 虚拟环境中的 `python -m pip install -e .`,已由 Python 3.12
|
||||
验证通过;桌面 GUI 和真机流程不属于本次验收。`init.ps1` 仍未正确选择 Python 3.11+,统一入口
|
||||
由 T-003 修复。若命令当前不可运行,必须在回复里如实说明原因。
|
||||
验证通过;桌面 GUI 和真机流程不属于本次验收。`init.ps1` 使用合规既有 venv,或在缺失时自动选择
|
||||
Python 3.11+ 创建它;本机现有 venv 实际验证为 3.12。若命令当前不可运行,必须在回复里如实说明原因。
|
||||
|
||||
+19
-11
@@ -59,25 +59,33 @@
|
||||
|
||||
## 五、构建与运行命令
|
||||
|
||||
> 采购服务命令已由 T-001 实际验证。采购工具以下离线测试、编译和 wheel 元数据命令已由
|
||||
> Python 3.12 实际验证;桌面 GUI 和真机流程不属于 T-002 验收范围。
|
||||
> `init.ps1` 已由 T-003 在 Windows PowerShell 实际验证:它优先复用合规的既有采购工具虚拟环境
|
||||
> (本机实际为 Python 3.12);仅在虚拟环境不存在时,才从 Python Launcher 的已安装版本中确定性选择
|
||||
> 最高的 Python 3.11+ 创建它,以 editable 方式安装采购工具,并跑两端
|
||||
> 离线门禁。桌面 GUI 和真机流程不属于该入口的验收范围。
|
||||
|
||||
| 用途 | 采购服务(`admin/`) | 采购工具(`client/`) |
|
||||
| --- | --- | --- |
|
||||
| 安装依赖 | `go mod download` | `py -3.12 -m venv .venv` 后运行 `.\.venv\Scripts\python.exe -m pip install -e .` |
|
||||
| 安装依赖 | `go mod download` | Windows 运行 `./init.ps1`;它复用合规 venv,或选择 Python Launcher 中最高的 Python 3.11+ 创建 venv 后执行 `pip install -e .` |
|
||||
| 本地开发 | `go run ./cmd/server` | `.\.venv\Scripts\python.exe -m cmbuyer_client` |
|
||||
| 构建 | `go build ./...` | `py -3.12 -m pip wheel --no-deps . --wheel-dir <输出目录>`,再运行 `py -3.12 scripts/verify_wheel_metadata.py <wheel 路径>` |
|
||||
| 测试 | `go test ./...` | `py -3.12 -m unittest discover -s tests -t .` |
|
||||
| 静态检查 | `go vet ./...` | `py -3.12 -m compileall -q src tests scripts` |
|
||||
| 构建 | `go build ./...` | `.\.venv\Scripts\python.exe -m pip wheel --no-deps . --wheel-dir <输出目录>`,再运行 `.\.venv\Scripts\python.exe scripts/verify_wheel_metadata.py <wheel 路径>` |
|
||||
| 测试 | `go test ./...` | `.\.venv\Scripts\python.exe -m unittest discover -s tests -t .` |
|
||||
| 静态检查 | `go vet ./...` | `.\.venv\Scripts\python.exe -m compileall -q src tests scripts` |
|
||||
|
||||
Windows 的标准入口是仓库根 `./init.ps1`。它要求 Go、两端目录及其哨兵文件存在;已有合规
|
||||
`client/.venv` 时,所有采购工具检查与 validator 都使用该解释器。只有 venv 不存在时,才从 `py -0p`
|
||||
枚举的版本中确定性选择最高的 Python 3.11+ 创建它;没有合规版本时明确失败,绝不回退默认 `python`。
|
||||
它执行 admin 的 `go mod download` / test / vet / build、client 的 editable install / 包导入 / unittest /
|
||||
compileall。既有 `client/.venv` 若不是 Python 3.11+ 会明确失败,不会自动覆盖用户环境。`init.sh` 保持等价门禁语义;WSL 或 Unix 环境缺少所需 Go、Python 3.11+
|
||||
或项目文件时必须非零退出,语法通过或 Unix 成功不构成 Windows / 真机验收。
|
||||
|
||||
采购工具的运行时依赖只维护在 `client/requirements.txt`。`client/pyproject.toml` 通过 setuptools
|
||||
动态读取该文件生成 wheel 的 `Requires-Dist`,避免两份依赖列表漂移;
|
||||
`scripts/verify_wheel_metadata.py` 会验证生成 wheel 已声明全部这些依赖。
|
||||
|
||||
当前 Windows 默认 `python` 指向 Python 3.10.11,不满足采购工具的 Python 3.11+ 下限,
|
||||
不得把未加版本选择器的 `python` 当作采购工具的已验证命令。T-003 负责统一入口与解释器选择;
|
||||
在此之前使用 `py -3.12` 或 Python 3.11+ 虚拟环境。Python 3.12 虚拟环境中的完整
|
||||
`pip install -e .` 已验证通过;桌面 GUI 与真机流程不属于 T-002 验收范围。
|
||||
当前 Windows 默认 `python` 仍可能指向 Python 3.10,不满足采购工具的 Python 3.11+ 下限;
|
||||
不得把未加版本选择器的 `python` 当作采购工具命令。统一入口优先使用既有合规 venv,仅在需要创建时
|
||||
自动选择 Launcher 中最高的合规版本;本机现有 venv 实际为 Python 3.12。桌面 GUI 与真机流程不属于 T-003 验收范围。
|
||||
|
||||
Windows PowerShell 差异:
|
||||
|
||||
@@ -90,7 +98,7 @@ $env:GOTOOLCHAIN = "local"
|
||||
|
||||
| 层级 | 触发条件 | 命令 / 操作 | 通过证据 |
|
||||
| --- | --- | --- | --- |
|
||||
| 任务相关验证 | 每个任务必跑 | 改 `admin/` 跑 `go test ./...` + `go vet ./...`;改 `client/` 跑 `py -3.12 -m unittest discover -s tests -t .` + `py -3.12 -m compileall -q src tests scripts` | 退出码 0、测试数 |
|
||||
| 任务相关验证 | 每个任务必跑 | 改 `admin/` 跑 `go test ./...` + `go vet ./...`;改 `client/` 跑 `.venv\Scripts\python.exe -m unittest discover -s tests -t .` + `.venv\Scripts\python.exe -m compileall -q src tests scripts` | 退出码 0、测试数 |
|
||||
| 完整门禁 | 发布前;修改 HTTP 契约、数据库 schema、依赖或构建配置时;跨端改动时 | 两端全部测试 + 静态检查 + 两端构建 | 退出码 0、测试数、产物路径 |
|
||||
| 人工 / 设备验收 | 任何涉及真机页面判据、下单动作或付款路径的任务 | 连接真机执行,记录设备型号、Android 版本、拼多多版本、goods_id、截图与页面 XML 路径 | 人工结论 + 证据文件路径 |
|
||||
|
||||
|
||||
+34
-39
@@ -12,34 +12,35 @@
|
||||
## 当前快照
|
||||
|
||||
- 日期:2026-08-03
|
||||
- 阶段:**Phase 0 · 地基(采购服务与采购工具骨架已初始化,尚无采购业务代码)**
|
||||
- 阶段:**Phase 0 · 地基(两端骨架、核心数据模型与统一入口已完成,尚无真机采购业务代码)**
|
||||
- MVP 形态:手工填链接建单 → 批量开始试选 → 定时轮询 → **第一趟试选** → 人工确认 → **第二趟下单** → 待付款
|
||||
- 技术栈:已定。采购服务(`admin/`)使用 Go 1.23+ / gin / SQLite;采购工具(`client/`)
|
||||
使用 Python 3.11+ / uiautomator2 / PySide6。
|
||||
详见 [`03-tech-stack.md`](03-tech-stack.md)
|
||||
- 生产代码:`admin/` 已有最小 Go 服务、`GET /healthz` 与 SQLite 驱动封装;`client/` 已有
|
||||
Python 包、PySide6 最小入口、运行目录与日志脱敏策略;两端均尚无采购业务代码
|
||||
- 测试:采购服务 2 项离线单元测试;采购工具 6 项离线单元测试(不连接真机)
|
||||
- 数据:**无**
|
||||
- 标准启动路径:`./init.ps1`(Windows)/ `./init.sh`。两端骨架现已存在,但 `init.ps1` 仍使用
|
||||
默认 Python 3.10,不能正确验证要求 Python 3.11+ 的采购工具;T-003 负责统一入口与解释器选择。
|
||||
- 标准验证路径:`admin/` 下运行 `go test ./...`、`go vet ./...`、`go build ./...`;`client/` 下使用
|
||||
`py -3.12 -m unittest discover -s tests -t .`、`py -3.12 -m compileall -q src tests scripts`;仓库根运行
|
||||
`python scripts/validate_agent_context.py`
|
||||
- 当前 blocker:无外部 blocker。T-002 已完成;T-004 核心数据模型正在进行;T-003 统一入口与
|
||||
T-101 真机环境盘点已就绪。当前不宣称统一入口或桌面 GUI 已验收。
|
||||
- 生产代码:`admin/` 已有最小 Go 服务、健康检查、核心领域模型、SQLite 迁移与任务状态机;
|
||||
`client/` 已有 Python 包、PySide6 最小入口、运行目录与日志脱敏策略;尚无真机采购流程
|
||||
- 测试:采购服务已覆盖健康检查、核心模型、迁移与状态机等离线包级测试;采购工具 6 项离线单元测试
|
||||
(不连接真机)
|
||||
- 数据:SQLite 核心表与迁移已落成;无业务实例数据
|
||||
- 标准启动路径:Windows PowerShell 运行 `./init.ps1`,Unix shell 运行 `./init.sh`。Windows 入口
|
||||
优先使用合规的既有 venv;仅在其缺失时才从 Python Launcher 已安装版本中选择最高的 Python 3.11+,
|
||||
并且不覆盖低版本环境;成功后打印真实启动命令。
|
||||
- 标准验证路径:`./init.ps1` 已实际跑通 admin 的 mod download / test / vet / build、client 的
|
||||
editable install / 包导入 / unittest / compileall,以及仓库上下文校验。可单独运行两端命令诊断。
|
||||
- 当前 blocker:无外部 blocker。T-002、T-003、T-004 已完成;T-101 真机环境盘点已就绪,
|
||||
但尚未真机验收。桌面 GUI 与真机流程尚未验收。
|
||||
|
||||
## 当前目录要点
|
||||
|
||||
| 路径 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `docs/` | 已有 | 项目规范化文档,本次已完整生成 |
|
||||
| `docs/tasks/` | 已有(T-001、T-002、T-004~T-009) | T-001、T-002 已完成;T-004 正在进行;其余既有任务已完成 |
|
||||
| `docs/tasks/` | 已有(T-001~T-004、T-005~T-009、T-101) | T-001~T-004 已完成;T-101 已就绪、待真机验收 |
|
||||
| `docs/design/` | 已有(6 个原型) | web 登录 / 建单 / 工作台 / 详情,desk 采购执行 / 配置;均已人工确认 |
|
||||
| `scripts/` | 已有 | 上下文门禁、Vikunja 单向导出与 MCP 启动包装 |
|
||||
| `admin/` | 已初始化 | Go 1.23+ / gin / SQLite 骨架与健康检查;无采购业务路由 |
|
||||
| `admin/` | 已初始化 | Go 1.23+ / gin / SQLite,含核心模型、迁移与状态机;无真机采购执行 |
|
||||
| `client/` | 已初始化 | Python 3.11+ 包、依赖源、PySide6 最小入口、离线测试与 wheel 元数据检查;无真机或采购流程 |
|
||||
| `init.ps1` / `init.sh` | 已有(骨架) | 统一入口。两端目录建好后由 T-003 补全并验证 |
|
||||
| `init.ps1` / `init.sh` | 已完成 | 统一安装与离线验证入口;PowerShell 优先复用合规 venv,缺失时自动选择最高的 Python 3.11+,Unix 缺工具链明确失败 |
|
||||
|
||||
## 任务状态
|
||||
|
||||
@@ -48,59 +49,53 @@
|
||||
- 已完成:T-005(采购服务交互原型)、T-006(采购工具交互原型)、T-007(产品名称与
|
||||
源码目录契约)、T-008(Vikunja 任务权威与单向导出)、T-009(MVP 关键路径与并行波次),
|
||||
以及 T-001(采购服务 Go 骨架)。
|
||||
- 已完成:T-002(采购工具 Python 骨架)。正在进行:T-004(核心数据模型)。
|
||||
T-003(统一入口)与 T-101(真机环境盘点)已就绪,立即推进 T-101 → T-102 → T-103。
|
||||
- 已完成:T-002(采购工具 Python 骨架)、T-003(双端统一初始化与验证入口)、
|
||||
T-004(核心数据模型)。T-101(真机环境盘点)已建档并就绪,尚未真机验收,接续推进
|
||||
T-101 → T-102 → T-103。
|
||||
- T-103 是当前最高优先级和 MVP 生死线。通过前不开发依赖真机可读字段的 Phase 2 生产页面。
|
||||
- 已确认原型继续只作信息架构依据;原型假数据不调用真实接口、不驱动真机。真机结论改变
|
||||
可读字段时必须先回修原型与交互清单。
|
||||
|
||||
## 当前可运行内容
|
||||
|
||||
采购服务当前可运行:
|
||||
Windows 统一安装、离线验证与启动命令提示已可运行:
|
||||
|
||||
```bash
|
||||
cd admin
|
||||
go mod download
|
||||
go run ./cmd/server
|
||||
```powershell
|
||||
.\init.ps1
|
||||
```
|
||||
|
||||
采购服务验证与仓库级上下文门禁:
|
||||
它会在成功后输出以下真实启动命令,而不自动启动或连接设备:
|
||||
|
||||
```bash
|
||||
cd admin
|
||||
go test ./...
|
||||
go vet ./...
|
||||
go build ./...
|
||||
|
||||
cd ..
|
||||
python scripts/validate_agent_context.py
|
||||
```text
|
||||
采购服务:cd admin; go run ./cmd/server
|
||||
采购工具:cd client; .\.venv\Scripts\python.exe -m cmbuyer_client
|
||||
```
|
||||
|
||||
采购工具当前可运行的离线验证与 wheel 元数据检查:
|
||||
|
||||
```powershell
|
||||
cd client
|
||||
py -3.12 -m unittest discover -s tests -t .
|
||||
py -3.12 -m compileall -q src tests scripts
|
||||
.\.venv\Scripts\python.exe -m unittest discover -s tests -t .
|
||||
.\.venv\Scripts\python.exe -m compileall -q src tests scripts
|
||||
$wheelDir = Join-Path $env:TEMP ('cmbuyer-client-wheel-' + [guid]::NewGuid())
|
||||
New-Item -ItemType Directory -Path $wheelDir | Out-Null
|
||||
py -3.12 -m pip wheel --no-deps . --wheel-dir $wheelDir
|
||||
py -3.12 scripts/verify_wheel_metadata.py (Get-ChildItem $wheelDir -Filter '*.whl').FullName
|
||||
.\.venv\Scripts\python.exe -m pip wheel --no-deps . --wheel-dir $wheelDir
|
||||
.\.venv\Scripts\python.exe scripts/verify_wheel_metadata.py (Get-ChildItem $wheelDir -Filter '*.whl').FullName
|
||||
```
|
||||
|
||||
采购工具规范安装与本地开发入口:
|
||||
|
||||
```powershell
|
||||
# 在仓库根执行统一初始化;成功后再进入 client/
|
||||
.\init.ps1
|
||||
cd client
|
||||
py -3.12 -m venv .venv
|
||||
.\.venv\Scripts\python.exe -m pip install -e .
|
||||
.\.venv\Scripts\python.exe -m cmbuyer_client
|
||||
```
|
||||
|
||||
`client/requirements.txt` 是唯一依赖来源,`client/pyproject.toml` 动态读取它生成 wheel 的
|
||||
`Requires-Dist`。Python 3.12 已验证 6 项离线测试、编译与 wheel 元数据;完整运行时依赖安装
|
||||
(`pip install -e .`)已通过。`init.ps1` 当前仍选择 Python 3.10,因此不能声称统一入口已正确;
|
||||
桌面 GUI 与真机流程未作为 T-002 验收执行。
|
||||
(`pip install -e .`)已通过。`init.ps1` 优先使用合规既有 venv,缺失时自动选择最高的 Python 3.11+;
|
||||
本机现有 venv 实际验证为 Python 3.12。桌面 GUI 与真机流程未作为 T-003 验收执行。
|
||||
|
||||
## 关键背景
|
||||
|
||||
|
||||
+7
-3
@@ -3,7 +3,7 @@ id: T-003
|
||||
title: 建立双端统一初始化与验证入口
|
||||
phase: 0
|
||||
deps: [T-001, T-002]
|
||||
status: DOING
|
||||
status: DONE
|
||||
created: 2026-08-03
|
||||
vikunja_task_id: 20
|
||||
context_ref: bcec012
|
||||
@@ -19,7 +19,7 @@ write_paths:
|
||||
- docs/current-state.md
|
||||
---
|
||||
|
||||
<!-- BEGIN VIKUNJA EXPORT id=20 synced=2026-08-03T10:35:06Z sha256=24a880be86ebfda9b3176ed3fdbfae289c750427baa67eaa5207e4eb69a1841e -->
|
||||
<!-- BEGIN VIKUNJA EXPORT id=20 synced=2026-08-03T10:55:26Z sha256=ded66098a74140a3738f1afd64299eb429325a72fdd018aeb1dabbedc89cca56 -->
|
||||
## 问题 / 背景
|
||||
|
||||
T-001 与 T-002 已建立两端可运行骨架,但仓库根 init.ps1 / init.sh 仍沿用占位命令:Windows 默认 Python 3.10 不满足 client 的 Python 3.11+ 下限,桌面端仍按 requirements.txt 安装而不是规范的 editable package,启动命令也指向不存在的 src/main.py。统一入口若不能主动验证工具链和两端基线,后续任务会在错误环境上叠加实现。
|
||||
@@ -48,7 +48,11 @@ T-001 与 T-002 已建立两端可运行骨架,但仓库根 init.ps1 / init.sh
|
||||
|
||||
## 执行记录
|
||||
|
||||
(暂无)
|
||||
### 2026-08-03T10:54:57Z · ila
|
||||
|
||||
主 agent 终审通过:init.ps1/init.sh 已成为双端统一安装与离线门禁入口;不启动产品、不连接设备、不触发采购、下单或付款动作。
|
||||
Windows 入口优先复用并验证现有 Python 3.11+ venv,仅缺失时从 Launcher 合规版本确定性创建;安装、包导入、unittest、compileall、validator 全部使用同一 venv Python。当前实测 venv 为 Python 3.12。
|
||||
独立验证:在已合入 T-004 的最新组合基线上连续两次运行 init.ps1 成功;admin test/vet/build、client 6 tests/compileall、validator 通过。Python 3.10 venv fixture 与仅 3.10/3.9 Launcher fixture 均 fail closed;bash -n 通过,WSL 缺 Go 时明确非零退出。
|
||||
<!-- END VIKUNJA EXPORT -->
|
||||
|
||||
## 边界
|
||||
|
||||
@@ -1,84 +1,149 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
# cmbuyer 标准启动与验证入口(Windows PowerShell 版),与 init.sh 等价,二选一:
|
||||
# - Windows 原生 PowerShell:./init.ps1
|
||||
# - WSL / Git Bash:./init.sh
|
||||
#
|
||||
# 本项目是双产品结构:admin/(采购服务,Go)+ client/(采购工具,Python)。脚本按
|
||||
# admin/go.mod 与 client/requirements.txt 两个初始化哨兵分别处理;未初始化的一端会跳过并
|
||||
# 提示对应任务,不会把空目录误判为可运行项目,也不会静默通过。
|
||||
#
|
||||
# T-001 / T-002 / T-003 落地后,把下面的命令补全,并同步:
|
||||
# docs/03-tech-stack.md、docs/00-ai-start-here.md、docs/current-state.md
|
||||
# cmbuyer Windows 统一安装、验证与启动入口。
|
||||
# 这个入口只处理开发环境和离线门禁,不连接设备,也不触发采购、下单或付款动作。
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
Set-Location -Path $PSScriptRoot
|
||||
|
||||
# Go 工具链固定用本机版本,避免自动下载
|
||||
# Go 工具链固定用本机版本,避免自动下载造成不可复现的环境漂移。
|
||||
$env:GOTOOLCHAIN = "local"
|
||||
|
||||
$AdminDir = Join-Path $PSScriptRoot "admin"
|
||||
$ClientDir = Join-Path $PSScriptRoot "client"
|
||||
$Pending = @()
|
||||
$ClientVenv = Join-Path $ClientDir ".venv"
|
||||
$ClientPython = Join-Path $ClientVenv "Scripts\python.exe"
|
||||
|
||||
function Fail([string]$Message) {
|
||||
throw $Message
|
||||
}
|
||||
|
||||
function Require-Directory([string]$Path, [string]$Name) {
|
||||
if (-not (Test-Path -LiteralPath $Path -PathType Container)) {
|
||||
Fail "$Name 目录不存在:$Path。请先完成对应初始化任务。"
|
||||
}
|
||||
}
|
||||
|
||||
function Require-File([string]$Path, [string]$Name) {
|
||||
if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
|
||||
Fail "$Name 不存在:$Path。请先完成对应初始化任务。"
|
||||
}
|
||||
}
|
||||
|
||||
function Require-Command([string]$Name, [string]$Hint) {
|
||||
if (-not (Get-Command $Name -ErrorAction SilentlyContinue)) {
|
||||
Fail "缺少 $Name。$Hint"
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-Step([string]$Description, [scriptblock]$Action) {
|
||||
Write-Host "==> $Description"
|
||||
& $Action
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Fail "$Description 失败,退出码:$LASTEXITCODE"
|
||||
}
|
||||
}
|
||||
|
||||
function Confirm-Python311OrNewer([string]$PythonExecutable, [string]$Context) {
|
||||
& $PythonExecutable -c "import sys; raise SystemExit(0 if sys.version_info >= (3, 11) else 1)"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Fail "$Context 必须使用 Python 3.11+。不会自动覆盖既有虚拟环境;请手工删除 client/.venv 后重试。"
|
||||
}
|
||||
}
|
||||
|
||||
function Select-PythonLauncherSelector() {
|
||||
$launcherLines = @(& py -0p)
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Fail "无法从 Python Launcher 枚举已安装版本。请安装 Python 3.11+ 并确认 py -0p 可运行。"
|
||||
}
|
||||
|
||||
$minimumVersion = [version]::new(3, 11)
|
||||
$candidates = @()
|
||||
foreach ($line in $launcherLines) {
|
||||
$selectorMatch = [regex]::Match([string]$line, '^\s*-V:(?<selector>\S+)(?:\s+\*)?\s+(?<path>.+?)\s*$')
|
||||
if (-not $selectorMatch.Success) {
|
||||
continue
|
||||
}
|
||||
|
||||
$selector = $selectorMatch.Groups['selector'].Value
|
||||
$pythonPath = $selectorMatch.Groups['path'].Value
|
||||
$versionMatch = [regex]::Match($selector, '(?<major>\d+)\.(?<minor>\d+)(?:\.(?<patch>\d+))?')
|
||||
if (-not $versionMatch.Success) {
|
||||
continue
|
||||
}
|
||||
|
||||
$patch = if ($versionMatch.Groups['patch'].Success) { [int]$versionMatch.Groups['patch'].Value } else { 0 }
|
||||
$version = [version]::new(
|
||||
[int]$versionMatch.Groups['major'].Value,
|
||||
[int]$versionMatch.Groups['minor'].Value,
|
||||
$patch
|
||||
)
|
||||
if ($version -ge $minimumVersion) {
|
||||
$candidates += [PSCustomObject]@{ Selector = $selector; Version = $version; Path = $pythonPath }
|
||||
}
|
||||
}
|
||||
|
||||
if ($candidates.Count -eq 0) {
|
||||
Fail "Python Launcher 未发现 Python 3.11+。当前默认 python 不会作为回退;请安装合规版本后重试。"
|
||||
}
|
||||
|
||||
$selected = $candidates | Sort-Object @{ Expression = 'Version'; Descending = $true }, @{ Expression = 'Selector'; Descending = $false } | Select-Object -First 1
|
||||
Write-Host "==> 选择 Python Launcher 解释器:-V:$($selected.Selector)($($selected.Version))"
|
||||
return $selected
|
||||
}
|
||||
|
||||
Write-Host "==> 当前目录: $($PWD.Path)"
|
||||
|
||||
# ------------------------------------------------------- 采购服务(admin/,Go)
|
||||
if (Test-Path (Join-Path $AdminDir "go.mod") -PathType Leaf) {
|
||||
Write-Host "==> 采购服务:admin/ 同步依赖"
|
||||
Push-Location $AdminDir
|
||||
try {
|
||||
go mod download
|
||||
Write-Host "==> 采购服务:admin/ 静态检查"
|
||||
go vet ./...
|
||||
Write-Host "==> 采购服务:admin/ 测试"
|
||||
go test ./...
|
||||
} finally {
|
||||
Pop-Location
|
||||
Require-Directory $AdminDir "采购服务 admin"
|
||||
Require-File (Join-Path $AdminDir "go.mod") "采购服务哨兵 admin/go.mod"
|
||||
Require-Directory $ClientDir "采购工具 client"
|
||||
Require-File (Join-Path $ClientDir "requirements.txt") "采购工具哨兵 client/requirements.txt"
|
||||
Require-File (Join-Path $ClientDir "pyproject.toml") "采购工具打包配置 client/pyproject.toml"
|
||||
Require-Command "go" "请安装 Go 1.23+ 并重新打开 PowerShell。"
|
||||
if (Test-Path -LiteralPath $ClientVenv) {
|
||||
if (-not (Test-Path -LiteralPath $ClientVenv -PathType Container)) {
|
||||
Fail "client/.venv 不是目录。不会覆盖该路径,请人工处理后重试。"
|
||||
}
|
||||
Require-File $ClientPython "既有 client/.venv Python"
|
||||
Confirm-Python311OrNewer $ClientPython "既有 client/.venv"
|
||||
} else {
|
||||
Write-Host "==> 采购服务:admin/go.mod 不存在,跳过。先做 T-001(初始化 admin/ Go 骨架)。"
|
||||
$Pending += "T-001 初始化采购服务 admin/ Go 骨架"
|
||||
# 默认 python 在本机可能仍指向 3.10;仅在需要新建 venv 时,从 Launcher 中确定性选择最高的合规版本。
|
||||
Require-Command "py" "请安装 Python Launcher 和 Python 3.11+。"
|
||||
$PythonRuntime = Select-PythonLauncherSelector
|
||||
Require-File $PythonRuntime.Path "Python Launcher 选择的解释器"
|
||||
Invoke-Step "验证所选 Python Launcher 解释器" { & $PythonRuntime.Path -c "import sys; print(sys.version); raise SystemExit(0 if sys.version_info >= (3, 11) else 1)" }
|
||||
Invoke-Step "创建所选 Python 3.11+ 采购工具虚拟环境" { & $PythonRuntime.Path -m venv $ClientVenv }
|
||||
Require-File $ClientPython "新建 client/.venv Python"
|
||||
Confirm-Python311OrNewer $ClientPython "新建 client/.venv"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------- 采购工具(client/,Python)
|
||||
if (Test-Path (Join-Path $ClientDir "requirements.txt") -PathType Leaf) {
|
||||
Write-Host "==> 采购工具:client/ 同步依赖"
|
||||
Push-Location $ClientDir
|
||||
try {
|
||||
if (-not (Test-Path ".venv")) {
|
||||
python -m venv .venv
|
||||
}
|
||||
& ".venv\Scripts\python.exe" -m pip install -q -r requirements.txt
|
||||
Write-Host "==> 采购工具:client/ 语法检查"
|
||||
& ".venv\Scripts\python.exe" -m compileall -q src tests
|
||||
Write-Host "==> 采购工具:client/ 测试"
|
||||
& ".venv\Scripts\python.exe" -m unittest discover -s tests -t .
|
||||
} finally {
|
||||
# 后续所有采购工具检查与仓库 validator 均使用同一个合规 venv 解释器,避免混用宿主 Python。
|
||||
Invoke-Step "验证采购工具虚拟环境 Python" { & $ClientPython -c "import sys; print(sys.version); raise SystemExit(0 if sys.version_info >= (3, 11) else 1)" }
|
||||
|
||||
Push-Location $AdminDir
|
||||
try {
|
||||
Invoke-Step "采购服务:admin/ 同步依赖" { go mod download }
|
||||
Invoke-Step "采购服务:admin/ 测试" { go test ./... }
|
||||
Invoke-Step "采购服务:admin/ 静态检查" { go vet ./... }
|
||||
Invoke-Step "采购服务:admin/ 构建" { go build ./... }
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
} else {
|
||||
Write-Host "==> 采购工具:client/requirements.txt 不存在,跳过。先做 T-002(初始化 client/ Python 骨架)。"
|
||||
$Pending += "T-002 初始化采购工具 client/ Python 骨架"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------ 文档自检
|
||||
Write-Host "==> 校验 agent 上下文清单"
|
||||
python scripts/validate_agent_context.py
|
||||
|
||||
# -------------------------------------------------------------------- 汇总
|
||||
Write-Host ""
|
||||
if ($Pending.Count -gt 0) {
|
||||
Write-Host "==> 尚未初始化的部分:"
|
||||
foreach ($item in $Pending) { Write-Host " - $item" }
|
||||
Write-Host ""
|
||||
Write-Host "当前仓库只有文档。按 docs/06-tasks.md 领取上述任务后再运行本脚本。"
|
||||
exit 3
|
||||
Push-Location $ClientDir
|
||||
try {
|
||||
Invoke-Step "采购工具:以 editable 方式安装" { & $ClientPython -m pip install -e . }
|
||||
Invoke-Step "采购工具:验证已安装包" { & $ClientPython -c "import cmbuyer_client; print(cmbuyer_client.__version__)" }
|
||||
Invoke-Step "采购工具:测试" { & $ClientPython -m unittest discover -s tests -t . }
|
||||
Invoke-Step "采购工具:语法检查" { & $ClientPython -m compileall -q src tests scripts }
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
Write-Host "==> 启动命令"
|
||||
Write-Host " 采购服务:cd admin ; go run ./cmd/server"
|
||||
Write-Host " 采购工具:cd client ; .venv\Scripts\python.exe src/main.py"
|
||||
Invoke-Step "校验 agent 上下文清单" { & $ClientPython scripts/validate_agent_context.py }
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "基础验证失败时先修基线,不要在坏的起点上继续叠新功能。"
|
||||
Write-Host "真机连接与设备验收只能由人工完成,agent 不得据此把任务标为 DONE。"
|
||||
Write-Host "==> 基线验证通过。启动命令:"
|
||||
Write-Host " 采购服务:cd admin; go run ./cmd/server"
|
||||
Write-Host " 采购工具:cd client; .\.venv\Scripts\python.exe -m cmbuyer_client"
|
||||
Write-Host ""
|
||||
Write-Host "真机连接与设备验收只能由人工完成;本入口不执行任何采购、下单或付款动作。"
|
||||
|
||||
@@ -1,69 +1,88 @@
|
||||
#!/usr/bin/env bash
|
||||
# cmbuyer 标准启动与验证入口(Unix shell 版),与 init.ps1 等价,二选一。
|
||||
#
|
||||
# 注意:本项目的构建与验证工具链只在 Windows 侧(Go SDK、Python 环境、Android SDK)。
|
||||
# 在 WSL 中运行本脚本通常会因缺少工具链而失败——这是预期行为,不是 bug。
|
||||
# 正式验证请在 Windows PowerShell 运行 ./init.ps1。
|
||||
# 双产品目录为 admin/(采购服务,Go)与 client/(采购工具,Python);分别以 go.mod 与
|
||||
# requirements.txt 作为初始化哨兵,不能只按空目录存在判断。
|
||||
#
|
||||
# T-001 / T-002 / T-003 落地后补全命令,并同步:
|
||||
# docs/03-tech-stack.md、docs/00-ai-start-here.md、docs/current-state.md
|
||||
# cmbuyer Unix shell 统一安装、验证与启动入口。
|
||||
# 本脚本与 init.ps1 保持同一门禁语义;在 WSL 缺少 Windows 侧工具链时必须明确失败,
|
||||
# 不得将跳过或 bash 语法通过误报为 Windows 产品验收。
|
||||
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
export GOTOOLCHAIN=local
|
||||
|
||||
pending=()
|
||||
fail() {
|
||||
echo "错误:$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
require_directory() {
|
||||
local path="$1"
|
||||
local name="$2"
|
||||
[[ -d "$path" ]] || fail "$name 目录不存在:$path。请先完成对应初始化任务。"
|
||||
}
|
||||
|
||||
require_file() {
|
||||
local path="$1"
|
||||
local name="$2"
|
||||
[[ -f "$path" ]] || fail "$name 不存在:$path。请先完成对应初始化任务。"
|
||||
}
|
||||
|
||||
require_command() {
|
||||
local name="$1"
|
||||
local hint="$2"
|
||||
command -v "$name" >/dev/null 2>&1 || fail "缺少 $name。$hint"
|
||||
}
|
||||
|
||||
run_step() {
|
||||
local description="$1"
|
||||
shift
|
||||
echo "==> $description"
|
||||
"$@" || fail "$description 失败。"
|
||||
}
|
||||
|
||||
confirm_python311_or_newer() {
|
||||
local executable="$1"
|
||||
local context="$2"
|
||||
"$executable" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 11) else 1)' \
|
||||
|| fail "$context 必须使用 Python 3.11+。不会自动覆盖既有虚拟环境;请手工删除 client/.venv 后重试。"
|
||||
}
|
||||
|
||||
echo "==> 当前目录: $(pwd)"
|
||||
require_directory admin "采购服务 admin"
|
||||
require_file admin/go.mod "采购服务哨兵 admin/go.mod"
|
||||
require_directory client "采购工具 client"
|
||||
require_file client/requirements.txt "采购工具哨兵 client/requirements.txt"
|
||||
require_file client/pyproject.toml "采购工具打包配置 client/pyproject.toml"
|
||||
require_command go "请安装 Go 1.23+ 后重试。"
|
||||
|
||||
# ------------------------------------------------------- 采购服务(admin/,Go)
|
||||
if [ -f admin/go.mod ]; then
|
||||
echo "==> 采购服务:admin/ 同步依赖"
|
||||
( cd admin && go mod download )
|
||||
echo "==> 采购服务:admin/ 静态检查"
|
||||
( cd admin && go vet ./... )
|
||||
echo "==> 采购服务:admin/ 测试"
|
||||
( cd admin && go test ./... )
|
||||
client_python="client/.venv/bin/python"
|
||||
if [[ -e client/.venv ]]; then
|
||||
[[ -d client/.venv ]] || fail "client/.venv 不是目录。不会覆盖该路径,请人工处理后重试。"
|
||||
require_file "$client_python" "既有 client/.venv Python"
|
||||
confirm_python311_or_newer "$client_python" "既有 client/.venv"
|
||||
else
|
||||
echo "==> 采购服务:admin/go.mod 不存在,跳过。先做 T-001(初始化 admin/ Go 骨架)。"
|
||||
pending+=("T-001 初始化采购服务 admin/ Go 骨架")
|
||||
require_command python3 "请安装 Python 3.11+ 后重试。"
|
||||
confirm_python311_or_newer python3 "python3"
|
||||
run_step "创建 Python 3.11+ 采购工具虚拟环境" python3 -m venv client/.venv
|
||||
require_file "$client_python" "新建 client/.venv Python"
|
||||
confirm_python311_or_newer "$client_python" "新建 client/.venv"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------- 采购工具(client/,Python)
|
||||
if [ -f client/requirements.txt ]; then
|
||||
echo "==> 采购工具:client/ 同步依赖"
|
||||
( cd client \
|
||||
&& { [ -d .venv ] || python3 -m venv .venv; } \
|
||||
&& .venv/bin/python -m pip install -q -r requirements.txt )
|
||||
echo "==> 采购工具:client/ 语法检查"
|
||||
( cd client && .venv/bin/python -m compileall -q src tests )
|
||||
echo "==> 采购工具:client/ 测试"
|
||||
( cd client && .venv/bin/python -m unittest discover -s tests -t . )
|
||||
else
|
||||
echo "==> 采购工具:client/requirements.txt 不存在,跳过。先做 T-002(初始化 client/ Python 骨架)。"
|
||||
pending+=("T-002 初始化采购工具 client/ Python 骨架")
|
||||
fi
|
||||
run_step "验证采购工具虚拟环境 Python" "$client_python" -c 'import sys; print(sys.version); raise SystemExit(0 if sys.version_info >= (3, 11) else 1)'
|
||||
|
||||
# ------------------------------------------------------------------ 文档自检
|
||||
echo "==> 校验 agent 上下文清单"
|
||||
python3 scripts/validate_agent_context.py
|
||||
( cd admin && run_step "采购服务:admin/ 同步依赖" go mod download )
|
||||
( cd admin && run_step "采购服务:admin/ 测试" go test ./... )
|
||||
( cd admin && run_step "采购服务:admin/ 静态检查" go vet ./... )
|
||||
( cd admin && run_step "采购服务:admin/ 构建" go build ./... )
|
||||
|
||||
( cd client && run_step "采购工具:以 editable 方式安装" .venv/bin/python -m pip install -e . )
|
||||
( cd client && run_step "采购工具:验证已安装包" .venv/bin/python -c 'import cmbuyer_client; print(cmbuyer_client.__version__)' )
|
||||
( cd client && run_step "采购工具:测试" .venv/bin/python -m unittest discover -s tests -t . )
|
||||
( cd client && run_step "采购工具:语法检查" .venv/bin/python -m compileall -q src tests scripts )
|
||||
|
||||
run_step "校验 agent 上下文清单" "$client_python" scripts/validate_agent_context.py
|
||||
|
||||
# -------------------------------------------------------------------- 汇总
|
||||
echo
|
||||
if [ ${#pending[@]} -gt 0 ]; then
|
||||
echo "==> 尚未初始化的部分:"
|
||||
for item in "${pending[@]}"; do echo " - $item"; done
|
||||
echo
|
||||
echo "当前仓库只有文档。按 docs/06-tasks.md 领取上述任务后再运行本脚本。"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
echo "==> 启动命令"
|
||||
echo "==> 基线验证通过。启动命令:"
|
||||
echo " 采购服务:cd admin && go run ./cmd/server"
|
||||
echo " 采购工具:cd client && .venv/bin/python src/main.py"
|
||||
echo " 采购工具:cd client && .venv/bin/python -m cmbuyer_client"
|
||||
echo
|
||||
echo "基础验证失败时先修基线,不要在坏的起点上继续叠新功能。"
|
||||
echo "真机连接与设备验收只能由人工完成,agent 不得据此把任务标为 DONE。"
|
||||
echo "WSL / Unix shell 仅在本机工具链齐备时能通过;这不构成 Windows 或真机验收。"
|
||||
|
||||
Reference in New Issue
Block a user