Files
cad-agent/CODEBUDDY.md
T
gjm 2fa27b1161 fix(mcp_frame): c++_dll 版本校验默认只比大版本,R24.3 单独分组
- acrxGetApiVersion 返回值编码为 (major<<16)|minor,据此拆分大/小版本
  (实测 R22.0=0x160000、R23.0=0x170000)。
- 同一大版本内二进制兼容(R24.0/R24.1/R24.2 可共用 ARX;2019/R23.0 编的 ARX
  可跑在 2020/R23.1 上),故默认只比大版本,避免为每个小版本各编一份。
- 唯一例外 R24.3:换了 MSVC toolset,与 R24.0~R24.2 不兼容,
  对 major==24 再按 minor>=3 分组判定。
- 同步更新 CODEBUDDY.md 与 ai.memory 说明。
2026-10-09 23:42:05 +08:00

88 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CODEBUDDY.md
This file provides guidance to CodeBuddy Code when working with code in this repository.
## 项目概述
CADProject 是一个将 **AutoCAD / 中望 CAD (ZWCAD)** 变为 MCP (Model Context Protocol) 服务端的插件工程。CAD 进程内运行一个 TCP JSON-RPC 服务,向大模型暴露 `tools/list` 与 `tools/call`,让 LLM 能驱动 CAD 执行绘图、缩放、截图等操作。仓库同时附带一组 Python 客户端脚本用于联调。
## 构建
构建系统为 **CMake + vcpkg + Visual Studio 生成器**,通过 CMake Presets 区分 CAD 版本。产物输出到 `bin/<Config>-<TAG>/` 与 `lib/<Config>-<TAG>/`。
```bash
# 配置 + 构建单个版本(以 R243 为例)
cmake --preset R243
cmake --build --preset R243 --config Release
# 或使用根目录脚本批量处理(内部即上面两条命令的组合)
./preset.bat # 仅 configure: R190 / R230 / R220
./build.bat # build --config release: R230 / R220
```
- **前置环境**:需要 `VCPKG_ROOT` 环境变量;第三方 CAD SDK 位于仓库同级的 `../envi-code/Arx`(AutoCAD)与 `../envi-code/Zrx`(ZWCAD),路径在 `cmakepresets.json` 的 `CAD_SDK_ROOT` 中配置。
- **可用 preset**:`R180`–`R260`(AutoCAD,ARX 18–26)、`Z2023`–`Z2026`(ZWCAD,ZRX)。每个 preset 绑定对应的 MSVC toolset(v90–v143)。preset 名称同时决定输出目录标签 `GENERATE_DIR_TAG`(如 `R243`、`Z2024`)。
- **必需 cache 变量**(缺失会 `FATAL_ERROR`):`CAD_SDK_ROOT`、`DEP_LIB_ROOT`、`DEP_INC_ROOT`、`CAD_SDK_VERSION`,AutoCAD 版还需 `CAD_SDK_SUBVERSION`。
- vcpkg 依赖见 `vcpkg.json`:`nlohmann-json`、`curl`、`ghc-filesystem`;triplet 为 `x64-windows-static-md`(静态库 + 动态 CRT,定义于 `cmake/x64-windows-static-md.cmake`)。
### 测试
工程内**没有单元测试框架**。所谓“测试”是根目录下的 Python 脚本,它们是 MCP 客户端的联调工具,**必须先启动已加载插件的 CAD,并确认 8080 端口在监听**:
```bash
python test.py # 最小示例:截图 -> 发给 DeepSeek 视觉模型 -> 回答
python test_autoagent.py # 仅拉取一次视口截图并保存为 test_screenshot.png
python countOfCircle.py # 伪造一次 zoom_window_normalized 调用,验证 TCP 链路
python agent_loop.py # 完整 Agent 循环(多回合 截图/缩放/结论),需 openai 包与 API Key
```
脚本通过 TCP 连接 `127.0.0.1:8080` 收发 JSON-RPC。`agent_loop.py` / `test.py` 中硬编码了 DeepSeek API Key 与模型名,属于调试脚本。
## 架构
### 两个构建目标
| 目标 | 产物 | 作用 |
| --- | --- | --- |
| `src/cad_mcp_frame` | `cad_mcp_frame.arx`(ZWCAD 下为 `.zrx`) | MCP **基座**。随 CAD 加载,起 TCP 服务、解析工具配置、路由执行。 |
| `src/cad_mcp_plugins` | `cad_mcp_plugins.dll` | 示例 **C++ 工具插件**,通过 ABI 被基座动态加载。 |
### 基座运行模型(`src/cad_mcp_frame/`)
1. CAD 加载 `.arx` → `acrxEntryPoint(kInitAppMsg)` → `mcp::init_mcp_server()`(`cad_mcp_frame.cpp:41`)。
2. `init_mcp_server()`(`mcp_server.cpp:225`)在主 UI 线程创建**仅消息窗口**(`HWND_MESSAGE`,`McpWndProc`),并启动后台 `TcpServerLoop` 线程监听 `127.0.0.1:8080`。
3. **跨线程安全是核心设计**:TCP 线程只负责 `recv`,把请求封装成 `TaskData`(含 socket)后 `PostMessage(WM_MCP_EXECUTE_TASK)` 投递给消息窗口。真正的工具执行 `ExecuteTaskInMainThread()` 运行在 **CAD 主线程**,从而安全调用 ARX API。执行结果再通过该 socket 发回。
4. 配置加载:`mcp_ConfigParser::LoadAndRegister()` 读取模块所在目录下的 `mcp_config.json`(`getModelDirPath()`,即 `.arx` 同级目录),按 `tools[].backend.type` 注册工具到全局 `mcp_Tools` 注册表(`unordered_map<name, shared_ptr<mcp_Tool>>`)。
5. 卸载:`close_mcp_server()` 停线程、销毁消息窗口、清空工具表。
支持的 JSON-RPC 方法:`tools/list`(返回所有工具描述)、`tools/call`(路由到 `mcp_Tools::Call`)。非法 JSON 返回 `-32700`,未知方法返回 `-32601`。
### 三种工具后端(`backend.type`)
- **`lisp_inline`**:把 `script_template` 中的 `{占位符}` 替换为调用参数,`sendStringToExecute` 到命令行(异步)。布尔值转 `T`/`nil`。见 `mcp_tool.cpp:43`。
- **`lisp_file`**:先 `(load "文件" nil)` 再执行 `call_template`,`file_name` 相对于配置中的 `lisp_directory` 解析。见 `mcp_tool.cpp:61`。
- **`c++_dll`**:`LoadLibrary` 第三方 DLL。**同一 DLL 全进程只加载一次**(句柄由 `mcp_configParser.cpp` 的模块缓存 `g_loadedDllModules` 持有,`mcp_Tools::clear()` 时统一 `FreeLibrary`),仅**首次加载**时校验版本兼容性:`acrxGetApiVersion` 返回值编码为 `(major<<16)|minor`,**默认只比大版本**(同一大版本内二进制兼容,如 R24.0/R24.1/R24.2 可共用同一 ARX);**唯一例外 R24.3**(换了 MSVC toolset,与 R24.0~R24.2 不兼容),对 `major==24` 再按 `minor>=3` 分组。基座侧版本用**编译期常量** `ARX`/`SUB_ARX`。注意运行时的 `acrxGetApiVersion`(`rxapi.lib` 的 `acrxGetApiVersionImpl`)是**有状态实现**,返回值会随调用次数变化,不能用作基座侧版本。取 `factory_function` 与 `Destroy_<factory>` 创建/销毁工具,用 `mcp_Tool_DllProxy` 托管工具对象生命周期(RAII,**不再 FreeLibrary 模块**)。跨 DLL 通过 `SetConfigAbiSafe` / `ExecuteAbiSafe` 传 C 字符串,JSON 序列化全部在 DLL 内部完成。见 `mcp_configParser.cpp`、`mcp_tool.cpp`。
### 插件 ABI(`inc/mcp_plugin_api.h`)
第三方工具只需继承 `mcp_Tool`,实现纯虚 `Execute(args)`,并用 `EXPORT_MCP_TOOL(ToolClass, FactoryName)` 宏导出工厂 + 销毁函数。`mcp_Tool_Utility` 提供 `make_text_result` / `make_image_result` / `make_mixed_result` / `make_error` 等返回体构造器。`mcp_plugins.cpp` 中的 `mcp_Tool_ViewportScreenshot`(GDI+ 抓屏 → PNG → Base64 → 多模态返回)是完整参考实现。
### 关键头文件
- `inc/cadsdk.h`:ARX 开发总伞头文件,一次性引入几乎所有 ObjectARX/ZWCAD 头文件,处理 ZWCAD 与 AutoCAD 的宏/库差异。业务 `.cpp` 通常只需 `#include "cadsdk.h"`。
- `src/cad_mcp_frame/StdAfx.h`:预编译头(MFC + Windows),是 `cad_mcp_frame` 的 PCH 入口。
### 配置与产物布局
- 运行时配置:`mcp_config.json`,必须与 `.arx` 同目录。示例见 `bin/Debug-R230/mcp_config.json`(含 `zoom_window_normalized`、`zoom_extents`、`get_viewport_screenshot` 三个工具);`src/cad_mcp_frame/cad-mcp-frame.json` 是模板(文件名带连字符,非运行时文件)。
- `global_settings.plugin_directory` 指向 C++ DLL 目录,`lisp_directory` 指向 LISP 目录(默认都相对模块目录)。示例 LISP 见 `bin/Debug-R230/mcp_plugins/mcp_table_array.lsp`。
- `cmake/functions.cmake` 提供工程级封装:`target_link_objectarx`(自动按 ZWCAD 与否链接 `ThirdParty::ZRX`/`ThirdParty::ARX`、注入 `ARX`/`SUB_ARX` 宏)、`target_set_name_and_suffix`(`.arx` 在 ZWCAD 下自动变 `.zrx`)、`add_def_file_name`、`set_debug_post_build` 等。新增目标应复用这些函数而非手写链接。
- `cmake/ThirdPartyDeps.cmake` 注册所有 `ThirdParty::*` INTERFACE 目标(ARX/ZRX/cURL/SQLite3/BitAnswer/modernGlue/CadOcr)。
## 约定与注意点
- **不要改动线程模型**:任何涉及 ARX API 的工具逻辑必须在主线程(`ExecuteTaskInMainThread` 派发链)中执行,不能在 `TcpServerLoop` 线程里直接调用。
- **C++ 标准随 SDK 版本浮动**:`cmakelists.txt` 按 `CAD_SDK_VERSION` 自动设定 C++98/03/14/20,跨版本改动需兼容旧标准(低版本 SDK 最高只到 C++14)。
- 新增 CAD 版本支持时,需在 `cmakepresets.json` 同步添加 `configurePresets` 与 `buildPresets`,并在 `cmake/ThirdPartyDeps.cmake` 中确认对应库列表(如 `CAD_SDK_VERSION GREATER 23` 时追加 `acpal.lib`/`acgeoment.lib`)。
- `bin/`、`lib/`、`out/` 均为构建产物,已在 `.gitignore` 中忽略;源码在 `src/`、`inc/`、`cmake/`。