DaVinci MCP Server
README.md
# DaVinci MCP Server
把 **Vector DaVinci Configurator 6 / 5** 与 **DaVinci Developer Classic** 的命令行工具,包装成一套面向 AI Agent 的 [MCP](https://modelcontextprotocol.io) 工具集。
Agent 可以直接说「校验这个工程、把错误修掉、生成代码」,而不需要记住 `dvcfg-b` / `DVCfgCmd` 的几十个参数、`-p=` 的写法、退出码含义和 Config Core 的并发限制。
同一套工具同时覆盖两代工程:`.dvjson` 走 `dvcfg-b`(CFG6),`.dpa` 走 `DVCfgCmd`(CFG5),由服务按后缀自动路由。
CFG5 没有 `project create` 这样的命令,因此工程创建用**模板克隆**实现:复制标准工程、重写工程名与路径、再跑一次校验。
还支持 **Groovy Automation Interface**:Agent 可以按模板生成 `.dv.groovy`、做静态与编译检查、执行任务,
把「只有 GUI 才能做的批量改配置 / 查询 / 出报告」变成可复用的脚本。
脚本怎么写不靠模型记忆——`davinci_api_index` 直接从安装目录的 JAR 里反射出真实的类与方法
(纯 Python 解析 class 文件,不需要 JDK),`davinci_script_api` 负责查;没有安装目录时退回
一份按能力域组织、每条都有官方出处的内置目录。写之前先查、写完再核对。
其中 `DV_ON_GENERATION_START` / `DV_GENERATION_STEP` 两类任务可以挂进 CFG5 的生成流程:
在生成前跑自定义检查,发现问题时用 `resultSink` 报 ERROR,直接中止生成。
再往上加了一层 **ECUC 只读分析**(可选依赖 [py-armodel](https://github.com/melodypapa/py-armodel)):
命令行只能整工程校验,看不了单个参数;这一层把 ARXML 解析成可查询的语义视图,
支持参数检索、两份配置的语义 diff、结构体检与清单导出,补上 CFG5 CLI 的空白。
最后补了一块 **AUTOSAR 版本探测与模块资产**:回答「这个工程 / 这个模块是按哪个 AUTOSAR 版本做的」,
并定位每个模块的 Vector User Manual 与静态代码,让参数级问题能「规范 → 手册 → 代码」三源对照。
版本对了,Agent 才能去查对应版本的规范;否则拿最新版文档解释旧工程,参数名和可选项早已变样。
探测不靠猜——只采信工程设置字段、ARXML 的 `xsi:schemaLocation`、模块 `ADMIN-DATA` 三类证据,
每条都带出处与置信度,探不到就返回 `null`。
还有一块 **生成物清单**:Agent 要改代码时,先得知道哪些文件是生成的、改了会不会被下次生成覆盖。
生成目录不是固定常量,工具从工程设置里取证定位(CFG6 的 `Output`、CFG5 的 `Appl/GenData` 都只是默认值),
再列出目录内的文件与文件夹,逐文件标注生成证据,而不是让模型猜「这个文件看起来像生成的」。
最后是 **工程差异对比**:给两个工程,按「文件 → 设置 → 输入文件 → ECUC 参数」四层比出差异。
回放分两条路:ECUC 参数用 Groovy(`replay` 默认 `dryRun`,确认后在 `transaction` 里写入;
`verify` 只读核对,可放进 CI),输入文件(DBC/CDD/ECU Extract 等)用 DaVinci 命令行重新导入
(CFG5 `DVCfgCmd -u --input` / CFG6 `project update -c`)。为什么要分开:输入文件是配置的源头,
直接改派生出来的参数,下次导入就会被覆盖。生成物差异单独汇总,不会用几千个 `.c/.h`
淹掉真正的配置变更。
```
┌──────────────────────────────┐
Claude / Cursor │ MCP Client │
VS Code / 自研 └──────────────┬───────────────┘
│ JSON-RPC (stdio / sse)
┌──────────────▼───────────────┐
│ davinci-mcp server │
│ ┌────────────────────────┐ │
│ │ 工具层(62 个 MCP 工具)│ │
│ ├────────────────────────┤ │
│ │ 服务层:Configurator 6 / │ │
│ │ Configurator 5 / │ │
│ │ Groovy / Developer / │ │
│ │ Pipeline / ECUC / 版本 │ │
│ │ 生成物清单 / 工程差异 │ │
│ ├────────────────────────┤ │
│ │ 执行层:路径白名单、 │ │
│ │ argv 执行器、项目锁、 │ │
│ │ 后台作业、诊断解析 │ │
│ └───────────┬────────────┘ │
└──────────────┼───────────────┘
subprocess│argv(无 shell)
┌──────────────▼───────────────┐
│ dvcfg-b DVCfgCmd dvdevc │
│ CFG6 CFG5 Developer│
└──────────────────────────────┘
▲
只读解析 │ (不参与写操作)
┌──────────────┴───────────────┐
│ ARXML ── py-armodel ── 索引 │
└──────────────────────────────┘
```
## 1. 为什么需要它
| 直接用 CLI 的问题 | 本服务的处理 |
| --- | --- |
| 两代工具参数风格不同(`-p=` / `-p`、`-g` / `project generate`) | 工具参数是结构化字段,服务层按工程后缀选择后端并拼装 |
| 生成一次十几分钟,工具调用会超时 | 超过 `wait_seconds` 自动转后台作业,返回 `job_id` |
| 同一工程并发执行会写坏 Config Core | 服务端按工程加锁,直接返回 `project_busy` |
| 输出是给人看的,Agent 难以判断成败 | 解析出 `diagnostics`(错误/警告计数、文件、行号、模块) |
| 退出码 1/2/130、`dvdevc` 的 3/7 含义不明 | 统一映射为 `status` + 中文说明 + 修复建议 |
| Agent 可能把工程路径写到任意位置 | 路径白名单 + 扩展名校验 + 符号链接逃逸拦截 |
| Automation Interface 脚本 API 多、易写错 | 内置模板 + 静态检查 + DaVinci 编译检查,先预检再执行 |
| 命令行只能「整工程校验」,说不清某个参数配了什么 | 可选 py-armodel 解析成 ECUC 语义索引,支持参数检索、变体 diff 与结构体检 |
## 2. 快速开始
### 2.1 环境要求
- Python **3.10+**
- DaVinci Configurator Classic **6.2 及以上**(提供 `dvcfg-b`)— 处理 `.dvjson`
- 可选:DaVinci Configurator **5.x**(提供 `DVCfgCmd`)— 处理 `.dpa`
- 可选:DaVinci Developer Classic **4.17 SP2 及以上**(提供 `dvdevc`)
- 有效许可证 + 可用的 MICROSAR BSW 包
> CFG5 的 CLI 通常不单独安装,而是随 SIP 交付在 `<SIP>/DaVinciConfigurator/Core/DVCfgCmd.exe`。
> 只需设置 `DAVINCI_CFG5_SIP` 或 `DAVINCI_CFG5_BIN`,无需迁移工程即可直接校验与生成。
### 2.2 安装
```bash
git clone <this-repo> davinci-mcp-server
cd davinci-mcp-server
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e . # 仅 CLI 相关能力
pip install -e ".[ecuc]" # 追加 ECUC 只读分析(py-armodel)
```
> ECUC 分析是可选能力:不装 `py-armodel` 时其余工具照常工作,
> 相关工具会返回 `dependency_missing` 并提示安装命令。
### 2.3 配置
所有配置都走环境变量,**代码里没有任何硬编码安装路径**。
| 变量 | 必填 | 说明 |
| --- | --- | --- |
| `DAVINCI_DVCFG_BIN` | 建议 | `dvcfg-b` / `dvcfg-b.exe` 绝对路径;不填则查 PATH 与常见安装目录 |
| `DAVINCI_DVDEVC_BIN` | 可选 | `dvdevc` / `dvdevc.exe` 绝对路径 |
| `DAVINCI_CFG5_BIN` | 可选 | `DVCfgCmd` / `DVCfgCmd.exe` 绝对路径(最高优先级) |
| `DAVINCI_CFG5_HOME` | 可选 | CFG5 安装根目录,服务会在其 `Core/` 下找 `DVCfgCmd` |
| `DAVINCI_CFG5_SIP` | 可选 | SIP 根目录,服务会在 `DaVinciConfigurator/Core/` 下找 `DVCfgCmd` |
| `DAVINCI_HOME` | 可选 | DaVinci 安装根(含 `plugins/`)。设置后 `davinci_api_index` 可省 `home` 参数,`env_doctor` 也能提示索引状态 |
| `DAVINCI_BSW_PACKAGE` | 建议 | MICROSAR BSW 包根目录,设置后多数工具可省略 `bsw_package` |
| `DAVINCI_MCP_ROOTS` | **必填** | 允许访问的工作根目录,多个用系统路径分隔符隔开(`;` / `:`) |
| `DAVINCI_MCP_STRICT_PATHS` | 可选 | `1` 时连只读输入(BSW、待导入 ARXML)也必须在根目录内 |
| `DAVINCI_MCP_TIMEOUT` | 可选 | 单条命令硬超时,默认 900 秒 |
| `DAVINCI_MCP_MAX_JOBS` | 可选 | 并发作业上限,默认 2(不建议调大) |
| `DAVINCI_MCP_LOG_DIR` | 可选 | 作业日志目录,默认 `~/.cache/davinci-mcp/logs` |
| `DAVINCI_MCP_AUDIT_LOG` | 可选 | 审计日志(JSONL),记录每次 CLI 调用的 argv 与退出码 |
| `DAVINCI_MCP_FAIL_ON` | 可选 | 校验失败阈值,默认 `ERROR`(`NONE` / `ERROR` / `WARNING`) |
| `DAVINCI_MCP_ECUC_TIMEOUT` | 可选 | 单个 ECUC 文件的解析超时,默认 120 秒(纯 Python,与 CLI 超时无关) |
| `DAVINCI_MCP_ALLOW_RAW` | 可选 | 预留的原始透传开关(默认关闭) |
Windows 示例(PowerShell):
```powershell
$env:DAVINCI_DVCFG_BIN = "D:\Vector\DaVinciConfigurator\CLI\dvcfg-b.exe"
$env:DAVINCI_DVDEVC_BIN = "D:\Vector\DaVinciDeveloper\Bin\dvdevc.exe"
$env:DAVINCI_CFG5_SIP = "D:\Vector\SIP\MICROSAR_R22-11"
$env:DAVINCI_BSW_PACKAGE = "D:\Vector\MICROSAR\BSW"
$env:DAVINCI_MCP_ROOTS = "D:\work\ecu"
```
Linux 示例:
```bash
export DAVINCI_DVCFG_BIN=/opt/vector/davinci-configurator/CLI/dvcfg-b
export DAVINCI_CFG5_BIN=/opt/vector/sip/DaVinciConfigurator/Core/DVCfgCmd
export DAVINCI_BSW_PACKAGE=/opt/vector/micrsar/bsw
export DAVINCI_MCP_ROOTS=/home/dev/ecu
```
### 2.4 接入 MCP 客户端
**Claude Code / 通用 stdio 客户端**(`mcp.json` 或 `~/.claude.json`):
```json
{
"mcpServers": {
"davinci": {
"command": "davinci-mcp",
"args": ["serve"],
"env": {
"DAVINCI_DVCFG_BIN": "D:/Vector/DaVinciConfigurator/CLI/dvcfg-b.exe",
"DAVINCI_CFG5_SIP": "D:/Vector/SIP/MICROSAR_R22-11",
"DAVINCI_BSW_PACKAGE": "D:/Vector/MICROSAR/BSW",
"DAVINCI_MCP_ROOTS": "D:/work/ecu"
}
}
}
}
```
**VS Code(`.vscode/mcp.json`)**:
```json
{
"servers": {
"davinci": {
"type": "stdio",
"command": "davinci-mcp",
"args": ["serve"],
"env": { "DAVINCI_MCP_ROOTS": "${workspaceFolder}" }
}
}
}
```
**远程 / 多客户端(HTTP)**:
```bash
davinci-mcp serve --transport streamable-http --host 127.0.0.1 --port 8765
```
### 2.5 自检
```bash
davinci-mcp doctor # 检查 dvcfg-b / DVCfgCmd / dvdevc / BSW / 根目录 / 许可证提示
davinci-mcp list-tools # 列出注册的 62 个工具
davinci-mcp config # 打印当前配置
```
## 3. 工具清单
### 3.1 环境与发现
| 工具 | 作用 |
| --- | --- |
| `davinci_env_doctor` | 环境自检,返回每项 pass/warn/fail 与修复建议(含 py-armodel 可选依赖状态) |
| `davinci_version` | 查询 `dvcfg-b` / `DVCfgCmd` / `dvdevc` 版本(CFG5 优先读 branding jar) |
| `davinci_list_projects` | 扫描 `.dvjson` / `.dpa` / `.dcf`,自动跳过 `Output`、`GenData` 等生成目录 |
| `davinci_project_info` | 工程结构摘要:目录布局、设置项、配置/生成物数量(识别 CFG5 布局) |
| `davinci_scan_output` | 统计产物:文件数、扩展名分布、最新文件(只知道目录时用) |
| `davinci_generation_roots` | 从工程设置定位生成目录,给出 source / confidence / exists 与文件数 |
| `davinci_generated_files` | 列出生成目录内的文件夹与文件,逐文件标注 generated / likely_generated / unverified |
| `davinci_help` | 透传 `<tool> <subcommand> --help`,用于核对版本差异 |
### 3.2 Configurator 工程操作
| 工具 | 对应命令 | 会改工程 |
| --- | --- | --- |
| `davinci_project_create` | `project create`(CFG6) | 新建 |
| `davinci_cfg5_project_create` | 模板克隆(CFG5 无对应命令) | 新建 |
| `davinci_project_validate` | `project validate` | 否 |
| `davinci_project_generate` | `project generate` | 否(输出产物) |
| `davinci_cfg5_validate` | `DVCfgCmd -v` | 否 |
| `davinci_cfg5_generate` | `DVCfgCmd -g` | 否(输出产物) |
| `davinci_cfg5_update` | `DVCfgCmd -u` | **是**(需 `confirm=true`) |
| `davinci_cfg5_save` | `DVCfgCmd Save` | **是**(需 `confirm=true`) |
| `davinci_cfg5_run` | 受控透传 | 取决于参数 |
| `davinci_cfg5_report` | 解析 ExecutionReport XML | 否 |
| `davinci_project_update` | `project update`(`.dpa` 自动转到 `DVCfgCmd -u`) | **是**(需 `confirm=true`) |
| `davinci_project_activate_rec_modules` | `project activate-rec-modules` | 是 |
| `davinci_project_derive_ecuc` | `project derive-ecuc` | 是 |
| `davinci_project_generate_swct` | `project generate-swct` | 否(输出头文件) |
| `davinci_build` | 校验 → 更新 → 生成 → 导出 | 取决于参数 |
### 3.3 导入导出与运维
| 工具 | 对应命令 |
| --- | --- |
| `davinci_export_list` / `davinci_export_run` | `export list` / `export run` |
| `davinci_import_arxml` | `import arxml-artifacts`(需 `confirm=true`) |
| `davinci_automation_list` / `davinci_automation_run` | `automation list` / `automation run` |
| `davinci_console_status` / `davinci_console_stop` | `status` / `stop` |
| `davinci_job_status` / `davinci_job_logs` / `davinci_job_cancel` | 后台作业管理 |
### 3.4 CFG5(DVCfgCmd)
`.dpa` 工程由 CFG5 后端处理。通用工具 `davinci_project_validate / generate / update` 会按后缀自动路由,
因此大多数场景不需要区分版本;需要 CFG5 专有参数时再用下面这些工具。
| 工具 | 对应命令 | 说明 |
| --- | --- | --- |
| `davinci_cfg5_project_create` | 模板克隆 | 从现有 `.dpa` 复制出新工程,重写名称/路径后可自动冒烟校验 |
| `davinci_cfg5_validate` | `DVCfgCmd -p <dpa> -v` | 解析 ExecutionReport XML,返回 counts / findings / gate |
| `davinci_cfg5_generate` | `DVCfgCmd -p <dpa> -g` | 支持 `-m/-x/--genType/--genArg/--saveProject` |
| `davinci_cfg5_update` | `DVCfgCmd -u <dpa>` | 支持 `--input/--onlyEcuc/--onlyLegacyDiag` |
| `davinci_cfg5_save` | `DVCfgCmd Save [--module]` | 工作目录自动设为工程目录 |
| `davinci_cfg5_run` | 任意白名单参数 | 覆盖 import / export / 特定 SP 选项 |
| `davinci_cfg5_report` | — | 单独解析任意 ExecutionReport XML |
CFG5 的 `-v` 是 **validate**(不是 verbose),`-g` 是 generate,`-u` 是 update——与 CFG6 的
`project validate / generate / update` 一一对应,但参数不能混用。
#### 3.4.1 工程创建:为什么是「模板克隆」
CFG5(5.x)没有与 `dvcfg-b project create` 等价的结构化创建命令:
| 路径 | 能否自动化 | 说明 |
| --- | --- | --- |
| GUI → New ECU Project | 否 | 必须选 SIP/BSW、MCU、编译器,要人工确认 |
| `DVCfgCmd`(5.30 SP1+,Linux) | 部分 | Vector KB 标注 5.30 SP1 起支持 Linux 下的 project creation;选项随 SP 变化,旧 SIP 上没有 |
| 模板克隆(本工具) | 是 | 复制 `.dpa` + `Config`,重写根路径与工程名,再跑一次 `-v` 冒烟 |
`davinci_cfg5_project_create` 的参数:
| 参数 | 说明 |
| --- | --- |
| `template_project` | 模板 `.dpa`,常用 SIP 的 `Applications/SipAddon/StartApplication` |
| `output_dir` / `project_name` | 新工程建为 `output_dir/project_name`,`.dpa` 自动改名 |
| `copy_dirs` | 额外复制的一级目录,默认 `["Config"]`;`Appl/GenData/Log` 禁止复制 |
| `replacements` | 额外文本替换,用于换 BSW 路径,例如 `{"D:/old/bsw": "D:/new/bsw"}` |
| `verify` | 创建后跑 `-v`,返回 `verify.ok / counts / report_file` |
| `dry_run` | 只返回复制与改写计划,不落盘,也不需要 confirm |
改写规则刻意保守:只替换「工程根路径」「`<名字>.dpa`」「`>名字<`」三类位置,
外加显式 `replacements`;其余字节不动,避免把模块前缀、版本号改坏。
建议先 `dry_run=true` 看一遍 `files` / `skipped`,再落盘。
`davinci_help(binary="cfg5")` 会额外返回 `creation_capability`:在本机
`DVCfgCmd --help` 文本里探测是否提到工程创建。它只做文本探测、不猜选项名,
真要用新版 CLI 的创建能力时以本机输出为准。
### 3.5 Groovy 脚本(Automation Interface)
DaVinci 的自动化脚本是 Groovy DSL(`.dv.groovy`),官方入口是
`dvcfg-b automation setup / list / info / run`。这组工具覆盖「写 → 查 → 检 → 跑」全流程。
| 工具 | 对应命令 | 说明 |
| --- | --- | --- |
| `davinci_api_index` | — | 扫安装目录的 JAR,建本机 Java API 索引(class 文件解析,无需 JDK) |
| `davinci_script_api` | — | 查 API:有索引查真实签名,否则查内置文档目录;也能核对脚本符号 |
| `davinci_script_templates` | — | 内置模板:空白、工程信息、校验、生成、ECUC 报告、Data Mining 查询、写参数、生成步骤、生成前钩子 |
| `davinci_script_create` | — | 从模板生成 `.dv.groovy`,自动补后缀 |
| `davinci_script_read` | — | 读取源码 + 任务/参数/静态检查结果 |
| `davinci_script_write` | — | 写入完整源码(覆盖需 `confirm=true`) |
| `davinci_script_list` | — | 本地扫描脚本,列出任务与问题 |
| `davinci_script_tasks` | `automation list` | 让 DaVinci 真正加载脚本,列出权威任务清单 |
| `davinci_script_info` | `automation info` | 单个任务的类型、描述、用户参数 |
| `davinci_script_lint` | — | 静态规则;`compile_check=true` 时追加 DaVinci 加载检查 |
| `davinci_script_run` | `automation run` | 执行任务;`dry_run=true` 只编译不执行 |
| `davinci_script_setup` | `automation setup` | 创建 dvgroovy / Gradle 脚本工程脚手架 |
| `davinci_cfg5_script_install` | — | 把 `.dvgroovy` 安装到 CFG5 工程目录,供 GUI 加载 |
脚本结构与任务类型:
```groovy
import static com.vector.cfg.automation.api.ScriptApi.*
scriptTask("Validate", DV_PROJECT) {
taskDescription "Run validation with the project settings"
code {
generation { validate() }
validation {
def results = validationResults
scriptLogger.info "Validation finished: ${results.size()} result(s)"
}
}
}
```
- `DV_PROJECT` 需要先加载工程;`DV_APPLICATION` 可自行创建/打开工程;
另有 `DV_GENERATION_STEP`、`DV_ON_GENERATION_END`、`DV_ON_FILE_PREPROCESSING_RESULT`、
`DV_ON_SUCCESSFUL_UPDATE_WORKFLOW`、`DV_EDITOR_SELECTION`、`DV_EDITOR_MULTI_SELECTION`。
- 用户参数用 `newUserDefinedArgument("name", String, "help")` 声明,
CLI 通过 `-a 'TaskName' -a '--name=value'` 传入;本服务对应 `task_args={"TaskName": "--name=value"}`。
- `daVinci { }` 只用于 IDE 代码补全,运行时可选。
#### 3.5.1 Agent 怎么知道 Groovy 能做什么
模型对 Automation API 的先验知识不可靠,凭记忆写出来的调用有一半是幻觉。
这里用两层机制解决:**优先查本机 JAR 里的真实签名,查不到才退回随包文档目录**。
##### 第一层:从安装目录的 JAR 反射(`source="jar"`)
```text
davinci_api_index(home="C:/Program Files/Vector/DaVinciConfigurator")
davinci_script_api(symbol="IValidationResultUI#isId")
davinci_script_api(query="validation result")
davinci_script_api(script="D:/work/Check.dv.groovy")
```
`davinci_api_index` 会扫安装目录的 `plugins/*.jar`,解析 `.class` 里的类、方法、字段、
泛型签名,存成本地索引。**不需要 JDK**(DaVinci 只带 JRE,现场也不会为查 API 装 JDK),
纯 Python 读 class 文件格式,跨平台。
| 能力 | 说明 |
| --- | --- |
| 类型 | class / interface / enum / annotation / record,含嵌套类型(`Outer.Inner`) |
| 方法 | 名称、参数、返回、修饰符;泛型保留,如 `List<IValidationResultUI.SolvingAction> getSolvingActions()` |
| 字段 | 类型、修饰符、枚举常量 |
| 可见性 | 默认只收 `public` / `protected`,`include_private=true` 才全收 |
缓存按「JAR 路径 + 大小 + mtime」算指纹:装完 DaVinci 或换了 BSW 包,指纹变了会自动重建;
`rebuild=true` 强制重建。
沙箱里用一个自造的 JAR(`tests/data/java`,非 Vector 真实签名)走通了全链路:
```jsonc
// davinci_script_api(symbol="IValidationResultUI#isId")
{"ok": true, "source": "jar", "name": "com.vector.cfg.automation.api.IValidationResultUI",
"members": ["public abstract boolean isId(String, int)"]}
// davinci_script_api(script="Check.dv.groovy")
{"resolved": ["isId", "scriptTask"],
"unresolved": ["autoFixEverything"],
"unknown_types": ["NoSuchType"],
"summary": "JAR 索引里解析到 2 个调用、0 个类型;未解析调用 2 个、未知类型 2 个"}
```
`unresolved` 的语义比文档目录硬得多:**不是「我的快照里没写」,是「这个 JAR 里确实没有」**。
脚本里 `def` 出来的自定义方法会被自动剔除,不会误报。
解析器用 JDK 20 的 `java.base` 做过一轮真实数据验证(2000 个 class,含 record、sealed、
复杂泛型):**2000/2000 全部解析成功,10000 类/秒**,5000 个类约 0.5 秒。复杂签名也能正确还原:
```text
public abstract Iterator<E> iterator() // java.util.List
public <V> Function<V, R> compose(Function<? super V, ? extends T>) // java.util.function.Function
public static <T> Optional<T> of(T) // java.util.Optional
```
真实 DaVinci 的 bundle 比这简单,索引一次通常在秒级;之后走缓存,查询是内存操作。
##### 第二层:随包内置的文档目录(`source="builtin"`)
安装目录拿不到时(CI 容器、只看代码不看机器)退回内置目录:8 个能力域、约 50 条入口,
每条都标了出处等级。
| evidence | 含义 |
| --- | --- |
| `doc-example` | 官方 API Reference 的示例代码里出现过,可以照抄结构 |
| `doc-mention` | 文档正文提到、但没有完整示例,签名需自行确认 |
| `template` | 本仓库模板已使用并核对过 |
它还显式列出 `known_gaps`:写模型的 setter、Data Mining 查询语法、UI 控件 API、
打开/创建工程的应用级 API——这些没有公开示例,目录不收录,避免让 Agent 以为它们存在。
##### 选哪个
`source` 参数控制,默认 `auto`:
| 取值 | 行为 |
| --- | --- |
| `auto` | 有有效索引就用 JAR,否则用内置目录;返回值里 `source` / `note` 说明用了哪个 |
| `jar` | 只用 JAR,没有索引直接报 `index_missing`(适合 CI 里强制走真实签名) |
| `builtin` | 只用内置目录(离线、对比、或想看清「我到底抄了哪些」) |
两条路都**不替代编译**:静态解析看得见「有没有」,看不见「类型对不对」。
最终仍要 `davinci_script_lint(compile_check=true)`。
对应资源:`davinci://groovy/api`(能力地图,自动选源)。
### 3.6 Developer 工作区
| 工具 | 对应命令 |
| --- | --- |
| `davinci_dev_workspace_create` | `dvdevc project create` |
| `davinci_dev_workspace_link` | `dvdevc project link` |
| `davinci_dev_root_design_create` | `dvdevc model create-root-design` |
| `davinci_dev_workspace_update` | `dvdevc project update` |
| `davinci_dev_workspace_convert` | `dvdevc project convert`(非 analysis-only 需确认) |
| `davinci_dev_run` | 其他 `dvdevc` 子命令(白名单 + 确认) |
### 3.7 ECUC 只读分析(py-armodel)
CFG5 的 `DVCfgCmd` 只有「整工程校验 / 生成 / 更新」三个粒度,回答不了下面这些问题:
- `DemEventParameter_0` 的 `DemEventId` 到底配了几?
- 这个变体和上个基线相比,哪些参数变了?
- 配置里有没有指向已删除容器的引用?有没有留空的壳容器?
这组工具用 [py-armodel](https://github.com/melodypapa/py-armodel) 把 ECUC ARXML 解析成
「模块 → 容器 → 参数/引用」的语义索引,在其上做查询与对比。**它只读,不写回 ARXML。**
| 工具 | 作用 | 关键参数 |
| --- | --- | --- |
| `davinci_ecuc_index` | 建立结构索引(模块/容器树/统计) | `arxml`(单文件或列表)、`limit` |
| `davinci_ecuc_query` | 按路径通配/模块/容器/参数名/值片段检索 | `pattern`、`module`、`value_contains`、`kind` |
| `davinci_ecuc_diff` | 两份配置的参数级语义对比 | `before`、`after`、`max_changes` |
| `davinci_ecuc_audit` | 结构体检(空容器、类型不符、悬空引用、重名) | `arxml`、`max_items` |
| `davinci_ecuc_export` | 导出扁平清单(CSV/JSON),供评审与影响分析 | `out_path`、`format`、`confirm` |
路径是跨文件稳定的键,构造规则:
```text
/模块名/容器 short-name/子容器 short-name/参数定义名
/Dem/DemGeneral/DemEventParameter_0/DemEventId
/Dem/DemGeneral/DemEventParameters/DemEventParameter_0/DemEventId
```
- 模块名取 `DEFINITION-REF` 的末段;容器用 `short-name`(AUTOSAR 保证同父唯一),
重名时追加 `#2` 并在 `conflicts` 中报告。
- 参数名取定义路径末段;同名多值参数按出现顺序追加 `#2`、`#3`。
**diff 的语义**:容器按 `(定义, short-name)` 二次匹配,因此「把事件容器挪到新的父容器下」
只报一条 `moved`,不会刷出「删 4 个参数 + 加 4 个参数」。只有两侧都唯一时才判定为移动,
批量同名容器不做猜测。
```jsonc
{
"counts": {"added": 0, "removed": 0, "changed": 1},
"containers": {"added": 1, "removed": 2, "moved": 1},
"changes": [
{"kind": "moved", "path": "/Dem/DemGeneral/DemEventParameter_0",
"after_path": "/Dem/DemGeneral/DemEventParameters/DemEventParameter_0"},
{"kind": "changed", "path": "/Dem/DemGeneral/DemMaxNumberEvents",
"before": 128, "after": 256, "type": "integer"}
],
"summary": "参数变化:改值 1,新增容器 1,删除容器 2,移动容器 1"
}
```
**为什么不做写回**:py-armodel 的 writer 会重新序列化整个文档。实测往返后
`ANNOTATION-TEXT` 内嵌的 XHTML 会丢内容、元素顺序与命名空间前缀会重排,
Vector 侧的增量识别和代码评审 diff 都会受污染。所以改配置仍然走 `DVCfgCmd` / GUI,
这一层只负责「看清现状」。真要批量改,用 Groovy(3.5)或 `cfg5_update` 导入。
**已知边界**(实测,py-armodel 1.9.8):
| 现象 | 处理 |
| --- | --- |
| 参数字面量与类型不符(整型写了文本) | py-armodel 直接抛异常,整文件解析失败;服务返回 `parse_error` 并提示先修正该值 |
| 数值统一按 float 承载 | 整型参数已归一为 `int`(`128` 不会显示成 `128.0`);`0x80` 会归一为 `128`,语义对比按数值而非字面量 |
| 只支持 AUTOSAR 4.x 的 ECUC | 3.x 的 `TOP-LEVEL-PACKAGES` 结构不支持,会返回解析错误 |
| 引用指向 BSWMD/其他文件 | 标为 `reference_out_of_scope`(info),不算错误,避免误报 |
| 大工程 | 2.6 MB / 3000 容器 / 9000 参数约 0.3 秒、55 MB 内存;单文件超 50 MB 建议按模块拆分 |
### 3.8 AUTOSAR 版本探测与规范定位
回答「`DemEventId` 这个参数什么意思」「这个配置项能不能用」之前,先得知道工程是按哪个
AUTOSAR 版本做的。拿 R23-11 的文档解释一个 4.2.2 的工程,参数名、容器路径、可选项
都可能已经变了,结论会系统性偏错。
CFG5/CFG6 的 AUTOSAR 版本是**工程级**设置,工程文件里没有「每个模块一个版本字段」;
真正逐模块可测的是**每个模块描述文件用了哪个版本的 schema 序列化**。BSW 包、第三方
MCAL、OEM 提供的 ECUC 文件版本不一致时,这个差异会直接表现为「参数定义过期 / 校验
报不认识的定义」。所以工具同时给工程版本和逐模块证据,并把不一致的模块单列。
| 工具 | 作用 | 关键参数 |
| --- | --- | --- |
| `davinci_ar_version` | 探测工程版本、逐模块版本证据、冲突清单 | `paths`(目录/`.dpa`/`.dvjson`/ARXML)、`deep`、`include_modules` |
| `davinci_spec_lookup` | 模块 + 版本 → SWS 文档名、ECUC 定义路径、检索式 | `module`、`release`、`topic` |
`davinci://autosar/specs` 资源暴露约 50 个常见模块与 SWS 文档的对照表,可先浏览再查。
**证据分级**(每条都带 `source`,能追到具体文件甚至压缩包内的条目):
| 证据 | 置信度 | 说明 |
| --- | --- | --- |
| 工程设置里的显式字段 | `high` | CFG6 `Settings/General.json` 的 `autosarVersion`、`.dpa` 内的工程设置条目 |
| `xsi:schemaLocation` | `medium` | AUTOSAR TPS_ARXMLSerializationRules 要求必须声明,`AUTOSAR_4-2-2.xsd` 直接编码了序列化依据的版本 |
| 模块 `ADMIN-DATA` 的 SDG/SD | `medium` | 厂商自定义,要求 GID 或内容本身提到 autosar/version 才采信,避免把文档修订号当版本 |
| 命名空间 `r4.0` | 不投票 | 只说明「4.0 起的兼容序列」,区分不了 4.2.2 与 4.4.0;只用于给出 `series: "4.x"` |
**探不到就返回 `null`**,并在 `guidance` 里说明可能原因(传了生成目录、文件被裁剪),
不会默认成最新版本——这是这块功能最重要的约束。
```jsonc
{
"project": {"release": "4.2.2", "confidence": "high", "agreement": 0.67,
"schema_major": "4.0",
"evidence": [{"kind": "project-setting", "release": "4.2.2",
"source": ".../Settings/General.json",
"value": "general.autosarVersion=4.2.2"}]},
"modules": [
{"module": "Dem", "release": "4.2.2", "confidence": "medium", "inherited": true,
"spec_document": "AUTOSAR_SWS_DiagnosticEventManager",
"spec_query": "AUTOSAR_SWS_DiagnosticEventManager 4.2.2"},
{"module": "NvM", "release": "4.0.3", "confidence": "medium", "inherited": true}
],
"mismatches": [{"module": "NvM", "release": "4.0.3"}],
"unresolved": [],
"summary": "工程 AUTOSAR 版本 4.2.2(high),2 个模块,1 个模块版本不一致(NvM)"
}
```
`mismatches` 不是错误,而是**该重新核对的清单**:一个 4.0.3 的模块定义放进 4.2.2 工程,
通常还能跑,但新版本增加的参数它不认识,诊断时要单独提示。
**规范定位**:
```python
davinci_spec_lookup(module="Dem", release="4.2.2", topic="DemEventId")
# → documents: [{"name": "AUTOSAR_SWS_DiagnosticEventManager", "layer": "SWS"}]
# → ecuc_definition: "/AUTOSAR/EcucDefs/Dem"
# → queries: ["AUTOSAR_SWS_DiagnosticEventManager 4.2.2 DemEventId",
# "AUTOSAR SWS Dem 4.2.2 DemEventId", ...]
# → release_path: "R4.2.2",document_url_hint: .../standards/R4.2.2/CP/<doc>.pdf
```
文档名是按 AUTOSAR 发布命名整理的,条目里标了 `origin: "curated"`;站点改版或模块拆分时
名字会变,所以查询结果始终附带检索式。**检索式才是主路径,文件名只是加速**。
**扫描范围**:传目录时默认找 `*.dpa`、`*.dvjson`、`Settings/*.json`、`Config/**/*.arxml`,
找不到就递归找 `.arxml`(BSW 包、MCAL 目录没有 `Config/` 结构);`deep=true` 才连
`Appl/GenData` 等生成目录一起扫。要把「模块定义」和「工程配置」放在一起比,直接把两边都传进去:
```python
davinci_ar_version(paths=[".../MyEcu", "D:/SIP/MICROSAR"])
# → project.release 取工程设置;模块的 release 各自来自它所在文件
# → mismatches 列出「BSW 包里的定义仍是 4.0.3」这类差异
```
单文件上限 64 MB,`.dpa` 解压总量上限 96 MB / 120 个条目,超了会在 `notes` 里说明,
不静默截断。纯标准库实现,不需要安装 py-armodel,也不需要 Vector 二进制。
#### 3.8.1 模块资产:Vector User Manual 与静态代码
SWS 规范讲「参数在标准里是什么意思」,Vector User Manual 讲「Vector 实现里这个参数
怎么用、有哪些实现限制」,静态代码是最终事实。回答参数级问题要三源对照,缺了任何一环
都可能给出「规范里有、Vector 里没有」的答案。
| 工具 | 作用 | 关键参数 |
| --- | --- | --- |
| `davinci_module_assets` | 定位模块的 User Manual、静态代码、模块定义 ARXML | `project`、`module`、`bsw_package`、`allow_outside` |
定位按证据分层,与生成目录的思路一致:
| 证据 | 置信度 | 说明 |
| --- | --- | --- |
| `bsw_package` 参数 | `high` | 显式指定 BSW 包(MICROSAR 交付)根目录 |
| 工程设置里的 BSW 包路径 | `high` | `Settings/*.json`、`.dvjson`、`.dpa` 内 JSON 中 key 含 `bsw` + `package/path/dir/root` |
| 工程目录 / 父目录布局 | `medium` | 模块目录可能在工程内,Vector 交付也常与工程并排 |
| 白名单根目录推断 | `low` | 前面全落空时才用 `DAVINCI_MCP_ROOTS` |
文档识别:文件名含模块名 + 手册词形(`UserManual` / `UM` / `Handbook`)且为
`pdf/chm/html` → `manual`(high);模块目录内 `doc/` 下的文档 → `doc`(按是否含模块名
给 medium/low);交付根两层内的集中文档目录(`Documentation/` 等)也参与匹配。
代码识别:模块目录下的 `src/` / `inc/` 里的 `.c/.h`;模块同名的文件(`NvM.c`、`NvM.h`)
作为 `entry_points` 单列。**生成输出目录(`GenData/`、`Output/` 等)里的同名 `.c/.h`
标成 `generated_code`,不算静态代码**——生成物是配置的派生结果,不能当实现依据。
找模块目录时会跳过生成目录,避免 `GenData/NvM` 被当成模块交付。
```json
// davinci_module_assets(project=".../MyEcu", module="NvM").static_code
{
"module_dir": "D:/SIP/MICROSAR/BSW/NvM",
"static_code": {
"count": 42, "generated_code_count": 0,
"roots": ["D:/SIP/MICROSAR/BSW/NvM/src", "D:/SIP/MICROSAR/BSW/NvM/inc"],
"entry_points": ["D:/SIP/MICROSAR/BSW/NvM/src/NvM.c",
"D:/SIP/MICROSAR/BSW/NvM/inc/NvM.h"],
"files": [{"kind": "code", "path": "...", "confidence": "medium",
"source": "settings", "detail": "静态代码(src/)"}]
},
"documentation": {"count": 1, "files": [{"kind": "manual",
"path": "D:/SIP/MICROSAR/BSW/NvM/doc/NvM_UserManual.pdf",
"confidence": "high"}]}
}
```
工具只定位文件(stat,不读内容);拿到的路径直接用读文件工具打开。
找不到时对应清单为空、`available=false` 并说明原因——不会编造文档名。
### 3.9 生成物清单(哪些文件是生成的)
修改代码前必须先回答一个问题:**这个文件是生成的,还是人写的?** 生成文件手改后,下一次
`generate` 会被静默覆盖,改动等于没做。但生成目录不是固定常量:CFG6 可以改 `Output`,
CFG5 可以改 `Appl/GenData`,有的工程把生成物放到工程目录之外。
所以工具不去猜一个路径,而是分三层取证:
| 证据 | 置信度 | 说明 |
| --- | --- | --- |
| 工程设置里的显式字段 | `high` | `.dvjson` / `Settings/*.json` 中的 `outputFolder`、`generationDirectory` 等;`.dpa` 内设置条目同样采信 |
| DaVinci 默认布局 | `medium` | CFG5 `Appl/GenData` / `GenData`,CFG6 `Output` |
| 目录名推断 | `low` | 一级子目录名匹配 `GenData`、`Output`、`Gen*`;仅当前两层都没有结果时使用 |
| 工具 | 作用 | 关键参数 |
| --- | --- | --- |
| `davinci_generation_roots` | 定位生成目录:路径、来源、置信度、是否存在、文件数/体积/最新时间 | `project`、`dirs`、`include_missing`、`allow_outside` |
| `davinci_generated_files` | 列文件夹与文件,并逐文件分类 | `project`、`view`、`pattern`、`exclude`、`max_depth`、`limit`、`classify` |
```jsonc
// davinci_generation_roots(project="D:/work/ecu/Demo.dvjson")
{
"roots": [{
"path": "D:/work/ecu/GenData", "exists": true,
"source": "project-setting", "confidence": "high",
"detail": "Demo.dvjson 的 generation.outputFolder(字段 outputFolder=GenData)",
"file_count": 1842, "size_human": "12.3 MB", "latest": "2026-11-08 21:04:12"
}],
"notes": []
}
```
逐文件分类只有三档,且每档都带 `evidence`:
| category | 含义 |
| --- | --- |
| `generated` | 有明确证据:位于工程设置指定的生成目录、文件头写了 `auto-generated` / `do not edit`、或命名是 `Rte_*` / `*_Cfg.*` |
| `likely_generated` | 位于默认生成目录,或文件本身只有命名线索,没有文件头佐证 |
| `unverified` | 目录是显式指定/按名字猜的,文件本身也没有生成标记——需要人工确认 |
```jsonc
// davinci_generated_files(project=".../Demo.dvjson", pattern=["*.h"], limit=100)
{
"totals": {"files": 1842, "generated": 1790, "likely_generated": 40, "unverified": 12,
"folders": 37, "size_human": "12.3 MB"},
"trees": [{
"folders": [{"rel_path": "Rte", "files": 128, "bytes": 912340,
"categories": {"generated": 128, "likely_generated": 0, "unverified": 0}}],
"files": [{
"rel_path": "Rte/Rte_Cfg.h", "bytes": 8123, "modified": "2026-11-08 21:04:12",
"category": "generated",
"evidence": ["位于工程设置指定的生成目录(来源:project-setting)",
"AUTOSAR RTE 生成文件命名(Rte_*)"]
}]
}]
}
```
几个使用要点:
- **`*_Callout.c` 是例外**:它通常是生成器产出的桩,首次生成后由人工维护。返回值里的 `hint`
会提示,不要因为 `category=generated` 就认为它每次都会被覆盖。
- **`view` 可以省流量**:`folders` 只看目录结构与每层文件数,`files` 只看文件,`tree` 两者都给。
- **过滤**:`pattern=["*.h", "Rte/*"]`、`exclude=["*_Callout.c"]`;`max_depth=0` 只看根目录。
- **大目录**:默认统计最多 2 万个文件、文件头最多检查 2000 个,超出会在 `notes` 里说明;
`limit` 只控制返回条目数,不影响统计。
- **越界目录**:工程设置指向 `DAVINCI_MCP_ROOTS` 之外时,该候选标为 `blocked` 并给出提示,
不影响其他目录;确认要读时传 `allow_outside=true`(`DAVINCI_MCP_STRICT_PATHS=1` 时无效)。
### 3.10 工程差异对比(ECUC → Groovy,输入文件 → 命令行)
两个工程之间「到底改了什么」,靠肉眼比 ARXML 不现实,靠纯文本 diff 又会被格式和生成物干扰。
这一层分四层取证,先给结论,再按「变更的性质」选回放方式。
| 层次 | 依据 | 能回答的问题 |
| --- | --- | --- |
| 文件级 | 相对路径对齐、SHA-256 判内容、同哈希异路径判重命名 | 哪些文件新增 / 删除 / 改名 / 改内容 |
| 设置级 | `Settings/*.json`、根 `.dvjson`、`.dpa` 内 JSON 展平成键路径 | 哪个设置项从什么改成了什么 |
| 输入文件级 | 设置引用(high)→ `Input/` 布局(medium)→ 扩展名(low) | 哪个 DBC / CDD / LDF / ECU Extract 变了 |
| ECUC 语义级 | py-armodel 索引(可选依赖) | 哪个参数改值 / 新增 / 删除,容器是否移动 |
生成目录默认排除:生成物是配置的派生结果,`GenData/` 下几千个文件全变并不代表配置改了。
需要时传 `include_generated=true`,或直接看 `files.generated` 里的计数与样本。
| 工具 | 作用 |
| --- | --- |
| `davinci_project_diff` | 四层差异:`files` / `settings` / `inputs` / `ecuc`,带计数、分类与截断标记 |
| `davinci_project_diff_script` | `mode=replay` / `verify` 渲染 Groovy;`mode=cli` 渲染输入文件命令行回放 |
`replay` 只自动写「两侧都存在、标量、路径可解析」的 ECUC 参数,其余一律进 `manual`:
新增参数需要 `OrCreate`、删除参数没有公开 remove、容器移动无法用 `.value` 表达。
这不是偷懒,是避免生成一段跑起来必然报错的脚本。
```groovy
// davinci_project_diff_script(mode="replay") 的关键片段
def changes = [
[kind: 'changed', path: '/Dem/DemGeneral/DemMaxNumberEvents',
wire_path: '/ActiveEcuC/Dem/DemGeneral/DemMaxNumberEvents',
before: 128, after: 256],
]
def manual = [
[kind: 'added', path: '/Dem/DemGeneral/DemNewParam',
reason: '新增参数在目标工程里不存在,路径访问无法创建;用 GUI 或 OrCreate 访问器添加'],
]
if (dryRun.value) {
// 逐条确认路径能否解析,提前暴露拼错或模型布局差异
// ...
} else {
transaction {
changes.each { item ->
mdfModel(AsrPath.create(item.wire_path)) { parameter ->
parameter.value = item.after
}
}
}
saveProject()
}
```
写法有出处:`mdfModel(AsrPath.create(...))`、`transaction` 内改属性来自官方 *Model API — Getting Started*;
`saveProject()` 与 `parameter.value=` 来自本仓库的 `set_parameter` 模板。默认 `dryRun=true`,
先跑一遍看 `[resolved]` / `[unresolved]`,再决定是否写入。
`verify` 不开启事务,只按记录值读取并比较;`--failOnDiff=true` 时失配抛异常,适合放进 CI 回归。
两种脚本返回前都会过一遍 `davinci_script_lint` 用的那套静态规则。
#### 输入文件:为什么不能写成 Groovy
DBC、CDD、LDF、FIBEX、ODX 和 ECU Extract 是**配置的输入**,不是配置本身。DaVinci 的流程是
「导入输入 → 派生 / 合并 ECUC → 生成代码」;直接改派生出来的参数,下一次导入就会把它们覆盖回去。
所以 `inputs` 层只回答「哪个文件变了」,回放交给 DaVinci 命令行。
识别分三层,和生成目录一样带证据:
| 证据 | 置信度 | 说明 |
| --- | --- | --- |
| 工程设置里的显式引用 | `high` | `Settings/*.json`、`.dvjson`、`.dpa` 内 JSON;键名要含 `input` / `ifp` / `fileList` / `extract` / `diagnostic` 等 |
| `Input/`(含 `Input/Preprocessing`、`Input/OEMInput/Preprocessing`) | `medium` | CFG6 官方工程结构把 `Input/` 定义为输入文件目录 |
| 扩展名兜底 | `low` | `.dbc` / `.cdd` / `.ldf` / `.fibex` / `.odx` / `.pdx` / `*_dvarjson.json` |
`.arxml` 只有落在 `Input/` 下或被输入类设置引用时才算输入;`Config/` 下的 ARXML 是配置本体。
输入文件同时会出现在 `files` 主表里,分类标为 `input`,不会和生成物混在一起。
工程目录外的引用只做 stat、不读内容,大小相同时记为 `unverified`,不会生成覆盖命令。
CFG5 工程目录里的 `.dpa` 也会按条目扫描(只读输入后缀、有大小与预算上限),
所以「输入在归档里」不会被漏掉;这类条目没有磁盘路径,回放会转人工。
回放按工程类型分流:
```text
CFG5(.dpa)
DVCfgCmd -u <left.dpa> --input "<right>/Input/Can.dbc,<right>/Input/Diag.cdd"
# 一次 -u 可以带多个文件;改内容的合并成一条命令
CFG6(.dvjson)
copy /Y "<right>/Input/Can.dbc" "<left>/Input/Can.dbc" # 已存在先备份 .bak
dvcfg-b project update -p "<left>.dvjson" -b "<bsw>" -c # -c = apply ifp changes
```
`-b` 是 `dvcfg-b project update` 的必填项,工具先从左侧工程设置里找 `bswPackage`;
找不到就降级为人工项,而不是生成一条注定失败的命令。新增输入文件需要在 Input Files
助手里注册模块映射,删除也需要在助手里移除——公开命令没有对应开关,这两类都进 `manual`。
```json
// davinci_project_diff(...).inputs.replay 的关键字段
{
"variant": "cfg5",
"commands": [
{"kind": "update", "tool": "DVCfgCmd",
"argv": ["DVCfgCmd", "-u", "D:/work/A/Demo.dpa",
"--input", "D:/work/B/Input/Can.dbc,D:/work/B/Input/Diag.cdd"]}
],
"manual": [
{"kind": "added", "name": "New.ldf",
"reason": "新增输入文件需要在 Input Files 助手里注册模块映射"}
],
"counts": {"commands": 1, "update": 1, "manual": 1}
}
```
两个可选参数用于纠正环境推断:`cli_path` 指定 `DVCfgCmd` / `dvcfg-b` 的绝对路径,
`bsw_package` 在工程设置里没有 `bswPackage` 时补上 CFG6 的 `-b`。两者都不猜默认安装位置。
`mode="cli"` 会把这套计划渲染成可执行脚本:`.cmd` / `.bat` 走 Windows 批处理,
`.sh` 走 POSIX shell,`.json` 给自动化流水线。脚本默认带 `DAVINCI_CLI` 变量、
复制前备份、`errorlevel` 检查;它**不会自动执行**,与 Groovy 的 `dryRun` 一样,
先让人看清要改什么。
```text
davinci_project_diff_script(left=..., right=..., mode="cli", out_path="replay.cmd", confirm=true)
davinci_project_diff_script(left=..., right=..., mode="replay") # Groovy + input_replay 一起返回
```
几个边界:
- **文件路径对齐依赖相同布局**:目录 ↔ 目录最可靠;目录 ↔ `.dpa`、`.dvjson` ↔ `.dpa` 会在 `notes`
里提示类型不同,此时以 ECUC 语义差异为准。
- **`.dpa` 是归档**:按条目比较;ARXML 解到临时目录交给 py-armodel 解析,不写回工程。
归档里的输入文件没有磁盘路径,CLI 回放会降级为人工项,需先解出到磁盘。
- **`.dcf` 不能回放输入文件**:它不是 CFG5/CFG6 的工程容器,`variant` 返回 `unknown`,
只给人工清单,不猜命令行语法。
- **没有 py-armodel**:`ecuc.available=false`、`reason=dependency_missing`,文件、设置与输入结论照常返回。
- **路径前缀**:默认 `/ActiveEcuC`(官方示例写法)。工程自定义了活动 ECU 容器名时,改 `active_root`
重新生成;`dryRun` 的 `[unresolved]` 会直接暴露这个问题。
## 4. 典型工作流
### 4.1 从零把工程编译出代码
```text
用户:把 D:/work/ecu/Demo.dvjson 校验一下,没问题就生成代码
Agent:
1. davinci_project_validate(project="D:/work/ecu/Demo.dvjson")
→ ok=false, errors=2, findings=[EcuC 未解析引用, Os 任务未分配]
2. 分析两条错误 → 建议执行 update 的 solve-all
3. davinci_project_update(..., actions=["solve-all"], confirm=true)
4. davinci_project_validate(...) → errors=0
5. davinci_project_generate(...) → status=running, job_id=job-a1b2
6. davinci_job_status("job-a1b2") → succeeded
7. davinci_generated_files(project=".../Demo.dvjson", view="folders")
→ 37 个目录、1284 个文件;生成根来自工程设置,不靠猜
```
或者一步到位:
```text
davinci_build(project="D:/work/ecu/Demo.dvjson", update_first=true, update_confirmed=true)
```
### 4.2 修校验错误
```text
davinci_project_validate(project, fail_on="WARNING")
→ top_modules: EcuC(12), Os(8), Dem(3)
→ diagnostics.findings 按 severity 排序,带 file/line/module
```
Agent 可以据此定位到具体 ARXML,而不是靠猜。
### 4.3 BSW 包升级
```text
1. activate_rec_modules(project, bsw_package=新包)
2. project_update(confirm=true) # 引用修正 / 输入变更 / RTE 配置
3. project_validate() # 重点看「参数已不存在」「新增必填参数」
4. project_generate()
```
内置提示词 `davinci_bsw_update` 固化了这个顺序。
### 4.4 CFG5(.dpa)工程
新建工程(以 SIP 自带工程为模板):
```text
1. davinci_cfg5_project_create(
template_project="D:/SIP/Applications/SipAddon/StartApplication/StartApplication.dpa",
output_dir="D:/work/ecu", project_name="BodyEcu", dry_run=true)
→ file_count / skipped / 无写入
2. davinci_cfg5_project_create(..., confirm=true)
→ created=true, project_file="D:/work/ecu/BodyEcu/BodyEcu.dpa", verify.ok=true
```
```text
用户:把 D:/work/ecu/Legacy.dpa 校验一下,没问题就生成
Agent:
1. davinci_cfg5_validate(project="D:/work/ecu/Legacy.dpa")
→ ok=true, counts={error:0}, gate.passed=true
2. davinci_cfg5_generate(project=..., modules=["Rte"], save_project=true)
→ status=running, job_id=job-5f6e
3. davinci_job_status("job-5f6e") → succeeded
4. davinci_cfg5_report(report_file=".../Log/davinci-mcp/Legacy.generate.*.xml")
→ generation.modules / files / failed_modules
```
也可以直接用通用工具,服务会按 `.dpa` 自动选 CFG5:
```text
davinci_project_validate(project="D:/work/ecu/Legacy.dpa") → backend="cfg5"
```
遇到未封装的选项时(示例为官方文档中的 Platform Function 导出):
```text
davinci_cfg5_run(
project="Legacy.dpa",
arguments=["--exportDir", "D:/work/export",
"--exportPlatformFunctions", "--syncContract"],
)
```
透传参数会做两件事:工程与输出路径照样过白名单;未知选项直接拒绝(先 `davinci_cfg5_run(arguments=["--help"])` 确认)。
### 4.5 用 Groovy 做批量检查
```text
用户:把 D:/work/ecu/Demo.dvjson 里所有 ECUC 报告导出来,存到 D:/work/report
Agent:
1. davinci_script_templates() → 选 ecuc_report
2. davinci_script_create(script_path="D:/work/ecu/Scripts/EcucReport", template="ecuc_report")
3. davinci_script_lint(script=..., project=..., compile_check=true)
→ ok=true,DaVinci 已成功加载
4. davinci_script_run(project=..., scripts=[...],
task_args={"EcucReport": "--output=D:/work/report/ecuc.html"},
no_save=true, confirm=true)
5. 检查 report 文件存在后,再用 no_save=false 正式执行
```
自定义逻辑时用 `davinci_script_write` 直接写源码;不要凭记忆猜 API——
先 `davinci_script_lint(compile_check=true)`,让 DaVinci 的 Groovy 编译器给出真实错误行号。
#### 4.5.1 把检查嵌进生成流程(CFG5)
CFG5 的生成流程分三段:**Calculation → Validation → Generation**。Groovy 用三种任务类型接入:
| 任务类型 | 执行时机 | 能否阻止生成 | 注册方式 |
| --- | --- | --- | --- |
| `DV_ON_GENERATION_START` | 整个 GenerationProcess 开始前;参数 `phasesToExecute, generators` | 否 | Script Locations(Project scope) |
| `DV_GENERATION_STEP` | 由工程配置决定;`phase.calculation` / `phase.validation` / `phase.generation` | 是(`resultSink` 报 ERROR) | Script Locations + Project Settings > Generation > Generation Steps |
| `DV_ON_GENERATION_END` | 生成结束后;参数 `generationResult, generators` | 否 | Script Locations(Project scope) |
通常说的「pre-generation」对应 `phase.validation`:模型已算完、代码还没生成,正是做工程自定义检查的位置。
要更早介入(改模型、补派生数据)则用 `phase.calculation`。
```groovy
scriptTask("PreGenerationCheck", DV_GENERATION_STEP) {
code { phase, generationType, resultSink ->
if (phase.validation) {
validation {
resultCreation {
def id = createValidationResultIdForScriptTask(
9001, "Pre-generation check", EValidationSeverityType.ERROR)
def builder = newResultBuilder(id, "Dem event id 冲突")
builder.addErrorObject(bswmdModel(EcuC.DefRef).single)
resultSink.reportValidationResult(builder.buildResult())
}
}
}
}
}
```
两个容易踩的点:
- **定义 ≠ 生效**:`DV_GENERATION_STEP` 必须在 Project Settings 的 Generation Steps 里被引用,
否则文件加载了也不会执行;`DV_ON_GENERATION_START` 需要在 Script Locations 里注册,
且 scope 选 **Project**(Session 只对当前 GUI 会话有效)。
- **别用 `System.exit` 或抛异常来阻止生成**:那会杀掉 Config Core,日志里只剩一次中断。
用 `resultSink` 报 ERROR,失败原因会进生成结果,CI 也能读到。
CFG5 的 `DVCfgCmd` 没有 `automation run` 这类命令,脚本注册只能在 GUI 里做一次
(Project scope 会把引用写进工程,之后随工程走)。`davinci_script_create` 生成这两类模板时
会返回 `next_steps`,按步骤操作即可。
### 4.6 配置变更评审(CFG5)
```text
用户:比较这两个变体的 ECUC 配置,告诉我改了什么、有没有风险
Agent:
1. davinci_ecuc_diff(before=".../VariantA/Config/ECUC/Dem/Dem.arxml",
after =".../VariantB/Config/ECUC/Dem/Dem.arxml")
→ counts / containers / changes / summary
2. davinci_ecuc_query(arxml=目标文件, module="Dem", value_contains="...")
→ 查同一模块的相关参数,判断单点改动是否破坏成组约束
3. davinci_ecuc_audit(arxml=目标文件)
→ 空容器、类型不符、悬空引用
4. davinci_cfg5_validate(project=".../VariantB/VariantB.dpa")
→ Vector 侧校验,与静态体检结论交叉验证
5. davinci_ecuc_export(arxml=目标文件, out_path=".../review.csv", confirm=true)
→ 附上扁平清单,供人工评审
6. 输出变更表 + 风险点 + 建议回归范围(哪些模块需要重新生成)
```
配套提示词 `davinci_ecuc_review` 固化了这套顺序,可直接在客户端调用。
### 4.7 按版本查规范(避免新文档套旧工程)
```text
用户:DemEventId 的取值范围和依赖关系是什么?
Agent:
1. davinci_ar_version(paths=".../MyEcu")
→ project.release = "4.2.2"(high,来自 Settings/General.json)
→ mismatches = [NvM 4.0.3]:先提示这个模块的配置项可能已过期
2. davinci_spec_lookup(module="Dem", release="4.2.2", topic="DemEventId")
→ AUTOSAR_SWS_DiagnosticEventManager + 检索式 + R4.2.2 下载路径
3. davinci_ecuc_query(arxml=".../Config/ECUC/Dem/Dem.arxml",
pattern="/Dem/**/DemEventId")
→ 工程里实际配了哪些值,作为规范结论的落点
4. 回答时标注「AUTOSAR 4.2.2 SWS DiagnosticEventManager」;
版本探不到就说无法确认,不拿最新版规范硬套
```
配套提示词 `davinci_ar_spec_answer` 固化了这套顺序。
### 4.8 判断一个文件该不该手改(生成物边界)
```text
用户:Com_Cfg.h 里有个宏不对,我直接改这个文件行不行?
Agent:
1. davinci_generation_roots(project="D:/work/ecu/Demo.dvjson")
→ 生成目录 D:/work/ecu/GenData(source=project-setting,confidence=high)
2. davinci_generated_files(project=".../Demo.dvjson",
pattern=["**/Com_Cfg.h"], view="files")
→ category=generated
→ evidence: ["位于工程设置指定的生成目录", "配置生成文件命名(*_Cfg)"]
3. 结论:不要直接改。改 Config/ECUC 下的 Com 参数,再 davinci_project_generate
重新生成;否则下次生成会被覆盖。
4. 如果命中 *_Callout.c 且 hint 提示「首次生成后可能人工维护」,
才建议在生成目录里改,并说明它不会被下次生成覆盖。
```
配套提示词 `davinci_generated_boundary` 固化了这套判断顺序。
### 4.9 比较两个工程,把差异带回 DaVinci
```text
用户:A 是上个版本,B 是这次改完的,看看改了哪些配置,给我一个能在 DaVinci 里跑的脚本。
Agent:
1. davinci_project_diff(left="D:/work/A", right="D:/work/B")
→ files: +2 -1 ~4 ↔1;settings 3 处;ECUC 改值 12 / 新增 1 / 删除 0
→ files.generated.counts.modified = 812:确认这是生成物,不进主表
2. 读 ecuc.auto(12 条可写)与 ecuc.manual(1 条新增参数、0 条删除)
→ 新增参数需要人工在 GUI 或 OrCreate 里添加
3. davinci_project_diff_script(left=..., right=..., mode="replay")
→ lint 0 error;assumptions 标出 /ActiveEcuC 路径前缀
4. 在 DaVinci 里先 dryRun:日志里全部 [resolved] 再传 --dryRun=false;
出现 [unresolved] 时停下,检查 active_root 与容器 short-name
5. 需要回归时生成 mode="verify" 的脚本,CI 里加 --failOnDiff=true
```
配套提示词 `davinci_project_diff_review` 固化了这套顺序。
## 5. 安全模型
服务按「**读宽松、写严格、改要确认**」设计:
1. **路径白名单**:写入类路径必须位于 `DAVINCI_MCP_ROOTS` 内,`..` 与符号链接在 `resolve()` 后校验,越界直接 `path_rejected`。只读输入(BSW 包、待导入 ARXML)默认允许外部路径,可用 `DAVINCI_MCP_STRICT_PATHS=1` 收紧。
2. **无 shell**:全部通过 `subprocess.Popen(argv)` 执行,参数中的 `;`、`|`、`$()` 不会被解释。有单测覆盖注入场景。
3. **扩展名校验**:`.dvjson` / `.dpa` / `.dcf` / `.arxml` 分别对应不同操作;CFG5 服务拒绝非 `.dpa` 输入,避免拿错后端。
4. **破坏性操作需确认**:`project update`、`cfg5 update/save`、`import arxml-artifacts`、`convert`、`stop --all`、`script run`、`cfg5 script install` 必须 `confirm=true`。
5. **单工程串行**:同工程并发直接拒绝,防止 Config Core 写冲突。
6. **超时与进程树清理**:超时后 `SIGTERM → SIGKILL` 整个进程组(Windows 用 `taskkill /T`),不留僵尸 JVM。
7. **审计**:可选 JSONL 记录每次调用的 argv、cwd、退出码、耗时,便于团队追溯。
8. **输出限流**:stdout/stderr 上限可配,日志落盘后可分段读取,避免撑爆上下文。
9. **脚本是任意代码**:`davinci_script_run` 不做沙箱,只做路径白名单与确认;执行前先 `dry_run=true`,并确保工程已提交版本控制。
10. **ECUC 分析只读**:只解析、不写回;导出文件必须落在 `DAVINCI_MCP_ROOTS` 内并需 `confirm=true`。解析在单线程中串行执行(py-armodel 用全局单例),带超时保护,不会卡住其他工具。
11. **差异脚本默认不落地**:`davinci_project_diff_script` 不传 `out_path` 时只返回文本;写文件必须 `confirm=true`。脚本自身默认 `dryRun=true`,即使被 `davinci_script_run` 执行也不会改工程。
## 6. 错误与退出码
所有工具返回统一信封,失败也不会抛 traceback:
```json
{
"ok": false,
"action": "校验工程",
"status": "failed",
"exit_code": 1,
"diagnostics": {"counts": {"error": 2, "warning": 1, "info": 1}},
"top_modules": [{"module": "EcuC", "findings": 1}],
"error": {"code": "failed", "message": "命令执行失败"},
"hint": "优先查看 stderr_tail:常见原因是 license 未激活、BSW 包版本与工程不匹配、模型存在未解决引用。"
}
```
| 退出码 | status | 含义 |
| --- | --- | --- |
| 0 | `ok` | 成功 |
| 1 | `failed` | 命令执行失败 |
| 2 | `usage_error` | 参数用法错误 |
| 6 | `usage_error` | CFG5:命令行参数无效(模块路径无法识别) |
| 130 | `cancelled` | 被取消 |
| 3 | `access_error` | `dvdevc`:无法创建/修改路径 |
| 7 | `workspace_not_found` | `dvdevc`:workspace 不存在 |
| — | `timed_out` / `spawn_error` / `project_busy` / `path_rejected` / `confirmation_required` | 服务层状态 |
## 7. 后台作业
```text
davinci_project_generate(project, wait_seconds=120)
→ {"status": "running", "job_id": "job-1a2b3c4d", "log_path": "..."}
davinci_job_status("job-1a2b3c4d")
davinci_job_logs("job-1a2b3c4d", offset=0, max_chars=20000) # 增量读取
davinci_job_cancel("job-1a2b3c4d")
```
- 作业日志写在 `DAVINCI_MCP_LOG_DIR`,服务重启后日志仍在(内存中的作业记录会丢失)。
- 并发上限 `DAVINCI_MCP_MAX_JOBS`,超出直接报错而不是排队——DaVinci 许可与 Config Core 都不适合高并发。
## 8. 已知限制
- **许可证无法离线校验**:`doctor` 只能提示,真正校验发生在首次 `project` 命令。
- **诊断解析是启发式**:不同版本输出格式可能变化,解析失败时仍返回原始 `stdout_tail` / `stderr_tail`,不会丢信息。
- **CFG5 的工程创建是模板克隆,不是从零生成**:模板里的 SIP/BSW、MCU、编译器与模块集会被完整继承;要换 BSW 路径用 `replacements` 或 GUI Project Settings,换 MCU 只能在 GUI 里改。
- **模板克隆不改写 `.dcf`**:Developer 工作区按原名复制,避免 `.dpa` 里的引用失效;需要改名请在 Developer 中另存。
- **CFG5 的选项覆盖以 `-h` 为准**:`-v/-g/-u/Save` 已封装;`import`、`export`、`--syncContract` 等通过 `davinci_cfg5_run` 透传,参数需自行确认。
- **CFG5 校验不支持按模块过滤**:`DVCfgCmd -v` 没有 `-m/-x`,通用工具传入时会返回 `ignored_options` 而不是静默丢弃。
- **CFG5 没有 build 流水线**:`davinci_build` 会明确拒绝 `.dpa`,请依次调用 `cfg5_validate → cfg5_update? → cfg5_generate`。
- **`project_info` 不是完整模型视图**:`.dvjson` 只读 `Settings/General.json`,`.dpa` 只统计目录与文件数;精确信息请以 DaVinci GUI 为准。
- **生成目录定位是启发式**:`.dvjson` / `Settings/*.json` 的字段名没有公开 schema,工具按「键名含 generation/output/target 且含 dir/folder/path」匹配,并要求路径真实存在。找不到字段时退回默认布局;两者都没有就返回空,不猜。字段命名很特殊的工程请用 `dirs` 显式指定。
- **`.dpa` 内设置条目不保证可读**:按 zip 条目扫描 JSON/XML/INI,遇到加密或私有编码会退化;归档内即使包含 `Appl/GenData` 条目也只提示、不列出,清单只针对磁盘目录。
- **生成物分类以位置为主**:位于工程设置指定的生成目录时,目录内文件默认算 `generated`——这符合「生成器输出」的语义,但不排除有人往该目录里放了手写文件;要更严格请用 `pattern` 缩小范围并看 `evidence`。
- **文件头只读前 4 KB / 后 1 KB**:生成标记写在文件尾部很远的位置时可能漏检;此时仍可由目录位置与命名给出分类。
- **`*_Callout.c` 等桩文件不等于可安全覆盖**:它们初次由生成器产出,之后常由人工维护;工具只在 `hint` 里提示,不做「可编辑/不可编辑」的硬判断。
- **CFG5 的 Groovy 没有公开的无头入口**:Vector 文档只描述了 GUI 的 Script Locations;`DVCfgCmd` 的公开选项里没有脚本执行。`davinci_cfg5_script_install` 只负责安装,批量执行请迁移到 CFG6。
- **JAR 反射只看签名、不看语义**:能回答「有没有这个方法、参数是什么」,回答不了「这个方法在这里能不能调」(受作用域与运行时状态限制);方法体不解析,注解值不还原。
- **JAR 索引依赖安装目录布局**:默认扫 `plugins/*.jar` 等常见位置,并把包名前缀限定为 `com.vector`;定制安装或换了包名时用 `jars=` 或 `package_prefix=""` 兜底。
- **Groovy 能力目录不是全量 API 索引**:只收录官方文档有出处的入口(约 50 条),写模型 setter、Data Mining 查询语法、UI 控件 API 因无公开示例而刻意不收录;目录外的符号可能是对的,最终由 `compile_check` 判定。
- **Groovy 静态检查不是编译器**:括号、`scriptTask`、危险 API 等规则能提前发现问题,但类型与 API 是否真实存在由 `compile_check=true` 决定。
- **`dvdevc` 子命令覆盖以官方交互手册为准**:`davinci_dev_run` 提供白名单透传,遇到新子命令无需改代码。
- **ECUC 分析与 Vector 校验不是一回事**:py-armodel 只做静态结构检查,不判断模块间语义约束、不执行生成;结论要与 `cfg5_validate` 交叉验证。
- **ECUC 分析不写回**:writer 往返会丢 `ANNOTATION-TEXT` 的 XHTML 等内容,因此只提供只读查询/对比/导出。批量修改请用 Groovy 或 `cfg5_update`。
- **ECUC 解析对非法值零容忍**:单个参数的类型错误会让整个文件解析失败,这是 py-armodel 的实现方式;报错会指出文件,需人工定位该值。
- **版本探测不是 AUTOSAR 权威判定**:`xsi:schemaLocation` 反映的是文件序列化时依据的 schema,工具重新保存后可能被升级;命名空间只能给出 `4.x` 兼容序列。工程设置的显式字段最可信,但没有该字段时结论只能到 `medium`。
- **`AUTOSAR_00046.xsd` 这类新命名不映射 release**:5 位编号是 schema 修订号,与 release 的对应表由 AUTOSAR 站点维护;工具原样返回 `schema_revision`,不猜。
- **模块版本是「描述文件版本」,不是 BSW 包版本**:它说明模块定义/配置按哪个 AUTOSAR 版本序列化,不等于 MICROSAR 包或 MCAL 驱动自身的版本号。
- **`.dpa` 内部结构不公开**:按 zip 条目做通用扫描(设置类文件优先,ARXML 提模块),遇到加密或私有编码会退化为文本扫描,找不到就返回 `null`。
- **SWS 文档名对照表是人工整理的**:约 50 个常见模块,标了 `origin: "curated"`;站点改版或模块拆分时文件名会变,检索式才是主路径。
- **文件差异不解析大文件内容**:超过 8 MB 的文件不计算 SHA-256;单侧哈希总量上限 512 MB,超出后只按大小 + 修改时间判断,置信度降为 `low`,同大小同时间的内容变化会漏报。
- **生成物排除沿用 §3.9 的启发式**:生成目录被改到工程目录之外、或目录名不在默认清单里时可能漏排,主表会混入生成文件;此时用 `max_changes` 之外先看 `by_category` 判断。
- **ECUC 语义差异受 py-armodel 限制**:单个非法值会让整个文件解析失败,此时 `ecuc.available=false`、`reason=parse_error`,文件级结论仍然有效。
- **回放脚本只写标量参数**:新增/删除参数、容器移动、设置与文件差异都只列清单。`dryRun` 能证明路径可解析,不能证明类型一定可赋值;第一次 `--dryRun=false` 请在测试工程上做。
- **模型路径前缀需要确认**:默认 `/ActiveEcuC` 来自官方示例;不同工程的 Active ECU 容器名可能不同,`[unresolved]` 全量出现时先改 `active_root`。
- **`.dpa` 回放要解包**:ARXML 解到临时目录解析,单条目上限 16 MB、总量 128 MB、最多 200 个文件;超出部分不参与语义对比。
## 9. 开发与测试
```bash
pip install -e ".[dev,ecuc]"
pytest -q
```
ECUC 解析类用例用 `pytest.importorskip` 语义做条件跳过:没装 `py-armodel` 时
只跳过解析相关用例,索引对比/查询的纯逻辑仍然会跑。
测试不依赖真实 DaVinci 安装:`tests/fake_bin/` 下有三个行为一致的假 CLI(共 307 个用例),覆盖:
- argv 拼装是否与官方语法一致(CFG6 的 `-p=` / `-m=a,b`,CFG5 的 `-p <dpa> -v/-g/-u`)
- 退出码 1/2/3/6/7 的映射
- 诊断解析(去重、文件/行号/模块提取)与 CFG5 ExecutionReport XML(含命名空间)
- `.dpa` 自动路由、CFG5 参数白名单、`.dpa` 后缀拒绝
- 超时杀进程、输出截断、无 shell 注入
- 路径逃逸拦截
- 项目锁、确认机制
- 异步作业生命周期
- Groovy 模板渲染、静态规则、`automation list` 编译检查、任务执行与失败识别、生成钩子签名与注册提醒、CFG5 安装
- Groovy 能力目录:域覆盖、检索(中英文/按域)、单符号解析、源码核对(含 import 与字符串剥离)、MCP 注册
- JAR 反射:常量池/修饰符/泛型描述符解析、包前缀过滤、坏 JAR 与超大条目容错、指纹缓存、`类#方法` 查询
- ECUC 索引统计、通配查询、整数归一化、语义 diff(含容器移动)、结构体检、CSV 导出、依赖缺失降级
- CFG5 模板克隆(复制范围、身份重写、自定义替换、空目录/嵌套目录拒绝、冒烟校验)
- AUTOSAR 版本探测(schemaLocation / 工程设置 / ADMIN-DATA / 命名空间四级证据、模块冲突、`.dpa` 压缩包、坏文件不中断、大量容器的流式解析、规范检索式)
- 模块资产定位(设置/参数/布局三层候选根、手册词形匹配、`src`/`inc` 静态代码与 `entry_points`、
生成目录内的同名代码标 `generated_code`、找不到时不猜、MCP 端到端)
- 生成物清单(工程设置/归档/默认布局/目录名四层取证、`generationMode` 不误判、越界目录拦截、文件头与命名分类、Callout 提示、过滤/深度/截断、二进制文件不按文本解码)
- 工程差异对比(文件改名识别、生成物排除与回填、设置键值展平、输入文件三层取证与角色分类、
CFG5 `-u --input` / CFG6 复制+`project update -c` 回放、BSW 缺失与归档降级、
ECUC 增删改与可写判定、`.dpa` 归档对比、依赖缺失与无 ARXML 降级、脚本渲染与转义、
`confirm` 与扩展名校验、cmd/sh/json 三种 CLI 输出)
- MCP 工具/资源/提示词注册与 `call_tool` 端到端
```
tests/
├── fake_bin/dvcfg-b # 假 Configurator 6 CLI
├── fake_bin/DVCfgCmd # 假 Configurator 5 CLI(生成 ExecutionReport XML)
├── fake_bin/dvdevc # 假 Developer CLI
├── conftest.py # 临时工程 + 假环境夹具
├── test_runner.py # 执行器
├── test_paths.py # 路径策略
├── test_parsing.py # 输出解析
├── test_configurator.py # Configurator 服务
├── test_cfg5.py # CFG5 服务、报告解析、路由
├── test_cfg5_create.py # CFG5 模板克隆创建
├── test_groovy.py # Groovy 模板、静态检查、执行
├── test_groovy_api.py # Groovy 能力目录与源码核对
├── test_java_index.py # JAR 反射:class 解析、泛型、缓存、服务层
├── test_ecuc.py # ECUC 索引/查询/对比/体检/导出
├── test_arversion.py # AUTOSAR 版本探测与规范定位
├── test_modassets.py # 模块资产:Vector 手册与静态代码定位
├── test_genfiles.py # 生成目录发现与生成物清单
├── test_projdiff.py # 工程差异对比、输入文件取证与 Groovy/CLI 回放
├── test_developer.py # Developer 服务
├── test_server.py # MCP 层
├── data/java/ # JAR 夹具源码 + 构建脚本(build.sh,需 JDK 16+)
└── data/arversion/ # 版本探测夹具(4.2.2 / 4.0.3 / ADMIN-DATA / 截断文件 / 工程目录)
```
## 10. 目录结构
```
src/davinci_mcp/
├── cfg5_create.py # CFG5 工程创建(模板克隆 + 身份重写)
├── cfg5_report.py # CFG5 ExecutionReport XML 解析
├── cli.py # davinci-mcp serve / doctor / list-tools / config
├── config.py # 环境变量、可执行文件发现(含 DVCfgCmd)
├── ecuc.py # ECUC 索引/查询/对比/体检(不依赖 armodel 亦可导入)
├── errors.py # 结构化错误
├── groovy.py # Groovy 模板 + 静态分析
├── groovy_api.py # Groovy 能力目录(官方 API 索引 + 源码核对)
├── java_index.py # JAR 反射:class 解析 / 索引缓存 / 检索
├── jobs.py # 后台作业 + 项目锁
├── models.py # CommandResult、退出码语义
├── arversion.py # AUTOSAR 版本探测:证据采集、汇总、规范定位
├── modassets.py # 模块资产定位:Vector User Manual 与静态代码
├── genfiles.py # 生成目录发现、文件分类、目录清单
├── projdiff.py # 工程差异:文件/设置/输入文件/ECUC 四层对比、Groovy 与 CLI 回放渲染
├── parsing.py # 诊断/导出器/工程摘要/产物扫描
├── paths.py # 路径白名单
├── runner.py # argv 执行器
├── server.py # MCP 工具/资源/提示词装配
├── service_base.py # 统一信封 + 作业编排
├── service_cfg5.py # DVCfgCmd(CFG5)
├── service_configurator.py # dvcfg-b(CFG6)
├── service_developer.py # dvdevc
├── service_arversion.py # 版本探测服务:目录展开、扫描编排
├── service_modassets.py # 模块资产服务:BSW 包解析、白名单校验
├── service_genfiles.py # 生成物清单服务:路径白名单、结果汇总
├── service_projdiff.py # 差异对比服务:解析编排、依赖降级、脚本落盘
├── service_ecuc.py # ECUC 只读分析(可选依赖 py-armodel)
├── service_groovy.py # Groovy 脚本生命周期
└── service_pipeline.py # 多步流水线
```
## 11. 参考资料
- [DaVinci Configurator Classic CLI Reference](https://help.vector.com/davinci-configurator-classic/en/latest/user-manual/references/cli-reference.html)
- [dvcfg-b project generate](https://help.vector.com/davinci-configurator-classic/en/latest/user-manual/references/cli/dvcfg-b/project-generate.html)
- [dvcfg-b project validate](https://help.vector.com/davinci-configurator-classic/en/latest/user-manual/references/cli/dvcfg-b/project-validate.html)
- [DaVinci Configurator 与 Developer Classic 交互手册(dvdevc 命令)](https://help.vector.com/davinci-configurator-classic/en/6.3/user-manual/_attachments/UserManual_InteractionWithCfg6.pdf)
- [CFG5 Platform Functions / DVCfgCmd 用法(官方迁移文档)](https://help.vector.com/davinci-configurator-classic/en/latest/user-manual/project-setup/share-configuration/ecu-project-sync-platform-functions.html)
- [DaVinci Configurator SIP Type Functionality(`DVCfgCmd -p <dpa> -g`)](https://support.vector.com/kb/?id=kb_article_view&sysparm_article=KB0013919)
- [AutomationInterface 文档(脚本结构、任务类型、用户参数)](https://help.vector.com/davinci-configurator-classic/en/current/automation-interface/6.2.3-SP2/_attachments/AutomationInterfaceDocumentation.pdf)
- [Command Line Usage(automation list / run、取消语义)](https://help.vector.com/davinci-configurator-classic/en/latest/user-manual/base/using-the-tool/command-line-usage.html)
- [dvcfg-b automation setup / list / info / run](https://help.vector.com/davinci-configurator-classic/en/latest/user-manual/references/cli/dvcfg-b/automation.html)
- [py-armodel(AUTOSAR 4.x 元模型解析与生成,pip 包名 `armodel`)](https://github.com/melodypapa/py-armodel)
- [AUTOSAR ECUC 配置参数规范(ECUC_SWS)](https://www.autosar.org/fileadmin/standards/R21-11/CP/AUTOSAR_CP_SWS_ECUConfiguration.pdf)
- [AUTOSAR TPS ARXML Serialization Rules(schemaLocation 与版本声明,TPS_ASR_00012)](https://www.autosar.org/fileadmin/standards/R19-11/CP/AUTOSAR_TPS_ARXMLSerializationRules.pdf)
- [AUTOSAR Classic Platform 标准下载页](https://www.autosar.org/standards/classic-platform/)
- [Model Context Protocol](https://modelcontextprotocol.io)
## License
MIT。本项目只封装公开的命令行接口,不包含任何 Vector 源码或二进制。
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo recent community issues