Files
SkyJourneyandClaude Opus 5 4ce9a92013 feat(huanxi): 拆为个人端 / 管理端两个插件,技能全面对齐寰汐 v2
寰汐 v2 上线双 MCP(个人端 /mcp/ 与管理端 /admin-mcp/),两条端点是**两条独立的
信任边界**——Token 前缀不同、工具集不同、视角不同(管理端看全量、个人端只看我参与的)。
一个插件塞两套会让普通员工的客户端里出现他根本调不动的管理工具,因此拆成两个插件,
按角色各装各的。

## huanxi(个人端,全体员工)

7 个技能:shared / report / leader / task / issue / meeting / org

- 新增 `issue` `meeting`——v2 的议题域与会议域(M6v2 会议×议题解耦后的产物)
- **删除 `weekly`**——v2 没有 weekly_report 表,周报已并入报告体系
- 各技能重写为**流水线定义**而非使用说明:写明工具调用顺序、ID 在步骤间怎么传、
  人工确认节点落在哪。「禁止自动提交」这条 v1 已验证的硬约束保留
- 删掉 `references/` 拆分文件——v2 技能自包含

## huanxi-admin(管理端,仅后台管理员)

4 个技能:admin-shared / admin-report / admin-module / admin-ops

MCP server key 取 `huanxi-admin`(与个人端的 `huanxi` 不同名),否则两插件并存时
会键冲突。

## 缓存目录按信任边界隔离

`~/.claude/huanxi-cache/` 下分 `personal/` `admin/` `dict/`:前两者视角不同,
混用会越权展示或数据错乱;`dict/` 与身份无关可共享。业务数据(任务/日报/会议/议题)
**显式声明不缓存**——v1 没写这条,Agent 会自行决定缓存然后拿到陈旧数据。

## 源码单一真相不在本仓库

技能源码在寰汐仓库 `skills/`,与 MCP docstring 同仓库同 commit——签名一改,
技能与工具在同一次改动里更新,从结构上消除跨仓库漂移(本仓库记忆
`feedback_plugin_dev.md` 记录的 4 类漂移覆盖全部 6 个 v1 技能,正是这个病)。
本仓库退化为**分发壳**,只接收 `python skills/sync_marketplace.py` 的产物,不手工编辑。

寰汐侧有 CI 守卫:技能里出现的每个工具名必须存在于实际注册表、个人端技能不得
指导调用管理端独有工具、不得硬编码状态字面量。

## 本分支不合 main

插件配置的域名此刻跑的还是 v1,合进 main 会通过自动更新推给已安装用户,
他们的技能会去调 v1 上不存在的工具。合并前置条件写在 CLAUDE.md「已发布插件」节。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Vyeia9k43dVaUFNLo8Lny
2026-08-06 18:56:55 +08:00

91 lines
3.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: huanxi-task
description: "寰汐任务管理:查任务、建任务、改状态与进度、分配执行人、认领。当用户说「我有什么任务」「建个任务」「把这个标成完成」「派给谁」时使用。"
---
# 寰汐任务管理
**前置:先读 `huanxi-shared`(尤其「状态是可配置的两层模型」一节)。**
---
## ID 传递链
任务操作几乎都是这条链,**中间结果要展示给用户**,不要一路闷头做到底:
```
module_query() → module_id
task_query(module_ids=[...]) → task_id[] ← 展示给用户看
↓ ⏸ 用户指明改哪些
task_update(updates=[{id, ...}])
```
---
## 查
```
task_query(scope="mine") 我负责执行的(默认)
task_query(scope="all", module_ids=[...]) 某几个模块的全部任务
task_query(q="关键词") 标题模糊搜
task_get(task_ids=[...]) 详情:描述 + 层级路径
```
过滤维度都收列表,一次查多个模块比循环调用好。
---
## 改状态与进度
**先 `dict_get` 取 task 类型的状态选项**,拿到 `status_option_id` 再传:
```
dict_get(kinds=["status_options"])
→ 筛 entity_type == "task"
→ 按 category 找到目标状态(not_started/in_progress/completed/cancelled
→ 取它的 id
task_update(updates=[{id: 任务id, status_option_id: 状态id}])
```
状态与进度**有联动,只传一个就够**:进度设到 100 会自动转完成;已完成的任务把进度
调低会自动回落进行中。两个都传等于重复表达同一个意思。
**非叶子任务不能直接设进度**——返回里 `progress_readonly` 为 true 的那些,进度是子任务
聚合出来的,硬设会被拒绝。要推进它,去改它的子任务。
---
## 建任务
```
task_create(module_id=..., tasks=[{title, description?, priority?, end_date?,
parent_id?, milestone_id?, assignee_ids?}])
```
- 建子任务传 `parent_id`,**最多三级**(任务 / 子任务 / 孙任务)
- 需要是该模块的成员或负责人
- `priority` 的取值以工具说明为准——**不要凭直觉写**,这个字段有 DB 级约束,写错直接报错
---
## 执行人
```
task_set_assignees(task_id=..., user_ids=[...]) 整组覆盖,传空即清空
task_claim(task_ids=[...], claim=true/false) 认领 / 取消认领(只动自己)
```
**`task_set_assignees` 是替换不是追加。** 想加一个人,要先 `task_get` 拿到现有名单,
把新人拼进去再整组传回——直接传一个人会把其余执行人全部踢掉。这是最容易出错的地方,
覆盖前把「改完会变成谁」说给用户听。
被指派的人若不是模块成员,会自动加入该模块;新增执行人会收到飞书通知。
---
## 不在工具里的操作
删除任务、跨模块转移任务**不在 MCP**,请引导用户去网页端——这两个动作作用于整棵子树
且不可逆,需要看清楚影响范围再点。