weaver-work-cli 0.1.33 → 0.1.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/dist/chunks/{archive-FVFY6GZN.js → archive-PDV724YK.js} +5 -4
  2. package/dist/chunks/{archive-oa-NW3OD4UV.js → archive-oa-4XE4MNXQ.js} +4 -3
  3. package/dist/chunks/{asset-7QJKMIDV.js → asset-PDL2QE2N.js} +8 -7
  4. package/dist/chunks/{attachment-content-OSAVA6K3.js → attachment-content-MDDGOE5E.js} +3 -3
  5. package/dist/chunks/{blog-I7SDPNW4.js → blog-UYR3EUXW.js} +5 -4
  6. package/dist/chunks/{caizhilian-O37ZIQNY.js → caizhilian-LG2X5NMF.js} +5 -4
  7. package/dist/chunks/{calendar-7KXE4ED3.js → calendar-FG4BAZHE.js} +4 -3
  8. package/dist/chunks/{chunk-Q6LWB5HX.js → chunk-6FTTSA45.js} +4 -3
  9. package/dist/chunks/{chunk-MQ2I5AA3.js → chunk-6LTFIFLM.js} +3 -2
  10. package/dist/chunks/{chunk-WRRJ4GG2.js → chunk-CORFRD7Q.js} +4 -3
  11. package/dist/chunks/{chunk-WY74UBJ6.js → chunk-DMV2TOMH.js} +2194 -240
  12. package/dist/chunks/{chunk-MEEFGWTM.js → chunk-ELYDWBZJ.js} +135 -10
  13. package/dist/chunks/{chunk-EEWPQE3O.js → chunk-FUWVHMVV.js} +7 -6
  14. package/dist/chunks/{chunk-HEL5XTYI.js → chunk-GGJFMNJM.js} +26 -4
  15. package/dist/chunks/{chunk-KAS45KNR.js → chunk-IZUDA353.js} +1 -1
  16. package/dist/chunks/{chunk-2FLWXFVS.js → chunk-J7USS3ED.js} +4 -4
  17. package/dist/chunks/{chunk-IHUYP6LO.js → chunk-JSMFPO43.js} +1 -1
  18. package/dist/chunks/{chunk-RBGOMK4Y.js → chunk-KKRL3REV.js} +5 -4
  19. package/dist/chunks/{chunk-OCU4RLHC.js → chunk-NI6GIPIM.js} +195 -36
  20. package/dist/chunks/{chunk-PRHJGPMA.js → chunk-NR6RKXPA.js} +2 -2
  21. package/dist/chunks/{chunk-D223PTXU.js → chunk-OJQUJZQF.js} +33 -7
  22. package/dist/chunks/{chunk-ILMBNVSG.js → chunk-UJJD4QWF.js} +4 -3
  23. package/dist/chunks/{chunk-6ATGWRZM.js → chunk-UZZBA6PV.js} +177 -14
  24. package/dist/chunks/{chunk-GFPXQIY2.js → chunk-VRYHGG6O.js} +2 -2
  25. package/dist/chunks/{chunk-NHA62QD7.js → chunk-XJY7G4DD.js} +3 -3
  26. package/dist/chunks/{chunk-VBCFFFGT.js → chunk-Z32KWY6G.js} +4 -1
  27. package/dist/chunks/{conflict-SFNEVJY5.js → conflict-BQZEQ4SP.js} +2 -2
  28. package/dist/chunks/contract-XIRAFTEV.js +9111 -0
  29. package/dist/chunks/{cowork-CKWYHXYB.js → cowork-BLG62BL2.js} +46 -26
  30. package/dist/chunks/{ebuilder-form-KOLJRVZD.js → ebuilder-form-NUKG5QW4.js} +3 -3
  31. package/dist/chunks/{ehr-WFOC3B4D.js → ehr-2STW5ILH.js} +174 -10
  32. package/dist/chunks/{esb-LJZTN663.js → esb-UUDQUNKY.js} +4 -4
  33. package/dist/chunks/{fna-F7QRIIZC.js → fna-6RCY4NU5.js} +15 -9
  34. package/dist/chunks/{host-VQ6JJXGQ.js → host-7RXEDMAH.js} +3 -3
  35. package/dist/chunks/{host-KXPTEWFS.js → host-EJZFROU3.js} +3 -3
  36. package/dist/chunks/{host-BCGUVEWX.js → host-FWDOSRH5.js} +3 -3
  37. package/dist/chunks/{host-DGE2TZD4.js → host-RHM3NPXV.js} +3 -3
  38. package/dist/chunks/{host-BQBRHVR3.js → host-UFF33TWJ.js} +3 -3
  39. package/dist/chunks/{hrm-NI6XAKW5.js → hrm-PKJ6ELSH.js} +3 -3
  40. package/dist/chunks/{im-7TRTF3KT.js → im-YJAXS7CO.js} +3 -3
  41. package/dist/chunks/{invoice-AOXWJKYT.js → invoice-HWVSXGX6.js} +3 -3
  42. package/dist/chunks/{jiuchuanhui-7NQWEZAW.js → jiuchuanhui-L7VKILZB.js} +4 -3
  43. package/dist/chunks/{lazy-dispatch-RNS4EE4S.js → lazy-dispatch-NMYEIHRH.js} +4 -4
  44. package/dist/chunks/{mail-VDHJAB4O.js → mail-B42RRU7G.js} +46 -24
  45. package/dist/chunks/{meeting-GA7XCNNP.js → meeting-CFYVBJSS.js} +77 -12
  46. package/dist/chunks/{okr-TQIRERPQ.js → okr-GCLF6V7W.js} +4 -3
  47. package/dist/chunks/{plan-4RY4LN2P.js → plan-ZVL7GBRI.js} +4 -3
  48. package/dist/chunks/{project-D6XT2OC5.js → project-4YWAAE2K.js} +4 -3
  49. package/dist/chunks/{registry-QKMI43Q6.js → registry-EP4VTHZS.js} +8 -8
  50. package/dist/chunks/{registry-JHRIDQ3A.js → registry-FRJ6H7BT.js} +4 -4
  51. package/dist/chunks/{registry-VOGKFFTR.js → registry-SG2PGVCF.js} +2 -2
  52. package/dist/chunks/{room-recommend-D4EUOOWY.js → room-recommend-R3JVUUAC.js} +4 -4
  53. package/dist/chunks/{schedule-XPFBHPCV.js → schedule-NIJBTYDO.js} +4 -4
  54. package/dist/chunks/{workflow-HLBZRWIY.js → workflow-BB24DFBY.js} +11 -4
  55. package/dist/index.js +31 -26
  56. package/dist/internal/e10/auth-recovery.js +114 -1
  57. package/dist/internal/e10/client.js +16 -2
  58. package/dist/internal/e10/fetch-timing.js +31 -0
  59. package/dist/internal/e10/request-runtime.js +108 -7
  60. package/dist/shortcuts/archive/host.js +3 -2
  61. package/dist/shortcuts/archive-oa/host.js +2 -1
  62. package/dist/shortcuts/asset/host.js +6 -5
  63. package/dist/shortcuts/blog/host.js +3 -2
  64. package/dist/shortcuts/caizhilian/host.js +3 -2
  65. package/dist/shortcuts/calendar/host.js +2 -1
  66. package/dist/shortcuts/contract/host.js +2 -1
  67. package/dist/shortcuts/cowork/host.js +10 -1
  68. package/dist/shortcuts/cowork/operations/types.js +17 -2
  69. package/dist/shortcuts/ebuilder-form/host.js +3 -1
  70. package/dist/shortcuts/ehr/host.js +2 -1
  71. package/dist/shortcuts/ehr/operations/recruit-write.js +35 -0
  72. package/dist/shortcuts/ehr/operations/recruit.js +147 -0
  73. package/dist/shortcuts/esb/host.js +2 -1
  74. package/dist/shortcuts/fna/host.js +2 -1
  75. package/dist/shortcuts/fna/operations/expense-chart.js +19 -7
  76. package/dist/shortcuts/hrm/host.js +2 -1
  77. package/dist/shortcuts/im/host.js +3 -2
  78. package/dist/shortcuts/index.js +5 -0
  79. package/dist/shortcuts/invoice/host.js +5 -4
  80. package/dist/shortcuts/jiuchuanhui/host.js +2 -1
  81. package/dist/shortcuts/mail/host.js +10 -1
  82. package/dist/shortcuts/mail/operations/types.js +17 -2
  83. package/dist/shortcuts/meeting/host.js +3 -2
  84. package/dist/shortcuts/meeting/index.js +79 -1
  85. package/dist/shortcuts/meeting/invitation/text.js +71 -0
  86. package/dist/shortcuts/meeting/manifest.js +10 -0
  87. package/dist/shortcuts/meeting/operations/eb/catalog.js +5 -0
  88. package/dist/shortcuts/meeting/operations/eb/conflict.js +6 -1
  89. package/dist/shortcuts/meeting/operations/eb/create-flow.js +2105 -169
  90. package/dist/shortcuts/meeting/operations/eb/crm-search.js +478 -0
  91. package/dist/shortcuts/meeting/operations/eb/factory.js +161 -8
  92. package/dist/shortcuts/meeting/operations/eb/index.js +2 -0
  93. package/dist/shortcuts/meeting/operations/eb/room-recommend.js +36 -2
  94. package/dist/shortcuts/meeting/operations/eb-fallback.js +4 -0
  95. package/dist/shortcuts/meeting/operations/env.js +6 -0
  96. package/dist/shortcuts/meeting/operations/invitation.js +200 -28
  97. package/dist/shortcuts/okr/host.js +2 -1
  98. package/dist/shortcuts/plan/host.js +2 -1
  99. package/dist/shortcuts/project/host.js +2 -1
  100. package/dist/shortcuts/workflow/endpoints.js +8 -3
  101. package/dist/shortcuts/workflow/operations/form.js +341 -36
  102. package/dist/shortcuts/workflow/operations.js +23 -1
  103. package/docs/ehr.md +1 -1
  104. package/docs/fna.md +2 -1
  105. package/package.json +1 -1
  106. package/skill-template/business-info.json +18 -0
  107. package/skill-template/domains/cowork.md +14 -0
  108. package/skills/weaver-e10-cowork/SKILL.md +101 -0
  109. package/skills/weaver-e10-cowork/references/cowork-read.md +90 -0
  110. package/skills/weaver-e10-cowork/references/cowork-write.md +131 -0
  111. package/skills/weaver-e10-cowork/references/safety-boundaries.md +45 -0
  112. package/skills/weaver-e10-jucailin/SKILL.md +21 -3
  113. package/skills/weaver-e10-jucailin/references/recruit-read.md +25 -0
  114. package/skills/weaver-e10-jucailin/references/recruit-write.md +13 -0
  115. package/skills/weaver-e10-jucailin/references/salary.md +15 -11
  116. package/skills/weaver-e10-mail/SKILL.md +12 -9
  117. package/skills/weaver-e10-meeting/SKILL.md +499 -300
  118. package/skills/weaver-e10-meeting/references/meeting-eb.md +334 -0
  119. package/skills/weaver-e10-meeting/references/meeting-invitation.md +64 -6
  120. package/skills/weaver-e10-meeting.zip +0 -0
  121. package/skills/weaver-e10-okr/references/source-manifest.json +3 -3
  122. package/skills/weaver-e10-qiyecheng/SKILL.md +5 -2
  123. package/skills/weaver-e10-qiyecheng/references/catalog.md +2 -2
  124. package/skills/weaver-e10-qiyecheng/references/expense-chart.md +15 -1
  125. package/skills/weaver-e10-qiyecheng/references/source-manifest.json +22 -21
  126. package/skills/weaver-e10-yimiaoban/references/source-manifest.json +3 -3
@@ -3,9 +3,9 @@ name: weaver-e10-meeting
3
3
  display_name: 泛微E10会议管理
4
4
  display_name_en: Weaver E10 Meeting Management
5
5
  description: "泛微 E10 会议管理:查会议、预约建会(推荐会议室、查冲突与空闲时段)、改期/改地点/改参会人、取消删除、流程建会、会议室查询与推荐、生成邀请函、读取会议附件、回执签到、纪要与决议任务、参会二维码。详见 description_zh。"
6
- description_zh: "泛微 E10 会议管理,帮您处理会议日常事务:[会议]-查询今天/本周/我的会议与会议详情,预约建会(自动推荐会议室、检测参会人会议冲突与日程空闲、冲突时给出当天可选时段),改期/换地点/改参会人、取消、删除;受限环境可走审批流程建会并自动出邀请函;[会议室]-查询会议室与占用,按人数/设备/常用程度智能推荐;[邀请函]-按会议真实数据生成邀请函文档;[资料]-读取会议与议题的附件、抽取文档正文;参会回执、签到与补签、纪要、议题、决议与决议任务;[二维码]-把文本渲染成参会码/签到码图片。认证与会话由 weaver-e10-shared 提供。"
6
+ description_zh: "泛微 E10 会议管理,帮您处理会议日常事务:[会议]-查询今天/本周/我的会议与会议详情,预约建会(自动推荐会议室、检测参会人会议冲突与日程空闲、冲突时给出当天可选时段),改期/换地点/改参会人、取消、删除;受限环境可走审批流程建会,提交后必出邀请函;[会议室]-查询会议室与占用,按人数/设备/常用程度智能推荐;[邀请函]-生成邀请函文档(有会议 id 用真实数据;没有也能按会议名+时间出预置函);[资料]-读取会议与议题的附件、抽取文档正文;参会回执、签到与补签、纪要、议题、决议与决议任务;[二维码]-把文本渲染成参会码/签到码图片。认证与会话由 weaver-e10-shared 提供。"
7
7
  description_en: "Weaver E10 meeting management: [Meetings] query today/week/my meetings and details, book meetings with automatic room recommendation, attendee conflict and calendar-availability checks (plus same-day alternative slots), reschedule / change room / change attendees, cancel, delete; flow-based booking with automatic invitation when the app only allows workflow creation; [Rooms] occupancy queries and smart recommendation by capacity, equipment and personal usage; [Invitation] generate invitation docx from real meeting data; [Content] list and read meeting/topic attachments and extract document text; receipts, sign-in, minutes, topics, decisions and decision tasks; [QR] render text into attendee/sign-in QR images. Auth and session are provided by weaver-e10-shared."
8
- version: 2.21.0
8
+ version: 2.45.8
9
9
  author: 泛微网络科技股份有限公司
10
10
  agent_created: true
11
11
  requires:
@@ -25,6 +25,128 @@ cliHelp: "weaver-work-cli meeting --help"
25
25
 
26
26
  本 Skill 通过 `weaver-work-cli meeting` 命令调用真实 operation,不绕过 CLI 直接拼接口。
27
27
 
28
+ ## ⛔ 建会动手前必读(照着做,别自己发挥)
29
+
30
+ 用户说「帮我约个会 / 预约明天和 XX 开会」时,**先按这个顺序做,不要一上来就问一堆**:
31
+
32
+ 0. **不确定 CLI 有没有某个能力 → `weaver-work-cli meeting ops`(纯文本)**,查具体能力用
33
+ `meeting ops --grep 关键词`(如 `--grep suggest`、`--grep 建会`)。
34
+ ⛔ **不准用 `meeting schema --json` 判断能力存在性**:完整 308KB、stdout 只回 20KB 预览,
35
+ `operations` 数组被截到前 10 条,排在后面的能力一定看不到;⛔ 更不准凭印象回用户"当前版本没有这个能力"。
36
+
37
+ 0.5 **⛔ 时间和会议室只能由用户拍板,不许替他决定**
38
+
39
+ CLI 用两个标记区分「用户确认过的」和「你猜的」:**`timeConfirmed` / `roomConfirmed`**。
40
+
41
+ - ✅ **只有这两种情况传 `true`**:
42
+ ① 用户**原话明确**给出了("明天 9 点到 10 点"、"用 502 茶室");
43
+ ② 用户**在选项里点选**后,把 `options[].value` **整体原样回传**(value 里自带该标记,别手动拼)。
44
+ - ⛔ **其他一切情况都不传**:用户只说"明天/上午/下午"、你从上下文推断、你觉得 9 点最合适、
45
+ 你觉得这间房最合适 —— **一律不传**。
46
+ 不传时**即使你填了** `begin_datetime` / `address`,CLI 也不会当成已定,而是返回时段/房间选项让用户点选。
47
+ - ⛔ **禁止把候选写成定论**。`NEEDS_SELECTION` 返回的 `options` 是**候选**,不是已选:
48
+ 不许说「时间:09:00–10:00」「地点:测试会议室1」这种既定语气,
49
+ 要问「这几个时段您选哪个」「这几间会议室您用哪间」。
50
+ - ⛔ **禁止绕过**:不许先自己调 `room.list` / `room.recommend` 挑一间,再带 `roomConfirmed: true` 硬塞;
51
+ 也不许因为"懒得再多问一轮"就直接传标记。用户没说过,就是没说过。
52
+
53
+ 1. **确认顺序固定:名称 → 时间 → 参会人 → 地点 → 流程**。
54
+ 流程只是审批载体,**不许在四要素定下来之前就问"用哪条流程"**。CLI 也是这个顺序:
55
+ 时间没确认先回 `slot`,地点没确认再回 `room`,四个都定了才回 `flow`;
56
+ `flow` 的 `options[].value` 里已带 `begin_datetime`/`end_datetime`/`address` 和两个确认标记,
57
+ 用户点选流程后**原样回传 value** 就直接进确认,不要再问一遍时间/地点。
58
+
59
+ 2. **没给具体几点 → 直接走 ① 的 `prepare` 且不传 `begin_datetime`**,它会返回「所有参会人空闲 **且**
60
+ 该时段有可用会议室」的时段选项,直接做成选项让用户挑;禁止问"安排在几点"。
61
+ 只有"只想看空闲、还不建会"时才单独调 `meeting.eb.meeting.create.suggest`。
62
+ - 每个时段选项的 `reason` 会写明「N 人全部空闲(会议回执 + 日程已核);M 间会议室可用:…」——
63
+ 这就是"人和房都空闲"的凭据,`options[].rooms` 是该时段真实的可用房间清单。
64
+ - ⚠️ 没传参会人时无法核验人是否空闲(只有房间),`warnings` 会说明,要如实转达;
65
+ 姓名查不到员工 id 的人也会单独列出"未核验",别当成"已确认空闲"。
66
+
67
+ 3. **没指定会议室 → 不要"问",要"给选项"**。`suggest` 返回里的 `rooms`、`prepare` 返回里的
68
+ `roomOptions` / `options` 自带候选(已按人数/常用/时段占用排序,默认 3 个)。
69
+ - ⛔ **禁止开放式提问**:不要说「会议地点是必填项,需要你指定一间 / 你想用哪间会议室」——
70
+ 这是把选择题变成填空题,等于没推荐。
71
+ - ✅ **必须做成选项控件**:`options[].label` 作标题、`reason` 作副标题,第一个标「推荐」。
72
+ - ⛔ **不要自己再去调 `meeting.eb.room.list` 拼候选** —— 排好序的 `options` 就在返回值里,
73
+ 另拉列表既丢排序又会把不合适(容量不够/已被占用)的房间混进来。
74
+ - 候选为空(该时段全被占用)→ 给「改时段 / 线上会议 / 地点待定」三个选项,仍不要让用户手填房间名。
75
+ 4. **不要问「参会人数」**。CLI 自动算 = `hrm_members` 人数 **+ 召集人自己**(已在上线账号里就不重复加),
76
+ 用于会议室容量过滤;`total_member` / `memberCount` 是可选参数,**只有用户明确说了"几个人"才传**。
77
+ ⛔ 不要自己推算人数、也不要因为"看起来只有 1 个参会人"就降级给人少的房间。
78
+ 5. **不要逐个问必填项**。会议名称没给就从上下文拟一个(如"十一月开发进度沟通会")让用户一次确认;
79
+ 其余缺什么**一次列完问**,禁止"先问人 → 再问类型"这种分轮追问。
80
+ 6. **流程建会不要传 `workflowId`**。CLI 固定用当前登录环境的**固化流程候选**
81
+ - ⛔ **任何情况下都不要自己往 prepare 里填 `workflowId`**(除非用户原话点名"用 XX 流程")。
82
+ 四要素没定完之前,**回复里连流程名 / 流程 id 都不要提**(先报流程名再问时间 = 顺序反了)。
83
+ - 时间/地点闸门的返回里带 `workflowPending: true` = 流程还没定,别把它当成"流程已选好"。
84
+ (泛微生产 = 那两条建会流程),逐个探测"当前账号有没有发起权限",然后按结果分三种走:
85
+ - **只有 1 个有权限 → 直接发起**,不弹窗;`warnings` 会说明"只有 X 有权限,已直接用它"。
86
+ - **两个都有权限 → 返回 `selectionType: 'flow'`,弹窗让用户选**(每个 option 带流程名 + id + 字段清单)。
87
+ ✅ 这一步**一定在时间/地点确认之后**(四要素先定,见规则 1);`options[].value` 已带时间和地点的值,
88
+ **原样回传整个 value**(不是只回传 workflowId)就能直达确认。
89
+ ⛔ 禁止自己替用户挑(取第一个会导致字段全填不进另一条)。
90
+ - **都没有权限 → 报 `flow_not_launchable`「当前账号没有发起建会流程的权限」**:如实告知用户
91
+ 找管理员开通发起权限、或请有权限的同事发起;⛔ 不许改走直连建会绕过流程管控。
92
+ - 用户**已经说过**用哪条流程(如"还是用会议申请流程")→ 直接带那个 `workflowId` 调一次 prepare,
93
+ 跳过这一步。
94
+ - ⛔ 不要因为"想确认用哪条流程"去读 `mt_new_wf` 或检索流程 —— 不传就是正确用法。
95
+ 7. **人 / 地点 / 类型 / 客户必须走专用入参**(`address` / `hrm_members` / `caller` / `contacter` / `mt_type` / `crm_members`),
96
+ 传名称或 id 都行、CLI 会补成 `{id,name}`;塞进 `extraFields` 会被服务端打回「请按名称选择」。
97
+ 7.5 **⛔ 用户提到客户名称 → 先 `crm.search` 再 `crm_members`,不许只写进会议名称/内容**
98
+ (2026-10-31 用户投诉「没有给我把参会客户代入进去」:agent 只把「中国民航」写进 `mt_name`/`mt_desc` 就提交了,
99
+ 单子里「参会客户」是空的)。固定两步,缺一步都算错:
100
+
101
+ macOS/Linux:
102
+
103
+ ```bash
104
+ # ① 查 customerId(入参字段就是 keyword,别写 custom_name)
105
+ weaver-work-cli --json meeting run meeting.eb.crm.search --input-json '{"keyword":"中国民航"}'
106
+
107
+ # ② 把 items 原样(或 [{id,name}])传给建会
108
+ # quick/prepare 都可,必须带 name —— 只给 id 会被拒绝(crm_name_required)
109
+ ```
110
+
111
+ - ⛔ **哪怕用户只给了一个简称、一个词("中国民航""腾讯""泛微"),也必须先查这一次**。
112
+ 不许因为"名字不完整"就跳过查询、改成弹「客户怎么写」的选择框 —— 2026-10-31 用户投诉的就是这个:
113
+ 小E 弹了「填入参会客户字段 / 仅写入会议内容备注」两个选项,**"仅写入备注"正是明令禁止的做法**。
114
+ 先查,再谈确认;不存在"先问怎么填"这一步。
115
+ - `exact: false`(命中名 ≠ 关键词)→ **把命中的全名原样念出来问"是这家吗"**,用户认了就往下走。
116
+ ⛔ 不要问成选择题("填客户字段 / 只写备注"),也不要拿首个匹配当定论。
117
+ - `items: []`(真没查到)→ 才问用户:「CRM 里没搜到「X」,能给我完整的公司名吗?或这家先不关联客户?」
118
+ 用户说"不关联"才传 `crm_skip: true`。
119
+ - 用户说了客户却没查就直接建会 → **一步建会(quick)会直接报 `crm_member_required` 拒绝提交**。
120
+ - **联系人:有几位就自动带几位,⛔ 不要弹「选哪位」**(2026-10-31 用户明确要求):
121
+ ESB 已输出 `lxr`(联系人明细),`crm.search` 的 `items[].contacts` 形如
122
+ `[{"name":"利明","mobile":"11111111111","dept":"信息部"}]`(同人已去重,字段 id 换租户也能按值认)。
123
+ - **有联系人** → 什么都不用问。`crm_members` 一传,CLI 就会把**全部联系人**写成「参会客户明细」行(一人一行);
124
+ ⛔ 不许做"本次参会客户联系人选哪位"这类选择框,也不许只带其中一位。
125
+ - **没有联系人**(`contacts` 为空 / 该客户没建档)→ **这时才问**:「要不要补一下联系人姓名和手机号(方便的话再给职位)」;
126
+ - 用户说"没有"就留空,**不许编**。
127
+ - ⛔ **不要传 `crm_member_details` 来"挑人"**:CLI 默认按 CRM 全量补全,传了也只当补充字段用。
128
+ 只有用户**明确说"只写某某"**时,才传 `crm_detail_mode:"only"` + `crm_member_details`:
129
+ ```json
130
+ crm_detail_mode: "only",
131
+ crm_member_details: [{"xm":"利明","sjhm":"11111111111","zw":"信息部","xb":"男"}]
132
+ ```
133
+ 明细表列是「职位」,ESB 给的是「部门」⇒ 直接放 `zw`(比空着有用),回复里点一句"这是部门"。
134
+ - **`khdz`(客户地址)现在只回明细行 id、没有地址文本**,CLI 会回 `addressHint` 说明——
135
+ ⛔ 别当成"客户没地址",也别把行 id 当地址用。要用地址得让 ESB 输出地址文本字段。
136
+ - `prepare` 若发现「传了客户却没带明细」会 warning 提醒你走上面这步。
137
+ 8. **凡是 `status: 'NEEDS_SELECTION'`,一律用选项控件呈现,不要写成文本列表**。
138
+ CLI 返回的 `options[]` 每项都带 `key` / `label` / `value` / `reason`,`recommended` 是首选:
139
+ - **流程选择**(`selectionType: 'flow'`)→ 弹窗让用户选,选项标题用流程名。
140
+ - **会议室选择**(`selectionType: 'room'` / `'room_conflict'`)→ 同上,**默认只 3 个候选**,
141
+ 第一个标「推荐」,副标题写 `reason`(如"可容 10 人 · 有投影 · 你常用")。
142
+ - ⛔ **不要自己另调 `room.list` / `type.list` 拼一份更长的候选** —— 那份没排序、也没做容量与占用过滤,
143
+ 会把不合适(坐不下 / 该时段已被占)的房间混进来;用户真正要的是"你帮我挑好,我点一下"。
144
+ - ⛔ **不要把选项降级成一句话**:「请告诉我你要哪间」「会议地点是必填项,需要你指定一间」
145
+ 都是错的 —— 那是填空题,不是选择。
146
+ - 用户点了某个选项 → 把该 `value`(会议室是 `value.id`)作为对应入参重跑,不要自己猜。
147
+
148
+ 一句话:**能查的别问、能推的别让人填、要选的给选项卡**。让用户面对一堆空输入框 = 这次交互不合格。
149
+
28
150
  ## ⛔ 输出硬性规则(违反即交付不合格)
29
151
 
30
152
  1. **凡是给用户看的对象名称,一律是可点击链接**:会议 / 议题 / 纪要 / 会议室 / 签到 / 决议 的名字,
@@ -50,7 +172,7 @@ cliHelp: "weaver-work-cli meeting --help"
50
172
  - 回执:「帮我回执不参加」「谁还没回执」「回执情况」
51
173
  - 会议室/类型查询:「有哪些会议室」「会议室占用情况」「有哪些会议类型」
52
174
  - EB 版独有(仅 mode=eb):「会议议题」「议题类型」「会议纪要」「上会申请」「应用设置」「会议决议」「决议任务」
53
- - **会议决议 / 决议任务**:「把这次会议的决议落到系统里」「生成会议任务」「这次会议定了哪些事要谁做」「我负责的会议任务完成了吗」→ 见「命令表(EB 版)」的决议区块(**用 `meeting.eb.decision.publish` 一步完成**)
175
+ - **会议决议 / 决议任务**:「把这次会议的决议落到系统里」「生成会议任务」「这次会议定了哪些事要谁做」「我负责的会议任务完成了吗」→ 见「命令表」的决议行(**用 `meeting.eb.decision.publish` 一步完成**)
54
176
  - **不触发**(转对应 Skill):日程/日历类 → `weaver-e10-calendar`;审批流程发起 → `weaver-e10-workflow`;人员/部门查询 → `weaver-e10-hrm`。
55
177
 
56
178
  ## 认证与请求头契约
@@ -73,106 +195,133 @@ cliHelp: "weaver-work-cli meeting --help"
73
195
 
74
196
  ## 高优先级语义
75
197
 
76
- - 「今天的会议 / 下一个会」→ `meeting.list`(`filterDate` 客户端过滤;接口 body 过滤实测不生效,不要现场试 body)。
77
- - 「会议室占用 / 空闲 / 推荐」→ `meeting.room.list`(必须成对传 `beginDate`/`endDate`;`disabled=true` 已占用,不得推荐)。
78
- - 「预约会议 / 建会」→ 先 `meeting.create.prepare`(内部强制冲突检测),用户确认后 `meeting.create.apply`。
79
- - 「改期 / 换会议室 / 改参会人 / 变更会议」→ `meeting.change.prepare` → 确认后 `apply`。CLI 按会议状态**自动分流**:草稿走 `UPDATE`、正常会议走 `CHANGE`;权限由服务端判定并返回原文提示(如"您没有变更权限!"),必须原样转达用户。
80
- - 「取消会议 / 不开了」→ `meeting.cancel.prepare` → 确认后 `apply`。
81
- - 「删除会议记录」→ `meeting.delete.prepare` → 确认后 `apply`。
198
+ - 「今天的会议 / 下一个会」→ `meeting.eb.meeting.list`(`filterDate` 客户端过滤;接口 body 过滤实测不生效,不要现场试 body)。
199
+ - 「会议室占用 / 空闲 / 推荐」→ `meeting.eb.room.recommend`(按人数/常用/时段占用排序,带理由);
200
+ 只想看全部房间用 `meeting.eb.room.list`(`statusText=正常` 才是可用)。
201
+ - **⛔ 建会只走这三步,不要再加任何前置查询(不要查 baseSet、不要查 schema、不要先查会议室/冲突)**:
202
+ ```bash
203
+ # ① 预检:按「时间候选 → 会议室候选 → 冲突 → 流程」的顺序逐关推进,全部确认后才给确认摘要(不提交)
204
+ # 用户没说具体几点、没说哪间房 → **两个都不传**(连 begin_datetime 都不要填),
205
+ # CLI 自己返回「人空闲+会议室空闲」的时段选项;不用先调 suggest。
206
+ weaver-work-cli --json meeting run meeting.eb.meeting.create.flow.prepare \
207
+ --input-json '{"mt_name":"十一月开发进度沟通会","dateFrom":"2026-10-31","hrm_members":"<id,id>","mt_type":"<类型名>"}'
208
+
209
+ # 用户**明确**说了时间/房间(或刚在选项里点选过)→ 带上确认标记,一次通过:
210
+ weaver-work-cli --json meeting run meeting.eb.meeting.create.flow.prepare \
211
+ --input-json '{"mt_name":"十一月开发进度沟通会","begin_datetime":"2026-10-31 10:00","end_datetime":"2026-10-31 11:00","timeConfirmed":true,"address":"<房间 id>","roomConfirmed":true,"hrm_members":"<id,id>","mt_type":"<类型名>"}'
212
+ # ⛔ 没带 timeConfirmed / roomConfirmed 时,即使上面填了时间/房间,CLI 也不会当成已定,
213
+ # 会返回选项让用户点选 —— 这是故意设计的,别以为"填了就能过"。
214
+ # → status=NEEDS_SELECTION:selectionType 分四类,一律用选项控件让用户点
215
+ # slot = 没给 / 没确认 → 给时段选项,value 已带 begin_datetime/end_datetime/address/timeConfirmed,原样带回重跑 ①
216
+ # room = 没指定 / 没确认 → 房间选项(第一个带「推荐」;你传入的那间会标「(你指定的,待确认)」)
217
+ # room_conflict = **已确认**的房间被占 → 改空闲房间或改时段
218
+ # room_unavailable= 该时段无可用房间 → 改时段 / 线上会议 / 地点待定
219
+ # flow = **最后一步**:名称/时间/参会人/地点都确认了,两个建会流程**都有**发起权限 → 让用户选
220
+ # (只有 1 个有权限时 CLI 直接发起;都没有权限则报 flow_not_launchable)
221
+ # ✅ **顺序是「先四要素、最后选流程」**:
222
+ # 时间没确认 → 先回 slot;地点没确认 → 再回 room;都定了才轮到 flow。
223
+ # 本轮返回里的 `confirmed` 就是已确认的四要素;`options[].value` 已带上
224
+ # begin/end/address + timeConfirmed/roomConfirmed —— 用户点选流程后
225
+ # **原样回传 value** 即直达 AWAITING_CONFIRMATION,不要再问一遍时间/地点。
226
+ # ⛔ 这几类回来时都**不是**"已定方案":不许把 options[0] 写进确认摘要当结论,必须先让用户点。
227
+ # → status=AWAITING_CONFIRMATION:这时时间和房间都已由用户确认过,拿到 continuation,给用户看摘要后进 ②
228
+
229
+ # ② 提交(confirm 必须 true;continuation 10 分钟内有效,别中间插别的调用拖过期)
230
+ weaver-work-cli --json meeting run meeting.eb.meeting.create.flow.apply \
231
+ --input-json '{"continuation":"<上一步的>","confirm":true,"waitSeconds":20}'
232
+ ```
233
+ - **不要**先 `meeting.eb.baseSet.get`:流程候选由 `prepare` 内部算(固化流程优先,未命中才回落 `mt_new_wf`),
234
+ 流程建会任何时候都允许;只有它返回 `conflict_rejected`(说明该环境反而禁流程)才改用
235
+ `meeting.eb.meeting.create.quick` 直连。
236
+ - **不要**为了确认参数去翻 `meeting schema` —— 上面三条命令的字段就是全部,照抄即可;
237
+ 真不够时用 `extraFields`(只放租户自建文本字段)。
238
+ - **⛔ 判断"CLI 有没有某能力"只看 `weaver-work-cli meeting ops`(纯文本、不压缩)**,
239
+ 绝不能用 `meeting schema --json` 的输出来下结论 —— 它完整 308KB、stdout 只回 20KB 预览,
240
+ `operations` 数组被截到前 10 条,**排在后面的能力一定看不到** —— 据此说"没有某能力"必然误判
241
+ (`meeting.eb.meeting.create.suggest` 就是例子:它一直在,只是排在后面看不到)。
242
+ 查具体能力:`meeting ops --grep 关键词`(如 `--grep suggest` / `--grep 建会`)。
243
+ - **连时间都没给**:`begin_datetime` 可以不传,`prepare` 会直接返回 `selectionType: 'slot'` 的 3 个时段
244
+ (已按参会人空闲 + 会议室空闲挑过,`options[].value` 里带 `begin_datetime`/`end_datetime`/`address`),
245
+ 把 value 原样带回重跑 ① 即可 —— **一轮**就能把"时间+会议室"一起定下来。
246
+ - **字段是按 datakey 填的**:中文名匹配已做归一化(`开始时间(具体开始时间)` 能命中「开始时间」),
247
+ 解析出的「语义键 → 表单 datakey」缓存在 `~/.weaver-work-cli/meeting/cache/flow-fields-<workflowId>.json`,
248
+ 之后直接用 datakey,字段改名也不影响。要绕过名字匹配直接给值就用 `fieldValues`(键 = datakey):
249
+ `{"fieldValues":{"1325677252711735872":"十一月开发进度沟通会"}}`,
250
+ datakey 从 `preview.fieldMapping`(形如 `会议名称(请填写…)(1325677252711735872)`)里取。
251
+ - **⛔ 用户只说了"明天/下周三"、没给具体几点时,禁止弹空输入框让他自己填时间** —— 两条路都行:
252
+ **建会就走上面 ①(`prepare` 不传 `begin_datetime`,一步拿到时段选项)**,这是首选;
253
+ 只有用户"只想看看哪天有空、还不想建会"时,才单独调 `meeting.eb.meeting.create.suggest`(它确实存在):
254
+ ```bash
255
+ weaver-work-cli --json meeting run meeting.eb.meeting.create.suggest \
256
+ --input-json '{"dateFrom":"2026-10-31","hrm_members":"易鹏","durationMinutes":60,"maxSlots":3}'
257
+ ```
258
+ 返回的每个候选都是「**所有参会人都空闲**(会议回执 + 日程都核对过)**且该时段有会议室可用**」:
259
+ ```
260
+ T1 10-31 09:00~10:00 3 间会议室可用:测试会议室1、xxx
261
+ T2 10-31 10:00~11:00 2 间会议室可用:…
262
+ ```
263
+ 把 `label` 做成选项让用户挑一个(`value.begin/end/address` 直接可回填),选定后带时间走 prepare。
264
+ - 没候选时它会说明原因(人没共同空闲 / 人空闲但订不到会议室),**如实转达**,别自己编一个时间;
265
+ - 用户说了"上午/下午"这种粗粒度,也走它(`workStartHour`/`workEndHour` 约束),不要直接默认 9 点。
266
+ - ⛔ 这个操作调不通(返回 `unknown operation`)时**先跑 `meeting ops --grep suggest` 自查**,
267
+ 确认 CLI 装的是不是最新版;**不要**直接对用户说"没有这个能力" —— 建会主链路本来就不需要它。
268
+ - ⛔ **仅限「会议建会」这一件事:不要自己手搓 `workflow.*`**
269
+ (`workflow.search` / `workflow.createForm` / `workflow.createRequestDirect`)。
270
+ 会议建会流程由 `meeting.eb.meeting.create.flow.*` 内部处理(它自己也调 `workflow.createForm`),
271
+ 你手搓一遍只会拿到一张裸表单,丢掉字段映射、会议室联动、冲突检测、邀请函。
272
+ ✅ **其它流程照常用 workflow 模块** —— 请假、报销、待办、审批、流程查询等,
273
+ 那是 `weaver-e10-workflow` 的地盘,本 skill 不管、也不禁止。别因为这条就不敢用 workflow。
274
+ ⛔ **也不要为了"确定用哪个流程"去检索、或读 `mt_new_wf` 再自己挑一个**:不传 `workflowId` 就是正确用法。
275
+ ⛔ 直连 `create.prepare/quick` 在 `only_flow_create=1` 时会抛 `conflict_rejected`(应用管控,CLI 不绕过),
276
+ 所以**不要用它去"试试看"** —— 按上面第一行先判断,省一次白跑的调用。
277
+ - **⛔ 不要主动调 `meeting.env.detect`**:默认就是 EB,直接调 `meeting.eb.*` 即可。
278
+ 只有用户明确问"这是 EB 版还是标准版"时才 detect(且要带 `refresh: true` 实探,别读缓存)。
279
+ - 「改期 / 换会议室 / 改参会人 / 变更会议」→ `meeting.eb.meeting.change.prepare` → 确认后 `apply`。CLI 按会议状态**自动分流**:草稿走 `UPDATE`、正常会议走 `CHANGE`;权限由服务端判定并返回原文提示(如"您没有变更权限!"),必须原样转达用户。
280
+ - 「取消会议 / 不开了」→ `meeting.eb.meeting.change.prepare`(`operate_type=CANCEL`、`mt_status=4`)→ 确认后 `apply`。
281
+ - 「删除会议记录」→ `meeting.eb.meeting.delete.prepare` → 确认后 `apply`。
82
282
  - 「提前结束会议」→ **CLI 不支持**(服务端 `overMeeting` 为空实现,调用会假成功但不生效),如实告知用户并建议在系统页面操作。
83
- - 「回执为否 / 请假」→ `meeting.receipt.update.prepare`(自动回查回执记录 id)→ 确认后 `apply`。
84
- - 「签到情况」→ `meeting.sign.list`(输出已签/未签统计;其 `signs[].id` 是**签到记录 id**,补签/清除要用它,不是会议 id)。
85
- - 「补签 / 帮他补上签到」→ 先 `meeting.sign.list` 定位记录 → `meeting.sign.mark.prepare` → 确认后 `apply`;「补签退」用 `meeting.sign.back.prepare`。二者会改写签到事实,必须用户明确确认。
86
- - 「清除签到记录 / 撤销签到」→ `meeting.sign.clear.prepare` → 确认后 `apply`。
283
+ - 「回执为否 / 请假」→ `meeting.eb.receipt.list` 定位记录 → `meeting.eb.receipt.update.prepare` → 确认后 `apply`。
284
+ - 「签到情况」→ `meeting.eb.sign.list`(输出已签/未签统计;其 `signs[].id` 是**签到记录 id**,补签/清除要用它,不是会议 id)。
285
+ - 「补签 / 帮他补上签到」→ 先 `meeting.eb.sign.list` 定位记录 → `meeting.eb.sign.mark`(走更新,**禁止用 `sign.create`**);二者会改写签到事实,必须用户明确确认。
286
+ - 「清除签到记录 / 撤销签到」→ `meeting.eb.sign.clear.prepare` → 确认后 `apply`。
87
287
  - 「我要签到 / 扫码签到」→ **CLI 不支持**(依赖现场二维码票据 qrticket 与设备 IP),引导用户现场扫码或走 H5 签到;**绝不代签**。
88
- - **默认就走 EB operations**(见「命令表(EB 版)」),不必先判断环境:今天的会议 → `meeting.eb.meeting.list`(先 count 再 list);建会 → 先读 `meeting.eb.baseSet.get` 判断是否需走流程,再 `meeting.eb.meeting.create.prepare`(**prepare 内部自动执行会议室/参会人冲突检测**:命中禁止提交 → `conflict_rejected` 直接停止;**仅提醒也会拦下来** —— 见下面「建会的四条护栏」,必须让用户拍板,不能自己决定继续);变更/取消 → `meeting.eb.meeting.change.prepare`(取消用 `operate_type=CANCEL`、`mt_status=4`);签到 → `meeting.eb.sign.list`;回执 → `meeting.eb.receipt.list`;纪要 → `meeting.eb.minute.list`;议题 → `meeting.eb.topic.list`;**补签 → `meeting.eb.sign.mark`(走更新,禁止用 `sign.create`)**;**会议决议 → `meeting.eb.decision.publish`(写决议 + 自动把会议标为已决议,一步到位,勿拆成两步)**;决议任务 → `meeting.eb.decisionTask.list` / `.update`;**改决议 → `meeting.eb.decision.update`**(改明细默认是追加,整组替换传 `detail1Mode:"cover"`)。
89
-
90
- ## 命令表(标准版:EB 降级后 / 显式指定时使用)
91
-
92
- > ⛔ **默认不要从这张表里挑 operation。** 本 skill 默认走第十一节「命令表(EB 版)」。
93
- > 只有拿到 `api/env_fallback`(EB 走不通、CLI 已实探标准版可用)或用户明确要求标准版时才用这张表。
94
- > 环境已确认是 EB 时,这张表里的会议接口会返回 `api/env_mismatch` 并被拒——
95
- > 因为它们返回的是**另一套数据**(标准版 74 间会议室 vs EB 1 间),拿给用户就是编造。
96
-
97
- | 用户意图 | CLI operation | Reference |
98
- | --- | --- | --- |
99
- | 探测环境模式(EB/标准) | `meeting.env.detect` | [meeting-queries.md](references/meeting-queries.md) |
100
- | 建会前置判断(onlyFlowCreate/工作流) | `meeting.calendar.base` | [meeting-queries.md](references/meeting-queries.md) |
101
- | 会议列表 / 今天的会议 | `meeting.list`(便捷命令 `weaver-work-cli meeting today`) | [meeting-queries.md](references/meeting-queries.md) |
102
- | 会议详情表单结构 / 提醒 options | `meeting.detail.field` | [meeting-queries.md](references/meeting-queries.md) |
103
- | 会议室列表与占用 | `meeting.room.list` | [meeting-queries.md](references/meeting-queries.md) |
104
- | 会议室占用视图 | `meeting.room.usage` | [meeting-queries.md](references/meeting-queries.md) |
105
- | 会议类型列表 | `meeting.type.list` | [meeting-queries.md](references/meeting-queries.md) |
106
- | 会议室/人员/属性冲突检测 | `meeting.conflict.room` / `member` / `roomAttribute` | [meeting-create.md](references/meeting-create.md) |
107
- | 预约会议 | `meeting.create.prepare` → `meeting.create.apply` | [meeting-create.md](references/meeting-create.md) |
108
- | 会议变更(改期 / 改地点 / 改参会人) | `meeting.change.prepare` → `meeting.change.apply` | [meeting-change.md](references/meeting-change.md) |
109
- | 取消会议 | `meeting.cancel.prepare` → `meeting.cancel.apply` | [meeting-lifecycle.md](references/meeting-lifecycle.md) |
110
- | 删除会议记录 | `meeting.delete.prepare` → `meeting.delete.apply` | [meeting-lifecycle.md](references/meeting-lifecycle.md) |
111
- | 回执列表 | `meeting.receipt.list` | [meeting-receipts-signs.md](references/meeting-receipts-signs.md) |
112
- | 更新回执 | `meeting.receipt.update.prepare` → `apply` | [meeting-receipts-signs.md](references/meeting-receipts-signs.md) |
113
- | 签到记录与统计 | `meeting.sign.list` | [meeting-receipts-signs.md](references/meeting-receipts-signs.md) |
114
- | 补签 / 补签退 | `meeting.sign.mark.prepare` → `apply` / `meeting.sign.back.prepare` → `apply` | [meeting-receipts-signs.md](references/meeting-receipts-signs.md) |
115
- | 清除签到记录 | `meeting.sign.clear.prepare` → `apply` | [meeting-receipts-signs.md](references/meeting-receipts-signs.md) |
116
- | 生成对象详情页链接(会议/会议室/签到…) | `meeting.link`(**禁止手工拼 URL**) | [meeting-eb.md](references/meeting-eb.md) |
117
-
118
- ## 命令表(EB 版,仅 mode=eb 使用)
119
-
120
- > 全部 EB operation 的实现契约(interfacePk、URL query 参数、写操作 body 结构)见 [meeting-eb.md](references/meeting-eb.md)。
121
-
122
- | 用户意图 | CLI operation | Reference |
123
- | --- | --- | --- |
124
- | EB 会议列表 / 详情 | `meeting.eb.meeting.list` / `meeting.eb.meeting.detail` | [meeting-eb.md](references/meeting-eb.md) |
125
- | EB 建会 / 变更 / 删除 | `meeting.eb.meeting.create.prepare`→`apply` / `meeting.eb.meeting.change.prepare`→`apply` / `meeting.eb.meeting.delete.prepare`→`apply` | [meeting-eb.md](references/meeting-eb.md) |
126
- | EB 会议室列表 / 详情 | `meeting.eb.room.list` / `meeting.eb.room.detail` | [meeting-eb.md](references/meeting-eb.md) |
127
- | EB 会议室新建 / 更新 / 删除 | `meeting.eb.room.create` / `.update` / `.delete`(各 prepare→apply) | [meeting-eb.md](references/meeting-eb.md) |
128
- | EB 会议室占用列表 / 详情 | `meeting.eb.roomUsage.list` / `.detail` | [meeting-eb.md](references/meeting-eb.md) |
129
- | EB 占用新建 / 删除 | `meeting.eb.roomUsage.create` / `.delete`(prepare→apply) | [meeting-eb.md](references/meeting-eb.md) |
130
- | EB 签到列表 / 详情 | `meeting.eb.sign.list` / `.detail` | [meeting-eb.md](references/meeting-eb.md) |
131
- | EB 签到新建 / 更新 | `meeting.eb.sign.create` / `.update`(prepare→apply) | [meeting-eb.md](references/meeting-eb.md) |
132
- | EB 回执列表 / 详情 | `meeting.eb.receipt.list` / `.detail` | [meeting-eb.md](references/meeting-eb.md) |
133
- | EB 回执新建 / 更新 | `meeting.eb.receipt.create` / `.update`(prepare→apply) | [meeting-eb.md](references/meeting-eb.md) |
134
- | EB 纪要列表 / 详情 | `meeting.eb.minute.list` / `.detail` | [meeting-eb.md](references/meeting-eb.md) |
135
- | EB 纪要新建 / 更新 / 删除 | `meeting.eb.minute.create` / `.update` / `.delete`(各 prepare→apply) | [meeting-eb.md](references/meeting-eb.md) |
136
- | EB 会议类型列表 / 新建 / 删除 | `meeting.eb.type.list` / `.create` / `.delete` | [meeting-eb.md](references/meeting-eb.md) |
137
- | EB 议题类型列表 / 详情 / 更新 / 删除 | `meeting.eb.topicType.list` / `.detail` / `.update` / `.delete` | [meeting-eb.md](references/meeting-eb.md) |
138
- | **EB 创建议题**(`create_mt_topic`,必填 `topic_title`;挂会议传 `mt_id`) | **`meeting.eb.topic.create.prepare` → `apply`** | [meeting-eb.md](references/meeting-eb.md) |
139
- | EB 会议议题列表 / 详情 / 更新 / 删除 | `meeting.eb.topic.list` / `.detail` / `.update` / `.delete` | [meeting-eb.md](references/meeting-eb.md) |
140
- | EB 应用设置(`only_flow_create`/`open_mt_approve` 建会闸门与冲突策略的依据) | `meeting.eb.baseSet.get` | [meeting-eb.md](references/meeting-eb.md) |
141
- | **EB 发布会议决议**(写决议 + 自动把会议标为已决议) | **`meeting.eb.decision.publish.prepare` → `apply`** | [meeting-eb.md](references/meeting-eb.md) |
142
- | EB 决议列表 / 详情 / 删除 | `meeting.eb.decision.list` / `.detail` / `.delete.prepare` → `apply` | [meeting-eb.md](references/meeting-eb.md) |
143
- | **EB 更新决议**(改概述文本;改明细默认是**追加**,要整组替换传 `detail1Mode:"cover"`;不会同步到已生成任务) | **`meeting.eb.decision.update.prepare` → `apply`** | [meeting-eb.md](references/meeting-eb.md) |
144
- | EB 决议任务列表(按会议 / 执行人 / 状态) | `meeting.eb.decisionTask.list` | [meeting-eb.md](references/meeting-eb.md) |
145
- | EB 更新决议任务完成状态 | `meeting.eb.decisionTask.update.prepare` → `apply` | [meeting-eb.md](references/meeting-eb.md) |
146
- | **直建 / 删除单条决议任务**(create **仅兜底**:ESB 已自动生成任务,手工再建会重复;`executor` 放 `detail1`) | `meeting.eb.decisionTask.create` / `.delete` 的 `prepare` → `apply` | [meeting-eb.md](references/meeting-eb.md) |
147
- | **把决议任务推送到会议群聊**(默认只预览,`confirm:true` 才真发) | **`meeting.decision.notifyGroup`** | [meeting-eb.md](references/meeting-eb.md) |
148
- | **一条命令跑完**:群聊→纪要→文档→提交决议(ESB 自动生成任务)→推群(`level` 分档,提交决议/发群要 `confirm`) | **`meeting.pipeline.run`** | 见下「一条命令跑完」 |
149
- | EB 补签 / 补签退(自动定位签到记录,走更新) | `meeting.eb.sign.mark.prepare` → `apply` | [meeting-eb.md](references/meeting-eb.md) |
150
- | EB 会议室 / 参会人冲突检测(只查不建) | `meeting.eb.conflict.room` / `.member` | [meeting-eb.md](references/meeting-eb.md) |
151
- | EB 详情页链接(会议/会议室/占用/签到/回执/纪要/议题/设置) | `meeting.link`(按 `type` 解析 objid 并缓存) | [meeting-eb.md](references/meeting-eb.md) |
152
- | **按会议真实数据生成邀请函 docx**(只生成、不发送;有议题自动填议程表) | **`meeting.invitation.render`** | [meeting-invitation.md](references/meeting-invitation.md) |
153
- | **文本 → 二维码图片**(参会码/签到码/链接码;PNG/SVG,本地零依赖、离线可出图) | **`meeting.qrcode.render`** | 见下「二维码生成」 |
154
- | **参会人日程空闲**(查**日程应用**,不是会议表;自动过滤「会议日程」类型,id 动态解析不写死) | **`meeting.eb.schedule.free`** | 见下「日程空闲与会议室推荐」 |
155
- | **会议室推荐**(人数 + 地点/设备/类型要求 + 个人常用 + 时段占用;会议室/常用走缓存,占用实时查) | **`meeting.eb.room.recommend`** | 见下「日程空闲与会议室推荐」 |
156
- | **流程建会**(应用设置「只允许流程新建会议」时必须走这条;提交后自动出邀请函) | **`meeting.eb.meeting.create.flow.prepare` → `apply`** | 见下「流程建会」 |
157
- | **一步建会**(prepare+apply 合并,一次调用建完并出邀请函;多流程/需选择时自动退回选项) | **`meeting.eb.meeting.create.flow.quick`** | 见下「流程建会」 |
158
- | **找所有人共同空闲的时段**(冲突时给可选项,别只说"撞了") | **`meeting.eb.conflict.availability`** | 见下「冲突了要给出可选项」 |
159
- | **上传本地文件拿附件 id**(给纪要 `doc_file`/`video_file` 用;秒传 + 超时自动复核) | **`meeting.attachment.upload`** | [meeting-minute-file.md](references/meeting-minute-file.md) |
160
- | **查附件清单拿 fileId**(会议附件 `mt_accessorys`、项目文件 `project_files`、议题资料 `related_materials`) | **`meeting.attachment.list`** | 见下「读附件内容」 |
161
- | **按 fileId 下载附件**(会议附件用 E10 登录态;也可按 mtId 批量下) | **`meeting.attachment.download`** | 见下「读附件内容」 |
162
- | **下载并抽正文**(txt/md/csv/json/docx/xlsx/pptx;PDF/图片明确标 unsupported) | **`meeting.attachment.extract`** | 见下「读附件内容」 |
163
- | **回写原文/纪要并自动推进状态**(音频原文→2;文档原文→4;纪要文案→2) | **`meeting.minute.writeContent`** | [meeting-minute-file.md](references/meeting-minute-file.md) |
164
- | **单次查解析进度**(idle/pending/extracted/completed/failed,不轮询不阻塞) | **`meeting.minute.parseStatus`** | [meeting-minute-file.md](references/meeting-minute-file.md) |
165
- | **给会议挂附件**(上传带 refId 绑定记录 + 写 mt_accessorys;写 id 读名字,追加需传旧 id) | **`meeting.attachment.attach`** | [meeting-eb.md](references/meeting-eb.md) |
166
- | **群聊消息 → 纪要**(拉会议群消息→重排→过滤系统通知→拼原文→建纪要;可选接 ESB 生成文案/文档) | **`meeting.minute.fromGroupChat`** | [meeting-minute-file.md](references/meeting-minute-file.md) |
167
- | EB 传参口径(人员传 **HRM 员工 id**,非 E10 userId;日期 `yyyy-MM-dd HH:mm`) | — | [meeting-eb.md](references/meeting-eb.md) |
168
-
169
- > **给验证方(其他智能体)**:需要"验证所有会议功能"时,直接交付 [meeting-verification.md](references/meeting-verification.md)
170
- > —— 内含全部 **134 个 operation**(标准版 28 + EB 版 91 + 跨模式 15)的逐条判据、写链路模板、15 个负向用例、
171
- > 8 项不在范围的功能清单,以及可直接粘贴的验证提示词与回执模板。
288
+ - **其它场景也一律走 EB operations**(见「命令表」),不必先判断环境:变更/取消 → `meeting.eb.meeting.change.prepare`;签到 → `meeting.eb.sign.list`;回执 → `meeting.eb.receipt.list`;纪要 → `meeting.eb.minute.list`;议题 → `meeting.eb.topic.list`;**会议决议 → `meeting.eb.decision.publish`(写决议 + 自动把会议标为已决议,一步到位,勿拆成两步)**;决议任务 → `meeting.eb.decisionTask.list` / `.update`;**改决议 → `meeting.eb.decision.update`**(改明细默认是追加,整组替换传 `detail1Mode:"cover"`)。
289
+
290
+ ## 命令表:按能力域找 operation
291
+
292
+ > 完整清单随时可查:`weaver-work-cli meeting ops`(纯文本、不压缩);按关键词过滤 `meeting ops --grep 建会`。
293
+ > 下表只回答「有没有这个能力」,入参与契约见对应的 references。
294
+ > 简写约定:`eb.xxx` = `meeting.eb.xxx`,其余写全名。
295
+
296
+ | 能力域 | operation |
297
+ | --- | --- |
298
+ | 会议查询 | `eb.meeting.list` / `.detail`;标准版 `meeting.list` / `meeting.detail.field` |
299
+ | 建会(EB) | `eb.meeting.create.prepare`→`apply`;流程建会 `eb.meeting.create.flow.prepare`→`apply` / `.quick`;只推荐时间 `eb.meeting.create.suggest` |
300
+ | 建会(标准版,仅 `env_fallback` 后) | `meeting.create.prepare`→`apply`;前置判断 `meeting.calendar.base` |
301
+ | 变更 / 取消 / 删除 | EB `eb.meeting.change.*` / `eb.meeting.delete.*`;标准版 `meeting.change.*` / `meeting.cancel.*` / `meeting.delete.*` |
302
+ | 会议室 | EB `eb.room.list/detail/create/update/delete`、`eb.roomUsage.*`、`eb.room.recommend`;标准版 `meeting.room.list` / `meeting.room.usage` |
303
+ | 冲突 / 空闲 | EB `eb.conflict.room/member`、`eb.conflict.availability`、`eb.schedule.free`;标准版 `meeting.conflict.room/member/roomAttribute` |
304
+ | 回执 / 签到 | EB `eb.receipt.*`、`eb.sign.list/detail/create/update/mark`;标准版 `meeting.receipt.*`、`meeting.sign.*` |
305
+ | 纪要 / 附件 | `eb.minute.list/detail/create/update/delete`、`meeting.minute.fromGroupChat` / `.writeContent` / `.parseStatus`、`meeting.attachment.upload/list/download/extract/attach` |
306
+ | 议题 | `eb.topic.*`、`eb.topicType.*`(`topic.create` 挂会传 `mt_id`) |
307
+ | 决议 / 任务 | `eb.decision.list/detail/create/update/delete/publish`、`eb.decisionTask.list/update/create/delete`、`meeting.decision.notifyGroup` |
308
+ | 类型 / 应用设置 | `eb.type.list/create/delete`、`eb.baseSet.get`(建会时不用先查,`create.flow.prepare` 内部会读) |
309
+ | 邀请函 / 二维码 | `meeting.invitation.render`、`meeting.qrcode.render` |
310
+ | 详情页链接 | `meeting.link`(按 `type` 解析 objid,**禁止手工拼 URL**) |
311
+ | 一条命令跑完 | `meeting.pipeline.run`(群聊→纪要→文档→决议→任务→推群) |
312
+
313
+ > 环境模式先用 `meeting.env.detect` 确认。EB 环境下调标准版接口会被拒(`api/env_mismatch`)——
314
+ > 它们返回的是**另一套数据**(标准版 74 间会议室 vs EB 1 间),拿给用户就是编造。
315
+ > 各能力域的细节都在 references 里:查询会议/会议室/占用/类型 → [meeting-queries.md](references/meeting-queries.md);
316
+ > 建会与冲突检测 → [meeting-create.md](references/meeting-create.md);取消/删除会议 → [meeting-lifecycle.md](references/meeting-lifecycle.md);
317
+ > EB 版会议/会议室/占用/签到/回执/议题/决议 → [meeting-eb.md](references/meeting-eb.md);
318
+ > 纪要/附件/解析 → [meeting-minute-file.md](references/meeting-minute-file.md);邀请函 → [meeting-invitation.md](references/meeting-invitation.md);
319
+ > 变更 → [meeting-change.md](references/meeting-change.md);回执与签到 → [meeting-receipts-signs.md](references/meeting-receipts-signs.md)。
320
+ > 全部 134 个 operation 的逐条判据、写链路模板、负向用例见 [meeting-verification.md](references/meeting-verification.md)。
172
321
 
173
322
  ## ⛔ 建会的四条护栏(CLI 会强制拦,调用方不得自己放行)
174
323
 
175
- 这四条都是真机事故换来的,**任何一条都不允许"我看到 warning 了但还是提交了"**:
324
+ 这四条**任何一条都不允许"我看到 warning 了但还是提交了"**:
176
325
 
177
326
  1. **只允许流程建会时,不许直连建会**
178
327
  `only_flow_create=1` / `open_mt_approve=1` → `conflict_rejected`,改走 `meeting.eb.meeting.create.flow`(prepare→apply),不要绕。
@@ -188,45 +337,90 @@ cliHelp: "weaver-work-cli meeting --help"
188
337
  传了姓名(`hrm_members: "王丹丹,鲁云聪"`)CLI 会用 HRM 解析成 id 再写入,并在 warnings 里说明换过了。
189
338
  **解析不出来的会点名列出**:这几位不参与人员冲突检测,且**回执与签到建不起来**(等于没邀请成功),必须如实告诉用户,不能报"已邀请"。
190
339
 
191
- 4. **会议室三种情况都要处理,一个都不能省**(2026-10-29 用户明确要求):
340
+ 4. **会议室三种情况都要处理,一个都不能省**:
192
341
  | 情况 | CLI 行为(`create.flow.prepare` / `quick` 内部) | 返回的 `selectionType` |
193
342
  |---|---|---|
194
343
  | **你指定了会议室** | **照样查它在该时段是否被占用**;被占用就拦下不提交,并给出替代候选 | `room_conflict` |
195
344
  | **没指定会议室** | 按人数/常用度/时段占用推荐空闲房间,交用户挑 | `room` |
196
345
  | **没指定且推荐不出** | 拦下,给三条出路(指定房间 / 线上会 / 地点待定) | `room_unavailable` |
346
+ - **`address` 传 id、名称、`名称(id)` 都行,占用一定查**(2.39.3 起):CLI 先把 address 解析成台账里的
347
+ 真实房间(`resolveAddressRoom`),再查占用;传名称时**不再跳过占用检测**
348
+ (以前只对纯数字做校验,「测试会议室1」会一路放行到确认摘要)。
349
+ 名称在台账里对不上 → 返回 `selectionType: room` 并说明「没找到名为 X 的会议室」,**不会**把文本塞进表单。
350
+ 房间已封存(status=1)→ 同样拦下换房。用户说的名字不完整/口语化时,先 `meeting.eb.room.list` 核对再传。
351
+ - **选房阶段就能看到时间冲不冲突**:`selectionType: room` / `room_unavailable` 的返回里同样带
352
+ `memberConflicts`(会议冲突)和 `suggestedSlots`(全员空闲时段)—— prepare 是**并行算完才返回**的。
353
+ 所以"先让用户选房、选完再说时间撞了"是错的,**必须先告诉他时间冲不冲突,再让他选房**。
354
+ - **⛔ 看 `enrichFailures` 判断"到底查没查"**:返回里这个字段非空 = 某项增强检测**没跑成功**
355
+ (会议室推荐 / 会议室占用 / 参会人会议冲突 / 参会人日程空闲)。此时**绝对不能说"时间已确认空闲"**,
356
+ 没证据。正确说法:"这项没核验到(原因 X)",并原样转达原因。
357
+ 以前这些失败被 `.catch(() => null)` 静默吞掉,"没查"和"没冲突"长得一模一样,用户以为查过了
358
+ (会议室查不到就卡在选房 → 冲突检测不跑 → 却答复"流程表单本身不做冲突检测",就是这么错的)。
359
+ - **会议室台账缓存 24 小时,但「建会」链路强制拉最新**:`create.flow.prepare` / `create.flow.quick` /
360
+ `create.suggest` 内部都会强制刷新台账,所以刚导入/新建的会议室在建会时一定看得到。
361
+ 只有**纯查询**(`meeting.eb.room.recommend`)会走 24h 缓存(快);缓存超过 4 小时会在 warnings 提示
362
+ "数据可能过时",最近改过会议室就带 `refresh: true` 重查。候选为空时还会自动强制重拉一次
363
+ (`meta.cacheRetried: true`)。
364
+ ⛔ **不要因为"只有 1 间/查不到"就去断言系统里没有会议室** —— 先看 `meta.roomsTotal` 与 `cacheRetried`,
365
+ 必要时让用户跑 `meeting.eb.room.list` 确认真实条数(它**实时查库、不走缓存**)
366
+ (刚导入 100+ 间时,按旧缓存只报 1 间;实际 list 返回 155 间)。
367
+ - **`hrm_members` 要传员工 id**:姓名会被自动反查成 id,但**查不到就原样传下去**,
368
+ `conflict.member` 会报 `hrm_members 必须是数字 id`。用户只给姓名时,先
369
+ `hrm.employee.query --keyword <姓名>` 拿 id 再传。
370
+ - **`schedule.free` 的 `memberIds` 是数组、支持多人**(不是"只能查当前登录人"):
371
+ ```bash
372
+ weaver-work-cli --json meeting run meeting.eb.schedule.free \
373
+ --input-json '{"startDate":"2026-10-31 00:00","endDate":"2026-10-31 23:59","memberIds":["<id1>","<id2>"]}'
374
+ ```
375
+ 它同时核对**会议回执 + 日程应用**,并**自动过滤「会议日程」类型**避免重复计。
376
+ 所以"代查他人日程"可以做,别用"只能查自己"糊弄用户。
197
377
  - ⛔ **不要因为"用户指定了房间"就跳过冲突检测** —— CLI 两个都做,你也别自作主张只在没指定时才查。
198
378
  - 冲突返回里带 `conflicts`(占用明细:哪个会议、几点到几点)+ `options`(按空闲/人数/常用排序的替代房间)。
199
379
  正确反应:把"你指定的 X 在 10:00–11:00 已被占用"和候选一起给用户,**不要自己替他换房**。
200
380
  - 推荐不出候选时**不得断言"没有会议室"**(见下条),更不能默默提交一个没地点的会。
201
381
  - 推荐不出候选 → 返回 `decisions.roomUnavailable`(含原因,如"会议室列表为空/该时段全被占用"),
202
382
  必须用选项让用户确认:指定具体房间 / 改为线上会议 / 明确接受"地点待定"。**不要默默建成一场没地点的会**。
203
- - ⛔ **`meeting.eb.room.list` 返回 0 条 ≠ 这个环境没有会议室**(2026-10-29 真机)。
383
+ - ⛔ **`meeting.eb.room.list` 返回 0 条 ≠ 这个环境没有会议室**。
204
384
  EB 会议室台账(`uf_mt_room_base`)里可能明明有数据 —— 按 id 读 `meeting.eb.room.detail` 读得到、
205
385
  按 objId 直查有行 —— 但列表接口 `query_meeting_room_list` / `query_meeting_room_count` 读不出来
206
- (应用侧视图/接口配置问题)。而表单上的「会议地点」是 Ebuilder 浏览按钮,取数来源取决于租户表单配置,
207
- 未必和台账列表同一条链路。
386
+ (应用侧视图/接口配置问题:曾全天 0 条,把「会议室名称」配成传入字段后恢复 155 条)。
387
+ 而表单上的「会议地点」是 Ebuilder 浏览按钮,取数来源取决于租户表单配置,未必和台账列表同一条链路。
208
388
  **所以不得据此断言"无可用会议室"**,正确说法是"会议室列表接口读不到",并给出三条出路:
209
389
  ① 让用户直接在表单「会议地点」里点选;② 沿用历史单据里的会议室(名称或 id);
210
390
  ③ 改线上会议(`allowNoRoom: true`)。
211
391
  **禁止**改用标准版 `meeting.room.list` 拿另一套会议室顶上(EB 环境会被 `env_mismatch` 拒绝)。
392
+ - **按名称查会议室用 `room_name`**。服务端只做**精确匹配**:
393
+ `room_name=测试会议室1` → 1 条;传部分词(`测试`/`重庆`)服务端回 0 条 —— 但 CLI 会自动翻页扫全量、
394
+ 在客户端按「包含」重筛,所以**直接传部分词即可拿到模糊结果**(实测 155 条里查"重庆"命中 2 条,约 5 秒)。
395
+ 命中精确名时零额外开销;传 `noFallback:true` 可跳过这次扫描。
396
+ ⚠️ EB 的 `pageSize` 不生效(恒定回 10 条),要全量必须翻页 —— 这正是兜底做的事。
212
397
 
213
398
  ## 处理链:预约会议(高风险写,强制确认链)
214
399
 
215
- 1. **直接按 EB 走,不做前置环境判断**:`meeting.eb.meeting.create.prepare` 会**自行读取应用设置**并执行建会路径闸门(`only_flow_create=1` 或 `open_mt_approve=1` → 直接拒绝 `policy/conflict_rejected`,提示改用 `weaver-e10-workflow` 发起流程;读不到应用设置 → `conflict_check_failed`),**调用方不需要、也不得自行判断后继续建会**;只有返回 `env_fallback` 时才改用标准版 `meeting.create.prepare`(见 `details.standardOperation`);`env_unavailable` → 提示并停止。
400
+ 1. **建会直接进 `create.flow.prepare`,不查前置、不查 baseSet、不查 schema**(2026-10-30:有 agent 在这上面
401
+ 白跑了 6 次调用、90 秒)。`prepare` 内部会读 `mt_new_wf` 与冲突策略;它返回 `policy/conflict_rejected`
402
+ 才说明该环境禁流程建会,此时才改 `meeting.eb.meeting.create.quick` 直连(**不是**去 `weaver-e10-workflow` 手搓流程);
403
+ `env_fallback` 才改用标准版 `meeting.create.prepare`;`env_unavailable` → 提示并停止。
216
404
  2. **流程建会时,流程来源只有一个:应用设置 `mt_new_wf`。**
217
- - **⛔ 禁止用关键词检索流程**(`workflow.search`、`workflow: "会议"` 这类)。配置里已经给了流程 id,
218
- 检索既无信息增量,又会把无关流程带进来当结论 —— **真实事故(2026-10-29)**:agent 用关键词「会议」
405
+ - **⛔ 会议建会禁止用关键词检索流程**(`workflow.search`、`workflow: "会议"` 这类)。配置里已经给了流程 id,
406
+ 检索既无信息增量,又会把无关流程带进来当结论 —— **真实事故**:agent 用关键词「会议」
219
407
  检索出 11 个候选,「会议室预定流程-北方大区业务运营中心」排第一,用户当场质疑"我们配置的流程不包含这个"。
220
408
  配置已给 id 时,任何检索都是错的;只有"用户只说了流程名称、确实没有 id 来源"时才需要澄清。
221
409
  - **`mt_new_wf` 是逗号分隔多值时,禁止默认取第一个**。CLI 会逐个探测可发起性,多个可用就返回
222
410
  `NEEDS_SELECTION`(`options` 带流程名 + 各流程的字段名清单)→ 原样交给用户选。
223
411
  用户说"按上次那张 / 老规矩"时,才去查他的历史发起记录匹配流程名,匹配到就带**单个** `workflowId` 重跑。
224
- - 取表单一律用 `meeting.eb.meeting.create.flow.prepare`(内部按 `mt_new_wf` 调 `workflow.createForm`),
412
+ - 取表单一律用 `meeting.eb.meeting.create.flow.prepare`(内部按固化流程候选、未命中回落 `mt_new_wf` 调 `workflow.createForm`),
225
413
  **不要**自己拼 `workflow.createRequestDirect` / `workflow.createForm`。
226
- 3. **一次性问全,禁止分轮追问**:名称 / 时间(`yyyy-MM-dd HH:mm`)/ 会议室 / 参会人 / 会议类型。
227
- 缺哪几个就**一次把缺的全部列出来问**,不要"先问时间 → 再问人 → 再问房间"。
228
- 每多一轮追问就多一次模型推理(20–40 秒),用户体感"建个会要 2 分钟"基本都是这么来的(实测 CLI 全程只要 3 秒)。
229
- 用户一句话里已经给全的要素**不要再复述确认**,直接进下一步。
414
+ 3. **能自动推的绝不问用户;剩下要问的一次问全**
415
+ - **时间没说具体几点**(只说"明天/下周三/上午")→ **不要问,直接调 ① 的 `prepare` 且不传 `begin_datetime`**,
416
+ 它会返回「所有人都空闲 + 该时段有会议室」的时段选项(带会议室名,`value` 可直接回填)。
417
+ 这是 2026-10-30 用户明确要求的:没填时间就要推荐时间,不许弹空输入框让人手填。
418
+ 只有"只想看空闲、不建会"才单独用 `meeting.eb.meeting.create.suggest`。
419
+ - **会议室没指定** → **不要问,要给选项**(`prepare` 返回的 `options` / `roomOptions`,
420
+ 已排好序)。呈现规则见本节第 2 条:做成选项控件,禁止列成文本 + "需要你指定一间"。
421
+ - 其余真正缺的(会议名称 / 参会人 / 会议类型)**一次列完问**,不要"先问人 → 再问类型"。
422
+ 每多一轮追问就多一次模型推理(20–40 秒),用户体感"建个会要 2 分钟"基本都是这么来的(实测 CLI 全程只要 3 秒)。
423
+ - 用户一句话里已经给全的要素**不要再复述确认**,直接进下一步。
230
424
  4. **不要在 prepare 之前自己先去查会议室/类型/冲突** —— `prepare`/`quick` 内部已并行跑完(见上面「会议室不能默默留空」)。
231
425
  只有要给用户"换房 / 换时段"时才单独查:EB 走 `meeting.eb.room.recommend` / `meeting.eb.room.list` /
232
426
  `meeting.eb.type.list`;只有 `env_fallback` 之后才用标准版 `meeting.room.list` / `meeting.type.list`。
@@ -250,210 +444,103 @@ cliHelp: "weaver-work-cli meeting --help"
250
444
  5. 结果回读:`meeting.list` 确认状态(取消/删除后该会议不应再出现在正常列表)。
251
445
  6. **禁止**跳过 prepare 直接 apply;**禁止**在未确认目标存在时执行写操作。
252
446
 
253
- ## 处理链:生成邀请函 docx(只读,不发送)
447
+ ## 处理链:生成邀请函(docx + 对话内正文,只读,不发送)
448
+
449
+ ⛔ **邀请函要在对话里「贴出来」,不是丢个文件让人自己下载**(2026-10-31 用户明确要求:
450
+ 「不是发文件,是直接在智能体对话中展示」)。`meeting.invitation.render` 与建会返回的
451
+ `invitation` 对象里都有 **`text`** 字段 —— 那是与 docx 完全同源的 Markdown 全文。
452
+ 正确做法:**把 `text` 原样作为回复正文的一部分贴出来**(不要包在代码块里,不要省略),
453
+ 再附一句"docx 已生成在 `<filePath>`,可下载打印/外发"。
254
454
 
255
- 1. 直接走 `meeting.eb.meeting.list` 单查(**默认就是 EB**,不必先判断);只有返回 `env_fallback`(本环境是标准版)时,邀请函所需的 EB 字段取不到,如实告知用户即可。
455
+ **两种用法**:
456
+
457
+ | 场景 | 入参 | 说明 |
458
+ |---|---|---|
459
+ | 会议已生成(有 id) | `mtId` | 按**会议真实数据**生成,字段最全 |
460
+ | 会议还没生成(流程审批中 / 只有申请单信息) | `mt_name` + `begin_datetime`(再补 `end_datetime`/`address`/`hrm_members`/`mt_desc`/`caller`…) | 按**申请单信息**预生成**预置函**,`dataSource=payload` |
461
+
462
+ ⛔ **邀请函本质是「预置函」**:由项目人员下载后自行修改、自行发送。所以**不要因为没有会议 id 就说"生成不了"**——
463
+ 给了 `mt_name` + `begin_datetime` 就能出。取不到的字段渲染成黄色高亮【待补充】,人工补即可。
464
+
465
+ 1. 有会议 id 走 `mtId`;没有就按上表第二种用法直接出,不必等会议生成。
256
466
  2. 定位会议 id:用户给了会议名 → 先用 `meeting.eb.meeting.list`(`mt_name` 模糊)让用户确认,**不要猜 id**。
257
- 3. 问清「来访客户名称 / 客户单位」,作为 `extra.guest_org` 传入 —— **接口不返回该字段**,不传就会渲染成高亮【待补充】。
258
- 4. 跑 `meeting.invitation.render`,把 `filePath` 与 `pendingFields` 原样告诉用户;有待补充字段时提示"文档里已黄色高亮标出,请补完再发出"。
467
+
468
+ > 读人员字段(2.44.0):`meeting.eb.meeting.detail` 的 `caller`/`contacter`/`hrm_members`/`mt_creator`/
469
+ > `attend_user` 回的是**原始值** —— 页面建的单存**员工 id**、工作流建的单存**姓名文本**。所以另给一份
470
+ > `personnelText`(字段名 → 姓名)。⛔ 跟用户说话一律用 `personnelText` 的值,**不要**把 id 念成
471
+ > "这个字段没填好 / 显示成一串数字" —— 数据是好的,只是存储形态不同。
472
+ 3. 问清「来访客户名称 / 客户单位」,作为 `extra.guest_org` 传入 —— **会议表不返回该字段**,不传就会渲染成【待补充】。
473
+ (**流程建会时不用问**:`create.flow` 自动把「参会客户」名称当 `guest_org` 带进去。)
474
+
475
+ > 兜底说明(2.42.0):`address`/`hrm_members` 等字段列表单查可能为空,CLI 会用 `meeting.eb.meeting.detail`
476
+ > 补空(看 `detailSupplemented`);召集人按 `caller → 创建人 → 发起人本人` 顺序兜底(看 `callerSource`,
477
+ > `session.user` = 用了发起人)。所以正常情况下一封邀请函只该剩「客户单位 / 议程」这类业务信息要人工确认。
478
+ 4. 跑 `meeting.invitation.render`,**把返回的 `text` 全文贴进回复正文**,再告诉用户 `filePath`(docx 可下载打印);
479
+ 有待补充字段(`pendingFields`)时提示"正文里标【待补充】的地方需要补,补完我可以重新生成"。
259
480
  5. 议程**不用问、不用传**:会议有议题就按议题自动填进议程表,没有就保留模板示例行。看返回的 `agendaSource`:
260
481
  - `meeting.topic` → 已按议题填好,正常;
261
482
  - `template` → 该会议没排议题,**必须提醒用户议程表里还是模板示例内容,需人工改**(`warnings` 里也会说)。
262
483
  只有当用户明确说"议程这样写"时,才用 `extra.agenda`(`内容|时长|时间段`,换行分隔)覆盖。
263
484
  6. **本操作不发送任何消息**:不要调用 IM/邮件,也不要把文件内容读进上下文拼接。
264
485
 
265
- ## 处理链:给纪要挂附件 + 回填文字(上传→解析→写回)
486
+ ## 处理链:纪要 / 附件 / 总结(细节见 references)
266
487
 
267
- 用户给的是一段**录音/录像或一份会议材料**,要变成一条完整纪要时:
488
+ > 完整口径(上传保护、解析状态机、采样与降级、ESB 五个动作流)都在
489
+ > [meeting-minute-file.md](references/meeting-minute-file.md)。本节只给主链和硬约束。
268
490
 
269
- 1. `meeting.attachment.upload`(`file`=本地路径)→ 拿 `fileId`
270
- - 返回 `reused:true` 表示秒传命中;`recovered:true` 表示超时但文件已落地 —— **这两种都不许再重试上传**。
271
- 2. `meeting.eb.minute.create.prepare → apply`:`file_type`= `1`(音频/视频)或 `0`(文档),
272
- 把 `fileId` 分别写进 `video_file` / `doc_file`。
273
- 3. **解析由你自己做**(CLI 不做 ASR/OCR,接口也触发不了解析):
274
- - 音频/视频(mp4/mp3/m4a/wav…)→ 用你的音频转写能力,直接转这个本地文件;
275
- - docx / pdf / 图片 → 直接读该文件提取文字。
276
- 输出**只保留原文**(不总结、不解读、不加开场白),格式按用户给过的"高精度文本提取器"提示词。
277
- 4. 把原文写进 `minutes_content`:`meeting.eb.minute.update.prepare → apply`(必带 `id` + `mt_id`)。
278
- 5. 再按"生成会议纪要"的提示词,把原文整理成结构化纪要,写进 `parse_content`(HTML 富文本)。
279
- 6. 别承诺"已开始解析":判断解析是否完成看 `video_taskResult=='1'` 且 `parse_content` 非空,
280
- **不要看 `minutes_status`**(该字段常年卡在 1)。
281
- 7. 详见 [meeting-minute-file.md](references/meeting-minute-file.md)。
491
+ **① 录音/材料 → 纪要**
282
492
 
283
- ### 走群聊消息生成纪要
493
+ 1. `meeting.attachment.upload`(`file`=本地路径)→ `fileId`。`reused:true`(秒传)/`recovered:true`(超时但已落地)都**不要再传第二次**。
494
+ 2. `meeting.eb.minute.create.prepare → apply`:`file_type` = `1`(音视频)/ `0`(文档),`fileId` 写进 `video_file` / `doc_file`。
495
+ 3. **解析由你自己做**(CLI 不做 ASR/OCR,接口也触发不了解析):音视频用转写能力,docx/pdf/图片直接读;输出只保留原文,不总结、不加开场白。
496
+ 4. 原文写 `minutes_content`:`meeting.eb.minute.update.prepare → apply`(必带 `id` + `mt_id`)。
497
+ 5. 再按"生成会议纪要"的提示词整理成结构化纪要,写 `parse_content`(HTML 富文本)。
498
+ 6. ⛔ 别承诺"已开始解析":判断完成看 `video_taskResult=='1'` 且 `parse_content` 非空,**不看 `minutes_status`**(常年卡在 1)。
284
499
 
285
- **直接调 `meeting.minute.fromGroupChat`**,一条命令跑完,不用手工拼流程:
500
+ **② 群聊 → 纪要**:直接 `meeting.minute.fromGroupChat`,一条命令跑完。
286
501
 
287
502
  Windows PowerShell:
288
503
 
289
504
  ```powershell
290
- # 只要原文(最快,约 1.2 秒)
291
- weaver-work-cli --json meeting run meeting.minute.fromGroupChat --input-json '{"mt_id":"<会议id>"}'
292
- # 连纪要文案一起生成(ESB 633,约 40 秒)
293
- weaver-work-cli --json meeting run meeting.minute.fromGroupChat --input-json '{"mt_id":"<会议id>","pipeline":"minutes"}'
294
- # 再生成文档(ESB 628)
295
- weaver-work-cli --json meeting run meeting.minute.fromGroupChat --input-json '{"mt_id":"<会议id>","pipeline":"document"}'
296
- ```
297
-
298
- macOS/Linux:命令完全一致,仅路径写法不同。
299
-
300
- 它内部做的事(这些口径都踩过坑,写在操作里了):
301
-
302
- 1. 按 `mt_id` 读会议 → 取 `imchat_groupid`(也可显式传 `groupId`);
303
- 2. `im.msg.sync.group` 拉消息,**默认时间窗 = max(会议创建时间, 开始前 7 天) ~ min(现在, 结束后 2 小时)**
304
- (群里分工多是会前发的,只拉当天会漏;窗口也别无限放大,见下条);
305
- 3. **按 `msgtime` 升序重排**(接口返回是倒序,不排时间线就反了);
306
- 4. 过滤 `typeName=通知` 的系统消息,并在 `warnings` 里报告忽略条数;需要保留传 `keepSystem=true`;
307
- 5. `sender=我` 时用 `from_uid` 反查真名(`im.person.resolveByIds`);
308
- 6. 拼「时间 说话人:内容」→ 建纪要写 `minutes_content`(状态 4);
309
- 7. `mt_minutes_ai_page` 自动从该会议已有纪要反查,拿不到会 warning(也可传 `aiPageId`);
310
- 8. **用户另外给了材料(`files` / `content`)时是「合并」不是二选一**:只要会议有
311
- `imchat_groupid`,群聊照旧并入,用户材料排在前面(原文里能看到
312
- `===== 用户提供的会议材料 =====` 与 `===== 群聊记录(N 条)=====` 两个分节)。
313
- 只有**既没有群、也没有材料**才报 `group_missing`。
314
-
315
- **⚠️ 权限边界**:读消息用**当前登录账号**调 `POST /api/em/msg/executeIm/chat/syncGroupMsg`,
316
- 只能读到该账号所在的群;账号不在群里会返回空(是权限,不是接口坏了)。
317
-
318
- **⚠️ 消息量很大时**(几千/几万条):超过 `sampleThreshold`(默认 200)会自动采样去噪
319
- (保留 @ 与关键任务句、丢弃单字回复/纯表情/复读、每人非关键消息限 60 条),
320
- 返回里 `sampled`/`sampledDropped` 会标出来,**必须如实告知用户"这是采样后的结果"**。
321
- 真正的瓶颈是 ESB 633 会被超长原文撑爆,所以先跑 `pipeline=text` 出原文确认,再决定要不要生成纪要。
322
-
323
- **⚠️ 原文超长会自动降级为摘要版**:采样后仍超 `maxTranscriptChars`(默认 20000 字)时,
324
- 只保留**分工/结论/待办**类发言,写进纪要的内容开头会带
325
- `【群聊摘要:共 N 条消息,仅保留… K 条,省略 M 条】`,完整原文另存到 `fullTranscriptPath`。
326
- 返回里 `digestMode=true` 时**必须告诉用户"这是摘要口径、不是逐字全文"并给出那个路径** ——
327
- 不然用户会以为纪要漏内容,而其实是我们主动省略的。
328
-
329
- **任务怎么定 —— 由你(智能体)来分析,不要指望正则**:
330
-
331
- 1. **主路径**:先跑 `level=text` 或读回 `minutes_content` 拿到原文,**你自己读懂语义**,
332
- 把分析出的任务用 `decisions: [{executor, title}]` 传给 `meeting.pipeline.run`。
333
- 给了 `decisions` 就以它为准(返回里 `tasks.source="agent"`),CLI 只负责解析执行人 + 建任务。
334
- 2. **兜底**:没传 `decisions` 时 CLI 才用关键词匹配(返回里 `tasks.source="keyword"`),
335
- 只认两种写法:"@某人 …负责 xxx"(@ 必须在词首,避免把邮箱 `a@163.com` 当成提及)、
336
- 以及不带 @ 的"说话人:负责 xxx"。
337
- ⛔ **覆盖不到**「我来出方案」「先请 @某人 梳理一下」这类常见分工句 —— 别拿兜底结果当最终答案,
338
- 也别为了迁就它去改正则:**这是模型的活,不是正则的活**。
339
- 兜底一条都没匹配到时不会建任务,并会提示改用 `decisions`。
340
- 执行人用 `from_uid` 后**用 `username` 查 HRM**(`user1@example.com` 这类邮箱账号是真实员工,
341
- 用 `email`/`keyword` 查会查不到);解析不出人的**列出来告诉用户**,不要静默丢弃。
342
-
343
- ### 总结一场会议(`meeting.summary.get`)
344
-
345
- 用户说"总结一下这场会""这个会讨论了什么""进展怎么样"时用它。**只读、零副作用**,
346
- 一次把四路材料聚齐:
347
-
348
- ```bash
349
- weaver-work-cli --json meeting run meeting.summary.get --input-json '{"mt_id":"<会议id>"}'
350
- # 只要某几路(少拉就快):{"mt_id":"<会议id>","include":["minutes","tasks"]}
505
+ weaver-work-cli --json meeting run meeting.minute.fromGroupChat --input-json '{"mt_id":"<会议id>"}' # 只要原文,约 1.2s
506
+ weaver-work-cli --json meeting run meeting.minute.fromGroupChat --input-json '{"mt_id":"<会议id>","pipeline":"minutes"}' # 连纪要文案(约 40s)
507
+ weaver-work-cli --json meeting run meeting.minute.fromGroupChat --input-json '{"mt_id":"<会议id>","pipeline":"document"}' # 再出文档
351
508
  ```
352
509
 
353
- 返回 `data` 四段,缺哪段都会**在 `warnings` 里说清原因**,不会静默给 null:
354
-
355
- | 段 | 内容 | 取不到时 |
356
- | --- | --- | --- |
357
- | `overview` | 会议名/时间/地点/主题/状态 + `groupId` | 会议不存在 → 直接报错 |
358
- | `minute` | `content`(原文,群聊+材料合并)+ `parseContent`(**ESB 生成的结构化纪要**,信息密度最高) | 没有纪要 / 详情读空 → warning |
359
- | `tasks` | `progress.summary`(total/done/overdue/inProgress/pending)+ `progress.items[]`(每任务每人 `finish_status`) | 没有任务 → warning |
360
- | `attachments` | `items`(fileId 清单)+ `texts`(抽出的正文) | 没有附件 → warning;只要清单传 `withAttachmentText:false` |
361
- | `chat` | `transcript`(时间正序、已过滤系统通知、`sender=我` 已换成真名)+ 实际窗口 | 会议没有 `imchat_groupid` → warning |
510
+ - 读消息用**当前登录账号**,只能读到自己所在的群;返回空是权限问题,不是接口坏了。
511
+ - 消息量大时会**采样**、原文超长会**降级为摘要**:`sampled` / `digestMode` 为 true 时**必须告诉用户"这是采样/摘要口径"**,并给出 `fullTranscriptPath`,否则用户会以为纪要在漏内容。
512
+ - 用户另外给了材料(`files`/`content`)时是**合并**,不是二选一;既没群也没材料才报 `group_missing`。
362
513
 
363
- **总结由你来做,CLI 只负责取材料**(跟上面 `decisions` 一个道理):优先读 `minute.parseContent`
364
- (已按"会议概况/议题讨论/决策事项/任务部署/待解决问题"分好段),它缺失时再读 `chat.transcript`
365
- + `minute.content` 自己归纳;要讲进展就配 `tasks.progress`。
514
+ **③ 任务从哪来 —— 由你分析,不靠正则**
366
515
 
367
- 常用入参:`minuteId`(指定纪要,默认取最新一条)、`groupId`(覆盖会议自带的群)、
368
- `chatFrom`/`chatTo`(覆盖默认窗口)、`maxChatChars`(默认 20000,超了截断并标注)、
369
- `maxAttachmentChars`(默认 4000)。
516
+ - 主路径:先拿到原文(`level=text` 或读 `minutes_content`),**自己读懂语义**,把任务以 `decisions: [{executor, title}]` 传给 `meeting.pipeline.run`(返回 `tasks.source="agent"`)。
517
+ - 兜底:没传 `decisions` 才用关键词匹配(`tasks.source="keyword"`),只认「@某人 …负责 xxx」和不带 @ 的「说话人:负责 xxx」,**覆盖不到「我来出方案」这类常见分工句** —— 别拿兜底结果当最终答案。
518
+ - 执行人用 `username` 查 HRM(邮箱账号 `user1@example.com` 是真实员工,用 email/keyword 查不到);解析不出的**列给用户**,不静默丢弃。
370
519
 
371
- ⚠️ **群聊默认窗口**是 `max(会议创建时间, 开始前 7 天) ~ min(现在, 结束后 2 小时)`,
372
- 因为群里分工多是**会前**发的(只拉当天会漏)。窗内没消息会明确提示放宽 `chatFrom`/`chatTo`。
520
+ **④ 总结一场会**(`meeting.summary.get`,只读、零副作用)
373
521
 
374
- ### 把任务推回群聊(`meeting.decision.notifyGroup`)
522
+ `{"mt_id":"<id>"}` 一次聚齐 `overview` / `minute` / `tasks` / `attachments` / `chat` 五段,缺哪段都在 `warnings` 里说明原因。
523
+ 优先读 `minute.parseContent`(ESB 已按"概况/讨论/决策/任务/待解决"分好段),缺失时再用 `chat.transcript` + `minute.content` 自己归纳。
524
+ **总结由你做,CLI 只取材料**。少拉就快:`include:["minutes","tasks"]`。
375
525
 
376
- 决议任务生成后群里**不会自动收到通知**,要显式推。流程是「群聊 → 纪要 → 决议任务 → 推回群聊」的闭环:
526
+ **⑤ 一条命令跑完**(`meeting.pipeline.run`,用户说"把这个会开完"时用)
377
527
 
378
- ```powershell
379
- # ① 先预览:不带 confirm 不会发出任何消息
380
- weaver-work-cli --json meeting run meeting.decision.notifyGroup --input-json '{"mt_id":"<会议id>"}'
381
- # ② 用户看过预览、确认后再发
382
- weaver-work-cli --json meeting run meeting.decision.notifyGroup --input-json '{"mt_id":"<会议id>","confirm":true}'
383
- ```
384
-
385
- ⛔ **必须两步**:群消息对外可见、超时后撤不回。不带 `confirm:true` 时返回 `preview:true, sent:false`,
386
- 正文在 `text` 里 —— **把预览读给用户看,等他点头再发第二次**,不要自己连着发。
387
-
388
- 默认只推**未完成**任务(`onlyPending` 默认 true),已完成的不再刷一遍;执行人缺失写「未指派」,不猜人。
389
-
390
- **默认会 @ 到任务执行人**(传 `mention:false` 可关):先 `im.group.users` 拿群成员,
391
- 按姓名匹配 `executors`;发送时文本里用 `:@uid;` 占位符,**并且请求体必须带 `atUsers: [{cid, uid}]`** ——
392
- 只有 `atUsers` 才能让服务端生成落库的 `aus`,客户端才显示成蓝色可点;手写 `@姓名` 或自己拼 `aus` 都无效。
393
- 执行人不在群里就只在正文写名字,会 warning 列出,不硬凑。
394
- 详见 [meeting-eb.md](references/meeting-eb.md)。
395
-
396
- ### 一条命令跑完:`meeting.pipeline.run`
397
-
398
- 前面几段都能单独调,但用户说"把这个会开完"时,串起来更合适(省 3~4 次进程启动)。
399
-
400
- ```powershell
401
- # 跑到文档为止(默认 level=document,约 30 秒)
402
- weaver-work-cli --json meeting run meeting.pipeline.run --input-json '{"mt_id":"<会议id>"}'
403
-
404
- # 预览"要建哪些任务 + 群里会发什么"(不写、不发)
405
- weaver-work-cli --json meeting run meeting.pipeline.run --input-json '{"mt_id":"<会议id>","level":"notify"}'
528
+ `level` 分档:`text` < `minutes` < `document`(默认)< `tasks` < `notify`。
529
+ ⛔ `tasks` / `notify` **必须 `confirm:true`**:不带 confirm 只跑到文档,返回 `tasks.planned` + `notifyPreview`,**一个字都不写、不发**;把这两段给用户看,点头后再带 confirm 跑第二次。
530
+ 关键口径:任务由**用户配置的 ESB 在"标记已决议"时自动生成**(一条明细 → 一个任务),所以**不要调 `decisionTask.create`**;推群前会轮询最多 15s 等任务落地,始终 0 条则跳过推送(群里收到「共 0 项」比不发更糟)。
406
531
 
407
- # 确认后真跑(提交决议 → ESB 自动生成任务 → 推群);传 minuteId 复用上一步的纪要,省 30 秒
408
- weaver-work-cli --json meeting run meeting.pipeline.run --input-json '{"mt_id":"<会议id>","level":"notify","minuteId":"<上一步返回的纪要id>","confirm":true}'
409
- ```
532
+ **⑥ 把任务推回群**(`meeting.decision.notifyGroup`)
410
533
 
411
- `level` 分档:`text` < `minutes` < `document`(默认)< `tasks` < `notify`。
534
+ ⛔ **必须两步**:先不带 `confirm` 拿 `preview:true, sent:false` 和 `text` 给用户看,点头后再带 `confirm:true` 发。群消息对外可见、超时撤不回,不要自己连着发。
535
+ 默认只推未完成任务(`onlyPending`),执行人缺失写「未指派」,不猜人。
536
+ @ 执行人:文本用 `:@uid;` 占位,**请求体必须带 `atUsers: [{cid, uid}]`** 才会生成落库的 `aus`;手写 `@姓名` 或自己拼 `aus` 都无效。
412
537
 
413
- ⛔ **`tasks` / `notify` 必须 `confirm:true`**:不带 confirm 时只跑到文档,然后返回
414
- `tasks.planned`(将从原文提取到哪些任务、指派给谁)和 `notifyPreview`(群里会发的原文),
415
- **一个字都不写、不发**。把这两个给用户看,点头后再带 confirm 跑第二次。
416
-
417
- 内部几个关键口径:
418
-
419
- - **任务从纪要原文提取**:只认「@某人 负责 xxx」;邮箱里的 `@`(`a@example.com`)不算提及;
420
- 自己推到群里的通知(以「【」开头)会被跳过 —— 否则转述会被再提取一遍,凭空多任务;
421
- - **执行人用 `username` 查 HRM**(邮箱账号 `user1@example.com` 是真实员工,用 email/keyword 查不到),
422
- 查不到的**列进 `tasks.unresolved` 跳过**,不猜人;
423
- - **计划时间**:开始 = 会议结束时间,截止 = 开始 + `taskDueDays` 天(默认 7)的 18:00;
424
- - **不重复提交决议**:会议已有任务时按 `skipExistingTasks`(默认 true)跳过,否则每跑一次就糊一层;
425
- - **曾取消的会议**:`decision.publish` 会自动在「写决议」与「标记已决议」之间插 800ms(否则 ESB 会把同一批明细生成两轮任务,实测复现过),并在 warnings 里说明;
426
- - **CLI 不手工建任务**:`tasks` 这一步只做 `decision.publish`(写决议概述 + 标记已决议),
427
- 任务由**用户配置的 ESB 在"标记已决议"时自动生成**(一条明细 → 一个任务)。所以不要调 `decisionTask.create`;
428
- - **推群前等任务落地**:ESB 自动生成任务有 3~6 秒延迟,立即推群会列不到刚生成的任务
429
- (实测踩过)。所以 publish 后会轮询最多 15 秒,等任务数涨上来再发;
430
- **如果服务端始终是 0 条任务,就跳过推送**(群里收到「共 0 项」比不发更糟),warning 里说明可稍后重推。
431
-
432
- ### 走 ESB 解析(正式链路,全链路实测验证)
433
-
434
- **五个动作流自己负责写入和状态推进,CLI 只管"传文件"和"查状态"**:
435
-
436
- 1. `meeting.attachment.upload` → `fileId`;`meeting.eb.minute.create` 挂上
437
- (`file_type` 0/1,`doc_file`/`video_file`,**`mt_minutes_ai_page` 传本租户的页面 id**,如 `<智能纪要页面id>`)。
438
- 2. 调 ESB「解析附件」`esbFlowId=<解析附件flowId>`
439
- (`mainTable`:`minuteId`/`mt_id` 必填,`doc_file`/`video_file`/`file_type` 可选)。
440
- - **文档:同步**,可能顶到 60 s 超时报 `write_uncertain` —— **不代表没执行**,去查纪要字段;
441
- - **音频:异步**,约 9 s 返回,原文约 2 分钟就绪(服务端写 `video_taskResult=0→1`)。
442
- 3. 两种类型原文就绪后,服务端都会把 `minutes_status` 写成 **4(文字提取完成)**。
443
- 用 `meeting.minute.parseStatus` 单次查询,别连续轮询。
444
- 4. 调 ESB「根据智能体解析文本生成智能纪要文本」`esbFlowId=<生成纪要flowId>`
445
- (`mainTable` 只需 `minuteId`)→ 它把结构化纪要写进 `parse_content`,状态置 **1(生成中)**。
446
- ⛔ **不要自己拟纪要文案**:提示词在 ESB 里,自己写会和小E 现有格式不一致。
447
- 5. 调 ESB「保存解析并生成文档」`esbFlowId=<生成文档flowId>`
448
- (`mainTable`:`parse_content` + `mt_minute_id`)→ 生成文档、回写 `mt_minutes=<文档id>`、状态置 **2(已完成)**。
449
- ✅ **直接调,不用问用户**(口径:"肯定要生成的啊,不要问")。
450
- 6. ⛔ **不要调「获取解析纪要音频结果」**:它是 1 分钟一轮的定时任务、会自己写表单,重复调可能覆盖;
451
- 只需要 `meeting.minute.parseStatus` 查进度(它返回 `nextAction` 直接告诉你下一步该调哪个)。
452
-
453
- > ⚠️ **流程 id 是租户级配置**(各环境不同),文中 `<…flowId>` / `<智能纪要页面id>` 均为占位符。
454
- > `meeting.minute.fromGroupChat` 对「生成纪要 / 生成文档」两条内置了参考租户默认值,
455
- > 其他租户用 `flowGenerateMinutes` / `flowGenerateDocument` 覆盖;页面 id 传 `aiPageId`。
538
+ **⑦ ESB 解析链路**(正式链路)
456
539
 
540
+ `attachment.upload` → `minute.create` 挂附件 → ESB「解析附件」(文档同步、可能 60s 超时报 `write_uncertain` 但**不代表没执行**;音频异步约 9s 返回、原文约 2 分钟就绪)→ 等 `video_taskResult=1` / `minutes_status=4` → ESB「生成智能纪要文本」(写 `parse_content`)→ ESB「保存解析并生成文档」。
541
+ ⛔ 不要自己拟纪要文案(提示词在 ESB 里,自己写会和小E 现有格式不一致)。
542
+ ⛔ 不要调「获取解析纪要音频结果」:它是 1 分钟一轮的定时任务、会自己写表单,重复调可能覆盖;查进度只用 `meeting.minute.parseStatus`。
543
+ ⚠️ 流程 id / 页面 id 是**租户级配置**,文中 `<…>` 均为占位符。
457
544
  ## 读附件内容(会议附件 / 项目文件 / 议题资料)
458
545
 
459
546
  ⛔ **旧结论作废**:以前 skill 里写"附件回读只有文件名、拿不到 fileId ⇒ 下载不了",**是错的**。
@@ -521,7 +608,9 @@ weaver-work-cli --json meeting run meeting.attachment.extract --input-json '{"mt
521
608
  直接念给用户听:"11-10 当天 9:00-18:00 内没有所有人都空闲的 120 分钟时段,张三 09:00~11:30 有会…"。
522
609
  - **选项必须自解释**:`slotOptions` 的 `label` 形如 `11:30~15:30(会议当天) · 全部参会人空闲`(**一定要带"空闲"字样**,否则用户只看到两个时间点,不知道这是推荐还是随便给的);`roomOptions` 带容量与 `· 推荐`;多流程 `options` 带流程名。
523
610
  - **一律用选项**:`roomOptions`(R1/R2/R3)、`slotOptions`(T1/T2/T3)、多流程时 `options`(W1/W2)都带 `key`+`label`+`value`,
524
- 直接做成选择项;选完把 `value` 回填(会议室 `address`、时段改 `begin_datetime/end_datetime`、流程带 `workflowId`)重新 prepare。
611
+ 直接做成选择项;选完把 `value` **整体**回填重新 prepare(时段 value 自带 `timeConfirmed: true`、
612
+ 房间 value 自带 `roomConfirmed: true`,别只挑 `begin_datetime` / `address` 单个字段抄,
613
+ 抄漏标记就会被再问一轮;流程带 `workflowId`)。
525
614
  - 想单独查时段(不建会):
526
615
  `weaver-work-cli --json meeting run meeting.eb.conflict.availability --input-json '{"rangeStart":"2026-10-30 00:00","rangeEnd":"2026-10-30 23:59","durationMinutes":120,"hrmMembers":"<id1>,<id2>"}'`
527
616
 
@@ -546,7 +635,7 @@ weaver-work-cli --json meeting run meeting.attachment.extract --input-json '{"mt
546
635
  - **每次 CLI 调用还有约 1.3 秒固定开销**(node 进程启动,实测 `workflow.createForm` 总耗时 2.2 秒里 1.3 秒是启动)。
547
636
  所以**减少调用次数比优化单次更有用**:5 次调用 ≈ 6.5 秒纯启动开销,压到 2 次就省掉 4 秒,
548
637
  更重要的是每少一次调用,就少一轮模型推理(20–40 秒)。
549
- 真实对照(2026-10-29 小E 一次建会):**22 次 CLI 调用 / 10 分钟**,而单次 CLI 只要 2 秒 ——
638
+ 真实对照:**22 次 CLI 调用 / 10 分钟**,而单次 CLI 只要 2 秒 ——
550
639
  时间几乎全花在轮次上,且 `meeting-room-list` 被重复调了 3 次、`meeting-room-usage` 3 次。
551
640
 
552
641
  - **建会优先用 `meeting.eb.meeting.create.flow.quick`**(带 `confirm: true`),一次调用拿到 `requestId / meetingId / invitation`;
@@ -559,20 +648,129 @@ weaver-work-cli --json meeting run meeting.attachment.extract --input-json '{"mt
559
648
 
560
649
  应用设置勾了「只允许通过流程新建会议」(`only_flow_create=1`)或「会议提交需审批」
561
650
  (`open_mt_approve=1`)时,**直连 `create_meeting` 会被闸门拒绝**——这是应用管控,CLI 不绕过。
562
- 但这**不是停手**:改走流程即可,链路同样以「出邀请函」收尾。
651
+ 但这**不是停手**:改走流程即可。注意流程建会是**异步**的——提交后要等审批通过、会议真的生成,
652
+ 才有会议 id;**但邀请函不需要等**(见下面「邀请函是预置函」)。
563
653
 
564
654
  ```bash
565
- # ① 准备:按应用设置 mt_new_wf 载入建会流程表单,把会议字段按中文名映射(不提交)
655
+ # ① 准备:算流程候选 + 映射表单字段(不提交)
656
+ # 用户没明确给时间/房间 → 两个都不传,让 CLI 返回选项(见顶部规则 0.5)
657
+ weaver-work-cli --json meeting run meeting.eb.meeting.create.flow.prepare \
658
+ --input-json '{"mt_name":"周会","mt_desc":"排期","total_member":3}'
659
+ # 用户明确给过时间/房间 → 带确认标记
566
660
  weaver-work-cli --json meeting run meeting.eb.meeting.create.flow.prepare \
567
- --input-json '{"mt_name":"周会","begin_datetime":"2026-11-05 14:00","end_datetime":"2026-11-05 15:00","mt_desc":"排期","total_member":3,"address":"<会议室名称(ID)>"}'
661
+ --input-json '{"mt_name":"周会","begin_datetime":"2026-11-05 14:00","end_datetime":"2026-11-05 15:00","timeConfirmed":true,"address":"<会议室id>","roomConfirmed":true,"mt_desc":"排期","total_member":3}'
568
662
 
569
- # ② 提交:确认后提交审批;提交成功后会轮询会议表,会议生成即自动出邀请函
663
+ # ② 提交:确认后提交审批;**无论会议有没有生成,都会出邀请函**
570
664
  weaver-work-cli --json meeting run meeting.eb.meeting.create.flow.apply \
571
665
  --input-json '{"continuation":"<上一步 continuation>","confirm":true,"waitSeconds":20}'
572
666
  ```
573
667
 
668
+ - **✅ 邀请函是「预置函」,提交完必有**(2026-10-30 用户明确要求:项目人员下载后自己改、自己发,
669
+ 不该卡在"会议已生成"之后):
670
+ `apply` 提交后会轮询会议表(默认 20 秒,`waitSeconds` 可调),
671
+ - 命中会议 → `invitation.pending=false` + `filePath`(**完整数据版**);
672
+ - 没命中(多数是还在审批)→ `invitation.pending=true` + `preRendered=true` + `filePath`
673
+ —— 已按**申请单已知信息**预生成了一份,取不到的字段是【待补充】黄色高亮。
674
+ - ⛔ **不管哪种情况都有 `filePath`**。所以:**永远不要说"没有邀请函"**,
675
+ 正确说法是「邀请函已生成(路径 X)——这份是按申请单预生成的,会议还在审批中;
676
+ 审批通过后我可以按真实会议数据再生成一版完整字段的」。
677
+ - ⛔ **更要紧的是把 `invitation.text` 全文贴在回复里**。
678
+ 只回一个路径 = 用户还得自己去本地打开才知道写了什么,等于没给。
679
+ - **刷新为完整版**:审批通过后 `meeting.eb.meeting.list` 找到该会议 id →
680
+ `meeting.invitation.render --mtId <id>`(只生成、不发送)。
681
+ - ⛔ **不要因为"会议还在审批"就重复 `apply`** —— 会重复建单/重复建会。
682
+ - **只有 `submit_mode=browser` 才可能返回 `status=BROWSER_FILL`**(2026-10-31 起默认不再进这一档,
683
+ 见下方「提交方式」)。万一真进到这一档:CLI 会返回 `contextId` + `finalMarkdown`(那段 `<browsertool>` 表单)
684
+ + `invitation.filePath`(按申请单预生成的预置函)。正确做法:把 `finalMarkdown` 内容原样作为本轮回复正文
685
+ (从 `<browsertool>` 到 `</browsertool>`、不包代码块),并告诉用户邀请函已生成在哪个路径;
686
+ ⛔ 不要说"流程没提交成功 / 没有邀请函",也不要因为"没有 requestId"重复 `apply`。
687
+
688
+ - **✅ 提交方式默认「弹表单」**(2026-10-31 用户纠正;之前默认直提是错的,别再改回去):
689
+ `create.flow.quick/apply` 默认 `submit_mode=browser` —— 在小e 里会**打开流程表单**,会议名称/时间/地点/参会人员/参会客户都已预填
690
+ (浏览按钮传的是 id,页面能落值),用户核对、修改后**自己点提交**。
691
+ - `browser` 下 CLI **不向服务端写入**,返回 `status=BROWSER_FILL` + `finalMarkdown`(那段 `<browsertool>`),
692
+ 没有 `requestId` / `meetingId` —— ⛔ **不能说"流程已提交"**,要说"表单已打开,您在页面上核对后点提交";
693
+ - 邀请函照给(预置函);审批通过、会议生成后再用 mtId 跑一次 `meeting.invitation.render` 拿完整版;
694
+ - 只有用户明确说"不用我确认,直接建"时才传 `submit_mode=direct`:直接写服务端 → 拿 `requestId` + `meetingId`,
695
+ 会议当场生成;判断落库看这两个 id,并用 `meeting.eb.meeting.detail --id <meetingId>` 回读核对;
696
+ - ⛔ 不管哪种模式,`quick` / `apply` 都是真提交,必须已拿到用户对时间/地点/人/客户的确认。
697
+ - **⛔ 提交前必须把 `formPreview` 贴给用户过一眼**(2.44.0 起,2026-10-31 用户要求
698
+ 「为什么没有直接发起流程表单让我确认重填后让我点击提交」):
699
+ 浏览器填单那条路走不通(浏览按钮不赋值),所以用"把要提交的内容原样列出来"替代核对环节。
700
+ `create.flow.prepare` 返回 `preview.formPreview`(人话 Markdown 表格,人员/客户显示**姓名**),
701
+ 拿到就**整段贴给用户**并问一句"确认这样提交吗",**等答复**再 `apply`/`quick`;
702
+ `apply`/`quick` 成功后同样返回 `submittedPreview`(本次实际提交的字段表),
703
+ ⛔ **必须一起贴出来**——用户要的就是"看得见到底填进去了什么",别只说"已提交成功"。
704
+ 只有用户一开始就说"不用确认,直接建"才可跳过 prepare 的确认环节。
574
705
  - 字段按**中文名**匹配(会议名称/开始时间/结束时间/会议内容/会议地点/参会人员/参会人数/召集人/联系人/备注),
575
706
  映射不到的原样进 `warnings` 并列出表单现有字段名——**租户改过字段名时看这条**,别硬编码 fieldId。
707
+ - **「召集人」「联系人」默认就是当前登录人,不用传**:
708
+ 以前这两个字段只有显式传 `caller`/`contacter` 才有值 —— **换个人用(别的账号)建会就整块空白**,
709
+ 流程单上看不出谁召集的,邀请函「召集人」也落成【待补充】。现在 CLI 自动取当前登录人(员工 id + 姓名)
710
+ 填进这两个字段,并在返回里给 `preview.autoFilled`(如 `{"召集人":"卜伟领(4980…)"}`)+ 一条 warning 说明。
711
+ - ⛔ **不要主动问用户"召集人是谁"** —— 默认自己,问了是多余的一轮;
712
+ - 只有用户**明确指定**别人("让张三召集"/"联系人写李四")才传 `caller`/`contacter`(员工 id 或姓名),
713
+ 显式传的值一律不被覆盖;只传其中一个时,另一个仍按当前登录人补齐;
714
+ - 查不到当前登录人对应的员工(`userId` 与员工 id 不一致的租户)时**不会瞎填**:两个字段都留空并给
715
+ warning 让你显式传 —— 看到这条要如实告知用户,别硬编一个 id 塞进去(会被服务端判"无法唯一解析")。
716
+ - **⛔ 别把「人 / 地点 / 类型」塞进 `extraFields`**:会议地点、参会人员、召集人、联系人、会议类型都有**专用入参**
717
+ (`address` / `hrm_members` / `caller` / `contacter` / `mt_type`),CLI 会把值补成浏览按钮要的
718
+ `{id, name}` 对象。塞进 `extraFields` 会按纯文本提交,必被打回。
719
+ `extraFields` 只用于租户自建字段(纯文本类,如联系方式)。
720
+ - **参会客户(`crm_members`)有专用入参**(**别再塞 `extraFields`**):
721
+ 表单上的「参会客户」在本租户是 **`Ebuilder` 浏览按钮**(`1326190634427154474` → `1332418251116929025`;
722
+ NEW `1325677244111462606` → `1332437840406257666`)。**这是正常配置,不是配错** ——
723
+ 同一张表单的「会议地点」也是 Ebuilder。链路固定三步:
724
+ 1. 用户说客户名 → `meeting.eb.crm.search` 查(`{"keyword":"<客户名>"}`,走动作流入参 `custom_name`),
725
+ 返回 `items: [{ customerId, name }]`,`customerId` 就是 ESB 的 `sjID`。
726
+ ⛔ 该动作流**一次只回首个匹配**("模糊查 10 条"在服务端做不到),且 `hasData` 恒 0 不可信:
727
+ - `exact: true`(命中名 == 关键词)→ 可往下走;
728
+ - `exact: false` → **必须把实际命中的客户名念给用户确认**,别拿首个匹配当定论(`腾讯` 会命中
729
+ 「深圳市腾讯斐泰科技有限公司」,`泛微` 会命中一个就叫「泛微」的客户,都不是用户想的那家);
730
+ - `items: []` 才是"查无此客户",可如实回复,建议换更短/更长的关键词再试一次;
731
+ - `blocked: "esb_template_empty"` 是**配置问题**(模板是空对象、入参被丢弃),不是"没这个客户"。
732
+ 给**全称**最稳(id 稳定、`exact` 为 true)。
733
+ 2. 命中结果**直接往下走**,只把命中的客户名念给用户确认一次(`exact:false` 时必须念,
734
+ ⛔ 不许自己当成"就是这家")。**不要**为此多问一轮"是不是这家?"再等答复 —— 除非名字明显不对。
735
+ 3. 选中的客户传 `crm_members`:**最省事是把 `search` 返回的 `items` 原样传过去**
736
+ (`[{customerId,name}]`;`[{sjID,mc}]`、`[{id,name}]`、`"客户名(客户id)"`、`"id,id"` 也都认),
737
+ CLI 统一补成 `[{id,name}]`,并按条数**自动填「应到客户数」**(想覆盖就传 `crm_member_count`)。
738
+ ⛔ **必须带客户名称**:只给 id 时服务端会把「参会客户」**静默存成空值**
739
+ (单据详情里是 `""`,不报错),所以 CLI 现在直接抛 `crm_name_required` 拒绝提交 ——
740
+ 按报错提示改用 `[{id,name}]` 或「客户名(客户id)」重发即可。
741
+ 4. **客户联系人自动带入,不用问、不用选**:
742
+ 传了 `crm_members` 就自动把该客户在 CRM 里的**全部**联系人写成「参会客户明细」行
743
+ (一人一行,本来就是多行结构)。入参带了 `contacts` 就直接用;没带就 CLI 自己回查一次 `crm.search`。
744
+ 返回里的 warning 会列出「已自动写入:利明 111…、胡老师 150…」——
745
+ ⛔ **不要**再说"这几位您选哪一位",也**不要**因为明细多于一人而反问;
746
+ 只有用户说"只写某某"时才用 `crm_member_details` 显式覆盖。
747
+ 明细表不存在(该流程没摆这张表)时 CLI 会明确告警,此时联系人只体现在客户名上,如实说明即可。
748
+ 5. **会议记录里的客户由 ESB 字段映射负责**(2.45.1 起):表单「参会客户」是 Ebuilder,值写进**流程单据**,
749
+ 提交后由 ESB 动作流按字段映射同步到会议表(`ufd_crm_members_new`)—— 这是管理员已经配好的链路,
750
+ CLI **不再自己补写**会议表,也不要去手工补。
751
+ `apply` 默认不返回 `crmLinked`;只有环境变量 `WEAVER_MEETING_CRM_PATCH=1` 时才走旧的 CLI 补写(仅调试用)。
752
+ ⛔ 别再说"要换回 Customer 组件"(此前判错过)。
753
+ ⛔ 也别拿会议表 `crm_members` 的空值去判断"客户没代进去":那一列不是客户字段的真实落点。
754
+ - **参会客户明细(`crm_member_details`,2.39.6 起,2.39.7 打通落库)**:宿主表单里另有一张明细表
755
+ (列:姓名/性别/职位/手机号码/备注)。逐行传
756
+ `[{"xm":"张三","xb":"男","zw":"采购经理","sjhm":"138…","bz":"主谈"}]`(中文键 `姓名/性别/职位/手机号码/备注` 同样认),
757
+ CLI 会按**列名反查各列字段 id**、按 `data.details` 提交,不用传 subFormId。
758
+ 提交后单据详情里 5 列全部落库(姓名/性别/职位/手机号码/备注)。
759
+ ⛔ 三个必须知道的现实:
760
+ 1. **明细字段只认「发起节点布局」**。表建了、节点权限也勾了,但**没摆上发起节点布局**(或摆在**隐藏行**上)
761
+ 时,`workflow.createForm` 里根本没有这 5 个字段 → CLI 会返回 `layoutWarning` 并忽略明细行
762
+ (主表照常写)。看到这句话**不要**回用户"表单里没有这张明细表",要说明"明细表没摆上/摆在隐藏行"。
763
+ 2. **明细表常被「显示联动」条件隐藏**(本租户就是:`参会客户` 为空时整表 `hideLine`)——
764
+ 这是**正常配置,不是配错**。CLI 会把这类表的字段照常下发并标 `conditional: true`,
765
+ 同时在 `layoutWarning` 里说明触发字段(如「触发字段:参会客户」)。**照常填即可**,
766
+ 把 `crm_members` 填上后表单里就显示了;⛔ 不要因为 `conditional: true` 就当它不可用。
767
+ 3. **同一条流程上两者可能都齐全,也可能只有其一**:本租户「会议申请流程」
768
+ (`1326190634427154474`) 同时有「参会客户」和「参会客户明细」;「会议申请流程(NEW)」
769
+ 有「参会客户/应到客户数」但没有明细表。落库前先看 `create.flow.prepare` 的
770
+ `fieldMapping`/`unmapped`,别假设两个字段一定同时存在。
771
+ - **「会议类型」在很多租户的表单里是必填**:`create.flow.prepare` 的返回会列出表单全部字段名,
772
+ 缺必填时 `createRequest` 会报缺字段。**先 `meeting.eb.type.list` 拿到类型名/id 再传 `mt_type`**,
773
+ 不要等报错了才补。
576
774
  - **浏览按钮字段必须传对象 `{"id":"…","name":"…"}`**(实测):
577
775
  会议地点(会议室)、参会人员(数组)、召集人 / 联系人(单人)传**纯 id 或纯姓名都会被当"名称"去匹配**,
578
776
  匹配不到就返回 `status: NEEDS_CONFIRMATION`("无法唯一解析的选项")——这不是流程走不通,是值格式不对。
@@ -594,11 +792,13 @@ weaver-work-cli --json meeting run meeting.eb.meeting.create.flow.apply \
594
792
  CLI **不会**替你取第一个(2026-10-29 修的就是这个:旧版把数组拼成 `"a,b"` 当单个 id,下游取了第一个能载入的,
595
793
  结果字段全填不进另一条流程的表单,用户以为"系统只支持一条")。只有**用户明确点名**某条流程后才传单个 id。
596
794
  - **流程 id 的权威链(唯一):入参 `workflowId`(用户已选定)> 应用设置 `mt_new_wf`。**
597
- - **⛔ 禁止用关键词检索流程**。不要用 `workflow.search`、也不要传 `workflow: "会议"` 去"探明有哪些建会流程"。
598
- **真实事故(2026-10-29)**:agent 用关键词「会议」检索,返回 11 个候选,
795
+ - **⛔ 会议建会**禁止用关键词检索流程。不要用 `workflow.search`、也不要传 `workflow: "会议"`
796
+ 去"探明有哪些建会流程"。
797
+ **真实事故**:agent 用关键词「会议」检索,返回 11 个候选,
599
798
  把「会议室预定流程-北方大区业务运营中心」排在第一并抛给用户,用户当场质疑"我们配置的流程不包含这个"。
600
799
  配置里已经给出 id,检索没有任何信息增量,只会引入干扰项。
601
800
  (只有"用户只报了流程名称、确实拿不到 id"时才需要澄清,且要用名称精确定位、不要用宽泛关键词。)
801
+ ✅ 这条**只管会议建会流程**;查待办、查审批、发起请假报销等,正常用 `workflow.*`。
602
802
  - **默认不要传 `workflowId`**:让 CLI 自己读 `mt_new_wf` 并处理多值(探测 + `NEEDS_SELECTION`)。
603
803
  **⛔ 更不要自己先读应用设置、再 split、再挑一个传进去** —— 这正是 2026-10-29 "明明配了 2 个流程却只用 1 个"
604
804
  的成因:agent 自行取第一个,CLI 完全无从察觉,也就无法纠正。把选择权留在 CLI/用户手里,不要提前决定。
@@ -631,7 +831,7 @@ weaver-work-cli --json meeting run meeting.eb.meeting.create.flow.apply \
631
831
 
632
832
  必须知道的四件事:
633
833
 
634
- - **字段名写错会硬报错**,不会静默丢:`DataError:dataKey:xxx,该字段不存在`(真机实测)。
834
+ - **字段名写错会硬报错**,不会静默丢:`DataError:dataKey:xxx,该字段不存在`。
635
835
  所以"写不进去"一定是名字不对,拿 `meeting.form.fields` 核对,别改值重试。
636
836
  - **`extraFields` 与内置字段同名时以内置字段为准**,并在 warnings 里说明被忽略(不会悄悄盖掉)。
637
837
  - **清空**自定义字段靠 `extraFields` 传空串 —— 内置字段的空串会被跳过(防误清),自定义字段走这个口子才清得掉。
@@ -713,7 +913,8 @@ weaver-work-cli --json meeting run meeting.eb.room.recommend \
713
913
  (`meeting.caller` / `meeting.mt_creator` / `none`);此时 warnings 会说明"已用创建人代替,可传 extra.caller 覆盖"。
714
914
  所以**不会**出现"前面说召集人是张三、后面又说召集人要补"的矛盾 —— 那种情况是会议表的 caller 字段真的为空。
715
915
  - **议程**:会议没有议题时保留模板示例行(`agendaSource: "template"`),warnings 会提示"请人工改成真实议程"。
716
- - **建会成功**:`create.apply` 直接生成邀请函 docx,路径在 `data.association.invitation.filePath`;
916
+ - **建会成功**:`create.apply` 直接生成邀请函,**正文在 `data.association.invitation.text`**(贴进回复),
917
+ docx 路径在 `data.association.invitation.filePath`;
717
918
  失败只回 `invitation.ok=false`(不影响建会),关掉:`WEAVER_MEETING_AUTO_INVITATION=0`。
718
919
 
719
920
  ## 二维码生成:`meeting.qrcode.render`
@@ -739,8 +940,6 @@ weaver-work-cli --json meeting run meeting.qrcode.render \
739
940
  - 参会码走「门禁/食堂」时,**码内容必须是对方系统认可的票据格式**(一般由 ESB/门禁侧接口下发),
740
941
  本 operation 只做最后一步渲染;内容接口未就绪时不要自造格式。
741
942
 
742
-
743
-
744
943
  ## ⚠️ 本 skill 的定位:EB 版会议(务必按此取 id)
745
944
 
746
945
  本 skill 面向的会议功能(议题、纪要、决议、邀请函、EB 写链路)**全部以 EB 版会议为准**:
@@ -751,7 +950,7 @@ weaver-work-cli --json meeting run meeting.qrcode.render \
751
950
  - 用户只说"某个会议"但没给 id 时:**优先用 `meeting.eb.meeting.list` 按名称模糊查**,把候选列给用户确认,**不要**用标准版列表的 id 顶替。
752
951
  - 纪要、议题这类"EB 独有"的数据,标准版环境下**没有**,如实说明,不要用标准版接口硬凑。
753
952
 
754
- ### ⛔ 标准版接口在 EB 环境会直接报 `env_mismatch`(2026-10-29 事故后加的硬闸)
953
+ ### ⛔ 标准版接口在 EB 环境会直接报 `env_mismatch`(事故后加的硬闸)
755
954
 
756
955
  有些租户(如 e-cology)**同时装了标准会议应用和 EB 会议应用**,两套数据完全不通:
757
956
 
@@ -797,7 +996,7 @@ agent 一旦误调标准版接口,**它不报错、照常返回数据**,于
797
996
  - **⚠️ EB 返回值解析(实测踩坑,必看)**:EB 接口里**人员 / 关联 / 状态 / 选择类字段返回的是「对象数组」**(如 `[{"name":"王五","id":"1300000000000000001"}]`),**不是字符串** —— 取 id 读 `[0].id`、显示名读 `[0].name`;**禁止**把整个数组当字符串拼接(会显示成 `System.Object[]`,看起来像"字段为空")。已实测这类形态:`executors` / `rummager` / `mt_id` / `relate_decision` / `decision_status` / `detail1[].executor`;而 `finish_status`("未完成"/"已完成")、日期、`id` 是字符串。另注意 **`sign.list` 返回的 `mt_id` 是「会议室/会议名称」而筛选参数 `mt_id` 才是会议 id**。
798
997
  - **⚠️ EB 写操作失败语义(实测踩坑,必看)**:**EB 写接口"报错"≠"没有写入"** —— 实测 `create_mt_decision` 因字段校验失败返回错误时,主表与明细其实**已经落库**,重试产生了重复数据。因此写操作失败后**必须先回查**(list/detail)再决定重试或删除;CLI 的语义化写操作(`decision.publish`、`sign.mark`)在拿不到明确成功证据时会抛 **`partial`** 并提示"先回查、勿盲目重试",请如实转达用户。
799
998
  - EB 版纪要**创建**未实现(该功能走 OpenAPI、无自定义 interfacePk),仅支持 `meeting.eb.minute.list` 查询。
800
- - 周期会议走工作流(`repeatWorkFlowBaseIds` 非空)与 `onlyFlowCreate=1`(EB 版为 `only_flow_create=1` / `open_mt_approve=1`)的流程建会需要工作流集成:**CLI 会主动拒绝并转 `weaver-e10-workflow`**(标准版 `assertCreatePathAllowed`;**EB 版为 `meeting.eb.meeting.create.prepare` 的建会路径闸门,2026-10-15 补齐** —— 此前 EB 版只写在文档里、代码未拦,导致 `only_flow_create=1` 仍能直接建会落库)。
999
+ - 周期会议走工作流(`repeatWorkFlowBaseIds` 非空)与 `onlyFlowCreate=1`(EB 版为 `only_flow_create=1` / `open_mt_approve=1`)的流程建会需要工作流集成:**CLI 会主动拒绝并转 `weaver-e10-workflow`**(标准版 `assertCreatePathAllowed`;**EB 版为 `meeting.eb.meeting.create.prepare` 的建会路径闸门** —— 此前 EB 版只写在文档里、代码未拦,`only_flow_create=1` 仍能直接建会落库)。
801
1000
  - **冲突处置严格按应用设置,CLI 不额外加码**:`=1`「禁止提交」→ 怎么都不允许提交(抛 `conflict_rejected`,不询问、不新建);`=0`「仅提醒」→ 如实告知冲突并建议换时间/换地点,**但不阻止提交** —— 用户了解冲突后仍要求新建时,可继续 `apply` 完成建会。**检测失败 → `conflict_check_failed` 拒绝**(策略无法判定时保守处理)。
802
1001
  - **签到**:查询统计(`meeting.sign.list`)与写操作(补签 `meeting.sign.mark`、补签退 `meeting.sign.back`、清除签到 `meeting.sign.clear`)**已实现**;**本人扫码签到(`signMeeting`)不提供**——它依赖现场二维码票据(qrticket)与设备 IP,由 AI 代签会破坏签到真实性,请引导用户现场扫码或走 H5 签到;**平台签到二维码接口(getQrCode / downLoadQrCode)未接**(契约未确认)——若只是要把一段文本画成码图,用 `meeting.qrcode.render`,但**不要拿它冒充平台签到码**(平台校验的是自己的票据)。
803
1002
  - **删除是软删**:`meeting.delete` 走 `update mt_detail set delete_type = 2`,会议**进入回收站、可以还原**;CLI 暂无还原能力,需要恢复时请引导用户到**会议回收站页面**操作。**不要**再对用户说"彻底删除、不可逆"。