WorkBuddy × TAPD 对接配置
目标:让一台从没接触过 TAPD 的机器,几分钟内让 WorkBuddy 能访问 TAPD。
所有脚本都是零依赖(只用 Node 内置模块),不需要 npm install,不需要任何第三方库。
> ## 🔐 铁律:凭证绝不落进 skill 包
>
> 这个 skill 目录里永远只有脚本和说明,不含任何用户的令牌、密码、workspace_id 或真实项目数据。
>
> - 凭证一律放在用户自己的工作目录(--dir / TAPD_DIR / 当前目录)里的 .tapd-credentials.json(600 权限),或环境变量。
> - 不要把令牌写进 SKILL.md、references/、任何脚本、任何示例里——连掩码片段(如 abc***xy)也不要写真实值,示例一律用合成占位符。
> - 交付/分享这个 skill 前自查:grep -rn "accessToken\|apiPassword" . 应当只出现占位符。
> - 脚本已内置硬护栏:tapd-pull.js 的 assertSafeDir()、setup.sh / autostart.sh 顶部检查,只要工作目录落在 skill 包内就直接报错退出,从机制上杜绝「手滑把凭证写进 skill」。
> - 从别处拷来的 skill 里若发现真实凭证 → 立刻去 TAPD 「个人访问令牌」页删掉重建,再清理文件。
先选路径(两条,可共存)
| 路径 A:TAPD 连接器(远程 MCP) | 路径 B:本地 OpenAPI 服务 | |
|---|---|---|
| 解决什么 | 让 WorkBuddy 自己直接查/改 TAPD | 让网页或脚本拿到 TAPD 数据 |
| 要写代码吗 | 不用 | 跑几个脚本 |
| 要令牌吗 | 不用(走 OAuth 授权) | 需要(个人访问令牌 / API 账号) |
| 能力 | 需求·缺陷·任务·迭代·Wiki·工时·附件·测试用例 全套读写 | 以读为主,写需自己调接口 |
| 典型场景 | 「帮我查一下 XX 项目待评审的需求」 | 「这个网页上点一下,从 TAPD 刷新数据」 |
默认先走 A。 只有当你确实需要一个「本地文件 / 网页可直接用的数据源」时才上 B。
两条路的前提相同:企业需要开通 TAPD 开放平台。没开通的话两者都会在认证处失败。
路径 A:接 TAPD 连接器(最快)
- WorkBuddy 左侧栏 → 连接器管理
- 搜 TAPD → 添加
- 完成授权(登录你的 TAPD 账号)
- 验证:让 WorkBuddy「查一下我在 TAPD 参与的项目」,能列出来就是通了
背后是这个远程 MCP:https://websocket.tapd.cn/mcp/mcp。
工具以 mcp__tapd__* 形式出现,常用的有:
| 工具 | 用途 |
|---|---|
get_current_user |
我是谁(确认授权成功) |
get_user_participant_projects |
我参与的项目 + workspace_id |
get_stories_fields_info |
某项目的状态字典(只有这个能拿到 status_9 这种别名)。⚠️ 只接受 workspace_id,多传参数直接 validation failed |
get_stories_or_tasks |
拉需求/任务。v_status 传中文名即可 |
get_iterations |
迭代列表 |
get_story_or_task_count |
计数 |
get_entity_custom_fields |
自定义字段 |
> 坑:有时连接器状态显示「已连接」,但工具在索引里取不到(ToolSearch 搜不到、直接调用报 not found),整个 TAPD 能力等于消失。此时不要以为是自己写错了——让用户去连接器管理页重新「信任 / 重新授权」一次,然后重试。这种情况下也没有本地兜底,只能先用上一次落盘的 data.json 快照干活。
路径 B:本地 OpenAPI 服务
0) 先体检(第一步永远是这个)
SK="$HOME/.workbuddy/skills/workbuddy-tapd-config/scripts"
node "$SK/tapd-check.js" # 体检当前目录
node "$SK/tapd-check.js" --dir ~/tapd-data # 指定工作目录
node "$SK/tapd-check.js" --status-map all # 顺便列出所有项目的状态中文名
node "$SK/tapd-check.js" --json # 机器可读(含建议的配置)
它按 ① 环境 → ② 凭证 → ③ 认证 → ④ 状态字典 → ⑤ 计数 的顺序跑,任何一步失败都会明确告诉你卡在哪、怎么修,最后吐出一份可直接粘贴的 .tapd-config.json。
--status-map 那一步尤其重要:它解决「statuses 到底该填什么」这个问题。
1) 拿凭证
只有一种推荐方式:个人访问令牌。
TAPD 网页 → 右上角头像 → 「我的设置」→ 左侧「个人访问令牌」→ 创建。
直链:https://www.tapd.cn/personal_settings/index?tab=personal_token
令牌只在创建时显示一次,当场复制。
(另一种是 API 账号 + 密码,需企业管理员在「公司管理 → API账号管理」创建。详见 references/credentials.md。)
2) 一键初始化
TAPD_ACCESS_TOKEN=你的令牌 bash "$SK/setup.sh" ~/tapd-data
它会:建目录 → 写 .tapd-config.json 草稿 → 存凭证(自动 chmod 600)→ 跑体检 → 打印后续命令。
没设环境变量时会在终端里提示你粘贴令牌(不回显,也不会进 shell 历史)。
> 🔐 绝不要让用户把令牌贴进聊天窗口。 正确做法是让他写进 .tapd-credentials.json(权限 600)或 export TAPD_ACCESS_TOKEN=...。所有脚本的终端输出都只显示掩码(形如 abc***xy(40 位))。
3) 用起来
# 拉数(--dry 只预览不写文件)
node "$SK/tapd-pull.js" --dir ~/tapd-data --dry
node "$SK/tapd-pull.js" --dir ~/tapd-data
# 只看「我能访问哪些项目」
node "$SK/tapd-pull.js" --dir ~/tapd-data --discover
# 起本地服务(给网页用)
node "$SK/refresh-server.js" --dir ~/tapd-data --open
# 开机自启(macOS)
bash "$SK/autostart.sh" install ~/tapd-data
bash "$SK/autostart.sh" status
bash "$SK/autostart.sh" uninstall
工作目录约定
脚本默认以当前目录为工作目录(可用 --dir 或 TAPD_DIR 环境变量覆盖):
工作目录/
├── .tapd-config.json # 拉什么(项目、状态、字段)
├── .tapd-credentials.json # 凭证,必须 600
├── data.json # 拉数产物
└── logs/ # 自启服务的日志
.tapd-config.json 关键字段:
| 字段 | 默认 | 说明 |
|---|---|---|
workspaces |
[] |
拉哪些项目。留空 = 自动取「我参与的全部项目」 |
statuses |
[] |
填中文状态名,如 ["设计完成待评审","待开发"]。留空会报错提醒 |
entity |
stories |
stories 需求 / bugs 缺陷 / tasks 任务 |
fields |
见文件 | 要拉哪些字段 |
planEndField |
custom_field_four |
哪个自定义字段当「计划完成时间」。各项目编号含义可能不同,需自查 |
dataFile |
data.json |
产物文件名 |
serve.port |
8787 |
本地服务端口 |
serve.defaultPage |
index.html |
打开根路径时落到哪个页 |
serve.label |
cn.workbuddy.tapd-refresh |
LaunchAgent 标签 |
本地服务的 HTTP 接口
网页照这套调即可(都带 CORS,file:// 打开的页面也能调):
| 接口 | 作用 |
|---|---|
GET /api/ping |
活着吗 + 有没有凭证 + 当前数据快照。判定条件是 "service":"tapd-refresh",不是只看 200 |
GET /api/data |
返回当前 data.json |
POST /api/refresh |
真去 TAPD 拉一遍,写回文件,返回新数据 |
GET /api/credential |
凭证状态(不回显明文) |
POST /api/credential |
保存凭证 {accessToken} 或 {apiUser, apiPassword} |
DELETE /api/credential |
清除凭证 |
失败时返回 {"ok":false,"error":"...","needCredential":true},页面据此把按钮换成「重填凭证」,而不是只甩一句英文错误码。
已验证的 TAPD API 事实(省得重新踩一遍)
以下全部实测过(2026-09,用真实令牌跑通,凭证未落盘到 skill 内):
| 事项 | 结论 |
|---|---|
| 认证 | 令牌走 Authorization: Bearer <token>;API 账号走 Basic base64(user:pass)。官方文档只写了 Basic,但 Bearer 是认的——假令牌会回 422 The access token provided is invalid(而不是 401),说明它认这条路 |
| 列项目 | GET /workspaces/user_participant_projects → data[] 带 id/name。这是冷启动自动发现 workspace_id 的正确接口 |
| 列项目(另一种) | GET /workspaces/projects 需要 company_id,缺了回 422 company_id is required |
| 状态字典 | GET /workflows/status_map?workspace_id=<id>&system=story → data 是扁平对象 { statusKey: "中文名" }。system 必填(story/bug/task) |
| 计数 | GET /stories/count?workspace_id=<id>&v_status=<中文名> → data.count。不用翻页就能拿总数 |
| 多状态 | v_status 支持竖线分隔,语义是「或」且计数正确(实测 28 + 33 = 61 ✅) |
| 响应约定 | status: 1 才算成功;status: 0 或缺失都是失败,原因在 info 字段里 |
| 分页 | limit 上限 200,用 page 翻页 |
v_status 字段 |
with_v_status=1 会让返回体多出 v_status 字段 = 中文状态名。 而 status 字段回的仍是本项目别名(status_6/developing/UI_design)。取中文名一定要读 v_status |
| 状态是每项目各自编码 | 同一个「设计完成待评审」在 A 项目是 status_6、B 项目是 status_9、C 项目是 status_13、D 项目是 status_14。存数据只存中文名,绝不存 key |
| 迭代 | 工作项接口只回 iteration_id,不回名字。要另查 GET /iterations?workspace_id=&fields=id,name 建字典 |
| 自定义字段 | GET /workspaces/workspace_custom_field_settings 对普通用户普遍 403。要查字段含义只能用连接器的 get_entity_custom_fields,或人工看界面 |
| 字段不存在不报错 | fields 里传不存在的字段名不会失败,只是不返回 |
数据规模参考:单个项目全状态可能 1600+ 条。别一次拉全部状态——先想清楚要哪几个。
关键坑(按踩坑概率排序)
status不是中文名,v_status才是。 见上表。写成status会拿到status_9,跨项目聚合必串。- 令牌不在「开放平台」菜单里,在「我的设置 → 个人访问令牌」。而 API 账号在「公司管理 → API账号管理」(没有「开放平台 → API 账号」这个入口)。
- 网页不能直连 TAPD。 实测
https://api.tapd.cn返回 401 时没有任何Access-Control-Allow-Origin响应头,浏览器预检必挂;而且把令牌放进页面等于把令牌摊在浏览器里。所以本地服务这层绕不过去。 - 「所有请求都失败」不能报成「成功 0 条」。 凭证错了却提示刷新成功,用户对着空表完全不知道发生了什么。
tapd-pull.js现在会在「零条 + 有错误」时抛出异常并带code,服务据此回needCredential。 with_v_status=1只是「加一个字段」,不是「把 status 换成中文」——这是最容易误解的一处。- 自启脚本里的 node 必须写稳定绝对路径(
/opt/homebrew/bin/node),别写 WorkBuddy 托管目录~/.workbuddy/binaries/node/versions/<版本>/bin/node——WorkBuddy 升级后路径就变了。 - 验证自启用
launchctl print gui/$(id -u)/<label>,别用launchctl list | grep(会截断,搜不到就以为没装)。 - 受限执行环境里
launchctl和绑定端口都可能不可用——见references/troubleshooting.md的 F 节。此时如实说明哪一层没验证到,别把「页面逻辑验证过」说成「整条链路验证过」。 data.json里不认识的顶层键会被保留(tapd-pull.js的preserved逻辑),这样页面上人工维护的元数据不会被刷新冲掉。- 换端口要同步改页面的探活列表。页面默认只探
8787~8790。 - 别把工作目录设成 skill 包目录。
setup.sh/autostart.sh默认用「当前目录」,如果你cd进 skill 目录再跑,凭证就落在 skill 里了。脚本已有护栏会拦住并报错,但正确姿势是一开始就传一个独立目录:bash "$SK/setup.sh" ~/tapd-data。
参考
references/credentials.md—— 凭证从哪拿、三种存放方式、认证方式实测对比、报错分诊、安全注意事项references/troubleshooting.md—— 认证/网络/端口/自启/数据口径 五大类排错,含受限环境的应对
给助手的工作流
用户说「帮我接 TAPD」时:
- 先问清目的:是要 WorkBuddy 自己查改 TAPD(→ 路径 A),还是要网页/脚本拿数据(→ 路径 B)。
- 走 A:引导他完成连接器授权,然后用
get_current_user+get_user_participant_projects验证。 - 走 B:先跑
tapd-check.js拿诊断,再按诊断结果给下一步,不要一上来就让他填一堆东西。令牌只让他写进文件或环境变量,不要贴进聊天。 - 报错时对照
troubleshooting.md的现象表定位,别泛泛地说「配置有问题」。 - 涉及具体项目的状态名,用
--status-map或get_stories_fields_info实际查出来再填,不要猜。