From 4ce9a9201316ec00b4414d88de6cd1de5518f433 Mon Sep 17 00:00:00 2001 From: SkyJourney Date: Thu, 6 Aug 2026 18:56:55 +0800 Subject: [PATCH] =?UTF-8?q?feat(huanxi):=20=E6=8B=86=E4=B8=BA=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E7=AB=AF=20/=20=E7=AE=A1=E7=90=86=E7=AB=AF=E4=B8=A4?= =?UTF-8?q?=E4=B8=AA=E6=8F=92=E4=BB=B6=EF=BC=8C=E6=8A=80=E8=83=BD=E5=85=A8?= =?UTF-8?q?=E9=9D=A2=E5=AF=B9=E9=BD=90=E5=AF=B0=E6=B1=90=20v2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 寰汐 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 Claude-Session: https://claude.ai/code/session_019Vyeia9k43dVaUFNLo8Lny --- .claude-plugin/marketplace.json | 7 +- .claude/memory/project_overview.md | 3 +- CLAUDE.md | 11 +- .../huanxi-admin/.claude-plugin/plugin.json | 24 ++ .../skills/huanxi-admin-module/SKILL.md | 86 +++++++ .../skills/huanxi-admin-ops/SKILL.md | 54 +++++ .../skills/huanxi-admin-report/SKILL.md | 65 ++++++ .../skills/huanxi-admin-shared/SKILL.md | 95 ++++++++ plugins/huanxi/.claude-plugin/plugin.json | 4 +- plugins/huanxi/skills/huanxi-issue/SKILL.md | 58 +++++ plugins/huanxi/skills/huanxi-leader/SKILL.md | 102 +++------ .../references/leader-summary.md | 85 ------- plugins/huanxi/skills/huanxi-meeting/SKILL.md | 54 +++++ plugins/huanxi/skills/huanxi-org/SKILL.md | 157 +++++-------- .../huanxi-org/references/resolve-ids.md | 81 ------- plugins/huanxi/skills/huanxi-report/SKILL.md | 138 +++++------- .../huanxi-report/references/report-draft.md | 64 ------ .../huanxi-report/references/report-submit.md | 56 ----- plugins/huanxi/skills/huanxi-shared/SKILL.md | 209 ++++++++---------- plugins/huanxi/skills/huanxi-task/SKILL.md | 120 +++++----- .../huanxi-task/references/task-create.md | 86 ------- .../huanxi-task/references/task-kanban.md | 56 ----- plugins/huanxi/skills/huanxi-weekly/SKILL.md | 133 ----------- .../huanxi-weekly/references/weekly-draft.md | 99 --------- 24 files changed, 744 insertions(+), 1103 deletions(-) create mode 100644 plugins/huanxi-admin/.claude-plugin/plugin.json create mode 100644 plugins/huanxi-admin/skills/huanxi-admin-module/SKILL.md create mode 100644 plugins/huanxi-admin/skills/huanxi-admin-ops/SKILL.md create mode 100644 plugins/huanxi-admin/skills/huanxi-admin-report/SKILL.md create mode 100644 plugins/huanxi-admin/skills/huanxi-admin-shared/SKILL.md create mode 100644 plugins/huanxi/skills/huanxi-issue/SKILL.md delete mode 100644 plugins/huanxi/skills/huanxi-leader/references/leader-summary.md create mode 100644 plugins/huanxi/skills/huanxi-meeting/SKILL.md delete mode 100644 plugins/huanxi/skills/huanxi-org/references/resolve-ids.md delete mode 100644 plugins/huanxi/skills/huanxi-report/references/report-draft.md delete mode 100644 plugins/huanxi/skills/huanxi-report/references/report-submit.md delete mode 100644 plugins/huanxi/skills/huanxi-task/references/task-create.md delete mode 100644 plugins/huanxi/skills/huanxi-task/references/task-kanban.md delete mode 100644 plugins/huanxi/skills/huanxi-weekly/SKILL.md delete mode 100644 plugins/huanxi/skills/huanxi-weekly/references/weekly-draft.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 05e8dba..b0eec24 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -8,7 +8,12 @@ { "name": "huanxi", "source": "./plugins/huanxi", - "description": "寰汐企业管理系统插件:日报/负责人日报/周报/任务管理/组织查询,含 MCP Server 自动配置(Bearer Token 直连)" + "description": "寰汐企业管理系统 · 个人端:日报、负责人日报、任务、议题、会议、组织检索六个工作流技能,自动配置个人端 MCP 连接(hxp_ Token,在寰汐个人中心自助生成)" + }, + { + "name": "huanxi-admin", + "source": "./plugins/huanxi-admin", + "description": "寰汐企业管理系统 · 管理端:汇报盘点、模块与成员配置、运维简报三个工作流技能,自动配置管理端 MCP 连接(hxa_ Token,由后台管理员发放)。普通员工无需安装" }, { "name": "memcore", diff --git a/.claude/memory/project_overview.md b/.claude/memory/project_overview.md index 1b07ddc..ca449ab 100644 --- a/.claude/memory/project_overview.md +++ b/.claude/memory/project_overview.md @@ -60,7 +60,8 @@ description: "触发描述(用户实际口语,不用内部视角)" | 插件 | 技能 | 特性 | |------|------|------| -| `huanxi` | 6 个(report/leader/task/weekly/org/shared) | userConfig Bearer Token + MCP Server(URL 走 office 子域,无端口) | +| `huanxi` | 7 个(report/leader/task/issue/meeting/org/shared) | 个人端;userConfig Bearer Token + MCP Server(URL 走 office 子域,无端口) | +| `huanxi-admin` | 4 个(admin-report/admin-module/admin-ops/admin-shared) | 管理端;同上机制,Token 前缀 `hxa_`,与个人端是两条独立信任边界 | | `memcore` | 4 个(memory-sync/lint/update/shared) | 纯技能,无 MCP;memcore-shared 作内部 include(路径锁定 + 阈值常量 + PROJECT_DIR 解析),支持 synonyms.md 等价词表、Phase 3C 即时引用快扫、Phase 0 并发冲突保护、lint_report 稳定 ID + resolved 跳过、Base commit 兜底 | | `obsidian` | 10 个(obsidian/bases/canvas/daily/history/meta/plugins/search/tasks/workflow-pkm) | 纯技能,无 MCP;对标社区基准(kepano/obsidian-skills 31.8k★、AgriciDaniel/claude-obsidian)后扩展 canvas 视觉层;核心 obsidian 含 OFM 语法速查;workflow-pkm 含 Web Clip 子流程 | diff --git a/CLAUDE.md b/CLAUDE.md index cb11aaa..a90e6ed 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -76,10 +76,19 @@ description: 一句话说明该技能的用途(Claude 用此判断何时触发 | 插件 | 技能 | 说明 | |------|------|------| -| `huanxi` | `/huanxi-shared` `/huanxi-report` `/huanxi-leader` `/huanxi-task` `/huanxi-weekly` `/huanxi-org` | 寰汐企业管理系统完整工作流,含 MCP Server 自动配置 | +| `huanxi` | `/huanxi-shared` `/huanxi-report` `/huanxi-leader` `/huanxi-task` `/huanxi-issue` `/huanxi-meeting` `/huanxi-org` | 寰汐 · **个人端**工作流,自动配置个人端 MCP(`hxp_` Token,员工在个人中心自助生成) | +| `huanxi-admin` | `/huanxi-admin-shared` `/huanxi-admin-report` `/huanxi-admin-module` `/huanxi-admin-ops` | 寰汐 · **管理端**工作流,自动配置管理端 MCP(`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) | +> **两个 huanxi 插件当前只在 `huanxi-v2` 分支上,未合 `main`。** +> 它们描述的是寰汐 **v2** 的 MCP 工具,而插件里配置的域名此刻跑的还是 **v1**——合进 main +> 会通过自动更新推给已安装用户,他们的技能会去调 v1 上不存在的工具(`dict_get` / +> `issue_create` / `meeting_query` 等),表现为一连串「工具不存在」。 +> +> **合并前置条件**:v2 已部署到插件 `mcpServers` 里配置的那个域名。 +> 源码单一真相在寰汐仓库 `skills/`,同步方式:`python skills/sync_marketplace.py`。 + ### memcore 技能调用关系 ``` diff --git a/plugins/huanxi-admin/.claude-plugin/plugin.json b/plugins/huanxi-admin/.claude-plugin/plugin.json new file mode 100644 index 0000000..58ae61c --- /dev/null +++ b/plugins/huanxi-admin/.claude-plugin/plugin.json @@ -0,0 +1,24 @@ +{ + "name": "huanxi-admin", + "description": "寰汐企业管理系统 · 管理端。全量视角,含汇报盘点、模块与成员配置、运维简报三个工作流技能。需要管理员发放的 hxa_ Token,高危操作(账号启停/提权/删除)不在此端点。", + "author": { + "name": "姜顺志" + }, + "userConfig": { + "token": { + "type": "string", + "title": "寰汐 Admin Token", + "description": "由后台管理员在「系统 → Admin Token」生成,hxa_ 前缀;普通员工无需安装本插件", + "sensitive": true + } + }, + "mcpServers": { + "huanxi-admin": { + "type": "http", + "url": "https://huanxi.office.yixiong-tech.com/admin-mcp/", + "headers": { + "Authorization": "Bearer ${user_config.token}" + } + } + } +} diff --git a/plugins/huanxi-admin/skills/huanxi-admin-module/SKILL.md b/plugins/huanxi-admin/skills/huanxi-admin-module/SKILL.md new file mode 100644 index 0000000..cc014c8 --- /dev/null +++ b/plugins/huanxi-admin/skills/huanxi-admin-module/SKILL.md @@ -0,0 +1,86 @@ +--- +name: huanxi-admin-module +description: "寰汐管理端模块与任务:全量查模块任务、建模块、改模块状态、整组配置成员、跨模块任务管理。当用户说「建个模块」「把某人加进模块」「全公司任务情况」「关掉这个模块」时使用。" +--- + +# 寰汐管理端 · 模块与任务 + +**前置:先读 `huanxi-admin-shared`。** + +全量视角,不受「我参不参与」过滤。 + +--- + +## 查 + +``` +module_query(status_category?, q?) 全量模块,带负责人与成员数 +module_get(module_ids=[...]) 详情含成员名单与各自角色 +task_query(module_ids?, assignee_ids?, status_category?, priority?, q?) +task_get(task_ids=[...]) +``` + +过滤维度都收列表,一次查多个比循环调用好。 + +--- + +## 建模块 + +``` +module_create(name, type_id, leader_user_id, description?) +``` + +`type_id` 先 `dict_get(kinds=["module_types"])` 取,`leader_user_id` 用 `user_query` 取。 +创建后会自动生成该模块的「杂记」任务,承载不值得单独建任务的零散工作。 + +--- + +## 改模块 + +``` +module_update(module_id, name?, description?, status_option_id?) +``` + +⏸ **切到「已取消」有副作用**:级联取消该模块下全部未完成任务,并给成员发飞书通知。 +这不是可撤销的操作,确认清楚再调。 + +模块**删除**不在本端点——那是纠错场景(建错了),需要在后台确认。 + +--- + +## 成员整组配置 + +``` +module_set_members(module_id, members=[{user_id, role}, ...]) +``` + +⏸ **替换语义**:不在名单里的现有成员**会被移除**。正确做法: + +``` +1. module_get 拿现有名单 +2. 在现有名单基础上做改动(加人/改角色/去人) +3. 把完整的最终名单整组传回 +4. 先把「改完会变成谁、谁会被移除」说给用户听,确认后再调 +``` + +返回的 `added` / `role_changed` / `removed` 三组是本次实际发生的变更, +用它向用户复述结果。 + +一人一模块只能有一个角色(`leader` / `reviewer` / `member`)。新加入的成员会收到飞书通知。 + +--- + +## 任务 + +``` +task_create(module_id, tasks=[{title, ...}]) +task_update(updates=[{id, status_option_id?, progress?, priority?, ...}]) +task_set_assignees(task_id, user_ids=[...]) +``` + +- 改状态先 `dict_get` 取 task 类型的 `status_option_id` +- 状态与进度**有联动,只传一个就够**(进度 100 自动完成;已完成的调低进度自动回落) +- 非叶子任务(`progress_readonly` 为 true)不能直接设进度,要改它的子任务 +- `task_set_assignees` 是**替换**不是追加,同 `module_set_members` 的注意事项 + +任务删除与跨模块转移不在本端点。 diff --git a/plugins/huanxi-admin/skills/huanxi-admin-ops/SKILL.md b/plugins/huanxi-admin/skills/huanxi-admin-ops/SKILL.md new file mode 100644 index 0000000..ff2794d --- /dev/null +++ b/plugins/huanxi-admin/skills/huanxi-admin-ops/SKILL.md @@ -0,0 +1,54 @@ +--- +name: huanxi-admin-ops +description: "寰汐管理端运维与内容:提交运维简报、查公告与自动报告、全量查会议与议题。当用户说「提交运维简报」「本周系统周报」「看看有哪些议题」时使用。" +--- + +# 寰汐管理端 · 运维与内容 + +**前置:先读 `huanxi-admin-shared`。** + +--- + +## 运维简报 + +``` +ops_briefing_submit(content, iso_week?) +``` + +Markdown **原文存档,不经 AI 加工**——这是设计决策,简报的价值在于运维侧的原始记录, +加工会丢失细节。你可以帮用户组织语言,但要让他确认最终文本,不要自作主张改写后直接提交。 + +**同一 ISO 周重复提交是版本覆盖**:旧版本保留但不再是当前版本,公告表里那条发布记录 +原地更新指向最新版。不传 `iso_week` 则用今天所在周。 + +⏸ 提交前把最终 Markdown 展示给用户确认。 + +--- + +## 公告与自动报告 + +``` +announcement_query(ids?, kind?, series_slug?, period_key?) +``` + +统一入口,覆盖系统周报、周度复盘、版本发布、运维简报、人工公告。 + +- 按生命周期分类查 → `kind` +- 某条内置报告的历次期次 → `series_slug` +- 具体某一期 → 加 `period_key` + +报告按受众分档(全员/管理层/老板/本人),过滤在服务端完成——查不到某条不代表它不存在。 + +--- + +## 会议与议题(只读) + +``` +meeting_query(scope="all", status_category?, series_ids?, module_ids?, tag_ids?) +issue_query(scope?, level?, status_category?, module_ids?, tag_ids?, q?) +``` + +管理身份可见全部议题,含标记为「仅管理层可见」的那些。 + +议题的写操作(建、记进展、关闭)**不在管理端**——那些应当由议题的当事人在个人端做, +管理端替他记进展会让决策链的「谁说的」失真。会议的写操作同理。 diff --git a/plugins/huanxi-admin/skills/huanxi-admin-report/SKILL.md b/plugins/huanxi-admin/skills/huanxi-admin-report/SKILL.md new file mode 100644 index 0000000..13983c3 --- /dev/null +++ b/plugins/huanxi-admin/skills/huanxi-admin-report/SKILL.md @@ -0,0 +1,65 @@ +--- +name: huanxi-admin-report +description: "寰汐管理端汇报盘点:谁没交日报、跨用户查汇报内容、团队负载看板。当用户说「全公司谁没交」「盘点汇报」「谁比较闲」「看看某人这周报了什么」时使用。" +--- + +# 寰汐管理端 · 汇报盘点 + +**前置:先读 `huanxi-admin-shared`。** + +管理端最高频的场景。个人端只能看自己和自己负责的模块,这里是全量视角。 + +--- + +## 谁还没交(最常被问) + +``` +report_pending(module_ids?, date?) +``` + +只返回**存在未提交人员**的模块——交齐的模块不占篇幅。不传 `module_ids` 则盘点全部。 + +**统计口径含两条容易忽略的规则,不要自己重算**: + +- 模块杂记不计入分母(那是零散工作的承载容器,不代表当天有汇报义务) +- 当日免报的人**整体排除**——既不算未提交也不算已提交,不是「视为已提交」。 + 这个区别很重要:算成已提交会污染「已交人数」,算成未提交会一直催不该催的人 + +回答用户时直接给名单和模块,不要把原始结构丢回去让他自己数。 + +--- + +## 查汇报内容 + +``` +report_query(user_id?, module_id?, date_from?, date_to?) 员工日报条目 +leader_report_query(user_id?, module_id?, date_from?, date_to?) 负责人日报 +``` + +三个维度可任意组合,都不传即查今天全部。典型用法: + +- 「张三这周报了什么」→ `report_query(user_id=..., date_from=周一, date_to=今天)` +- 「智能诊断模块上周的汇报」→ `report_query(module_id=..., date_from=..., date_to=...)` + +**只读**。管理端不能替别人写或提交日报——那会让汇报失去「本人确认」的意义。 + +--- + +## 负载看板 + +``` +people_board() +``` + +按人聚合的跨模块任务负载,**含 0 任务的人**。回答「谁比较闲」「谁扛得太多」时用它, +比逐个 `task_query` 快得多。含 0 任务的人是有意的——那正是「谁完全没有负载」的答案。 + +--- + +## 组合用法 + +「这周谁又没交日报、手上还压着多少活」这类问题,是 `report_pending` + `people_board` +两个结果的交叉,不需要额外工具:先拿未提交名单,再从看板里查这些人的任务数。 + +⏸ 涉及要不要点名、要不要发提醒时,先把名单给用户确认再说下一步—— +盘点的产出是信息,催办是另一个决定。 diff --git a/plugins/huanxi-admin/skills/huanxi-admin-shared/SKILL.md b/plugins/huanxi-admin/skills/huanxi-admin-shared/SKILL.md new file mode 100644 index 0000000..351d1f4 --- /dev/null +++ b/plugins/huanxi-admin/skills/huanxi-admin-shared/SKILL.md @@ -0,0 +1,95 @@ +--- +name: huanxi-admin-shared +description: "寰汐管理端 MCP 共享基础:管理身份语义、高危操作边界、缓存策略、状态两层模型、人员与组织查询。所有 huanxi-admin-* 技能必须先读本文件。" +--- + +# 寰汐管理端 · 共享规则 + +所有 `huanxi-admin-*` 技能的**必读前置**。本技能族用的是管理端 Token(`hxa_`), +与个人端(`hxp_`)是两条独立通道,**工具集不同、视角不同**。 + +--- + +## 你是以谁的身份在操作 + +管理端 Token 不绑定业务用户,执行时以 **Token 创建人的管理员身份**进行, +所有写操作按该身份记入审计。`whoami` 回答「我现在代表谁」。 + +创建人若已停用或被撤销后台权限,Token 会一并失效——这不是 bug,是随人事变动收回权限。 + +视角是**全量**的:模块、任务、汇报都不受「我参不参与」过滤。这是与个人端最大的差别, +也意味着你看到的东西大多不是你自己的,措辞上要注意(说「张三的日报」而不是「你的日报」)。 + +--- + +## 高危操作不在本端点 + +**账号启停、授予/撤销管理员与老板身份、通讯录全量同步、各类删除、状态选项与标签等 +字典的写操作——全部走网页后台。** + +理由不是「危险所以不给」,而是网页后台有确认弹窗与完整的操作上下文,MCP 通道没有 +等价的「让人看清楚再点」环节。用户提这类需求时,直接告诉他去后台哪个页面, +**不要试图用别的工具绕过去**。 + +--- + +## 参数以工具自身的说明为准 + +本文档与各技能都不重画参数表。参数名、必填项、取值范围以工具在 MCP 里注册的 +docstring 为唯一真相;技能只描述调用顺序、ID 如何传递、哪里必须停下来等用户确认。 + +工具名在 Claude 客户端里带前缀 `mcp__huanxi-admin__`,其他平台按各自约定; +本文档统一写裸名。 + +--- + +## 状态是可配置的两层模型 + +**不要硬编码状态字面量。** 分两层: + +- `category`:四类固定语义 `not_started` / `in_progress` / `completed` / `cancelled`,用于**判断** +- `status_option_id`:具体状态项的 UUID,用于**写入** + +改状态前先 `dict_get` 取对应 `entity_type`(module/task/issue/meeting,必须选对) +下的选项。字典本身的增删改不在本端点。 + +--- + +## 人员与组织查询 + +``` +user_query(q?, ids?, status?, has_backend_permission?) +org_tree() +``` + +`user_query` 比个人端多两个维度:`status`(active 在职 / observation 交接观察期 / +inactive 已停用)与 `has_backend_permission`。用于盘点「谁在观察期」「谁有后台权限」。 +**只读**——账号启停与权限授予见上文。 + +--- + +## 缓存 + +缓存根 `~/.claude/huanxi-cache/`,管理端用 `admin/` 子目录,与个人端隔离—— +两边看到的模块范围不同,混用会把不该展示的内容展示出去。 + +| 类别 | 策略 | +|---|---| +| 身份 `admin/me.json` | 永久 | +| 配置字典 `dict/*.json` | **`dict_version` 比对** + 24h 兜底 | +| 组织 `admin/org-tree.json` `admin/all-modules.json` | 24h | +| 工作日 `dict/workdays.json` | 按日期 key 永久 | +| **业务数据**(汇报/任务/会议/议题) | **一律不缓存** | + +字典为什么不能只靠 TTL:状态选项可能被停用,拿过期 ID 去写会**直接报错**—— +失败方向是「操作失败」而非「看到旧数据」,值得比对一次。`dict_get` 的返回自带 +`versions` 字段,连内容一起存即可,不要分两次调。 + +--- + +## 全局约定 + +1. **有副作用的写操作先确认**:`module_set_members`(替换语义,会移除名单外的人)、 + `module_update` 切「已取消」(级联取消该模块全部未完成任务并通知成员)。 +2. **盘点类查询直接给结论**:用户问「谁没交」,答案是名单,不是让他自己看原始数据。 +3. **先解析 ID 再操作**,不要凭名字猜。 diff --git a/plugins/huanxi/.claude-plugin/plugin.json b/plugins/huanxi/.claude-plugin/plugin.json index 3a10b06..e4e1eb8 100644 --- a/plugins/huanxi/.claude-plugin/plugin.json +++ b/plugins/huanxi/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "huanxi", - "description": "寰汐企业管理系统 Claude Code 插件。集成日报、负责人日报、周报、任务管理、组织查询六大工作流技能,并自动配置寰汐 MCP Server 连接(Bearer Token 直连模式)。", + "description": "寰汐企业管理系统 · 个人端。以你本人的身份操作,权限与网页端一致。含日报、负责人日报、任务、议题、会议、组织检索六个工作流技能,并自动配置 MCP 连接。", "author": { "name": "姜顺志" }, @@ -8,7 +8,7 @@ "token": { "type": "string", "title": "寰汐 Personal Token", - "description": "在寰汐系统后台「设置 → Personal Token」生成,hxp_ 前缀", + "description": "在寰汐「个人中心 → MCP Token 管理」自助生成,hxp_ 前缀", "sensitive": true } }, diff --git a/plugins/huanxi/skills/huanxi-issue/SKILL.md b/plugins/huanxi/skills/huanxi-issue/SKILL.md new file mode 100644 index 0000000..de9e6cd --- /dev/null +++ b/plugins/huanxi/skills/huanxi-issue/SKILL.md @@ -0,0 +1,58 @@ +--- +name: huanxi-issue +description: "寰汐议题:提出议题、记录进展与决策链、调整分级、关闭。当用户说「提个议题」「这事记一下」「议题进展」「关掉这个议题」时使用。" +--- + +# 寰汐议题 + +**前置:先读 `huanxi-shared`。** + +议题是「需要被讨论和跟进的事」,与任务的区别:任务有明确执行人和完成标准, +议题是待决策或待澄清的问题。**议题不需要审批**,任何非观察期用户直接建。 + +--- + +## 决策链是核心 + +议题的价值不在「现在什么状态」,而在 `progress_logs` 记录的**怎么走到这一步的**。 +`issue_get` 会带出完整决策链——起草结论、回顾判断时都应基于它,而不是只看当前状态。 + +--- + +## 常用流程 + +``` +提出 issue_create(issues=[{title, description?, level?, is_management_only?, + participant_ids?, module_ids?, tag_ids?}]) + +查 issue_query(scope="library"|"created"|"participating", level?, q?, ...) + issue_get(issue_ids=[...]) ← 含决策链 + +记进展 issue_record_progress(issue_id, content, meeting_id?) + ↓ meeting_id 填了 = 这条结论是某次会上定的,会议与议题因此建立关联 + ↓ 不填 = 独立记录的一条进展 + +调分级 issue_update(updates=[{id, level}]) ← 变更会记入决策链 + +关闭 ⏸ 先与用户确认结论文字 + issue_close(issue_id, conclusion) ← 结论必填 +``` + +--- + +## 分级 + +`critical`(必须讨论)/ `watch`(需关注)/ `info`(信息同步)。这是**议题**的分级, +与任务的 `priority` 是两套取值,别混。 + +--- + +## 几条容易踩的 + +- **关闭必须带结论,且要走 `issue_close`**。用 `issue_update` 改状态到「已完成」是另一条 + 路径,服务端会拒——「关了但没说为什么」不允许存在。 +- **`is_management_only` 的议题只对管理层/创建人/参与人可见**,其余人在列表和详情里 + 都看不到(不是置灰,是不存在)。你查不到某条议题时,可能就是这个原因,不要断言它不存在。 +- 编辑/关闭/重开/删除需要是**创建人或后台管理员**;记进展的范围更宽(创建人、参与人、 + 或该条挂在某会议下时该会议的主持人)。 +- 默认隐藏已完成/已取消,要看全部传 `include_closed=true`。 diff --git a/plugins/huanxi/skills/huanxi-leader/SKILL.md b/plugins/huanxi/skills/huanxi-leader/SKILL.md index c371785..e3dc558 100644 --- a/plugins/huanxi/skills/huanxi-leader/SKILL.md +++ b/plugins/huanxi/skills/huanxi-leader/SKILL.md @@ -1,101 +1,63 @@ --- name: huanxi-leader -description: "寰汐负责人日报工作流:查看下属汇报情况(+check)、AI 生成并保存草稿(+draft)、提交负责人日报(+submit)、撤回(+withdraw)。当用户说"查看下属汇报"、"写负责人日报"、"汇总下属情况"、"负责人日报"时触发。" +description: "寰汐负责人日报:查看下属汇报情况、起草模块汇总、批量提交。当用户说「写负责人日报」「模块汇总」「我下属今天报了什么」「谁还没交」时使用。" --- # 寰汐负责人日报 -**前置条件:先 Read `../huanxi-shared/SKILL.md`(缓存规则 + TTL 策略)** +**前置:先读 `huanxi-shared`。** -> ⚠️ **工具调用规范**:执行任何 `mcp__huanxi__*` 调用前,以工具实际注册的参数名和类型为准,本文档示例仅供工作流引导(见 shared 全局约定第 6 条)。 +与员工日报是两件事:员工日报是「我做了什么」的条目列表,负责人日报是「我这个模块 +整体怎么样」的一段整体内容,**结构不同、接口不同,不要混用**。 --- -## 标准工作流(完整流程) +## 标准流程 ``` -Step 0: 确认身份和负责的模块 - → Read ~/.claude/huanxi-cache/me.json(永久缓存) - → Read ~/.claude/huanxi-cache/modules.json(24h 缓存) - → 筛选 my_role == 'leader' 的模块 - → 若有多个 leader 模块,询问用户选择哪个(或所有) +Step 1 leader_report_get(date?, module_ids?) + ↓ 一次拿全每个模块的:进度、我这条汇总的现状、**未提交成员名单**、 + 以及成员们当天各自报了什么(member_reports) + ↓ 起草素材全在这里,不需要再调别的工具取 -Step 1: 获取并展示下属汇报汇总 - → 单模块:mcp__huanxi__leader_report_get_subordinates(date=今日, module_id) - → 多模块:mcp__huanxi__leader_report_get_batch(date=今日, module_ids=[...]) - 再按模块逐一展示 - → 展示结构化汇总: - ✅ 已提交(N人):[姓名] + 汇报内容摘要 - ⏳ 未提交(M人):[姓名] - → 若有未提交成员:告知用户(供参考,不强制等待) +Step 2 基于 member_reports 归纳,为每个模块起草一段汇总 + ↓ 归纳而非罗列——把「三个人各自做了什么」写成「这个模块本周推进到哪」 + ↓ 有 pending_members 时提醒用户:这几位还没交,汇总可能不完整 -Step 2: 询问是否 AI 汇总 - → 展示已提交成员的汇报内容后,询问: - "是否需要 AI 根据以上下属汇报自动生成今日负责人日报?" - → 用户同意 → mcp__huanxi__llm_generate_leader_summary(module_id, date=今日) - → 展示 AI 生成的汇总报告,供用户审阅和修改 - → 用户拒绝 → 引导用户手动填写报告内容 +Step 3 leader_report_save(entries=[{module_id, content}, ...]) -Step 3: 保存草稿 - → 详见 references/leader-summary.md - → mcp__huanxi__leader_report_save(report_date, content=<确认后内容>, module_id) +Step 4 ⏸ 展示全部草稿,等待用户明确确认 -Step 4: 确认并提交 - → 展示最终内容,等待用户明确确认("确认"/"提交"/"好的"等) - → ⚠️ 未收到确认前,禁止调用 leader_report_submit - → mcp__huanxi__leader_report_submit(report_date, module_id) +Step 5 leader_report_submit(module_ids=[...]) + ↓ 不传 module_ids 则提交我负责的全部(自动跳过已提交与内容为空的) ``` --- -## Shortcuts +## 「谁还没交」 -| 指令 | 说明 | -|------|------| -| `+check` | 查看指定日期下属提交情况 | -| [`+draft`](references/leader-summary.md) | AI 生成草稿并保存(需用户确认内容) | -| `+submit` | 提交负责人日报(必须先确认) | -| `+withdraw` | 撤回已提交负责人日报 | +这是最高频的单点问题,`leader_report_get` 的 `pending_members` 直接回答, +不需要遍历成员逐个查。 + +想看全公司范围而不只是我负责的模块,那是管理端的 `report_pending`(见 +`huanxi-admin`),个人端拿不到。 --- -## +check:查看下属汇报 +## 撤回 ``` -1. 确定模块(从 modules.json 缓存中取 leader 身份的模块) -2. mcp__huanxi__leader_report_get_subordinates(date, module_id) -3. 展示: - ✅ 已提交(N人):张三、李四、... - ⏳ 未提交(M人):王五、... - (非工作日时:提示"今日非工作日,成员无需强制提交") +leader_report_withdraw(module_ids=[...]) → 变回草稿,仅当天可撤 ``` --- -## +withdraw:撤回负责人日报 +## 几条容易踩的 -``` -1. 确认当前已提交状态 -2. 告知撤回影响,等待用户确认 -3. mcp__huanxi__leader_report_withdraw(report_date, module_id) -``` - ---- - -## 多模块处理 - -若用户有多个 leader 模块: - -``` -- 默认展示全部模块的下属情况(+check) -- 提交时需逐模块操作:每个模块单独调用 leader_report_save + submit -- 可用 leader_report_get_batch(date, module_ids) 批量拉取数据 -``` - ---- - -## 关键约束 - -- **禁止自动提交**:`leader_report_submit(report_date, module_id)` 前必须展示内容并等待用户确认 -- **成员未提交不阻塞**:负责人日报不依赖所有成员提交,可随时填写 -- 若当前用户不是任何模块的 leader,告知用户并建议使用 `/huanxi-report` 填写员工日报 +- **一个模块一条**:`module_id` 是主键的一部分,同一模块当天只有一条汇总, + 重复保存是覆盖不是新增。 +- **内容为空不能提交**:批量提交会静默跳过空内容的模块并在返回里说明, + 不要以为「提交成功」就等于每个模块都交了——看返回的 `skipped_empty_count`。 +- **不要前置校验下属是否交齐**:负责人日报不依赖员工日报的提交状态, + 下属没交也能交自己的汇总(这是有意设计,避免一个人拖住整条链)。 +- 只有 `leader` 角色的模块才会出现在这里;`reviewer` 不写负责人日报。 diff --git a/plugins/huanxi/skills/huanxi-leader/references/leader-summary.md b/plugins/huanxi/skills/huanxi-leader/references/leader-summary.md deleted file mode 100644 index a76bab9..0000000 --- a/plugins/huanxi/skills/huanxi-leader/references/leader-summary.md +++ /dev/null @@ -1,85 +0,0 @@ -# 负责人日报草稿(+draft) - -> ⚠️ 参数细节以 MCP `leader_report_save` / `llm_generate_leader_summary` 的 docstring 为准,本文档仅做工作流引导。 - -## 两种草稿模式 - -### 模式 A:AI 自动生成 - -``` -1. mcp__huanxi__llm_generate_leader_summary(module_id=<模块ID>, date=<日期>) -2. 展示 AI 生成的草稿内容给用户审阅 -3. 询问用户:"是否采用此草稿?或需要修改?" -4. 用户确认/修改完成后 → 执行保存步骤 -``` - -### 模式 B:用户手动撰写 - -``` -1. 展示下属汇报摘要(来自 leader_report_get_subordinates 结果) -2. 基于摘要,引导用户填写: - - 本模块今日整体进展 - - 遇到的问题与风险 - - 明日计划 -3. 拼合用户输入内容 → 执行保存步骤 -``` - ---- - -## 保存草稿 - -``` -mcp__huanxi__leader_report_save( - report_date = "YYYY-MM-DD", ← 日期格式 - scope_type = "module", ← 默认 "module";组织维度填 "org" - module_id = "<模块ID>", ← scope_type="module" 时必填,从 modules.json 缓存取 - # org_id = "<组织ID>", ← scope_type="org" 时必填,与 module_id 互斥 - content = "<正文内容>", ← 支持 Markdown,三段式(今日进展/问题与风险/明日重点) - # progress_corrections = [ ← 可选:手动修正模块进度 - # { "module_id": "", "new_progress": 75 } - # ] -) -``` - -**返回值**:保存成功后返回草稿 ID,告知用户已保存,询问是否立即提交。 - -**注意**: -- 同一用户同一日期同一 scope 只有一条记录(重复调用是更新) -- 默认走 module 维度;只有组织负责人需要 org 维度时才传 `scope_type="org"` + `org_id` - ---- - -## 多模块批量操作 - -若用户负责多个模块: - -``` -1. mcp__huanxi__leader_report_get_batch(date, module_ids=[...]) - → 一次获取所有模块的下属汇报情况 - -2. 逐模块调用 llm_generate_leader_summary 生成草稿 - -3. 逐模块调用 leader_report_save 保存 - -4. 统一确认后逐模块提交 -``` - ---- - -## 内容格式建议(供 AI 生成参考) - -```markdown -## 今日进展 - -- [任务A] 完成 XX 功能开发,进度 80% -- [任务B] 完成接口联调,已提测 - -## 问题与风险 - -- 暂无阻塞性问题 - -## 明日计划 - -- 继续推进 [任务C] -- 协助 [成员] 解决 XX 问题 -``` diff --git a/plugins/huanxi/skills/huanxi-meeting/SKILL.md b/plugins/huanxi/skills/huanxi-meeting/SKILL.md new file mode 100644 index 0000000..119690f --- /dev/null +++ b/plugins/huanxi/skills/huanxi-meeting/SKILL.md @@ -0,0 +1,54 @@ +--- +name: huanxi-meeting +description: "寰汐会议:查会议与议程、发起临时会议、维护议程条目、写会议纪要。当用户说「今天有什么会」「加个议程」「记会议纪要」「开个会」时使用。" +--- + +# 寰汐会议 + +**前置:先读 `huanxi-shared`。** + +系统里「会议」是通用概念,晨会只是一条周期会议系列。周期会议的每一期由系统自动生成, +**不要用 `meeting_create` 去建周期会议的某一期**——那个工具只发起临时会议。 + +--- + +## 常用流程 + +``` +查 meeting_query(scope="participating"|"created"|"hosting"|"all") + ↓ 与任务相反,**不隐藏已结束的会议**——翻历史记录是常见需求 + meeting_get(meeting_ids=[...]) ← 含参会人、纪要、完整议程 + +发起临时会 meeting_create(title, scheduled_at?, attendee_ids?, room_id?) + ↓ 发起人自动成为主持人与参会人 + ↓ room_id 先 dict_get 取 meeting_rooms + +维护议程 agenda_write(meeting_id, create?, update?, delete_ids?, reorder_ids?) + ↓ 一次调用可同时增、改、删、重排,返回操作后的完整议程 + +写纪要 meeting_minutes_save(meeting_id, content) +``` + +--- + +## 权限看下发的布尔,不要自己推算 + +`meeting_query` / `meeting_get` 返回里带 `can_edit`、`can_claim`。**直接用它们**—— +主持人、创建人、后台管理员的组合规则比看上去复杂(比如当前主持人不能自行改派给别人), +自己按规则推算必然与服务端不一致,表现为「按钮该显示却没显示」或「显示了点了报错」。 + +--- + +## 会议结束后是只读的 + +`ended` 为 true 的会议,议程与纪要都不能再改,任何写入都会被拒。这是归档语义, +不是 bug——需要补记请让管理员在网页端「重新打开」该会议(有显式操作留痕)。 + +--- + +## 不在工具里的操作 + +认领/撤回/指定主持人、结束/重新打开会议**不在 MCP**。这些是一次点击的 UI 动作, +AI 代劳收益低而误操作代价高,请引导用户去网页端。 + +`agenda_write` 的 `reorder_ids` 要传**完整**的条目顺序列表,不是只传要移动的那几个。 diff --git a/plugins/huanxi/skills/huanxi-org/SKILL.md b/plugins/huanxi/skills/huanxi-org/SKILL.md index 15faf66..8f5ec09 100644 --- a/plugins/huanxi/skills/huanxi-org/SKILL.md +++ b/plugins/huanxi/skills/huanxi-org/SKILL.md @@ -1,137 +1,84 @@ --- name: huanxi-org -description: "寰汐组织/模块/人员查询。当用户说"我有哪些模块"、"查一下某人账号/ID"、"刷新一下缓存"、"看组织架构"、"谁在哪个模块"、"帮我找一下XXX的用户ID"时触发。提供名字→ID 解析(+resolve)、缓存刷新(+sync)、当前用户(+me)、模块列表(+modules)、组织树(+tree)。" +description: "寰汐组织与检索:查人、查部门、全局搜索、按标签反查、团队任务看板。当用户说「XX是谁」「这个部门有哪些人」「搜一下」「团队在忙什么」时使用。" --- -# 寰汐组织与人员查询 +# 寰汐组织与检索 -**前置条件:先 Read `../huanxi-shared/SKILL.md`(缓存规则 + TTL 策略)** +**前置:先读 `huanxi-shared`。** -> ⚠️ **工具调用规范**:执行任何 `mcp__huanxi__*` 调用前,以工具实际注册的参数名和类型为准,本文档示例仅供工作流引导(见 shared 全局约定第 6 条)。 +本技能主要有两个职责:**把名字解析成 ID** 供其他技能使用,以及**维护缓存**。 --- -## 核心能力 +## 解析 ID -本技能提供「名字 → ID」解析能力,是所有其他 huanxi-* 技能的依赖。所有操作**缓存优先**。 +几乎所有写操作都要 ID。顺序是:先读缓存,未命中再调工具,拿到后写回缓存。 + +``` +user_search(q="冯普") 姓名模糊搜 → 拿 id +user_search(ids=[...]) 已知 id 批量取详情 +module_query(role?) 我参与的模块(带 my_role) +org_tree() 组织架构树,含各部门成员姓名 +``` + +`user_search` 结果里标注了 `offboarding`(离职观察期,不宜再派新活)与 `inactive` +(已停用)——把人派给这两类之前先提醒用户。 --- -## Shortcuts +## 全局检索 -| 指令 | 说明 | -|------|------| -| [`+me`](references/resolve-ids.md#me) | 查看当前用户身份(读 me.json,缓存永久) | -| [`+modules`](references/resolve-ids.md#modules) | 列出我参与的所有模块(24h 缓存) | -| [`+resolve`](references/resolve-ids.md) | 把模块名/人员名解析为 ID | -| [`+tree`](#org-tree) | 展示完整组织架构树(实时查询,不缓存) | -| [`+sync`](#sync) | 强制刷新 modules.json + users.json 缓存 | +``` +search(q="关键词") 一次返回六组:任务/模块/用户/标签/会议/议题,各组带总数 +``` + +不确定某个东西叫什么、在哪个模块时先用它定位,拿到 id 再调对应的 `*_get`。 +比逐个域去 query 快得多。 + +``` +tag_related(tag_id) 按标签反查五个域的关联内容 +``` + +标签是**平级横切索引**,同一个标签可以贴在用户/模块/任务/会议/议题任何一种上。 +这个工具回答「打了这个标签的所有东西都有哪些」。 --- -## +me:查看当前用户身份 {#me} +## 公告与报告 ``` -Step 1: Read ~/.claude/huanxi-cache/me.json - → 若存在且有 data 字段:直接展示(永久缓存,无需检查 TTL) - → 若不存在:执行 Step 2 - -Step 2: mcp__huanxi__user_get_me() -Step 3: Write ~/.claude/huanxi-cache/me.json: - { "cached_at": "", "data": <返回值> } -Step 4: 展示用户信息(name, feishu_user_id, 角色等) +announcement_query(kind?, series_slug?, period_key?, ids?) ``` +统一入口,覆盖系统周报、周度复盘、版本发布、运维简报、人工公告。 +**只返回你有权看的**——报告按受众分档(全员/管理层/老板/本人),过滤在服务端完成, +查不到某条不代表它不存在。 + +想看某条内置报告的历次期次,传 `series_slug`;想要具体某期,加 `period_key`。 + --- -## +modules:列出参与模块 {#modules} +## 团队看板 ``` -Step 1: Read ~/.claude/huanxi-cache/modules.json → 检查 TTL(24h) - → 未过期:直接展示 - → 过期或不存在:执行 Step 2 - -Step 2: mcp__huanxi__module_list() -Step 3: Write ~/.claude/huanxi-cache/modules.json: - { "cached_at": "", "data": <返回值> } -Step 4: 展示模块列表(id, name, my_role) +people_board() 按人聚合的跨模块任务负载,**含 0 任务的人** ``` +「我团队现在都在忙什么」「谁比较闲」用它,比逐个 `task_query` 高效得多。 +含 0 任务的人是有意的——那正是「谁完全没有负载」这个问题的答案。 + --- -## +resolve:名字 → ID 解析 +## 缓存维护 -详细流程见 [references/resolve-ids.md](references/resolve-ids.md)。 +本技能负责的三份缓存(详见 `huanxi-shared`): -**快速规则:** -- 模块名 → 先查 `modules.json`,未命中则拉 `module_list()` -- 人员名 → 先查 `users.json`,未命中则调 `user_list(name=xxx)`,结果追加写入缓存 -- 模糊匹配时若有多个结果,列出候选项让用户选择 +| 文件 | 来源 | TTL | +|---|---|---| +| `personal/me.json` | `whoami` | 永久 | +| `personal/users.json` | `user_search` | 24h | +| `personal/my-modules.json` | `module_query` | 24h | +| `admin/org-tree.json` | `org_tree` | 24h | ---- - -## +tree:组织架构树 {#org-tree} - -``` -Step 1: mcp__huanxi__org_get_tree()(不缓存,实时查询) -Step 2: 以树形结构展示组织架构 -``` - -> 组织架构变动相对频繁(人员入离职),不缓存,每次实时查询。 - ---- - -## +sync:强制刷新缓存 {#sync} - -``` -Step 1: mcp__huanxi__module_list() - → Write ~/.claude/huanxi-cache/modules.json(强制覆盖) - -Step 2: mcp__huanxi__user_list()(拉全量用户) - → Write ~/.claude/huanxi-cache/users.json(强制覆盖) - -Step 3: 告知用户:缓存已刷新(模块 N 个,用户 M 人) -``` - -> **何时需要 +sync**:添加新模块成员后、有新员工入职后、模块结构调整后。 -> -> ⚠️ **Token 变更时**:若切换了寰汐账号(修改了 MCP Bearer Token),`me.json` 是永久缓存,+sync 不会更新它。需手动删除 `~/.claude/huanxi-cache/me.json`,再执行 `/huanxi-org +me` 重新获取新身份。 - ---- - -## 缓存文件结构参考 - -**me.json:** -```json -{ - "cached_at": "2026-04-13T09:00:00+08:00", - "data": { - "id": "123", - "name": "张三", - "feishu_user_id": "ou_xxx" - } -} -``` - -> ⚠️ 用户身份的系统内部 ID 字段名是 `id`(与后端 `user_get_me` / `user_list` 返回结构一致),不是 `user_id`。 - -**modules.json:** -```json -{ - "cached_at": "2026-04-13T09:00:00+08:00", - "data": [ - { "id": "mod_001", "name": "前端开发", "my_role": "member" }, - { "id": "mod_002", "name": "后端API", "my_role": "leader" } - ] -} -``` - -**users.json:** -```json -{ - "cached_at": "2026-04-13T09:00:00+08:00", - "data": [ - { "id": "456", "name": "李四", "feishu_user_id": "ou_yyy" } - ] -} -``` +用户说「刷新一下」「组织变了」时,删掉对应文件重新拉取即可。 diff --git a/plugins/huanxi/skills/huanxi-org/references/resolve-ids.md b/plugins/huanxi/skills/huanxi-org/references/resolve-ids.md deleted file mode 100644 index 3cb14e5..0000000 --- a/plugins/huanxi/skills/huanxi-org/references/resolve-ids.md +++ /dev/null @@ -1,81 +0,0 @@ -# 名字 → ID 解析 - -> ⚠️ 参数细节以 MCP `module_list` / `user_list` / `user_get_me` 的 docstring 为准,本文档仅做工作流引导。 - -本文件详细说明如何将模块名、人员名解析为系统 ID,所有步骤均**缓存优先**。 - -**字段名约定**:用户/模块的系统内部 ID 字段名统一为 `id`(与后端返回结构一致),不要写成 `user_id`/`module_id` 作为 JSON 字段名。`module_id`/`user_id` 仅在传入 MCP 工具参数时使用。 - ---- - -## 模块名 → 模块 ID {#modules} - -``` -1. Read ~/.claude/huanxi-cache/modules.json - → 检查 cached_at,若 age < 24h → 进入匹配逻辑 - → 过期或不存在 → 调用 mcp__huanxi__module_list() 并写入缓存 - -2. 匹配逻辑: - a. 精确匹配 name == 输入 → 返回 id - b. 精确匹配失败 → 模糊匹配(name.includes(输入) 或 输入.includes(name)) - c. 模糊匹配唯一命中 → 确认并返回 id - d. 多个候选 → 列出候选项,让用户选择 - e. 零命中 → 告知用户,建议运行 +sync 刷新缓存 -``` - -**示例:** -- 用户说"前端模块" → 从缓存匹配到 `{ id: "mod_001", name: "前端开发" }` → 返回 `mod_001` -- 用户说"API" → 匹配到 `后端API` → 返回 `mod_002` -- 匹配到多个 → 展示候选列表 - ---- - -## 人员名 → 用户 ID {#users} - -``` -1. Read ~/.claude/huanxi-cache/users.json - → 检查 cached_at,若 age < 24h → 在 data 数组中查找 - -2. 查找逻辑: - a. name 精确匹配 → 返回 user.id - b. name 包含输入 → 列出候选 - c. 未找到 → 执行 Step 3 - -3. 缓存未命中时: - a. 调用 mcp__huanxi__user_list(name=<输入>) - b. 将结果追加(合并去重)写入 users.json(不覆盖已有缓存) - c. 重新执行 Step 2 匹配逻辑 - -4. 仍未找到 → 告知用户姓名不存在,建议确认拼写或运行 +sync -``` - -**特别注意:** -- 用户的系统内部 ID 字段名是 `id`(后端 `user_list` 返回结构),`≠ feishu_user_id` -- `feishu_user_id` 是飞书通讻录的 user_id(`on_` 前缀),`feishu_open_id` 是飞书 open_id(`ou_` 前缀);两者是**不同字段**,不要混用 -- 设置任务执行人时,MCP 工具的参数名叫 `assignee_ids`,传入的值是 user.id(系统内部 UUID 列表) -- 飞书消息通知由 MCP 服务端内部处理,调用工具时只需传系统内部 user.id 即可 - ---- - -## 自动 ID 解析流程(综合示例) - -当用户说"创建任务,负责人是李四,模块是前端开发"时: - -``` -1. 解析模块 → read modules.json → 匹配"前端开发" → mod_001 -2. 解析人员 → read users.json → 匹配"李四" → id: 456 -3. 若任一缓存未命中:先拉 MCP,写缓存,再继续 -4. 两个 ID 都拿到后 → 调用 task_create(module_id="mod_001", ...) -5. 创建完成后 → task_set_assignees(task_id, ["456"]) -``` - ---- - -## 常见错误处理 - -| 情况 | 处理 | -|------|------| -| 多个同名用户 | 展示完整名单(含部门/角色),让用户指定 | -| 模块名拼写不完整 | 模糊匹配,确认后继续 | -| 缓存文件损坏(JSON 解析失败)| 忽略缓存,直接调 MCP,重建文件 | -| MCP 返回空列表 | 告知用户,建议检查 Token 权限或联系管理员 | diff --git a/plugins/huanxi/skills/huanxi-report/SKILL.md b/plugins/huanxi/skills/huanxi-report/SKILL.md index b7eca7e..fb8446b 100644 --- a/plugins/huanxi/skills/huanxi-report/SKILL.md +++ b/plugins/huanxi/skills/huanxi-report/SKILL.md @@ -1,106 +1,76 @@ --- name: huanxi-report -description: "寰汐员工日报工作流:查看今日日报状态(+check)、保存草稿(+draft)、提交日报(+submit)、撤回日报(+withdraw)。当用户说"帮我写日报"、"填日报"、"提交日报"、"查看今日汇报情况"时触发。" +description: "寰汐员工日报:查看今日状态、填写并提交日报、撤回修改。当用户说「帮我写日报」「填日报」「提交日报」「今天要报什么」时使用。" --- # 寰汐员工日报 -**前置条件:先 Read `../huanxi-shared/SKILL.md`(缓存规则 + TTL 策略)** - -> ⚠️ **工具调用规范**:执行任何 `mcp__huanxi__*` 调用前,以工具实际注册的参数名和类型为准,本文档示例仅供工作流引导(见 shared 全局约定第 6 条)。 +**前置:先读 `huanxi-shared`(缓存策略、状态模型、确认约定)。** --- -## 标准工作流(完整流程) +## 标准流程 ``` -Step 0: 确认身份 - → Read ~/.claude/huanxi-cache/me.json(永久缓存) - → 若 me.json 为空:mcp__huanxi__user_get_me() → 写入缓存 +Step 1 report_get_context(date?) + ↓ 一次拿全:是否工作日、是否免报、整体状态、按模块分组的待汇报条目 + ↓ 非工作日 → 告知并询问是否仍要填(不中断) + ↓ 已全部提交 → 转「修改已提交内容」分支 + ↓ 免报日 → 告知无需提交,询问是否仍要记录 -Step 1: 检查是否工作日 - → 查 workdays.json["今日日期"] - → 未缓存:mcp__huanxi__system_get_workday() → 追加写入 workdays.json - → 非工作日:告知用户,询问"是否仍要填写?"(不强制中断) +Step 2 展示待汇报任务,引导用户逐条说今天做了什么 + ↓ 每条记住 task_id(后续提交要用) + ↓ 用户说不清的任务,可用 task_get 补上下文,不要替他编 -Step 2: 查看今日日报状态 - → mcp__huanxi__report_get_today() - → submitted → 告知"今日已提交",询问是否撤回 - → draft/empty → 继续 Step 3 +Step 3 (可选)润色 + ↓ 你自己润色即可,**不要找工具**——你就是那个语言模型 + ↓ 展示润色前后,让用户选 -Step 3: 获取待汇报任务并收集内容 - → mcp__huanxi__report_get_tasks_to_report() - → 返回的每个任务条目含:id(task_id)、title、module_id、module_name、progress 等 - → 展示待汇报任务列表(任务名、模块、当前进度) - → 引导用户逐一填写今日进展和完成百分比 - → 详见 references/report-draft.md +Step 4 report_save_draft(items=[...]) + ↓ 存草稿,此时还没提交 + ↓ 今天不报某条 → 该项加 dismissed=true;恢复 → restore=true -Step 4: 保存草稿并展示初稿 - → mcp__huanxi__report_save_draft(items=[...]) - → ⚠️ items 字段以 MCP docstring 为准;每条必须带 module_id(取自 Step 3 任务条目) - → 展示完整初稿内容供用户预览 +Step 5 ⏸ 展示完整初稿,等待用户明确确认 -Step 5: 询问是否 AI 润色 - → 询问用户:"是否需要 AI 润色优化表达?" - → 用户同意 → mcp__huanxi__llm_polish_report(content=<初稿内容>) - → 展示润色后版本,与初稿对比 - → 用户选择采用润色版或保留原版 - → 若采用润色版:mcp__huanxi__report_save_draft(items=[...]) 更新草稿 - → 用户拒绝 → 直接进入 Step 6 +Step 6 report_submit(task_ids=[...]) + ↓ 只提交确认过的那些;不传 task_ids 则提交全部草稿 +``` -Step 6: 确认并提交 - → 展示最终内容,等待用户明确确认("确认"/"提交"/"好的"等) - → ⚠️ 未收到确认前,禁止调用 report_submit_item - → 用户确认后: - a. mcp__huanxi__report_get_today() → 获取各条目的 item_id - b. 对每个需提交的草稿条目 → mcp__huanxi__report_submit_item(item_id) - c. 逐条提交,不影响其他条目 - → 详见 references/report-submit.md +**Step 5 不可省略。** 写日报和交日报是两个决定,用户可能只想先存着。 + +--- + +## 修改已提交内容 + +``` +report_withdraw(task_ids=[...]) → 变回草稿 + ↓ 修改 +report_save_draft(...) + ↓ ⏸ 确认 +report_submit(task_ids=[...]) +``` + +**仅当天可撤回。** 隔天的日报已进入统计口径,撤回会被拒绝——这时应告诉用户去找管理员, +而不是反复重试。 + +--- + +## 查历史 + +``` +report_history(scope="module", module_id=...) 某模块某天全体成员报了什么 +report_history(scope="task", task_id=..., date_from=..., date_to=...) + 某个任务被谁在哪天报过什么 ``` --- -## Shortcuts +## 几条容易踩的 -| 指令 | 说明 | -|------|------| -| [`+check`](#check) | 查看今日日报状态(已提交/草稿/空) | -| [`+draft`](references/report-draft.md) | 读取待报任务并保存草稿 | -| [`+submit`](references/report-submit.md) | 提交当天日报(必须先确认) | -| `+withdraw` | 撤回已提交日报(询问确认) | - ---- - -## +check:查看今日状态 {#check} - -``` -1. mcp__huanxi__report_get_today() -2. 展示: - - 提交状态(submitted / draft / 未填) - - 已填任务列表及内容摘要 - - 未填/dismissed 任务 -3. 若已提交:询问"是否需要撤回修改?" -4. 若草稿:询问"是否继续编辑并提交?" -``` - ---- - -## +withdraw:撤回日报 - -``` -1. mcp__huanxi__report_get_today() → 获取各条目状态和 item_id -2. 展示已提交的条目列表,询问用户要撤回哪条(可多选) -3. 等待用户确认(撤回后该条目变为草稿,其他已提交条目不受影响) -4. 对用户选择的每条 → mcp__huanxi__report_withdraw_item(item_id) -5. 告知撤回成功,可重新编辑后用 report_submit_item 重新提交 -``` - ---- - -## 关键约束 - -- **禁止自动提交**:Step 6 必须展示内容并等待用户明确确认("确认"/"提交"/"好的"等),不得自动调用 `report_submit_item` -- **逐条操作,不做全量**:提交/撤回必须使用 `report_submit_item` / `report_withdraw_item`(需传 item_id),禁止批量操作所有条目,除非用户明确要求"全部提交/撤回" -- **dismissed 状态**:用户主动标记"今天不汇报该任务",dismiss 的条目不计入汇报,不要提示用户补填 -- **非工作日**:检测到非工作日时,明确告知但不中断,询问用户意愿 -- **已提交则不重复操作**:Step 2 发现已提交时,不继续 Step 3-6,改为询问是否撤回 +- **条目用 `task_id` 定位**,不是条目自身的 id。`report_get_context` 返回里的 + `task_id` 就是后续 save/submit/withdraw 都要传的那个。 +- **空内容不能提交**:服务端会拒。要么写点内容,要么标 `dismissed`。 +- **模块杂记**(`is_module_misc`)承载零散工作,可以报也可以不报,但它**不计入 + 「未提交」统计**——用户只写了杂记不算完成当天汇报,提醒他还有别的任务没写。 +- **`progress_update` 是任务进度**(0-100),不是完成度描述。填了它会真的改任务进度。 +- 免报日(`is_exempt`)不产生未提交统计,也不必催。 diff --git a/plugins/huanxi/skills/huanxi-report/references/report-draft.md b/plugins/huanxi/skills/huanxi-report/references/report-draft.md deleted file mode 100644 index 6ff252d..0000000 --- a/plugins/huanxi/skills/huanxi-report/references/report-draft.md +++ /dev/null @@ -1,64 +0,0 @@ -# 保存日报草稿(+draft) - -> ⚠️ 参数细节以 MCP `report_save_draft` 的 docstring 为准,本文档仅做工作流引导。 - -## 前置 - -已通过 `report_get_tasks_to_report()` 获取待汇报任务列表。返回的每个任务条目至少含 `id`(task_id)、`title`、`module_name`,**以及 module_id 字段**(保存草稿必需)。 - ---- - -## items 字段(与后端签名一致) - -| 字段 | 必填 | 类型 | 说明 | -|------|------|------|------| -| `module_id` | ✅ **必填** | string (UUID) | 任务所属模块 ID,从 `report_get_tasks_to_report()` 返回的任务条目里取(不要从任务名推断) | -| `task_id` | 可选 | string (UUID) | 任务 ID;不传则为模块级汇报 | -| `content` | ✅ **必填** | string | 汇报内容(今日进展),支持 Markdown,可为空字符串 | -| `progress_update` | 可选 | int (0-100) | 任务进度百分比(字段名是 `progress_update`,不是 `progress`) | - -⚠️ **历史踩坑**:曾用错的字段名 `progress`、`status`,以及遗漏 `module_id`,会触发"参数缺失"错误。 - ---- - -## 执行步骤 - -``` -Step 1: 展示待汇报任务列表,引导用户逐一填写内容 - - 格式示例: - ┌───────────────────────────────────────── - │ 任务: [前端开发] 完成登录页面 UI 优化 - │ 当前进度: 60% - │ 今日进展(请输入): ___ - │ 完成百分比(0-100): ___ - └───────────────────────────────────────── - -Step 2: 收集所有填写内容,构建 items 数组 - ⚠️ 每个 item 必须含 module_id(来自 Step 0 的任务条目) - -Step 3: [可选] 若用户请求 AI 辅助 → mcp__huanxi__llm_polish_report(content) - 将润色建议展示给用户,由用户确认采用哪个版本 - -Step 4: mcp__huanxi__report_save_draft(items=[ - { - module_id: "<从任务条目取>", - task_id: "<从任务条目取>", - content: "今日完成 ...", - progress_update: 80 - }, - ... - ]) - -Step 5: 告知保存结果: - "已保存草稿,共 N 个任务条目。是否现在提交?" -``` - ---- - -## 注意事项 - -- `progress_update` 是 **整数百分比**(0-100),不是小数;字段名末尾必须是 `_update` -- 用户未填写 `content` 的任务:询问是否 dismiss(今天不汇报)还是暂时跳过 -- `report_save_draft` 是 upsert 操作,多次调用不会重复创建 -- 草稿保存成功后,下次调用 `report_get_today()` 可看到 draft 状态 diff --git a/plugins/huanxi/skills/huanxi-report/references/report-submit.md b/plugins/huanxi/skills/huanxi-report/references/report-submit.md deleted file mode 100644 index 66cb7f4..0000000 --- a/plugins/huanxi/skills/huanxi-report/references/report-submit.md +++ /dev/null @@ -1,56 +0,0 @@ -# 提交日报(+submit) - -> ⚠️ 参数细节以 MCP `report_submit_item` / `report_get_today` 的 docstring 为准,本文档仅做工作流引导。 - -## 前置条件 - -- 草稿已通过 `report_save_draft()` 保存 -- 用户已查看并确认内容 - ---- - -## 执行步骤 - -``` -Step 1: mcp__huanxi__report_get_today() → 获取最新草稿内容 - -Step 2: 展示完整草稿给用户审阅: - ┌───────────────────────────────────────── - │ 📋 今日日报预览(2026-04-13) - │ - │ ✅ 完成登录页面 UI 优化(进度 80%) - │ 今日进展:完成了头部导航栏的响应式改造... - │ - │ 🔄 接口联调(进度 50%) - │ 今日进展:与后端对接了 3 个接口... - └───────────────────────────────────────── - -Step 3: 等待用户明确确认("确认"/"提交"/"好的"/"ok"等) - ⚠️ 未收到确认前,禁止调用 report_submit_item - -Step 4: 对每个需提交的草稿条目(item.status == "draft"): - mcp__huanxi__report_submit_item(item_id=) - 逐条提交,不影响其他条目状态 - -Step 5: 告知提交结果: - "✅ 日报已提交!共 N 个任务条目。" -``` - ---- - -## 提交失败处理 - -| 错误 | 处理方式 | -|------|---------| -| 草稿为空 | 提示用户先填写内容(+draft) | -| 已提交 | 告知已提交,询问是否撤回 | -| 网络错误 | 告知用户,建议稍后重试 | - ---- - -## 重要约束 - -**禁止自动提交**:无论何种情况,`report_submit_item()` 调用前必须经过用户明确确认。 -这是强制规则,不得因为"用户已经填好了"或"工作流要求"而跳过确认步骤。 - -**逐条提交,不做全量**:需先从 `report_get_today()` 获取各条目的 `item_id`,再逐条调用 `report_submit_item(item_id)`,不得批量提交所有条目(除非用户明确要求"全部提交")。 diff --git a/plugins/huanxi/skills/huanxi-shared/SKILL.md b/plugins/huanxi/skills/huanxi-shared/SKILL.md index be5c7d4..355189c 100644 --- a/plugins/huanxi/skills/huanxi-shared/SKILL.md +++ b/plugins/huanxi/skills/huanxi-shared/SKILL.md @@ -1,142 +1,125 @@ --- name: huanxi-shared -description: "寰汐 MCP 共享基础:本地缓存策略(me/modules/users/workdays)、TTL 规则、缓存读写伪代码、MCP 工具索引。所有 huanxi-* 技能必须先 Read 本文件,再执行各自工作流。" +description: "寰汐 MCP 共享基础:工具命名约定、本地缓存策略与过期检查、状态两层模型、全局确认约定。所有 huanxi-* 技能必须先读本文件。" --- # 寰汐 MCP 共享规则 -本技能是所有 `huanxi-*` 技能的**必读前置**,定义缓存策略、工具索引和全局约定。 +所有 `huanxi-*` 技能的**必读前置**。 --- -## 必读声明 +## 一条最重要的约定:参数以工具自身的说明为准 -**所有 huanxi-* 技能开头都必须先 `Read` 本文件(`../huanxi-shared/SKILL.md`),再执行各自工作流。** +**本文件与各技能文档都不重画参数表。** 每个工具的参数名、必填项、取值范围以它在 MCP +里注册的 docstring 为唯一真相;技能只描述**调用顺序、ID 如何传递、哪里必须停下来等用户 +确认**。 + +> 这条不是洁癖。上一代技能包重画过参数表,结果字段名、枚举值、必填项四类漂移覆盖了 +> 全部六个技能——用户侧表现为频繁的「参数缺失」报错。工具签名变了而文档没跟上, +> 是必然发生而非可能发生的事。 --- -## 本地缓存机制 +## 工具命名 -缓存文件统一存放在 `~/.claude/huanxi-cache/`。 +Claude Code / Claude Desktop 里工具名带前缀:`mcp__huanxi__task_query`(个人端)、 +`mcp__huanxi-admin__report_pending`(管理端)。其他平台通常是裸名 `task_query`。 +本文档统一写**裸名**,实际调用时按你所在平台的约定加前缀。 -### 缓存文件清单 +两个端点信任边界不同: -| 文件 | 内容 | TTL | 刷新方式 | -|------|------|-----|---------| -| `me.json` | 当前用户身份(id, name, feishu_user_id;注意字段名是 `id` 而不是 `user_id`) | 永久 | 手动删除文件 | -| `modules.json` | 我参与的模块列表(id, name, my_role) | 24h | 过期自动重拉 或 `/huanxi-org +sync` | -| `users.json` | 组织用户搜索结果(name/feishu_user_id 索引) | 24h | 过期自动重拉 或 `/huanxi-org +sync` | -| `workdays.json` | 工作日查询结果(date → bool 的 KV 字典) | 永久(按日期 key) | 已有日期不重新查 | +| | 个人端 | 管理端 | +|---|---|---| +| Token | `hxp_` 开头 | `hxa_` 开头 | +| 身份 | 你本人,权限与网页端一致 | Token 创建人的管理员身份 | +| 视角 | 我参与的 | 全量,不受角色过滤 | -### 缓存读写伪代码 +--- -**读缓存(每次使用 MCP 数据前执行此逻辑):** +## 状态是可配置的两层模型(v2 起) + +**不要硬编码 `"in_progress"`、`"done"` 这类字面量。** 状态由后台配置,分两层: + +- `category`:四类固定语义 `not_started` / `in_progress` / `completed` / `cancelled`, + 用于**判断**(这条算不算完成) +- `status_option_id`:具体状态项的 UUID,用于**写入** + +改任何实体状态前,先 `dict_get` 取该 `entity_type`(module/task/issue/meeting,**必须选对**) +下的选项,再传对应的 `status_option_id`。传旧值或错的 entity_type 会被直接拒绝。 + +--- + +## 本地缓存 + +缓存根目录 `~/.claude/huanxi-cache/`,**按通道隔离**: ``` -function read_cache(file, ttl_hours): - 1. Read ~/.claude/huanxi-cache/{file}.json - 2. 若文件不存在 → cache_miss - 3. 读取 cached_at 字段,计算 age = now - cached_at(小时) - 4. 若 ttl_hours = Infinity 或 age < ttl_hours → 返回 data 字段(cache_hit) - 5. 否则 → cache_miss +~/.claude/huanxi-cache/ +├── personal/ hxp_ 视角:me.json / my-modules.json / users.json +├── admin/ hxa_ 视角:org-tree.json / all-modules.json +└── dict/ 与身份无关的配置字典(两个通道共享) +``` -function cache_miss_handler(tool_name, params): - 1. 调用 MCP 工具:mcp__huanxi__{tool_name}(params) - 2. Write ~/.claude/huanxi-cache/{file}.json: - { "cached_at": "<当前 ISO8601 时间>", "data": } +隔离是必须的:管理端看到的是全量模块,个人端只有我参与的——混用会让你把不该展示的 +东西展示给用户。 + +### 分层 TTL + +| 类别 | 文件 | 策略 | +|---|---|---| +| 身份 | `personal/me.json` | 永久(身份不变) | +| **配置字典** | `dict/*.json` | **版本戳比对** + 24h 兜底 | +| 组织 | `users.json` / `org-tree.json` / `my-modules.json` | 24h | +| 日历 | `dict/workdays.json` | 按日期 key 永久(查过的不再查) | +| **业务数据** | 任务 / 日报 / 会议 / 议题 / 公告 | **一律不缓存** | + +最后一行是硬规则。业务数据随时在变,缓存它只会让你把过期状态当成现状汇报给用户。 + +### 字典为什么要版本戳而不是只靠 TTL + +其余缓存过期了最多是显示旧数据;字典不一样——状态选项可能被后台停用,你拿 24 小时前 +的 ID 去改状态会**直接报错**。失败方向从「看到旧数据」变成「操作失败」,值得比对一次。 + +``` +用字典前: + 1. 调 dict_version() ← 极轻 + 2. 与 dict/versions.json 比对 + 3. 一致 → 用缓存;不一致 → 调 dict_get() 重取该类并更新缓存 +``` + +`dict_get` 的返回里**自带 versions 字段**,直接连内容一起存下来即可——不要分两次调用, +那中间字典若被改动,你会把新内容配上旧版本戳缓存起来,之后再也不会刷新。 + +### 读缓存伪代码 + +``` +read(file, ttl): + 1. 读 ~/.claude/huanxi-cache/{file} + 2. 文件不存在 → miss + 3. age = now - cached_at + 4. ttl 为永久 或 age < ttl → 返回 data + 5. 否则 → miss + +on_miss(tool, params): + 1. 调用工具 + 2. 写入 { "cached_at": , "data": <返回值> } 3. 返回 data ``` -**workdays.json 特殊逻辑(按 key 缓存):** - -``` -function get_workday(date): - 1. Read workdays.json → 得到 { "2026-04-14": true, ... } - 2. 若 date 已在 dict 中 → 直接返回 - 3. 否则 → 调用 mcp__huanxi__system_get_workday(date) - 4. 将 {date: result} 追加写入 workdays.json -``` - -### TTL 快速参考 - -``` -me.json → Infinity(永久,身份不变) -modules.json → 24h -users.json → 24h -workdays.json → Infinity(按 date key,已查过的不再查) -``` - ---- - -## MCP 工具索引 - -寰汐 MCP 工具前缀:`mcp__huanxi__` - -### 用户与认证 -| 工具 | 用途 | 缓存 | -|------|------|------| -| `user_get_me()` | 获取当前 Token 代表的用户 | → `me.json`(永久)| - -### 模块与组织 -| 工具 | 用途 | 缓存 | -|------|------|------| -| `module_list(my_role?)` | 列出我参与的模块 | → `modules.json`(24h)| -| `module_get(module_id)` | 获取模块详情(含成员) | 不缓存 | -| `user_list(name?, department_id?, is_active?, limit?)` | 搜索组织用户 | → `users.json`(24h)| -| `org_get_tree()` | 获取组织架构树 | 不缓存 | -| `people_get_board(user_id?, module_id?, date?)` | 人员任务看板(不传则全员;传 user_id 只看该人) | 不缓存 | - -### 任务管理 -| 工具 | 用途 | 缓存 | -|------|------|------| -| `task_list_mine(status?, module_id?, priority?, snapshot_active?)` | 我认领的任务 | 不缓存 | -| `task_list_by_module(module_id)` | 模块下所有任务 | 不缓存 | -| `task_get(task_id)` | 任务详情 | 不缓存 | -| `task_create(...)` | 创建任务 | — | -| `task_update(task_id, ...)` | 更新任务 | — | -| `task_set_assignees(task_id, assignee_ids)` | 设置执行人(幂等) | — | - -### 员工日报 -| 工具 | 用途 | -|------|------| -| `report_get_today(date?)` | 获取指定日期日报 | -| `report_get_tasks_to_report()` | 获取今日待汇报任务 | -| `report_save_draft(items=[...])` | 批量保存草稿(upsert)| -| `report_submit_item(item_id, date?)` | 提交单条日报条目 | -| `report_withdraw_item(item_id, date?)` | 撤回单条已提交日报条目 | - -### 负责人日报 -| 工具 | 用途 | -|------|------| -| `leader_report_get_subordinates(date, module_id)` | 查看下属汇报情况 | -| `leader_report_save(report_date, content, module_id?)` | 保存负责人日报草稿 | -| `leader_report_submit(report_date, module_id)` | 提交负责人日报 | -| `leader_report_withdraw(report_date, module_id)` | 撤回负责人日报 | -| `leader_report_get_batch(date, module_ids)` | 批量获取多模块日报 | - -### 周报 -| 工具 | 用途 | -|------|------| -| `weekly_report_get(year, week)` | 获取指定 ISO 周的周报 | -| `weekly_report_get_batch(year, week, module_ids)` | 批量获取多模块周报 | -| `weekly_report_save(module_id, year, week_number, content?, next_week_plan?)` | 保存周报草稿 | -| `weekly_report_submit(module_id, year?, week_number?)` | 提交周报(不传 year/week_number 默认提交当周) | -| `weekly_report_withdraw(module_id, year?, week_number?)` | 撤回周报 | - -### 系统与 LLM -| 工具 | 用途 | 缓存 | -|------|------|------| -| `system_get_workday(date?)` | 查询是否工作日 | → `workdays.json`(永久)| -| `llm_polish_report(content)` | AI 润色日报内容 | — | -| `llm_generate_leader_summary(module_id, date)` | AI 生成负责人日报草稿 | — | +`workdays.json` 特殊:按日期 key 存 `{ "2026-08-06": true }`,已查过的日期不再查。 --- ## 全局约定 -1. **提交前必须确认**:`report_submit_item`、`leader_report_submit`、`weekly_report_submit` 执行前必须向用户展示内容并等待明确确认,禁止自动提交。 -2. **非工作日不强制**:检测到非工作日时,告知用户并询问是否仍要填写,不得直接中断流程。 -3. **缓存优先**:执行任何需要 module_id / user_id 的操作前,先读缓存;缓存未命中或过期才调 MCP。 -4. **ISO 周数**:周报的 `year` 字段存 ISO year(`date.isocalendar()[0]`),不是日历年。12 月底 / 1 月初注意跨年。 -5. **task_set_assignees 幂等**:设置执行人使用此工具(幂等),不要用 task_update 的 assignee 字段追加。 -6. **工具调用以 MCP 定义为准**:调用任何 `mcp__huanxi__*` 工具前,**必须以该工具在 MCP Server 中实际注册的参数名和类型为准**,本文档及各 skill 中的调用示例仅供工作流引导,不得作为参数的唯一依据。如果示例与工具实际定义有出入,以工具定义优先。 +1. **提交类操作必须先确认**:`report_submit` / `leader_report_submit` / `issue_close` 等, + 执行前把最终内容展示给用户、等到明确确认(「确认」「提交」「好的」)再调。 + 不要因为用户说了「帮我写日报」就把提交也一并做了——写和交是两个决定。 +2. **删除与指派同样需要确认**:`task_set_assignees` 是**替换**语义(传空即清空), + 不是追加;覆盖别人的名单前先说清楚会变成什么样。 +3. **非工作日不强行中断**:`workday_check` 显示非工作日时告知用户并询问是否仍要填写, + 不要直接拒绝——补填、调休上班都是真实场景。 +4. **先解析 ID 再操作**:需要 module_id / user_id 的操作,先查缓存,未命中再调 + `module_query` / `user_search`。不要凭名字猜 ID。 +5. **批量优先**:工具的过滤维度基本都收列表,一次查多个比循环调用快得多,也更省上下文。 diff --git a/plugins/huanxi/skills/huanxi-task/SKILL.md b/plugins/huanxi/skills/huanxi-task/SKILL.md index 513a2d1..22e84fb 100644 --- a/plugins/huanxi/skills/huanxi-task/SKILL.md +++ b/plugins/huanxi/skills/huanxi-task/SKILL.md @@ -1,102 +1,90 @@ --- name: huanxi-task -description: "寰汐任务管理:创建任务(+create)、更新任务状态/进度(+update)、查看任务看板(+board)、设置执行人(+assign)。当用户说"创建任务"、"新建任务"、"更新任务"、"看任务板"、"任务分配"时触发。" +description: "寰汐任务管理:查任务、建任务、改状态与进度、分配执行人、认领。当用户说「我有什么任务」「建个任务」「把这个标成完成」「派给谁」时使用。" --- # 寰汐任务管理 -**前置条件:先 Read `../huanxi-shared/SKILL.md`(缓存规则 + TTL 策略)** - -> ⚠️ **工具调用规范**:执行任何 `mcp__huanxi__*` 调用前,以工具实际注册的参数名和类型为准,本文档示例仅供工作流引导(见 shared 全局约定第 6 条)。 +**前置:先读 `huanxi-shared`(尤其「状态是可配置的两层模型」一节)。** --- -## Shortcuts +## ID 传递链 -| 指令 | 说明 | -|------|------| -| [`+create`](references/task-create.md) | 创建新任务(引导式填写) | -| `+update` | 更新任务状态/进度/截止日 | -| [`+board`](references/task-kanban.md) | 查看我的任务看板 | -| `+assign` | 设置/变更任务执行人 | -| `+get` | 查看单个任务详情 | +任务操作几乎都是这条链,**中间结果要展示给用户**,不要一路闷头做到底: ---- - -## +create:创建任务 - -详见 [references/task-create.md](references/task-create.md) - -**快速概览:** ``` -1. 确定所属模块(从 modules.json 缓存解析名字 → ID) -2. 收集任务信息(标题、描述、截止日、优先级) -3. mcp__huanxi__task_create(module_id, title, ...) -4. [可选] 设置执行人 → mcp__huanxi__task_set_assignees(task_id, [user_id]) +module_query() → module_id + ↓ +task_query(module_ids=[...]) → task_id[] ← 展示给用户看 + ↓ ⏸ 用户指明改哪些 +task_update(updates=[{id, ...}]) ``` --- -## +update:更新任务 - -> ⚠️ 参数细节以 MCP `task_update` 的 docstring 为准,本节仅做工作流引导。 +## 查 ``` -Step 1: 确认任务 ID - → 若用户已提供 task_id:直接使用 - → 若用户描述了任务名称: - a. mcp__huanxi__task_list_mine() 获取我的任务列表 - b. 按标题关键词模糊匹配,列出候选任务供用户选择 - c. 仍未找到(可能属于他人或已归档)→ 告知用户提供精确 task_id - -Step 2: 展示当前任务状态,引导用户填写要修改的字段 - -Step 3: mcp__huanxi__task_update(task_id, { - title? : "新标题", - description? : "新描述", - progress? : 80, ← 0-100 整数 - progress_before? : 60, ← 修改 progress 时必传当前值(乐观锁,防并发覆盖) - status? : "not_started" | "in_progress" | "done" | "cancelled" | "on_hold", - end_date? : "YYYY-MM-DD", ← 字段名是 end_date,不是 due_date - priority? : "low" | "medium" | "high" | "critical" - }) - -Step 4: 告知更新结果 +task_query(scope="mine") 我负责执行的(默认) +task_query(scope="all", module_ids=[...]) 某几个模块的全部任务 +task_query(q="关键词") 标题模糊搜 +task_get(task_ids=[...]) 详情:描述 + 层级路径 ``` -⚠️ **历史踩坑**: -- 字段名 `due_date` 错误,后端为 `end_date` -- 状态值 `todo` 错误,后端为 `not_started` -- priority 缺 `critical`,没有 `urgent` -- 改 progress 不传 `progress_before` 会 409 冲突 +过滤维度都收列表,一次查多个模块比循环调用好。 --- -## +assign:设置执行人 +## 改状态与进度 + +**先 `dict_get` 取 task 类型的状态选项**,拿到 `status_option_id` 再传: ``` -Step 1: 确认任务 ID -Step 2: 解析执行人名字 → user_id(查 users.json 缓存) - → 详见 huanxi-org references/resolve-ids.md -Step 3: mcp__huanxi__task_set_assignees(task_id, assignee_ids=[user_id, ...]) - (此操作幂等:传完整列表,不是追加) -Step 4: 告知设置结果 +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 的那些,进度是子任务 +聚合出来的,硬设会被拒绝。要推进它,去改它的子任务。 + --- -## +get:查看任务详情 +## 建任务 ``` -Step 1: mcp__huanxi__task_get(task_id) -Step 2: 展示完整任务信息(标题/描述/状态/进度/执行人/截止日/评论数) +task_create(module_id=..., tasks=[{title, description?, priority?, end_date?, + parent_id?, milestone_id?, assignee_ids?}]) ``` +- 建子任务传 `parent_id`,**最多三级**(任务 / 子任务 / 孙任务) +- 需要是该模块的成员或负责人 +- `priority` 的取值以工具说明为准——**不要凭直觉写**,这个字段有 DB 级约束,写错直接报错 + --- -## 关键约束 +## 执行人 -- **任务创建后不自动认领**:`task_create` 不会自动设置执行人,需要单独调用 `task_set_assignees` -- **执行人是完整列表**:`task_set_assignees` 传入的是完整执行人 ID 列表(幂等替换),不是追加 -- **progress 是整数**:0-100 的整数,不是小数或百分比字符串 -- **模块创建权限**:用户必须是模块成员(任意角色)才能在该模块创建任务,否则返回 403 +``` +task_set_assignees(task_id=..., user_ids=[...]) 整组覆盖,传空即清空 +task_claim(task_ids=[...], claim=true/false) 认领 / 取消认领(只动自己) +``` + +**`task_set_assignees` 是替换不是追加。** 想加一个人,要先 `task_get` 拿到现有名单, +把新人拼进去再整组传回——直接传一个人会把其余执行人全部踢掉。这是最容易出错的地方, +覆盖前把「改完会变成谁」说给用户听。 + +被指派的人若不是模块成员,会自动加入该模块;新增执行人会收到飞书通知。 + +--- + +## 不在工具里的操作 + +删除任务、跨模块转移任务**不在 MCP**,请引导用户去网页端——这两个动作作用于整棵子树 +且不可逆,需要看清楚影响范围再点。 diff --git a/plugins/huanxi/skills/huanxi-task/references/task-create.md b/plugins/huanxi/skills/huanxi-task/references/task-create.md deleted file mode 100644 index f17534c..0000000 --- a/plugins/huanxi/skills/huanxi-task/references/task-create.md +++ /dev/null @@ -1,86 +0,0 @@ -# 创建任务(+create) - -> ⚠️ 参数细节以 MCP `task_create` 的 docstring 为准,本文档仅做工作流引导。 - -## 必填信息收集 - -在调用 `task_create` 前,引导用户提供: - -| 字段 | 必填 | 说明 | -|------|------|------| -| `module_id` | ✅ | 所属模块 UUID(从缓存解析名字 → ID) | -| `title` | ✅ | 任务标题(简洁明了)| -| `description` | 可选 | 任务详情、背景、验收标准(Markdown) | -| `end_date` | 可选 | 截止日期(YYYY-MM-DD 格式,**字段名是 end_date,不是 due_date**) | -| `priority` | 可选 | `low` / `medium` / `high` / `critical`,默认 `medium`(**没有 urgent**) | -| `status` | 可选 | `not_started`(默认)/ `in_progress` | -| `parent_task_id` | 可选 | 父任务 UUID,传此字段即为子任务 | -| `assignee_ids` | 可选 | 执行人 user_id 列表,**可在创建时一并传入**(无需再单独调 `task_set_assignees`) | - ---- - -## 执行步骤 - -``` -Step 1: 解析模块名 → module_id - → Read ~/.claude/huanxi-cache/modules.json - → 模糊匹配模块名(详见 huanxi-org resolve-ids.md) - -Step 2: [若用户提到执行人] 解析人名 → user_id(user 对象的 id 字段) - → Read ~/.claude/huanxi-cache/users.json - → 未命中 → mcp__huanxi__user_list(name=<人名>) → 追加写缓存 - -Step 3: 创建任务(推荐一次性把执行人也带上) - → mcp__huanxi__task_create( - module_id = "<模块ID>", - title = "任务标题", - description = "...", ← 可选 - end_date = "YYYY-MM-DD", ← 可选;字段名 end_date - priority = "medium", ← 可选;low/medium/high/critical - status = "not_started", ← 可选;默认 not_started - assignee_ids = [""] ← 可选;若 Step 2 有解析到,建议一并传入 - ) - → 返回:task_id - -Step 4: [仅当 Step 3 未传 assignee_ids 时] 单独设置执行人 - → mcp__huanxi__task_set_assignees( - task_id = "<刚创建的 task_id>", - assignee_ids = [""] - ) - -Step 5: 告知创建结果 - → 展示:任务标题、所属模块、执行人、截止日、task_id - → 询问:"是否需要进一步调整?" -``` - ---- - -## 权限说明 - -用户必须是所属模块的成员(任意角色)才能创建任务。若返回 403: -- 可能未加入该模块 -- 建议联系模块负责人添加成员,或请管理员使用 Admin MCP 操作 - ---- - -## 子任务支持 - -若需创建子任务: -``` -mcp__huanxi__task_create( - module_id = "<模块ID>", - title = "子任务标题", - parent_task_id = "<父任务ID>" ← 传此字段即为子任务 -) -``` - ---- - -## 字段名速查(避免漂移) - -| 概念 | 正确字段名 | 错误写法 | -|------|----------|---------| -| 截止日期 | `end_date` | ~~due_date~~ | -| 紧急优先级 | `critical` | ~~urgent~~ | -| 未开始状态 | `not_started` | ~~todo~~ | -| 父任务 ID | `parent_task_id` | ~~parent_id~~(后端 body 内是 parent_id,但 MCP 参数是 parent_task_id) | diff --git a/plugins/huanxi/skills/huanxi-task/references/task-kanban.md b/plugins/huanxi/skills/huanxi-task/references/task-kanban.md deleted file mode 100644 index a75c085..0000000 --- a/plugins/huanxi/skills/huanxi-task/references/task-kanban.md +++ /dev/null @@ -1,56 +0,0 @@ -# 任务看板(+board) - -> ⚠️ 参数细节以 MCP `task_list_mine` / `task_list_by_module` / `people_get_board` 的 docstring 为准,本文档仅做工作流引导。 - -## 查看我的任务 - -``` -Step 1: mcp__huanxi__task_list_mine() - → 返回我认领的所有任务(跨模块) - → 每条含:id / title / status / priority / progress / module_name / end_date / assignees - -Step 2: 按状态分组展示(状态值与后端枚举一致): - ──────────────────────────────────── - 📋 未开始(not_started) - · [前端开发] 完成登录页面 UI 优化 ← end_date: 04-15 - · [后端API] 接口文档更新 ← 无截止日 - - 🔄 进行中(in_progress) - · [前端开发] 接口联调 60% ← end_date: 04-20 - - ✅ 已完成(done) - · [前端开发] 初始化项目结构 100% - - ⏸️ 已挂起(on_hold) / ❌ 已取消(cancelled)— 默认折叠 - ──────────────────────────────────── -``` - -## 查看模块看板 - -``` -Step 1: 确认模块(从 modules.json 缓存解析) -Step 2: mcp__huanxi__task_list_by_module(module_id) - → 返回该模块所有任务(含其他成员的任务) -Step 3: 按状态分组展示,标注每个任务的执行人 -``` - -## 人员任务看板(管理视角) - -``` -Step 1: mcp__huanxi__people_get_board() - → 返回团队所有成员的任务分布(数量统计) -Step 2: 展示每人的任务负载情况(适合分配任务前参考) -``` - ---- - -## 快速过滤 - -用户常见需求: - -| 场景 | 做法 | -|------|------| -| "我今天要做什么" | task_list_mine() → 过滤 status=in_progress + 截止日临近 | -| "某个模块的任务" | task_list_by_module(module_id) | -| "即将到期的任务" | task_list_mine() → 筛选 end_date ≤ 今日+3天 | -| "团队任务分布" | people_get_board() | diff --git a/plugins/huanxi/skills/huanxi-weekly/SKILL.md b/plugins/huanxi/skills/huanxi-weekly/SKILL.md deleted file mode 100644 index d6c62d7..0000000 --- a/plugins/huanxi/skills/huanxi-weekly/SKILL.md +++ /dev/null @@ -1,133 +0,0 @@ ---- -name: huanxi-weekly -description: "寰汐周报工作流(仅限模块负责人):查看本周周报状态(+check)、基于本周负责人日报 AI 汇总草稿(+draft)、提交周报(+submit)、撤回(+withdraw)。当用户说"写周报"、"提交周报"、"本周总结"、"周报进度"时触发。" ---- - -# 寰汐周报(仅限模块负责人) - -**前置条件:先 Read `../huanxi-shared/SKILL.md`(缓存规则 + TTL 策略)** - -> ⚠️ **工具调用规范**:执行任何 `mcp__huanxi__*` 调用前,以工具实际注册的参数名和类型为准,本文档示例仅供工作流引导(见 shared 全局约定第 6 条)。 - ---- - -## 权限说明 - -**周报只有模块负责人(`my_role == 'leader'`)才需要提交。** - -若用户不是任何模块的负责人: -- 告知:"您目前不是任何模块的负责人,无需提交周报。" -- 建议:若有疑问,可联系管理员确认模块角色。 - ---- - -## ISO 周数规范(重要) - -寰汐周报使用 **ISO 8601 标准**: -- `year` 字段存 **ISO year**(不是日历年) -- 12月底/1月初可能跨年:如 2025-12-29 的 ISO year = 2026(第1周) -- Python 获取:`date.isocalendar()` → `(iso_year, week, weekday)` - -**当前日期 → ISO 周号计算示例:** -- 2026-04-13(周一)→ year=2026, week=16 - ---- - -## 标准工作流 - -``` -Step 0: 确认负责人身份和模块 - → Read ~/.claude/huanxi-cache/modules.json(24h 缓存) - → 若过期:mcp__huanxi__module_list() → 更新缓存 - → 筛选 my_role == 'leader' 的模块列表 - → 若列表为空:告知用户无需提交周报,流程终止 - → 若有多个 leader 模块:询问"要提交哪些模块的周报?" - -Step 1: 确定当前 ISO 周号 - → 根据今日日期计算 (iso_year, iso_week) - → 告知:第 iso_week 周(周一 ~ 周日 日期范围) - -Step 2: 批量拉取周报草稿 - → mcp__huanxi__weekly_report_get_batch( - year=iso_year, - week=iso_week, - module_ids=[] - ) - → 返回:各模块的现有草稿状态 - -Step 3: 逐日拉取本周负责人日报 - → 计算本周日期范围(周一到今日,YYYY-MM-DD 格式列表) - → 对每个日期逐一调用: - mcp__huanxi__leader_report_get_batch( - date=<单个日期>, - module_ids=[] - ) - → 汇总所有日期的返回数据 - → 展示:本周每日负责人日报记录(含各日进展摘要 + 下属提交情况) - -Step 4: 询问是否 AI 汇总 - → 展示本周负责人日报数据后,询问: - "是否需要 AI 根据本周负责人日报自动生成周报草稿?" - → 用户同意 → AI 基于 leader_report_batch 起草: - · content:本周模块整体进展总结 - · next_week_plan:下周模块工作计划 - → 展示草稿,供用户审阅和修改 - → 用户拒绝 → 引导用户手动填写本周总结和下周计划 - -Step 5: 逐模块保存草稿 - → 详见 references/weekly-draft.md - → mcp__huanxi__weekly_report_save(module_id, year, week_number, content, next_week_plan) - -Step 6: 确认并提交 - → 展示所有模块最终内容,等待用户明确确认("确认"/"提交"/"好的"等) - → ⚠️ 未收到确认前,禁止调用 weekly_report_submit - → mcp__huanxi__weekly_report_submit(module_id) -``` - ---- - -## Shortcuts - -| 指令 | 说明 | -|------|------| -| `+check` | 查看本周周报状态(草稿/已提交) | -| [`+draft`](references/weekly-draft.md) | 基于本周负责人日报 AI 生成草稿 | -| `+submit` | 提交周报(必须先确认) | -| `+withdraw` | 撤回已提交周报 | - ---- - -## +check:查看本周状态 - -``` -1. 确认 leader 模块列表(同 Step 0) -2. 若无 leader 模块:告知无需提交周报 -3. mcp__huanxi__weekly_report_get_batch(year, week, module_ids) -4. 展示各模块周报状态: - - submitted:已提交,展示摘要 - - draft:草稿中,展示已填内容 - - empty:未填,建议运行 +draft -``` - ---- - -## +withdraw:撤回周报 - -``` -1. 确认 leader 模块(从 modules.json 缓存中取) -2. 若有多个 leader 模块,询问要撤回哪个模块的周报 -3. 告知撤回影响(状态变为草稿,可重新编辑),等待用户确认 -4. mcp__huanxi__weekly_report_withdraw(module_id) - (默认撤回当周;如需撤回历史周:传 year + week_number) -5. 告知成功,可重新编辑后再次提交 -``` - ---- - -## 关键约束 - -- **仅负责人可提交**:首先检查 `my_role == 'leader'`,非负责人直接告知无需操作 -- **禁止自动提交**:`weekly_report_submit(module_id)` 前必须展示全部内容并等待用户确认 -- **year 存 ISO year**:高频出错点,必须使用 `isocalendar()[0]`,不要用 `date.year` -- 每个模块独立提交,有多个模块时逐一处理 -- 撤回后可重新编辑,不影响当前状态 diff --git a/plugins/huanxi/skills/huanxi-weekly/references/weekly-draft.md b/plugins/huanxi/skills/huanxi-weekly/references/weekly-draft.md deleted file mode 100644 index bed0433..0000000 --- a/plugins/huanxi/skills/huanxi-weekly/references/weekly-draft.md +++ /dev/null @@ -1,99 +0,0 @@ -# 周报草稿(+draft,仅限模块负责人) - -> ⚠️ 参数细节以 MCP `weekly_report_save` 的 docstring 为准,本文档仅做工作流引导。 - -## 数据来源 - -周报草稿基于**本周负责人日报汇总**(`leader_report_get_batch` 返回值),而非员工个人日报。 - -| 数据 | 来源 | 说明 | -|------|------|------| -| 本周每日负责人日报 | `leader_report_get_batch(date列表, module_ids)` | 含各日的模块进展 + 下属提交情况摘要 | -| 现有周报草稿 | `weekly_report_get_batch(year, week, module_ids)` | 已填写的草稿(若有) | - ---- - -## 草稿生成步骤 - -``` -Step 1: 解析本周负责人日报数据 - → 按日期排列,提取每日: - · 模块整体进展 - · 团队成员提交情况 - · 遇到的问题与风险 - -Step 2: AI 基于负责人日报起草 content(本周总结): - - 提炼本周模块核心进展(任务推进 + 里程碑) - - 汇总团队整体情况 - - 列出本周识别的问题与应对 - -Step 3: AI 起草 next_week_plan(下周计划): - - 基于本周未完成项和下周目标 - - 结合用户补充的计划 - -Step 4: 展示草稿给用户审阅修改 - -Step 5: 用户确认后逐模块保存: - mcp__huanxi__weekly_report_save( - module_id = "<模块ID>", - year = , ← 注意:ISO year,不是日历年 - week_number = , ← 后端字段名是 week_number,不是 week - content = "<本周总结>", - next_week_plan = "<下周计划>" - ) -``` - ---- - -## 内容格式建议(负责人视角) - -**content(本周总结):** -```markdown -## 本周模块进展 - -- **[任务A]** 完成 XX 功能开发,进度推进至 80%(负责人:张三) -- **[任务B]** 完成接口联调,已提测(负责人:李四) - -## 团队提交情况 - -本周全员提交日报,无缺报。 - -## 问题与风险 - -- [周三] 第三方接口超时问题,已升级厂商处理,预计周一恢复 - -## 本周总体评估 - -整体按计划推进,无阻塞性风险。 -``` - -**next_week_plan(下周计划):** -```markdown -- [任务A] 目标完成剩余 20% 并提测 -- [任务B] 协助测试团队完成验收 -- 启动 [新需求] 的技术调研 -``` - ---- - -## 已有草稿处理 - -若 `weekly_report_get_batch()` 中该模块已有草稿(非 empty): -- 展示现有草稿内容 -- 询问:"是在此基础上修改,还是基于本周负责人日报重新生成?" -- 基于用户选择执行对应操作 - ---- - -## 多模块处理 - -``` -for module in leader_modules: - 1. 提取该模块的 leader_report_batch(本周各日记录) - 2. AI 生成草稿(content + next_week_plan) - 3. 展示给用户确认/修改 - 4. weekly_report_save(module_id=module.id, year, week_number, ...) - 5. 告知:模块 "{module.name}" 草稿已保存 ✅ - -所有模块草稿完成后:统一展示,询问是否提交 -```