[feat] Add zentao plugin (Claude Code + Codex dual scaffold)
新增禅道项目管理系统插件,含项目集/产品/项目/执行、需求 (story/epic/requirement)、Bug、任务、测试、计划与发布、反馈工单 八个工作流技能,自动配置 MCP 连接(禅道「个人中心 → 获取凭证」 自助生成 14 天 Token)。 MCP Server 是团队自建的 zentao-mcp 网桥(部署在 pm.ops.yixiong-tech.com/mcp),基于开源 openapi-mcp-server 二次开发。 Claude 侧走 userConfig 钥匙链 + 自定义 token 头;Codex 侧受限于官方 插件格式只支持 bearer_token_env_var,走 Authorization: Bearer——网桥 那边已经加了 preferred_header/bearer_mode 配置项统一归一化处理,两条 路径都验证过连通。 三轮审查(静态字段对照 openapi.json、跨文件一致性、真实端点实测) 修正过程中发现的问题,技能文档里引用的工具名全部跟服务器真实注册 的 118 个工具核对过。 同步更新:.claude-plugin/marketplace.json、.agents/plugins/marketplace.json、 README.md、CLAUDE.md 的插件索引与说明;README 补充「获取凭证」操作 截图(已脱敏)。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016pFx6jnym6kRWRQ5JyDUNv
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
1606d73c41
commit
9d9e31c98e
@@ -51,6 +51,18 @@
|
||||
"authentication": "ON_INSTALL"
|
||||
},
|
||||
"category": "Productivity"
|
||||
},
|
||||
{
|
||||
"name": "zentao",
|
||||
"source": {
|
||||
"source": "local",
|
||||
"path": "./plugins/zentao"
|
||||
},
|
||||
"policy": {
|
||||
"installation": "AVAILABLE",
|
||||
"authentication": "ON_INSTALL"
|
||||
},
|
||||
"category": "Productivity"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
"name": "obsidian",
|
||||
"source": "./plugins/obsidian",
|
||||
"description": "Obsidian 知识库 AI 协作插件族:检测到 .obsidian/ 目录自动激活,含 vault 管理、搜索图谱、frontmatter、任务、每日笔记、Bases 数据库、Canvas 视觉层、版本历史、插件配置、PKM 编排工作流共 10 个技能"
|
||||
},
|
||||
{
|
||||
"name": "zentao",
|
||||
"source": "./plugins/zentao",
|
||||
"description": "禅道项目管理系统:项目集/产品/项目/执行、需求(story/epic/requirement)、Bug、任务、测试、计划与发布、反馈工单八个工作流技能,自动配置 MCP 连接(禅道「个人中心 → 获取凭证」自助生成 14 天 Token)"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -92,8 +92,9 @@ description: 一句话说明该技能的用途(Claude 用此判断何时触发
|
||||
| `huanxi-admin` | `/huanxi-admin-shared` `/huanxi-admin-report` `/huanxi-admin-module` `/huanxi-admin-ops` | 寰汐企业管理系统 · 管理端(4 技能),全量视角,需后台管理员发放 hxa_ Token,普通员工无需安装 |
|
||||
| `memcore` | `/memory-sync` `/memory-update` `/memory-lint` `/memcore-shared`(内部 include) | 项目记忆体系核心引擎 |
|
||||
| `obsidian` | `/obsidian` `/obsidian-bases` `/obsidian-canvas` `/obsidian-daily` `/obsidian-history` `/obsidian-meta` `/obsidian-plugins` `/obsidian-search` `/obsidian-tasks` `/obsidian-workflow-pkm` | Obsidian 知识库完整工作流(10 个技能;对标 kepano/obsidian-skills 31.8k★ 与 AgriciDaniel/claude-obsidian) |
|
||||
| `zentao` | `/zentao-shared` `/zentao-project` `/zentao-story` `/zentao-bug` `/zentao-task` `/zentao-test` `/zentao-plan` `/zentao-misc` | 禅道项目管理系统(8 个技能),含 MCP Server 自动配置(禅道「个人中心 → 获取凭证」14 天 Token);MCP Server 是基于开源 [merzzzl/openapi-mcp-server](https://github.com/merzzzl/openapi-mcp-server) 二次开发的 zentao-mcp 网桥,部署在 `pm.ops.yixiong-tech.com/mcp`,请求体字段统一包在 `payload` 里 |
|
||||
|
||||
四个插件均有 Codex/ChatGPT 桌面应用版本(见上方「Codex plugin.json」一节)。huanxi/huanxi-admin/obsidian 的 Codex 版共用本表里的同一份 `skills/`;`memcore` 的 Codex 版是独立目录 `plugins/memcore-codex/`(内容与下方 Claude 版 memcore 不同,改动时两边分别维护,不要假设同步)。已调研并确认不做 Google Antigravity(agy)兼容——其官方文档目前没有 marketplace 概念。
|
||||
五个插件均有 Codex/ChatGPT 桌面应用版本(见上方「Codex plugin.json」一节)。huanxi/huanxi-admin/obsidian/zentao 的 Codex 版共用本表里的同一份 `skills/`;`memcore` 的 Codex 版是独立目录 `plugins/memcore-codex/`(内容与下方 Claude 版 memcore 不同,改动时两边分别维护,不要假设同步)。已调研并确认不做 Google Antigravity(agy)兼容——其官方文档目前没有 marketplace 概念。
|
||||
|
||||
### memcore 技能调用关系
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
/plugin install huanxi-admin@yixiong-claude-hub
|
||||
/plugin install memcore@yixiong-claude-hub
|
||||
/plugin install obsidian@yixiong-claude-hub
|
||||
/plugin install zentao@yixiong-claude-hub
|
||||
```
|
||||
|
||||
已安装的插件会在会话启动时自动检测更新——本仓库不走语义化版本号,每次推送 `main` 分支即视为新版本。
|
||||
@@ -47,17 +48,18 @@ codex plugin marketplace add https://gitea.rk-health.com/yixiong/yixiong-claude-
|
||||
codex plugin add huanxi-admin@yixiong-codex-hub
|
||||
codex plugin add memcore@yixiong-codex-hub
|
||||
codex plugin add obsidian@yixiong-codex-hub
|
||||
codex plugin add zentao@yixiong-codex-hub
|
||||
```
|
||||
|
||||
- **ChatGPT 桌面应用(图形界面)**:市场源注册生效后,打开 **设置(Settings)→ 插件(Plugins)**,或侧边栏的 **Plugins** 入口,就能看到我们的市场和这四个插件,点击安装即可,不用碰命令行。
|
||||
- **ChatGPT 桌面应用(图形界面)**:市场源注册生效后,打开 **设置(Settings)→ 插件(Plugins)**,或侧边栏的 **Plugins** 入口,就能看到我们的市场和这五个插件,点击安装即可,不用碰命令行。
|
||||
|
||||
安装完成后开一个新会话,Codex 才会加载新装的技能和 MCP 工具。
|
||||
|
||||
> ⚠️ **桌面应用读不到 shell 里 `export` 的环境变量**:`huanxi`/`huanxi-admin` 的 Token 走环境变量注入(见下一节),但 macOS/Windows 上从 Dock/开始菜单启动的图形应用不会继承 `~/.zshrc` 里 `export` 的变量——这是终端应用和图形应用两种不同的启动路径决定的,不是我们插件的问题。桌面应用场景要设置成**系统级/用户级持久环境变量**才行,具体见下一节。
|
||||
> ⚠️ **桌面应用读不到 shell 里 `export` 的环境变量**:`huanxi`/`huanxi-admin`/`zentao` 的 Token 走环境变量注入(见下一节),但 macOS/Windows 上从 Dock/开始菜单启动的图形应用不会继承 `~/.zshrc` 里 `export` 的变量——这是终端应用和图形应用两种不同的启动路径决定的,不是我们插件的问题。桌面应用场景要设置成**系统级/用户级持久环境变量**才行,具体见下一节。
|
||||
>
|
||||
> ⚠️ **插件级 Token 配置目前是 Codex 官方还没定案的能力**:截至本文写作时,插件打包的 MCP server 没有类似 Claude 侧「安装时弹窗填 Token」的正式支持(见 [openai/codex#24401](https://github.com/openai/codex/issues/24401)),环境变量是目前唯一现实可用的路径。装完插件连不上 MCP,先检查 Token 环境变量是不是在 Codex/ChatGPT 启动**之前**就已经生效。
|
||||
|
||||
> Codex 侧的插件清单独立维护在 [`.agents/plugins/marketplace.json`](./.agents/plugins/marketplace.json)。除 `memcore` 外,其余三个插件与 Claude Code 版共用同一份 `skills/`;`memcore` 因为架构差异(会话入口、记忆目录约定、有无远程同步都不同)走的是独立目录 [`plugins/memcore-codex/`](./plugins/memcore-codex),两边分开维护。
|
||||
> Codex 侧的插件清单独立维护在 [`.agents/plugins/marketplace.json`](./.agents/plugins/marketplace.json)。除 `memcore` 外,其余四个插件与 Claude Code 版共用同一份 `skills/`;`memcore` 因为架构差异(会话入口、记忆目录约定、有无远程同步都不同)走的是独立目录 [`plugins/memcore-codex/`](./plugins/memcore-codex),两边分开维护。
|
||||
|
||||
## 插件一览
|
||||
|
||||
@@ -67,6 +69,7 @@ codex plugin marketplace add https://gitea.rk-health.com/yixiong/yixiong-claude-
|
||||
| [`huanxi-admin`](./plugins/huanxi-admin) | 4 | 寰汐管理端——汇报盘点、模块与成员配置、运维简报 | 需要后台管理员发放 `hxa_` Token 的管理岗 | ✅ | ✅ |
|
||||
| [`memcore`](./plugins/memcore) / [`memcore-codex`](./plugins/memcore-codex) | 4 | 项目记忆体系核心引擎——跨会话记忆的同步/增量更新/健康校验 | 用 Claude Code 或 Codex 做长期项目的开发者 | ✅ | ✅ |
|
||||
| [`obsidian`](./plugins/obsidian) | 10 | Obsidian 知识库全套协作工作流——vault 管理、搜索图谱、Bases、Canvas、每日笔记等 | 用 Obsidian 做知识管理的人 | ✅ | ✅ |
|
||||
| [`zentao`](./plugins/zentao) | 8 | 禅道项目管理——项目集/产品/项目/执行、需求(story/epic/requirement)、Bug、任务、测试、计划与发布、反馈工单 | 用禅道管项目/需求/Bug/任务的人 | ✅ | ✅ |
|
||||
|
||||
### huanxi / huanxi-admin
|
||||
|
||||
@@ -99,6 +102,30 @@ Claude Code 版([`plugins/memcore`](./plugins/memcore))以 `.claude/memory/`
|
||||
|
||||
检测到项目里有 `.obsidian/` 目录会自动激活,覆盖 vault 管理、全文与图谱搜索、frontmatter、任务、每日笔记、Bases 数据库、Canvas 视觉层、版本历史、插件配置、PKM 编排十个技能,对标社区里比较成熟的 Obsidian 技能实现后做了扩展。**无需任何配置**,Claude Code 和 Codex CLI 共用同一份技能内容。
|
||||
|
||||
### zentao
|
||||
|
||||
禅道是蚁熊内部的项目/需求/Bug/任务管理系统。插件覆盖项目集(program)/产品/项目/执行的层级管理、需求条线(story 用户故事 / epic 业务需求 / requirement 用户需求三种类型及其状态机)、Bug 全流程、任务状态机、测试用例与测试单、产品计划/版本/发布、反馈与工单、附件改名,共 8 个工作流技能。
|
||||
|
||||
**配置步骤:**
|
||||
|
||||
1. 登录禅道,头像下拉菜单点「获取凭证」:
|
||||
|
||||
<img src="./docs/images/zentao-token/01-menu.png" width="240" alt="头像下拉菜单 → 获取凭证" />
|
||||
|
||||
2. 点击「生成凭证」——注意提示:生成新凭证会让旧凭证立即失效,且明文只在生成后展示一次,务必当场保存;有效期 14 天,到期需重新获取:
|
||||
|
||||
<img src="./docs/images/zentao-token/02-generate.png" width="480" alt="生成凭证确认弹窗" />
|
||||
|
||||
3. 弹窗会给出「API 地址」和「Token」两项,Claude Code / Codex 安装时都只需要 Token(API 地址已经写死在插件的 MCP 配置里,不用手动填):
|
||||
|
||||
<img src="./docs/images/zentao-token/03-token.png" width="480" alt="API 地址与 Token 展示" />
|
||||
|
||||
4. **Claude Code**:执行 `/plugin install` 时会提示输入 Token,直接粘贴即可——存放在系统钥匙链,不会明文写入配置文件。
|
||||
5. **Codex CLI / ChatGPT 桌面应用**:Token 走环境变量注入,设置方式同 `huanxi`:
|
||||
|
||||
- **命令行**:`export ZENTAO_TOKEN=你的token`,建议写进 `~/.zshrc` / `~/.bashrc`
|
||||
- **ChatGPT 桌面应用**:macOS 用 `launchctl setenv ZENTAO_TOKEN 你的token`,Windows 走「系统属性 → 环境变量」新增用户变量 `ZENTAO_TOKEN`,设置后需重新打开应用
|
||||
|
||||
## 开发
|
||||
|
||||
给这个市场新增插件、技能实现规范、`marketplace.json`/`plugin.json` 格式说明,见 [CLAUDE.md](./CLAUDE.md)。
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "zentao",
|
||||
"description": "禅道项目管理系统:项目集/产品/项目/执行、需求(story/epic/requirement)、Bug、任务、测试、计划与发布、反馈工单等工作流技能,自动配置 MCP 连接。",
|
||||
"author": {
|
||||
"name": "蚁熊团队"
|
||||
},
|
||||
"userConfig": {
|
||||
"token": {
|
||||
"type": "string",
|
||||
"title": "禅道 API Token",
|
||||
"description": "在禅道「个人中心 → 获取凭证」自助生成,14 天有效期,到期需重新生成",
|
||||
"sensitive": true
|
||||
}
|
||||
},
|
||||
"mcpServers": {
|
||||
"zentao": {
|
||||
"type": "http",
|
||||
"url": "https://pm.ops.yixiong-tech.com/mcp",
|
||||
"headers": {
|
||||
"token": "${user_config.token}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "zentao",
|
||||
"version": "1.0.0",
|
||||
"description": "禅道项目管理系统插件,含项目集/产品/项目/执行、需求、Bug、任务、测试、计划与发布、反馈工单八个工作流技能,自动配置 MCP 连接。",
|
||||
"author": {
|
||||
"name": "蚁熊团队"
|
||||
},
|
||||
"skills": "./skills",
|
||||
"mcpServers": "./.mcp.json",
|
||||
"interface": {
|
||||
"displayName": "禅道",
|
||||
"shortDescription": "禅道项目/需求/Bug/任务/测试工作流",
|
||||
"longDescription": "禅道项目管理系统插件:覆盖项目集、产品、项目、执行、需求(story/epic/requirement)、Bug、任务、测试用例与测试单、产品计划、版本、发布、反馈、工单等工作流技能。安装后需在禅道「个人中心 → 获取凭证」自助生成 14 天有效期的 Token,并配置为环境变量 ZENTAO_TOKEN。",
|
||||
"developerName": "蚁熊团队",
|
||||
"category": "Productivity",
|
||||
"capabilities": ["Interactive", "Write"],
|
||||
"defaultPrompt": "帮我看看我名下有哪些未解决的 Bug 和任务"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"zentao": {
|
||||
"type": "http",
|
||||
"url": "https://pm.ops.yixiong-tech.com/mcp",
|
||||
"bearer_token_env_var": "ZENTAO_TOKEN"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
name: zentao-bug
|
||||
description: "禅道 Bug 管理:创建、查询、解决、关闭、激活 Bug。当用户说「提个 bug」「这个 bug 修好了」「bug 关掉」「查一下未解决的 bug」时使用。"
|
||||
---
|
||||
|
||||
# 禅道 Bug 管理
|
||||
|
||||
**前置:先读 `zentao-shared`(尤其"路径参数不出现在 inputSchema 里"一节)。**
|
||||
|
||||
---
|
||||
|
||||
## 状态机
|
||||
|
||||
```
|
||||
激活(open) ──resolve 解决──▶ 已解决(resolved) ──close 关闭──▶ 已关闭(closed)
|
||||
▲ │
|
||||
└──────────────────── activate 激活(重新打开)────────────────┘
|
||||
```
|
||||
|
||||
`close` 也可以直接对一个未解决的 bug 使用(跳过 resolve 直接关闭,比如确认不是真实
|
||||
问题),但更常见的路径是先 resolve 再 close。
|
||||
|
||||
---
|
||||
|
||||
## 查
|
||||
|
||||
```
|
||||
get_products_productID_bugs(productID, ...)
|
||||
get_projects_projectID_bugs(projectID, ...)
|
||||
get_executions_executionID_bugs(executionID, ...)
|
||||
get_bugs_bugID(bugID) 详情
|
||||
```
|
||||
|
||||
用户问"未解决的 bug"时先确认要看哪个维度(产品/项目/执行),三个列表接口过滤范围不同。
|
||||
|
||||
---
|
||||
|
||||
## 建
|
||||
|
||||
```
|
||||
post_bugs({ payload: { productID, title, openedBuild, project?, execution?, severity?,
|
||||
pri?, type?, steps?, story? } })
|
||||
```
|
||||
|
||||
`productID`/`title`/`openedBuild` 三个必填——**`openedBuild`(影响版本)容易漏**,
|
||||
不是可选项,**是字符串数组**,元素是版本 ID,主干传 `["trunk"]`(不是单个字符串
|
||||
`"trunk"`),可以同时关联多个版本。
|
||||
|
||||
`type`(Bug 类型)受限枚举:`codeerror` 代码错误 | `config` 配置相关 | `install` 安装部署
|
||||
| `security` 安全相关 | `performance` 性能问题 | `standard` 标准规范 | `automation` 测试脚本
|
||||
| `designdefect` 设计缺陷 | `others` 其他。
|
||||
|
||||
`severity`(严重程度)/`pri`(优先级)不传默认都是 3。
|
||||
|
||||
`story` 字段可以关联一个相关需求(story ID)。
|
||||
|
||||
---
|
||||
|
||||
## 解决(resolve)
|
||||
|
||||
```
|
||||
put_bugs_bugID_resolve({ bugID, payload: { resolution, resolvedDate?, resolvedBuild?,
|
||||
assignedTo?, comment? } })
|
||||
```
|
||||
|
||||
`resolution` 必填,受限枚举:`fixed` 已解决 | `notrepro` 无法重现 | `bydesign` 设计如此 |
|
||||
`duplicate` 重复Bug | `external` 外部原因 | `postponed` 延期处理 | `willnotfix` 不予解决 |
|
||||
`tostory` 转为需求。
|
||||
|
||||
**先跟用户确认具体是哪种解决方式再调用**(`zentao-shared` 全局约定:状态流转类操作先
|
||||
确认)——`fixed` 和 `willnotfix`/`notrepro` 对提交者的观感完全不同,不要因为用户说
|
||||
"这个处理一下"就默认填 `fixed`。`tostory` 这个选项比较特殊,选它意味着这个 bug 会被
|
||||
转成一条需求,用之前跟用户确认清楚是不是真的要转。
|
||||
|
||||
---
|
||||
|
||||
## 关闭(close)/ 激活(activate)
|
||||
|
||||
```
|
||||
put_bugs_bugID_close({ bugID, payload: { comment? } })
|
||||
put_bugs_bugID_activate({ bugID, payload: { openedBuild?, assignedTo?, comment? } })
|
||||
```
|
||||
|
||||
都没有必填字段。关闭前确认这个 bug 确实该关了(比如已经 resolve 过,或者提交者认可
|
||||
不是真实问题);激活是把已关闭/已解决的 bug 重新打开,一般用于验证不通过要打回。
|
||||
|
||||
---
|
||||
|
||||
## 改 / 删
|
||||
|
||||
```
|
||||
put_bugs_bugID({ bugID, payload: {...} })
|
||||
delete_bugs_bugID({ bugID })
|
||||
```
|
||||
|
||||
删除不可逆,执行前必须确认。
|
||||
@@ -0,0 +1,101 @@
|
||||
---
|
||||
name: zentao-misc
|
||||
description: "禅道反馈、工单、应用管理、附件改名。当用户说「提个反馈」「开个工单」「工单关掉」「建个应用」「改一下附件名字」时使用。"
|
||||
---
|
||||
|
||||
# 禅道反馈 / 工单 / 应用 / 附件
|
||||
|
||||
**前置:先读 `zentao-shared`(尤其"路径参数不出现在 inputSchema 里"一节)。**
|
||||
|
||||
---
|
||||
|
||||
## 反馈(feedback)
|
||||
|
||||
```
|
||||
get_products_productID_feedbacks(productID, ...)
|
||||
get_feedbacks_feedbackID(feedbackID)
|
||||
|
||||
post_feedbacks({ payload: { product, title, module?, type?, desc?, feedbackBy?, source? } })
|
||||
put_feedbacks_feedbackID({ feedbackID, payload: {...} })
|
||||
delete_feedbacks_feedbackID({ feedbackID })
|
||||
|
||||
put_feedbacks_feedbackID_close({ feedbackID, payload: { closedReason, comment? } })
|
||||
put_feedbacks_feedbackID_activate({ feedbackID, payload: {...} })
|
||||
```
|
||||
|
||||
**创建字段名注意:所属产品叫 `product`,不是 `productID`**(跟大多数其他实体不一致,
|
||||
`zentao-plan` 的 build/release 也是这个坑)。
|
||||
|
||||
**"没有反馈/工单"和"参数传错"在这两个接口上长得一模一样**:实测发现某个产品下没有
|
||||
反馈/工单记录时,后端返回的是 `HTTP 200` + **完全空的响应体**,跟 `zentao-shared` 里说的
|
||||
"路径参数传漏/传错 → 静默返回空结果"是同一种表现。`zentao-shared` 那条"先怀疑参数
|
||||
传漏了,再怀疑数据本身"的排查顺序在这两个接口上不管用——换任何一个真实存在的
|
||||
`productID` 都可能一样是空的。真要鉴别,换个已知有数据的接口(比如 `get_products`)
|
||||
确认这个 productID 本身没写错,或者直接问用户这个产品下是否本来就没有反馈/工单。
|
||||
|
||||
`type`(反馈类型)受限枚举:`story` 需求 | `task` 任务 | `bug` Bug | `todo` 待办 |
|
||||
`advice` 建议 | `issue` 问题 | `risk` 风险 | `opportunity` 机会——这个类型决定了反馈
|
||||
可能被后续转化成对应的实体,跟用户确认清楚类型再提交。
|
||||
|
||||
`closedReason` 关闭必填,受限枚举:`commented` 已处理 | `repeat` 重复 | `refuse` 不予采纳。
|
||||
关闭前按 `zentao-shared` 全局约定跟用户确认原因。
|
||||
|
||||
---
|
||||
|
||||
## 工单(ticket)
|
||||
|
||||
```
|
||||
get_products_productID_tickets(productID, ...)
|
||||
get_tickets_ticketID(ticketID)
|
||||
|
||||
post_tickets({ payload: { product, title, module?, type?, desc?, assignedTo?, deadline?,
|
||||
openedBuild? } })
|
||||
put_tickets_ticketID({ ticketID, payload: {...} })
|
||||
delete_tickets_ticketID({ ticketID })
|
||||
|
||||
put_tickets_ticketID_close({ ticketID, payload: { closedReason, comment } })
|
||||
put_tickets_ticketID_activate({ ticketID, payload: {...} })
|
||||
```
|
||||
|
||||
同样是 `product` 不是 `productID`。`type`(工单类型)受限枚举:`code` 程序报错 |
|
||||
`data` 数据错误 | `stuck` 流程卡断 | `security` 安全问题 | `affair` 事务。
|
||||
|
||||
`openedBuild`(影响版本)**是字符串数组**,可以关联多个版本,不是单个 ID,跟 `zentao-bug`
|
||||
里 `openedBuild` 的数组结构是同一个模式。
|
||||
|
||||
**关闭工单 `closedReason` 和 `comment` 都必填**(反馈关闭只要求 `closedReason`,工单
|
||||
两个都要)——`closedReason` 枚举:`commented` 已处理 | `repeat` 重复 | `refuse` 不予处理。
|
||||
|
||||
---
|
||||
|
||||
## 应用(system)
|
||||
|
||||
```
|
||||
get_products_productID_systems(productID, ...)
|
||||
|
||||
post_systems({ payload: { productID, integrated, children, name, desc? } })
|
||||
put_systems_systemID({ systemID, payload: {...} })
|
||||
```
|
||||
|
||||
**没有查询单条应用详情、也没有删除应用的接口**(只有创建/修改),这跟其他实体都不一样,
|
||||
需要删除或者查看单条详情要引导用户去网页端。
|
||||
|
||||
**`get_products_productID_systems` 实测对部分账号会返回 `HTTP 403 Access not allowed`**——
|
||||
应用管理看起来受账号权限控制,不是所有 Token 都能查。403 时先怀疑是权限不够(提示用户
|
||||
去禅道网页确认自己有没有应用管理权限),不要当成参数错误去排查。
|
||||
|
||||
四个必填字段里 `integrated`(是否集成应用:`0` 否 | `1` 是)和 `children`(集成应用需要
|
||||
包含哪些其他应用的 ID 列表,非集成应用传空数组 `[]`)都容易漏传——创建前先问清楚这个
|
||||
应用是不是"集成应用"(把多个子应用打包发布的那种),决定这两个字段怎么填。
|
||||
|
||||
---
|
||||
|
||||
## 附件改名(file)
|
||||
|
||||
```
|
||||
put_files_fileID({ fileID, payload: { fileName } })
|
||||
```
|
||||
|
||||
**这套 MCP 工具里附件相关能力只有改名这一个**(`zentao-shared` 已提过):上传新附件、
|
||||
删除附件都不在工具列表里,需要引导用户去网页端操作。`fileName` 必填,改名会连带更新
|
||||
附件的扩展名(如果新文件名里带了不同的后缀)。
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
name: zentao-plan
|
||||
description: "禅道产品计划、版本(build)、发布(release)管理。当用户说「排个产品计划」「打个包」「建个版本」「发布上线」时使用。"
|
||||
---
|
||||
|
||||
# 禅道产品计划 / 版本 / 发布
|
||||
|
||||
**前置:先读 `zentao-shared`(尤其"路径参数不出现在 inputSchema 里"一节)。**
|
||||
|
||||
---
|
||||
|
||||
## 三者关系
|
||||
|
||||
```
|
||||
productplan 产品计划(做什么、什么时候做)
|
||||
build 版本/构建(某次打包产出,挂在执行下)
|
||||
release 发布(把某个/某几个 build 正式对外发布)
|
||||
```
|
||||
|
||||
三者是独立管理的实体,不是严格的父子层级——`release` 通过 `build` 字段关联具体的构建,
|
||||
`build` 通过 `executionID` 关联执行、`system` 关联应用,`productplan` 只挂产品,不关联
|
||||
执行/构建。
|
||||
|
||||
---
|
||||
|
||||
## 产品计划(productplan)
|
||||
|
||||
```
|
||||
get_products_productID_productplans(productID, ...)
|
||||
get_productplans_planID(planID) 详情——注意参数叫 planID,不是 productplanID
|
||||
|
||||
post_productplans({ payload: { productID, title, parent?, begin?, end?, branchID?, desc? } })
|
||||
put_productplans_productplanID({ productplanID, payload: {...} }) # 改用的是 productplanID
|
||||
delete_productplans_productplanID({ productplanID })
|
||||
```
|
||||
|
||||
**详情接口和改/删接口的路径参数名不一样**(`planID` vs `productplanID`),照抄各自工具
|
||||
名对应的字面参数名。`productID`/`title` 必填,`parent` 可以挂一个父计划形成层级。
|
||||
|
||||
---
|
||||
|
||||
## 版本 / 构建(build)
|
||||
|
||||
```
|
||||
get_projects_projectID_builds(projectID, ...)
|
||||
get_executions_executionID_builds(executionID, ...)
|
||||
|
||||
post_builds({ payload: { executionID, product, name, system, builder, date,
|
||||
scmPath?, filePath?, desc? } })
|
||||
put_builds_buildID({ buildID, payload: {...} })
|
||||
delete_builds_buildID({ buildID })
|
||||
```
|
||||
|
||||
必填字段比较多:`executionID`(注意是 `executionID` 不是 `execution`)、`product`
|
||||
(注意是 `product` 不是 `productID`)、`name`、`system`(所属应用,需要先有
|
||||
`zentao-misc` 里的应用 ID)、`builder`(构建者)、`date`(打包日期)——**字段名在不同
|
||||
实体间不统一是这套 API 的通病**(`zentao-task` 也提过 name/title、executionID/execution
|
||||
的不一致),创建前对照该工具自己的 inputSchema 逐个字段确认,不要照抄其他实体的字段名。
|
||||
|
||||
没有单条版本详情接口,从列表里过滤。
|
||||
|
||||
---
|
||||
|
||||
## 发布(release)
|
||||
|
||||
```
|
||||
get_products_productID_releases(productID, ...)
|
||||
|
||||
post_releases({ payload: { productID, system, name, build, date, status?, desc? } })
|
||||
put_releases_releasID({ releasID, payload: {...} }) # 注意参数叫 releasID,不是 releaseID
|
||||
delete_releases_releasID({ releasID })
|
||||
```
|
||||
|
||||
必填:`productID`/`system`(所属应用)/`name`(应用版本号)/`build`(包含的构建,**是字符
|
||||
串数组**,可以关联多个构建,不是单个 ID)/`date`(计划发布日期)。
|
||||
|
||||
`status` 受限枚举:`wait` 未开始 | `normal` 已发布 | `fail` 发布失败 | `terminate` 停止维护
|
||||
——不像 bug/task 有专门的状态流转端点,发布状态直接在创建/修改时传 `status` 字段设置,
|
||||
改状态就是 `put_releases_releasID({ releasID, payload: { status: "normal" } })`。
|
||||
|
||||
**没有单条发布详情接口**,从 `get_products_productID_releases` 列表里过滤。
|
||||
|
||||
**参数名注意**:路径参数字面拼写是 `releasID`(缺一个 `e`),跟 testcase 的 `testcasID`
|
||||
是同一类官方 API 拼写坑,照抄不要纠正。
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
name: zentao-project
|
||||
description: "禅道项目集/产品/项目/执行管理:建项目集、建产品、建项目、建执行(迭代)、查层级关系。当用户说「建个产品」「开个新迭代」「这个项目集下有哪些产品」「项目状态」时使用。"
|
||||
---
|
||||
|
||||
# 禅道项目集 / 产品 / 项目 / 执行
|
||||
|
||||
**前置:先读 `zentao-shared`(尤其"路径参数不出现在 inputSchema 里"和"ID 层级关系"两节)。**
|
||||
|
||||
---
|
||||
|
||||
## 层级与挂靠关系
|
||||
|
||||
```
|
||||
program 项目集(可选层)
|
||||
└─ product 产品(program 可选,可以不挂任何项目集独立存在)
|
||||
└─ project 项目(products 关联字段可选,parent 挂项目集也可选)
|
||||
└─ execution 执行/迭代(project 必填,execution 必须先有 project)
|
||||
```
|
||||
|
||||
**只有 execution 是强制要有上级的**(`project` 字段必填);product 和 project 的上级
|
||||
关联都是可选字段,不要假设"没传 program 就建不了产品"。
|
||||
|
||||
---
|
||||
|
||||
## 查
|
||||
|
||||
```
|
||||
get_programs() 项目集列表
|
||||
get_programs_programID_products(programID) 某项目集下的产品
|
||||
get_programs_programID_projects(programID) 某项目集下的项目
|
||||
get_products() 产品列表(全量)
|
||||
get_products_productID(productID) 产品详情
|
||||
get_projects() 项目列表(全量,无单条详情接口)
|
||||
get_projects_projectID_executions(projectID) 某项目下的执行/迭代
|
||||
get_executions() 执行列表(全量)
|
||||
get_executions_executionID(executionID) 执行详情
|
||||
```
|
||||
|
||||
**没有 `get_projects_projectID`**(项目详情接口不存在,见 `zentao-shared`),要看单个
|
||||
项目信息从 `get_projects()` 列表里按 ID 过滤。
|
||||
|
||||
---
|
||||
|
||||
## 建项目集
|
||||
|
||||
```
|
||||
post_programs({ payload: { name, begin, end, PM?, desc? } })
|
||||
```
|
||||
|
||||
`name`/`begin`/`end` 必填,日期格式以字段说明为准(一般是 `YYYY-MM-DD`)。
|
||||
|
||||
---
|
||||
|
||||
## 建产品
|
||||
|
||||
```
|
||||
post_products({ payload: { name, program?, line?, type?, PO?, QD?, RD?, reviewer?,
|
||||
acl?, desc? } })
|
||||
```
|
||||
|
||||
只有 `name` 必填。`type` 取值受限:`normal` 正常 | `branch` 多分支 | `platform` 多平台;
|
||||
`acl` 是 `open` 公开 | `private` 私有——这两个字段写错值会被后端拒绝,不要凭直觉编。
|
||||
|
||||
---
|
||||
|
||||
## 建项目
|
||||
|
||||
```
|
||||
post_projects({ payload: { name, model, begin, end, workflowGroup, products?, parent?, PM? } })
|
||||
```
|
||||
|
||||
必填字段比产品多:`name`/`model`/`begin`/`end`/`workflowGroup`。
|
||||
|
||||
`model`(项目管理方式)取值受限,创建前跟用户确认清楚要哪种:
|
||||
`scrum` 敏捷 | `waterfall` 瀑布 | `kanban` 看板 | `agileplus` 融合敏捷 | `waterfallplus` 融合瀑布
|
||||
|
||||
`workflowGroup`(项目流程)是付费版功能,开源版可以不传/传空。
|
||||
|
||||
`parent` 是挂靠到哪个项目集(可选);`products` 是关联的产品(可选,接受多个)。
|
||||
|
||||
---
|
||||
|
||||
## 建执行(迭代)
|
||||
|
||||
```
|
||||
post_executions({ payload: { project, name, begin, end, lifetime?, days?, products?,
|
||||
plans?, PO?, QD?, PM?, RD?, acl? } })
|
||||
```
|
||||
|
||||
`project`/`name`/`begin`/`end` 必填——**`project` 必填意味着建执行前必须先有一个项目
|
||||
ID**,用 `get_projects()` 查出来给用户确认要挂在哪个项目下。
|
||||
|
||||
`lifetime`(执行类型)取值:`short` 短期 | `long` 长期 | `ops` 运维。
|
||||
|
||||
`plans`(关联计划)如果要传,格式是"产品 ID + 计划 ID"的二维数组,不是单纯的 ID 列表,
|
||||
具体结构以工具 inputSchema 为准。
|
||||
|
||||
---
|
||||
|
||||
## 改 / 删
|
||||
|
||||
```
|
||||
put_programs_programID({ programID, payload: {...} })
|
||||
put_products_productID({ productID, payload: {...} })
|
||||
put_projects_projectID({ projectID, payload: {...} })
|
||||
put_executions_executionID({ executionID, payload: {...} })
|
||||
|
||||
delete_programs_programID({ programID }) # 删除前必须确认,不可逆
|
||||
delete_products_productID({ productID })
|
||||
delete_projects_projectID({ projectID })
|
||||
delete_executions_executionID({ executionID })
|
||||
```
|
||||
|
||||
删除任意一层,其下挂靠的产品/项目/执行/需求/任务等大概率会受影响(具体级联行为以
|
||||
禅道后端实际处理为准,MCP 这层不做二次拦截)——删除前跟用户明确说清楚删的是哪一层、
|
||||
可能影响下面挂了什么,参考 `zentao-shared` 的"删除是不可逆操作"约定。
|
||||
@@ -0,0 +1,153 @@
|
||||
---
|
||||
name: zentao-shared
|
||||
description: "禅道 MCP 共享基础:payload 包装约定、路径/查询参数规则、ID 层级关系、状态字段规则、确认约定。所有 zentao-* 技能必须先读本文件。"
|
||||
---
|
||||
|
||||
# 禅道 MCP 共享规则
|
||||
|
||||
所有 `zentao-*` 技能的**必读前置**。
|
||||
|
||||
---
|
||||
|
||||
## 一条最重要的约定:参数以工具自身的 inputSchema 为准
|
||||
|
||||
**本文件与各技能文档都不重画完整字段表。** 每个工具的字段名、必填项、取值范围以它在 MCP
|
||||
里注册的 `inputSchema`/`description` 为唯一真相;技能只描述**调用顺序、ID 如何传递、
|
||||
payload 怎么包、哪里必须停下来等用户确认**。
|
||||
|
||||
> 上一代其他插件(寰汐)踩过这个坑:技能文档手画参数表,字段名/枚举值/必填项跟后端
|
||||
> docstring 逐渐漂移,用户侧表现为频繁的「参数缺失」报错。工具签名变了而文档没跟上,
|
||||
> 是必然发生而非可能发生的事——禅道这边直接不画表,从源头避免。
|
||||
|
||||
---
|
||||
|
||||
## 工具命名
|
||||
|
||||
Claude Code 里工具名带前缀:`mcp__zentao__post_bugs`;其他平台通常是裸名 `post_bugs`。
|
||||
本文档统一写**裸名**,实际调用时按你所在平台的约定加前缀。
|
||||
|
||||
命名规律是 `{method}_{路径按 / 拆分拼接}`,路径参数去掉冒号:
|
||||
|
||||
```
|
||||
GET /bugs/:bugID → get_bugs_bugID
|
||||
POST /bugs → post_bugs
|
||||
PUT /tasks/:taskID/start → put_tasks_taskID_start
|
||||
DELETE /stories/:storyID → delete_stories_storyID
|
||||
GET /products/:productID/stories → get_products_productID_stories
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 路径参数完全不出现在 inputSchema 里(最隐蔽的坑)
|
||||
|
||||
**`inputSchema` 里只有 `payload`(有请求体的话)和 query 参数,路径参数(`bugID`/
|
||||
`productID`/`taskID`……)不会被声明为任何属性**——用真实工具现场验证过:
|
||||
`get_bugs_bugID`/`delete_bugs_bugID`/`get_products_productID` 的 `inputSchema.properties`
|
||||
都是空的。想传路径参数,**必须自己从工具名最后一段解析出参数名**(`get_bugs_bugID` →
|
||||
要传 `bugID`),schema 本身看不出这个要求。
|
||||
|
||||
**更麻烦的是不传或传错不会报错**:现场测试 `get_bugs_bugID({})`(故意不传 `bugID`)
|
||||
返回的是 `HTTP 200`、内容为空字符串,跟正常"这个 ID 查不到东西"长得一样,非常容易被
|
||||
误判成"这条数据不存在"而不是"参数传漏了"。调用返回空结果时,**先检查是不是路径参数
|
||||
传漏了或传错了名字**,再怀疑数据本身。
|
||||
|
||||
**命名还有例外,不能全靠"猜工具名去掉动词就是参数名"**:`get_epics_storyID` /
|
||||
`get_requirements_storyID`(业务需求/用户需求详情)的路径参数**字面就叫 `storyID`**,
|
||||
不是更直觉的 `epicID`/`requirementID`——这是禅道官方 API 本身的历史命名,照抄字面
|
||||
参数名,不要自己"纠正"。
|
||||
|
||||
---
|
||||
|
||||
## 参数结构:payload 包装约定
|
||||
|
||||
请求体字段也**不会摊平在 inputSchema 顶层**,而是统一包在一个 `payload` 对象里;
|
||||
路径参数(上一节说的,虽然不在 schema 里但仍要传)和 query 参数才是顶层字段。三种形态:
|
||||
|
||||
```
|
||||
POST(新建,无路径参数):
|
||||
post_bugs({ payload: { productID: 2, title: "...", openedBuild: ["trunk"] } })
|
||||
|
||||
PUT(改,带路径参数):
|
||||
put_bugs_bugID({ bugID: 123, payload: { title: "..." } })
|
||||
put_tasks_taskID_start({ taskID: 456, payload: { realStarted: "2026-08-25" } })
|
||||
|
||||
GET(查,query 参数摊平在顶层,没有 payload——这类工具可选参数多,其余技能文档统一用
|
||||
"函数签名速查"写法举例,不是真的按位置传参,仍然是每个字段按名字传):
|
||||
get_products_productID_stories(productID: 2, browseType: "allstory", recPerPage: "50", pageID: "1")
|
||||
|
||||
DELETE(删,通常只有路径参数):
|
||||
delete_bugs_bugID({ bugID: 123 })
|
||||
```
|
||||
|
||||
**把 body 字段错误地摊平到顶层(不包 payload)是最常见的调用失败原因**,报错通常表现为
|
||||
"参数缺失"——先检查是不是漏包了 `payload`。
|
||||
|
||||
---
|
||||
|
||||
## 分页
|
||||
|
||||
**不是所有 GET 都分页**,列表类接口(约一半)才有,详情类没有。有的话固定是这两个参数:
|
||||
|
||||
- `recPerPage`:每页数量,不超过 1000
|
||||
- `pageID`:页码,从第 1 页开始
|
||||
|
||||
**没有 `limit` 这个参数名**——传了不存在的参数名会被静默丢弃(不报错、不生效),日志里
|
||||
`upstream_query_params` 会是空的,看起来"调用成功但没起作用",容易误判。默认页大小以
|
||||
具体工具的 inputSchema 说明为准,不要凭经验假设。
|
||||
|
||||
---
|
||||
|
||||
## ID 层级关系
|
||||
|
||||
```
|
||||
program 项目集(可选,product 不强制挂靠)
|
||||
└─ product 产品(创建只需 name 必填,program/其他都可选)
|
||||
├─ project 项目(创建必填 name/model/begin/end/workflowGroup;model 取值受限:
|
||||
│ scrum 敏捷 | waterfall 瀑布 | kanban 看板 | agileplus 融合敏捷 | waterfallplus 融合瀑布)
|
||||
│ └─ execution 执行/迭代(创建必填 project,即 execution 必须先有 project 才能建,
|
||||
│ 不能直接挂在 product 下)
|
||||
├─ story 用户故事 / epic 业务需求 / requirement 用户需求(三条需求线,见 zentao-story)
|
||||
├─ bug
|
||||
├─ testcase 测试用例 / testtask 测试单
|
||||
├─ productplan 产品计划 / build 版本 / release 发布
|
||||
├─ feedback 反馈 / ticket 工单 / system 应用
|
||||
└─ task 任务(挂在 execution 下)
|
||||
```
|
||||
|
||||
创建下级实体前,先查上级列表拿到 ID 展示给用户确认,不要凭名字猜 ID(`get_products`
|
||||
→ `get_products_productID_stories` 这类"先列表后详情/子资源"的两步调用是常态)。
|
||||
|
||||
**没有 `GET /projects/:projectID` 单条项目详情接口**——只有 `get_projects` 列表,要看
|
||||
某个项目的信息,从列表里按 ID 过滤,不要尝试拼一个不存在的详情工具名。
|
||||
|
||||
---
|
||||
|
||||
## 状态字段
|
||||
|
||||
**禅道各实体的状态是模块内固定的字符串常量**,不是可配置的两层模型——具体取值以对应
|
||||
工具的字段说明为准(比如 story 是 `draft/active/closed/change`,bug 是否 resolved/closed
|
||||
各有专门的 `put_*_*ID_resolve` / `put_*_*ID_close` 端点)。**不要凭直觉写状态字符串**,
|
||||
这些字段大多有 DB 级约束,写错直接报错,具体状态机在各自的 zentao-story/zentao-bug/
|
||||
zentao-task 里有说明。
|
||||
|
||||
---
|
||||
|
||||
## 鉴权
|
||||
|
||||
MCP 连接用的 Token 在禅道网页「头像下拉菜单 → 获取凭证」自助生成,**14 天有效期**,到期
|
||||
需要重新生成并更新插件配置里的 Token。如果调用突然全部 401,先怀疑 Token 过期。
|
||||
|
||||
---
|
||||
|
||||
## 全局确认约定
|
||||
|
||||
1. **状态流转类操作必须先确认**:关闭(close)、解决(resolve)、激活(activate)、
|
||||
变更(change)这类端点,执行前把要提交的内容/目标状态展示给用户,等到明确确认
|
||||
("确认"、"关闭它"、"好的")再调。不要因为用户说了"这个 bug 修完了"就顺手把
|
||||
resolve 也做了——修复和标记解决是两个决定。
|
||||
2. **删除是不可逆操作,必须先确认**:所有 `delete_*` 工具删的都是真实数据,没有回收站,
|
||||
执行前明确告知会删除什么。
|
||||
3. **先解析 ID 再操作**:需要 `productID`/`executionID`/`taskID` 这类 ID 的操作,先用
|
||||
对应的 `get_*` 列表工具查出来给用户看,不要凭名字或印象猜 ID。
|
||||
4. **附件目前只支持改名**:`put_files_fileID` 只能改附件文件名(`fileName` 字段),
|
||||
上传和删除附件不在这套 MCP 工具里,需要引导用户去网页端操作。
|
||||
@@ -0,0 +1,129 @@
|
||||
---
|
||||
name: zentao-story
|
||||
description: "禅道需求管理:用户故事(story)、业务需求(epic)、用户需求(requirement)三条需求线的创建、变更、关闭、激活。当用户说「提个需求」「这个需求变更一下」「需求关闭了」「史诗需求」时使用。"
|
||||
---
|
||||
|
||||
# 禅道需求管理(story / epic / requirement)
|
||||
|
||||
**前置:先读 `zentao-shared`(尤其"路径参数不出现在 inputSchema 里"一节——本技能的
|
||||
`get_epics_storyID`/`get_requirements_storyID` 就是那条规则里点名的例外命名)。**
|
||||
|
||||
---
|
||||
|
||||
## 三条需求线是什么关系
|
||||
|
||||
禅道把"需求"拆成三种独立实体,**不是同一张表的三个状态**,是三套平行的 API:
|
||||
|
||||
| | 中文 | 路径前缀 | 典型用途 |
|
||||
|---|---|---|---|
|
||||
| story | 用户故事 | `/stories` | 敏捷开发里最常用的最小需求单元 |
|
||||
| epic | 业务需求 | `/epics` | 更粗粒度、跨多个 story 的业务目标 |
|
||||
| requirement | 用户需求 | `/requirements` | 来自用户侧的原始需求,未必等于最终交付的 story |
|
||||
|
||||
三者创建字段结构完全一样(`productID`/`title` 必填,`pri`/`module`/`parent`/`estimate`/
|
||||
`spec`/`category`/`source`/`verify`/`assignedTo`/`reviewer` 可选),管理动作也对称
|
||||
(改 / 变更 change / 关闭 close / 激活 activate / 删除),**用户说"需求"时先确认是要
|
||||
哪一种**,不要默认都当 story 处理——三者互不包含,建错类型对方看不到。
|
||||
|
||||
---
|
||||
|
||||
## 详情接口的路径参数命名例外(必读)
|
||||
|
||||
```
|
||||
get_stories_storyID(storyID) 需求详情
|
||||
get_epics_storyID(storyID) 业务需求详情 —— 参数字面叫 storyID,不是 epicID
|
||||
get_requirements_storyID(storyID) 用户需求详情 —— 参数字面叫 storyID,不是 requirementID
|
||||
```
|
||||
|
||||
这是禅道官方 API 本身的命名(不是这个 MCP 网桥引入的),照抄传 `storyID` 就行,别自己
|
||||
"纠正"成语义上更合理的名字,传错名字会静默返回空结果(见 `zentao-shared`)。
|
||||
|
||||
---
|
||||
|
||||
## 查
|
||||
|
||||
```
|
||||
get_products_productID_stories(productID, browseType?, orderBy?, recPerPage?, pageID?)
|
||||
get_projects_projectID_stories(projectID, ...)
|
||||
get_executions_executionID_stories(executionID, ...)
|
||||
get_products_productID_epics(productID, ...)
|
||||
get_products_productID_requirements(productID, ...)
|
||||
```
|
||||
|
||||
`browseType` 常见取值:`allstory` 全部 | `assignedtome` 指派给我 | `openedbyme` 我创建 |
|
||||
`reviewbyme` 待我评审 | `draftstory` 草稿——不传默认是 `unclosed`(未关闭的)。
|
||||
|
||||
---
|
||||
|
||||
## 建
|
||||
|
||||
```
|
||||
post_stories({ payload: { productID, title, pri?, module?, parent?, estimate?, spec?,
|
||||
category?, source?, verify?, assignedTo?, reviewer?,
|
||||
project?, execution? } })
|
||||
post_epics({ payload: { productID, title, ... 同上(无 project/execution) } })
|
||||
post_requirements({ payload: { productID, title, ... 同上(无 project/execution) } })
|
||||
```
|
||||
|
||||
`productID`/`title` 必填,其余可选。`reviewer` 一旦设置,**该需求就必须经过评审**——
|
||||
问清楚用户是否真的需要评审流程再决定填不填。`category`/`source` 是受限枚举(类别/来源),
|
||||
取值以工具 description 为准,写错直接报错。
|
||||
|
||||
只有 story 能挂 `project`/`execution`(关联具体项目或迭代),epic/requirement 没有这两个字段。
|
||||
|
||||
---
|
||||
|
||||
## 变更(change)
|
||||
|
||||
```
|
||||
put_stories_storyID_change({ storyID, payload: { reviewer, title?, spec?, verify? } })
|
||||
put_epics_epicID_change({ epicID, payload: { reviewer, title?, spec?, verify? } })
|
||||
put_requirements_requirementID_change({ requirementID, payload: { title?, spec?, verify? } })
|
||||
```
|
||||
|
||||
**`reviewer` 必填这条规则只对 story 和 epic 成立**——变更这两类需求必须指定评审人,
|
||||
不能跳过评审直接改。**requirement 的变更接口没有 `reviewer` 这个参数,也没有任何必填
|
||||
字段**,三者看起来对称,实际上 requirement 少一层评审约束,不要照搬 story/epic 的调用
|
||||
方式给 requirement 传 `reviewer`(传了会被当成多余字段,不生效)。
|
||||
|
||||
注意这里改的路径参数名恢复正常(`epicID`/`requirementID`),跟上面"详情接口"那个
|
||||
`storyID` 例外命名不是一回事,两套接口的路径参数名不一样,调用前对照工具名确认。
|
||||
|
||||
---
|
||||
|
||||
## 关闭(close)
|
||||
|
||||
```
|
||||
put_stories_storyID_close({ storyID, payload: { closedReason, comment? } })
|
||||
```
|
||||
|
||||
`closedReason` 必填,受限枚举:`done` 已完成 | `subdivided` 已拆分 | `duplicate` 重复 |
|
||||
`postponed` 延期 | `willnotdo` 不做 | `cancel` 已取消 | `bydesign` 设计如此。
|
||||
|
||||
**关闭前必须先跟用户确认关闭原因**(`zentao-shared` 的全局约定:状态流转类操作先确认),
|
||||
不要因为用户说"这个需求做完了"就自动挑一个理由关掉——`done` 和用户实际想表达的可能
|
||||
不是一回事(比如其实是想选 `subdivided` 已拆成子需求)。
|
||||
|
||||
---
|
||||
|
||||
## 激活(activate)
|
||||
|
||||
```
|
||||
put_stories_storyID_activate({ storyID, payload: { assignedTo?, comment? } })
|
||||
put_epics_epicID_activate({ epicID, payload: { assignedTo?, comment? } })
|
||||
put_requirements_requirementID_activate({ requirementID, payload: { assignedTo?, comment? } })
|
||||
```
|
||||
|
||||
三者字段结构一样,都没有必填字段,用于把已关闭/已拆分的需求重新打开。
|
||||
|
||||
---
|
||||
|
||||
## 删
|
||||
|
||||
```
|
||||
delete_stories_storyID({ storyID })
|
||||
delete_epics_epicID({ epicID })
|
||||
delete_requirements_requirementID({ requirementID })
|
||||
```
|
||||
|
||||
不可逆,删除前必须确认(`zentao-shared` 全局约定)。
|
||||
@@ -0,0 +1,103 @@
|
||||
---
|
||||
name: zentao-task
|
||||
description: "禅道任务管理:创建任务、启动、完成、关闭、激活,查执行下的任务列表。当用户说「建个任务」「这个任务开始做了」「任务做完了」「任务关掉」时使用。"
|
||||
---
|
||||
|
||||
# 禅道任务管理
|
||||
|
||||
**前置:先读 `zentao-shared`(尤其"路径参数不出现在 inputSchema 里"一节)。**
|
||||
|
||||
---
|
||||
|
||||
## 状态机
|
||||
|
||||
```
|
||||
未开始 ──start 启动──▶ 进行中 ──finish 完成──▶ 已完成
|
||||
│ │
|
||||
└──────── close 关闭 ─────┘(不做了/取消,跳过完成)
|
||||
▲
|
||||
activate 激活(重新打开,从已完成/已关闭回到进行中)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 字段名坑:跟 story/bug 不一致
|
||||
|
||||
**任务标题字段叫 `name`,不是 `title`**(story/bug/epic/requirement 都是 `title`,
|
||||
只有 task 是 `name`,创建时容易写错)。
|
||||
|
||||
**创建任务时所属执行的字段叫 `executionID`**,不是 `execution`(bug 创建时挂执行用的
|
||||
是 `execution`)——同一个"所属执行"的语义,在不同实体的创建接口里字段名不统一,
|
||||
调用前对照该工具自己的 inputSchema,不要照抄别的实体的字段名。
|
||||
|
||||
---
|
||||
|
||||
## 查
|
||||
|
||||
```
|
||||
get_executions_executionID_tasks(executionID, ...) 某执行下的任务列表
|
||||
get_tasks_taskID(taskID) 任务详情
|
||||
```
|
||||
|
||||
任务只能按"所属执行"维度查列表,没有按产品/项目查任务的接口——要看某个产品下的任务,
|
||||
先找到相关执行再查。
|
||||
|
||||
---
|
||||
|
||||
## 建
|
||||
|
||||
```
|
||||
post_tasks({ payload: { name, executionID, type?, assignedTo?, estStarted?, deadline?,
|
||||
pri?, estimate?, module?, story?, desc? } })
|
||||
```
|
||||
|
||||
`name`/`executionID` 必填。`story` 字段可以关联到具体需求(story ID),常用于"这个
|
||||
任务是为了实现哪个需求"。
|
||||
|
||||
---
|
||||
|
||||
## 启动(start)
|
||||
|
||||
```
|
||||
put_tasks_taskID_start({ taskID, payload: { realStarted, assignedTo?, consumed?, left?, comment? } })
|
||||
```
|
||||
|
||||
`realStarted`(实际开始日期)必填。
|
||||
|
||||
---
|
||||
|
||||
## 完成(finish)
|
||||
|
||||
```
|
||||
put_tasks_taskID_finish({ taskID, payload: { currentConsumed, realStarted, finishedDate,
|
||||
assignedTo?, consumed?, comment? } })
|
||||
```
|
||||
|
||||
**三个必填字段**:`currentConsumed`(本次消耗)、`realStarted`(实际开始,即使之前
|
||||
`start` 过也要再传一次)、`finishedDate`(实际完成日期)。完成前把这三个数字/日期跟
|
||||
用户确认清楚(`zentao-shared` 全局约定:状态流转类操作先确认),尤其 `currentConsumed`
|
||||
容易被和"总计消耗 `consumed`"搞混——前者是这一次填报的增量工时,后者是累计总工时,
|
||||
两个都传的话以工具说明为准判断二者关系,不要凭直觉认为两者相等。
|
||||
|
||||
---
|
||||
|
||||
## 关闭(close)/ 激活(activate)
|
||||
|
||||
```
|
||||
put_tasks_taskID_close({ taskID, payload: { comment? } })
|
||||
put_tasks_taskID_activate({ taskID, payload: { left?, assignedTo?, comment? } })
|
||||
```
|
||||
|
||||
都没有必填字段。`close` 用于跳过完成流程直接终止任务(比如需求取消了);`activate`
|
||||
把已完成/已关闭的任务重新打开,可以顺带更新预计剩余工时 `left`。
|
||||
|
||||
---
|
||||
|
||||
## 改 / 删
|
||||
|
||||
```
|
||||
put_tasks_taskID({ taskID, payload: {...} })
|
||||
delete_tasks_taskID({ taskID })
|
||||
```
|
||||
|
||||
删除不可逆,执行前必须确认。
|
||||
@@ -0,0 +1,122 @@
|
||||
---
|
||||
name: zentao-test
|
||||
description: "禅道测试管理:创建/查询/修改测试用例(含步骤设计)、创建测试单提测。当用户说「写个测试用例」「设计测试步骤」「提测」「建个测试单」「查测试用例」时使用。"
|
||||
---
|
||||
|
||||
# 禅道测试管理(testcase / testtask)
|
||||
|
||||
**前置:先读 `zentao-shared`(尤其"路径参数不出现在 inputSchema 里"一节)。**
|
||||
|
||||
测试相关是高频场景——测试同学写用例、开发/测试提测,这个技能覆盖得比其他业务域更细,
|
||||
尤其是 testcase 的步骤结构,是全部 8 个技能里**唯一一处需要特别小心的嵌套/对应关系**。
|
||||
|
||||
---
|
||||
|
||||
## 测试用例(testcase)
|
||||
|
||||
### 详情接口的路径参数命名例外(跟 zentao-story 的 storyID 是同类坑)
|
||||
|
||||
```
|
||||
get_testcases_caseID(caseID) 详情:参数字面叫 caseID
|
||||
put_testcases_testcasID(...) 修改:参数字面叫 testcasID(注意,是 testcasID 不是 testcaseID,少一个 e)
|
||||
delete_testcases_testcasID(...) 删除:同上
|
||||
```
|
||||
|
||||
三个接口的路径参数名互相都不一样(`caseID` / `testcasID`),且 `testcasID` 是官方 API
|
||||
的拼写(缺了一个 `e`),**照抄字面参数名,不要自己纠正拼写**,传错名字会静默返回空结果。
|
||||
|
||||
### 查
|
||||
|
||||
```
|
||||
get_products_productID_testcases(productID, ...)
|
||||
get_projects_projectID_testcases(projectID, ...)
|
||||
get_executions_executionID_testcases(executionID, ...)
|
||||
get_testcases_caseID(caseID) 详情
|
||||
```
|
||||
|
||||
### 建——步骤是三个平行数组,靠索引位置对应
|
||||
|
||||
```
|
||||
post_testcases({ payload: {
|
||||
productID, title,
|
||||
module?, story?, pri?, type?, precondition?,
|
||||
steps?: string[], # 步骤描述,第 i 项
|
||||
expects?: string[], # 第 i 项步骤的期望结果
|
||||
stepType?: string[], # 第 i 项步骤的类型:step 步骤 | group 父级步骤(分组标题,无需期望结果)
|
||||
project?, execution?
|
||||
} })
|
||||
```
|
||||
|
||||
**这不是一个"步骤对象数组"(不是 `[{step, expect, type}, ...]`),是三个独立的字符串
|
||||
数组,`steps[i]`/`expects[i]`/`stepType[i]` 靠同一个下标 `i` 对应同一个步骤。** 三个
|
||||
数组长度必须一致,写用例时先把步骤列成一个表格跟用户确认,再按顺序拆成三个数组传,
|
||||
不要把某一步的期望结果错位对到别的步骤上——这种错位不会报错,只会在用例详情里显示
|
||||
"驴唇不对马嘴",很难事后发现。
|
||||
|
||||
`stepType` 为 `group` 的行是分组标题(比如"登录流程"这种大标题),对应的 `expects[i]`
|
||||
一般传空字符串。
|
||||
|
||||
举例——"登录"用例有一个分组、两个步骤:
|
||||
|
||||
```
|
||||
steps = ["登录流程", "打开登录页,输入正确账号密码", "点击登录按钮"]
|
||||
stepType = ["group", "step", "step"]
|
||||
expects = ["", "账号密码输入框正常显示", "跳转到首页,显示欢迎语"]
|
||||
```
|
||||
|
||||
`type`(用例类型)受限枚举:`unit` 单元测试 | `interface` 接口测试 | `feature` 功能测试 |
|
||||
`install` 安装部署 | `config` 配置相关 | `performance` 性能测试 | `security` 安全相关 |
|
||||
`other` 其他。
|
||||
|
||||
### 改 / 删
|
||||
|
||||
```
|
||||
put_testcases_testcasID({ testcasID, payload: {...} }) # 改步骤同样是三个数组整体替换,不是增量
|
||||
delete_testcases_testcasID({ testcasID })
|
||||
```
|
||||
|
||||
改步骤时**传的是完整的三个新数组,不是"追加一步"**——想加一个步骤,要先 `get_testcases_caseID`
|
||||
拿到现有的 steps/expects/stepType,在末尾追加后整体传回,跟 `huanxi-task` 里
|
||||
`task_set_assignees` 整组覆盖是同一种坑,直接传一步会把其余步骤全部覆盖掉。
|
||||
|
||||
---
|
||||
|
||||
## 测试单(testtask,提测)
|
||||
|
||||
**没有单条测试单详情接口**(只有创建/修改/删除,没有 `get_testtasks_testtaskID`),要看
|
||||
某个测试单的信息,从列表接口里按 ID 过滤。
|
||||
|
||||
### 查
|
||||
|
||||
```
|
||||
get_products_productID_testtasks(productID, ...)
|
||||
get_projects_projectID_testtasks(projectID, ...)
|
||||
get_executions_executionID_testtasks(executionID, ...)
|
||||
```
|
||||
|
||||
### 建
|
||||
|
||||
```
|
||||
post_testtasks({ payload: { productID, name, build, begin, end, execution?, type?,
|
||||
owner?, status?, desc? } })
|
||||
```
|
||||
|
||||
`productID`/`name`/`build`(提测构建/版本)/`begin`/`end` 必填。
|
||||
|
||||
**`type`(测试类型)是字符串数组,不是单值**——一个测试单可以同时标多种测试类型,取值
|
||||
受限:`integrate` 集成测试 | `system` 系统测试 | `acceptance` 验收测试 | `performance` 性能测试
|
||||
| `safety` 安全测试。传的时候是 `type: ["integrate", "system"]` 这种数组形式,不要传成
|
||||
单个字符串 `type: "integrate"`。
|
||||
|
||||
**跟其他实体不同,测试单的状态不是靠专门的 activate/close 端点切换,而是创建/修改时
|
||||
直接传 `status` 字段**:`wait` 未开始 | `doing` 进行中 | `done` 已关闭 | `blocked` 被阻塞。
|
||||
改状态就是 `put_testtasks_testtaskID({ testtaskID, payload: { status: "doing" } })`。
|
||||
|
||||
### 改 / 删
|
||||
|
||||
```
|
||||
put_testtasks_testtaskID({ testtaskID, payload: {...} })
|
||||
delete_testtasks_testtaskID({ testtaskID })
|
||||
```
|
||||
|
||||
删除不可逆,执行前必须确认。
|
||||
Reference in New Issue
Block a user