weaver-work-cli 0.1.39 → 0.1.42

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 (197) hide show
  1. package/README.md +4 -2
  2. package/dist/chunks/{archive-ENZYBBME.js → archive-J4I6MCKF.js} +2 -2
  3. package/dist/chunks/{archive-oa-YWLEC5V4.js → archive-oa-BRZKKTO4.js} +2 -2
  4. package/dist/chunks/{asset-OOV6DWPA.js → asset-L7D4FAOZ.js} +2 -2
  5. package/dist/chunks/{asset-idle-RE632MY5.js → asset-idle-DADLLV75.js} +2 -2
  6. package/dist/chunks/{attachment-content-RWN2FCLL.js → attachment-content-K4C7VLWQ.js} +3 -3
  7. package/dist/chunks/{blog-PEPOJAL7.js → blog-BVGQ7NZL.js} +2 -2
  8. package/dist/chunks/{caizhilian-WYIQDVPJ.js → caizhilian-SAADNFD6.js} +2 -2
  9. package/dist/chunks/{calendar-CIARBAOX.js → calendar-Q7NQY5Z2.js} +61 -23
  10. package/dist/chunks/{chunk-F2EQXUEE.js → chunk-3KTFS4IA.js} +397 -159
  11. package/dist/chunks/{chunk-G2JSIUWF.js → chunk-4PD5NWAX.js} +89 -0
  12. package/dist/chunks/{chunk-HJYVHXUQ.js → chunk-4RAE6JXP.js} +1 -1
  13. package/dist/chunks/{chunk-CQHGNCK2.js → chunk-72CKAUAG.js} +41 -8
  14. package/dist/chunks/{chunk-K3RUEEOL.js → chunk-APVFJUQH.js} +2 -2
  15. package/dist/chunks/{chunk-BJGXMFGD.js → chunk-BBKDXQEC.js} +2 -2
  16. package/dist/chunks/chunk-BIPYLLVS.js +501 -0
  17. package/dist/chunks/{chunk-GVPJZXJ2.js → chunk-EKWAQSLU.js} +92 -50
  18. package/dist/chunks/{chunk-XXJOSZTQ.js → chunk-FOAA27U5.js} +381 -57
  19. package/dist/chunks/{chunk-I2HB737U.js → chunk-G4UR6NXN.js} +2 -2
  20. package/dist/chunks/{chunk-YS5DPN4T.js → chunk-GEWYMQME.js} +1 -1
  21. package/dist/chunks/{chunk-P2DAISYW.js → chunk-GHXCDPTM.js} +1 -1
  22. package/dist/chunks/{chunk-L4N7B7ZD.js → chunk-IZ7S7QUS.js} +4 -4
  23. package/dist/chunks/{chunk-NLK2RZKG.js → chunk-JPRO6ER2.js} +122 -2214
  24. package/dist/chunks/{chunk-36DIFZAH.js → chunk-LADPYOWC.js} +2 -2
  25. package/dist/chunks/chunk-LDZQPUIA.js +1238 -0
  26. package/dist/chunks/chunk-NKZRQXST.js +2546 -0
  27. package/dist/chunks/{chunk-EINRJHQ3.js → chunk-QKNKR4RH.js} +3 -3
  28. package/dist/chunks/{chunk-T7JDJJ7H.js → chunk-R4CHUSKC.js} +126 -19
  29. package/dist/chunks/{chunk-EZGFHJFW.js → chunk-SA6VBIHY.js} +88 -15
  30. package/dist/chunks/{chunk-ZXRNHZTE.js → chunk-TTPJJJC4.js} +2 -2
  31. package/dist/chunks/{chunk-KTCB5R5H.js → chunk-W7BEHOSR.js} +2 -2
  32. package/dist/chunks/{chunk-MUQUHKPG.js → chunk-YRSZQUD2.js} +2 -2
  33. package/dist/chunks/{conflict-DRMDOL56.js → conflict-F2OMZRTO.js} +2 -2
  34. package/dist/chunks/{contract-73MERZWN.js → contract-5BETHRSG.js} +2 -2
  35. package/dist/chunks/{cowork-HNGBPD7A.js → cowork-3MN6EQQO.js} +27 -10
  36. package/dist/chunks/create-flow-5FQNNMVO.js +55 -0
  37. package/dist/chunks/{ebuilder-form-OY6DVNRK.js → ebuilder-form-SBHOYBUD.js} +3 -3
  38. package/dist/chunks/{ehr-RAQNEQO7.js → ehr-KMOJULKG.js} +432 -1234
  39. package/dist/chunks/env-LB7NBL2O.js +19 -0
  40. package/dist/chunks/{esb-6XV7C7YV.js → esb-W2PJCFCX.js} +4 -4
  41. package/dist/chunks/factory-6ZFQXQ46.js +30 -0
  42. package/dist/chunks/{fna-XTSRB7G7.js → fna-ZQPCUV4R.js} +2 -2
  43. package/dist/chunks/group-chat-2HHAJN46.js +20 -0
  44. package/dist/chunks/{host-YMBXWFWX.js → host-4CBHGOHT.js} +3 -3
  45. package/dist/chunks/{host-A7J6GDUP.js → host-ATKVNZAT.js} +3 -3
  46. package/dist/chunks/{host-3F5UM5GN.js → host-BQH22NTQ.js} +3 -3
  47. package/dist/chunks/{host-YAQAPYNP.js → host-X2CSLFM6.js} +3 -3
  48. package/dist/chunks/{host-VGPVP7YF.js → host-YTODKMSL.js} +3 -3
  49. package/dist/chunks/{hrm-TLHKC545.js → hrm-FFM4UJFS.js} +4 -4
  50. package/dist/chunks/{im-YOUCFMUK.js → im-VEHKDQPB.js} +8 -8
  51. package/dist/chunks/{invoice-WNBS2B4C.js → invoice-LVIKSIIF.js} +3 -3
  52. package/dist/chunks/{jiuchuanhui-XABWS5RN.js → jiuchuanhui-X6DINO5P.js} +2 -2
  53. package/dist/chunks/{lazy-dispatch-NLZ5UQQI.js → lazy-dispatch-KSWTN5L6.js} +4 -4
  54. package/dist/chunks/{mail-LRYMBFNL.js → mail-VDKRGUD3.js} +9 -4
  55. package/dist/chunks/{meeting-ESXL6MFI.js → meeting-CLC6HP3Z.js} +12 -10
  56. package/dist/chunks/{okr-EOV65SSF.js → okr-CHG4OO3U.js} +2 -2
  57. package/dist/chunks/{plan-YFPVKW6Y.js → plan-XWR75667.js} +2 -2
  58. package/dist/chunks/{project-MDVZUYQW.js → project-5BXOOKMG.js} +40 -23
  59. package/dist/chunks/recruit-stage-DGMFNNDE.js +4507 -0
  60. package/dist/chunks/{registry-VT5Y2HLA.js → registry-7FFOXIAW.js} +4 -4
  61. package/dist/chunks/{registry-QCLZEDAP.js → registry-BKBZPBAJ.js} +10 -8
  62. package/dist/chunks/{registry-YX4CSEMD.js → registry-RHMW6ANW.js} +2 -2
  63. package/dist/chunks/{registry-NYPYMZXG.js → registry-Z43434VG.js} +1 -1
  64. package/dist/chunks/{room-recommend-L3MWH4JW.js → room-recommend-62H7ZQQ6.js} +4 -4
  65. package/dist/chunks/{schedule-UASAVDVD.js → schedule-FNXKH3DQ.js} +4 -4
  66. package/dist/chunks/{workflow-KDGIUCNW.js → workflow-ADHKCAJK.js} +4 -4
  67. package/dist/index.js +33 -28
  68. package/dist/internal/e10/auth/commands.js +110 -56
  69. package/dist/internal/e10/auth/messages.js +6 -0
  70. package/dist/internal/e10/auth/session.js +28 -1
  71. package/dist/internal/e10/auth/xiaoe.js +315 -48
  72. package/dist/internal/e10/auth-recovery.js +36 -5
  73. package/dist/internal/e10/client.js +13 -0
  74. package/dist/internal/e10/context.js +61 -9
  75. package/dist/internal/e10/index.js +1 -1
  76. package/dist/internal/e10/network-error.js +93 -0
  77. package/dist/internal/e10/request-runtime.js +15 -0
  78. package/dist/shortcuts/calendar/operations/read.js +31 -22
  79. package/dist/shortcuts/calendar/operations/write.js +45 -1
  80. package/dist/shortcuts/cowork/operations/discuss-write.js +5 -1
  81. package/dist/shortcuts/cowork/operations/item-write.js +5 -3
  82. package/dist/shortcuts/cowork/operations/member-write.js +3 -1
  83. package/dist/shortcuts/cowork/operations/permission-write.js +5 -1
  84. package/dist/shortcuts/cowork/operations/shared.js +7 -0
  85. package/dist/shortcuts/ehr/operations/attend-write.js +43 -1
  86. package/dist/shortcuts/ehr/operations/hr-contact.js +7 -4
  87. package/dist/shortcuts/ehr/operations/hr-report.js +13 -7
  88. package/dist/shortcuts/ehr/operations/recruit-candidate-import.js +134 -59
  89. package/dist/shortcuts/ehr/operations/recruit-write.js +262 -17
  90. package/dist/shortcuts/ehr/operations/recruit.js +10 -4
  91. package/dist/shortcuts/ehr/operations/shared.js +47 -0
  92. package/dist/shortcuts/hrm/operations/org.js +118 -0
  93. package/dist/shortcuts/index.js +5 -0
  94. package/dist/shortcuts/mail/operations/mail-send.js +8 -2
  95. package/dist/shortcuts/meeting/operations/eb/catalog.js +9 -2
  96. package/dist/shortcuts/meeting/operations/eb/create-flow.js +461 -127
  97. package/dist/shortcuts/meeting/operations/eb/crm-search.js +87 -5
  98. package/dist/shortcuts/meeting/operations/eb/factory.js +33 -0
  99. package/dist/shortcuts/meeting/operations/eb/flow-memory.js +49 -0
  100. package/dist/shortcuts/meeting/operations/eb/group-chat.js +605 -0
  101. package/dist/shortcuts/meeting/operations/eb/index.js +2 -0
  102. package/dist/shortcuts/meeting/operations/eb/person-cache.js +96 -0
  103. package/dist/shortcuts/meeting/operations/eb/room-recommend.js +44 -6
  104. package/dist/shortcuts/meeting/operations/eb/room-summary.js +2 -0
  105. package/dist/shortcuts/meeting/operations/eb/usage-cache.js +99 -0
  106. package/dist/shortcuts/meeting/operations/from-group-chat.js +35 -12
  107. package/dist/shortcuts/project/operations/read.js +6 -25
  108. package/dist/shortcuts/project/operations/shared.js +22 -0
  109. package/dist/shortcuts/project/operations/write.js +28 -2
  110. package/dist/shortcuts/recruit-stage/context.js +119 -0
  111. package/dist/shortcuts/recruit-stage/continuation.js +73 -0
  112. package/dist/shortcuts/recruit-stage/errors.js +65 -0
  113. package/dist/shortcuts/recruit-stage/host.js +109 -0
  114. package/dist/shortcuts/recruit-stage/index.js +115 -0
  115. package/dist/shortcuts/recruit-stage/manifest.js +29 -0
  116. package/dist/shortcuts/recruit-stage/operations/interview-arrange.js +722 -0
  117. package/dist/shortcuts/recruit-stage/operations/interview-feedback.js +269 -0
  118. package/dist/shortcuts/recruit-stage/operations/jd-create.js +630 -0
  119. package/dist/shortcuts/recruit-stage/operations/list.js +431 -0
  120. package/dist/shortcuts/recruit-stage/operations/registry.js +38 -0
  121. package/dist/shortcuts/recruit-stage/operations/resume-import.js +1198 -0
  122. package/dist/shortcuts/recruit-stage/operations/search.js +158 -0
  123. package/dist/shortcuts/recruit-stage/operations/types.js +25 -0
  124. package/dist/shortcuts/recruit-stage/school-tiers.json +318 -0
  125. package/dist/shortcuts/recruit-stage/shared.js +608 -0
  126. package/dist/shortcuts/workflow/operations/form.js +21 -2
  127. package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupRules.js +52 -1
  128. package/dist/shortcuts/workflow/operations/todoSmartConvert/detailFieldRules.js +4 -2
  129. package/dist/shortcuts/workflow/operations/todoSmartConvert/summaryCache.js +19 -11
  130. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailCache.js +17 -24
  131. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailFetcher.js +14 -9
  132. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +78 -10
  133. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.core.js +3 -1
  134. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.detail.js +17 -11
  135. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.group.js +16 -40
  136. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +3 -2
  137. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +52 -15
  138. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.pipeline.js +16 -1
  139. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +151 -63
  140. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.subGroup.js +56 -0
  141. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +53 -16
  142. package/docs/e10-auth.md +22 -1
  143. package/docs/operation-manual.md +8 -0
  144. package/package.json +1 -1
  145. package/scripts/install-skill-to-xiaoe.mjs +105 -0
  146. package/scripts/mcp-meeting.mjs +234 -0
  147. package/scripts/package-skill.mjs +4 -2
  148. package/skill-template/business-info.json +24 -0
  149. package/skill-template/domains/recruit-stage.md +29 -0
  150. package/skills/weaver-e10-calendar/SKILL.md +2 -1
  151. package/skills/weaver-e10-calendar/references/calendar-write.md +54 -0
  152. package/skills/weaver-e10-cowork/SKILL.md +1 -1
  153. package/skills/weaver-e10-cowork/references/cowork-write.md +3 -1
  154. package/skills/weaver-e10-jucailin/SKILL.md +1 -1
  155. package/skills/weaver-e10-jucailin/references/attend-write.md +8 -0
  156. package/skills/weaver-e10-jucailin/references/hr-contact.md +8 -0
  157. package/skills/weaver-e10-jucailin/references/hr-report.md +8 -0
  158. package/skills/weaver-e10-jucailin/references/recruit-create.md +2 -2
  159. package/skills/weaver-e10-jucailin/references/recruit-read.md +1 -1
  160. package/skills/weaver-e10-jucailin/references/recruit-write.md +4 -3
  161. package/skills/weaver-e10-mail/SKILL.md +1 -1
  162. package/skills/weaver-e10-mail/references/mail-send.md +2 -0
  163. package/skills/weaver-e10-meeting/SKILL.md +119 -26
  164. package/skills/weaver-e10-meeting/references/meeting-minute-file.md +25 -11
  165. package/skills/weaver-e10-meeting.zip +0 -0
  166. package/skills/weaver-e10-recruit-stage/SKILL.md +226 -0
  167. package/skills/weaver-e10-recruit-stage/agents/openai.yaml +119 -0
  168. package/skills/weaver-e10-recruit-stage/lib/recruit-xiaoe-file.mjs +188 -0
  169. package/skills/weaver-e10-recruit-stage/references/recruit-arrange-interview.md +322 -0
  170. package/skills/weaver-e10-recruit-stage/references/recruit-capability-check.md +127 -0
  171. package/skills/weaver-e10-recruit-stage/references/recruit-check-install.md +65 -0
  172. package/skills/weaver-e10-recruit-stage/references/recruit-detail-process.md +63 -0
  173. package/skills/weaver-e10-recruit-stage/references/recruit-edit-interview-feedback.md +142 -0
  174. package/skills/weaver-e10-recruit-stage/references/recruit-jd-create.md +73 -0
  175. package/skills/weaver-e10-recruit-stage/references/recruit-jd-template.md +56 -0
  176. package/skills/weaver-e10-recruit-stage/references/recruit-list-candidate.md +101 -0
  177. package/skills/weaver-e10-recruit-stage/references/recruit-list-interview.md +148 -0
  178. package/skills/weaver-e10-recruit-stage/references/recruit-match-candidates.md +77 -0
  179. package/skills/weaver-e10-recruit-stage/references/recruit-output-links.md +59 -0
  180. package/skills/weaver-e10-recruit-stage/references/recruit-resolve-creator.md +69 -0
  181. package/skills/weaver-e10-recruit-stage/references/recruit-resolve-metadata.md +241 -0
  182. package/skills/weaver-e10-recruit-stage/references/recruit-resume-import.md +438 -0
  183. package/skills/weaver-e10-recruit-stage/references/recruit-resume-parse.md +128 -0
  184. package/skills/weaver-e10-recruit-stage/references/recruit-search-candidate.md +146 -0
  185. package/skills/weaver-e10-recruit-stage/references/recruit-urge-feedback.md +69 -0
  186. package/skills/weaver-e10-shared/SKILL.md +2 -2
  187. package/skills/weaver-e10-shared/references/e10-auth-and-session.md +4 -2
  188. package/skills/weaver-e10-shijingran/SKILL.md +3 -2
  189. package/skills/weaver-e10-shijingran/references/operations.md +3 -1
  190. package/skills/weaver-e10-shijingran/references/source-manifest.json +41 -40
  191. package/skills/weaver-e10-shijingran/references/write-operations.md +2 -0
  192. package/skills/weaver-e10-workflow/SKILL.md +7 -1
  193. package/skills/weaver-e10-workflow/aigroup/default.json +23 -9
  194. package/skills/weaver-e10-workflow/references/todo-smart-convert.md +37 -21
  195. package/skills/weaver-e10-workflow/tools/todo-summary.cjs +135 -43
  196. package/skills/weaver-e10-yepiaotong/SKILL.md +9 -10
  197. package/skills/weaver-e10-yepiaotong/references/invoice-agent-entry.md +6 -3
@@ -20,6 +20,18 @@ function needAiSummary(workflowName) {
20
20
  function requestMaxCharsFor(args, workflowName) {
21
21
  return readBoundedInt(args.summaryMaxChars ?? activeRuleFor(workflowName)?.summaryMaxChars, 'summaryMaxChars', DEFAULT_REQUEST_SUMMARY_MAX, 10, 500);
22
22
  }
23
+ /**
24
+ * 缓存**命中比对**用的字数口径:只在用户显式传了 `summaryMaxChars`(`--summary-chars`)时返回,
25
+ * 否则返回 undefined(= 不按字数过滤)。
26
+ * 2026-11-02 用户定稿:缓存失效只由 requestSummaryPrompt 调整触发;
27
+ * 规则/默认字数变化(如 50→150)不作废历史摘要,只有用户显式要求不同字数时才重写。
28
+ */
29
+ function explicitMaxCharsFor(args, workflowName) {
30
+ const explicit = args.summaryMaxChars;
31
+ if (explicit === undefined || explicit === null || String(explicit).trim() === '')
32
+ return undefined;
33
+ return requestMaxCharsFor(args, workflowName);
34
+ }
23
35
  /** 该组的单条摘要口径提示(规则 `requestSummaryPrompt`,空串表示没有)。 */
24
36
  function requestPromptFor(workflowName) {
25
37
  return (activeRuleFor(workflowName)?.requestSummaryPrompt ?? '').trim();
@@ -166,7 +178,10 @@ export function collectSummaryUnits(groups) {
166
178
  continue;
167
179
  }
168
180
  const kind = detectBusinessKind(group.title);
169
- if (!needsRequestSummary(kind))
181
+ // 规则 `needSummary:false`(default.json)⇒ 整组不进 AI 批次(标题兜底,见 runSummary)。
182
+ // 2026-11-03 用户定:此前这里只认硬编码业务类型(仅满意度被排除),导致规则里配了 false 的组
183
+ // 仍然生成素材、把「待写摘要」虚报成几百条。
184
+ if (!needAiSummary(group.title) || !needsRequestSummary(kind))
170
185
  continue;
171
186
  for (const item of group.displayItems) {
172
187
  if (item.type === 'group') {
@@ -232,12 +247,14 @@ export async function runSummaryContext(args, env, prefetched) {
232
247
  * 先建 requestId → 工作流组名 的映射,优先组的行查这张表。
233
248
  */
234
249
  const workflowTitleByRequest = new Map();
235
- for (const unit of units) {
236
- if (unit.groupId === 'priority')
250
+ // 从**全部工作流组**建映射(不能用 units:`needSummary:false` 的组不产 unit,但它们在优先组里
251
+ // 仍有副本,缺了映射就会被当成「建议优先处理的流程」⇒ 落 `*` 兜底 ⇒ 误判成需要 AI)。
252
+ for (const group of groups) {
253
+ if (group.topPriority)
237
254
  continue;
238
- for (const row of unit.rows) {
255
+ for (const row of rowsOfGroup(group)) {
239
256
  if (row.requestId && !workflowTitleByRequest.has(row.requestId)) {
240
- workflowTitleByRequest.set(row.requestId, unit.groupTitle);
257
+ workflowTitleByRequest.set(row.requestId, group.title);
241
258
  }
242
259
  }
243
260
  }
@@ -247,7 +264,11 @@ export async function runSummaryContext(args, env, prefetched) {
247
264
  for (const unit of units) {
248
265
  for (const row of unit.rows) {
249
266
  const name = ruleNameForRow(unit, row);
250
- const cached = summaryCache.get(row.requestId, row.lastFeedBackDateTime, requestMaxCharsFor(args, name), promptTagOf(requestPromptFor(name)), materialTagOfRow(row.requestId, row.lastFeedBackDateTime));
267
+ // 规则 `needSummary:false` ⇒ 不取详情、不进批次,摘要由 `runSummary` 用标题兜底
268
+ // (2026-11-03 用户定:优先组副本此前按组名判定,把这批条目也算成了待写)。
269
+ if (!needAiSummary(name))
270
+ continue;
271
+ const cached = summaryCache.get(row.requestId, row.lastFeedBackDateTime, explicitMaxCharsFor(args, name), promptTagOf(requestPromptFor(name)), materialTagOfRow(row.requestId, row.lastFeedBackDateTime));
251
272
  if (cached) {
252
273
  row.summary = cached;
253
274
  prefilled += 1;
@@ -309,6 +330,16 @@ export async function runSummaryContext(args, env, prefetched) {
309
330
  // 摘要缓存已命中(上一步预填)⇒ 不再喂 AI
310
331
  if (prefilledIds.has(row.requestId))
311
332
  continue;
333
+ // 规则 `needSummary:false` ⇒ 标题兜底、不进批次(优先组副本按**原工作流**口径判定)。
334
+ // 2026-11-03:此前只在「详情为空」时才复制标题,规则豁免完全没接,规则 false 的条目照样进批次。
335
+ if (!needAiSummary(ruleNameForRow(unit, row))) {
336
+ if (!(row.summary ?? '').trim()) {
337
+ row.summary = row.requestNameTitle ?? '';
338
+ if ((row.summary ?? '').trim())
339
+ titleCopied += 1;
340
+ }
341
+ continue;
342
+ }
312
343
  const { context, contextAvailable: available } = provider.get(row.requestId);
313
344
  if (!available) {
314
345
  // ★ 详情为空 ⇒ 不喂 AI,summary 直接复制标题(确定性操作,不走模型)。
@@ -475,22 +506,28 @@ export async function runSummary(args, env) {
475
506
  }
476
507
  }
477
508
  const ruleNameForGroup = (group, row) => group.topPriority ? (wfTitleByRequest.get(row?.requestId ?? '') ?? group.title) : group.title;
509
+ /**
510
+ * 逐条按**原工作流口径**判定(2026-11-03 用户定:优先组副本空摘要修复)。
511
+ *
512
+ * 旧实现按「组」判定,且优先组被整组跳过标题兜底——但优先组的组名匹配不到规则(会落到 `*` 兜底,
513
+ * `needSummary` 被当成 true),于是 `needSummary:false` 的条目(如内部留言、安全问题工单)
514
+ * 在优先组里的副本既没走标题兜底、又没走 AI 批次,summary 恒为空 ⇒ 导出闸门拦截。
515
+ * 现在改为逐条解析口径:`needSummary:false` ⇒ 标题兜底(与普通组副本一致),否则读摘要缓存。
516
+ */
478
517
  for (const group of groups) {
479
- if (!needAiSummary(group.title)) {
480
- for (const row of rowsOfGroup(group)) {
481
- if ((row.summary ?? '').trim())
482
- continue;
518
+ for (const row of rowsOfGroup(group)) {
519
+ if ((row.summary ?? '').trim())
520
+ continue;
521
+ const name = ruleNameForGroup(group, row);
522
+ if (!needAiSummary(name)) {
483
523
  row.summary = row.requestNameTitle ?? '';
484
524
  if ((row.summary ?? '').trim())
485
525
  titleSummary += 1;
526
+ continue;
486
527
  }
487
- continue;
488
- }
489
- for (const row of rowsOfGroup(group)) {
490
- if (!row?.requestId || (row.summary ?? '').trim())
528
+ if (!row?.requestId)
491
529
  continue;
492
- const name = ruleNameForGroup(group, row);
493
- const cached = summaryCache.get(row.requestId, row.lastFeedBackDateTime, maxCharsFor(name), promptTagOf(requestPromptFor(name)), materialTagOfRow(row.requestId, row.lastFeedBackDateTime));
530
+ const cached = summaryCache.get(row.requestId, row.lastFeedBackDateTime, explicitMaxCharsFor(args, name), promptTagOf(requestPromptFor(name)), materialTagOfRow(row.requestId, row.lastFeedBackDateTime));
494
531
  if (cached) {
495
532
  row.summary = cached;
496
533
  }
package/docs/e10-auth.md CHANGED
@@ -59,22 +59,43 @@ Chrome/Edge 原生确认框。宿主需要返回特定会话时,可以传
59
59
  结束后页面会自动退回浏览器自定义协议打开方式,不直接显示网络请求错误。
60
60
  智能小 E 统一登录不会经过浏览器,也不会显示“返回智能小 E”弹层;该弹层只属于用户另行显式发起的 `auth login` 浏览器 OAuth。
61
61
 
62
+ HTTPS E10 授权页跳转到 HTTP loopback 是桌面 OAuth 的标准回调方式:它属于浏览器
63
+ 顶层导航,不按 Mixed Content 子资源请求处理。但部分 E10 环境或浏览器安全策略会把
64
+ 回调改成 `https://127.0.0.1:<port>`;由于 CLI 本地监听器是 HTTP,此时浏览器会显示
65
+ `ERR_SSL_PROTOCOL_ERROR`,而旧版本 CLI 会继续等待直到超时。CLI 现在会识别发到 HTTP
66
+ 端口的 TLS ClientHello,在 WorkBuddy/终端立即给出协议错配提示,并保留 30 秒恢复窗口:
67
+ 只把浏览器当前地址开头明确改成 `http://`,保留完整路径和查询参数后回车,即可让同一次
68
+ 登录继续完成;未处理则返回 `authentication/oauth_callback_protocol_mismatch`,不再挂起
69
+ 5 分钟。长期应在 E10 认证服务侧保留传入的 HTTP loopback 回调,不要改写为 HTTPS。
70
+ 若仍收不到回调,再检查 CLI 与浏览器是否在同一台机器,以及 E10 侧的回调白名单。
71
+ 该排查只适用于显式浏览器登录,
72
+ `auth xiaoe` 和业务命令的 XiaoE 自动取登录信息使用独立处理函数,不创建本地 HTTP
73
+ 服务,也不校验或使用 callback 端口。
74
+
62
75
  XiaoE 宿主身份有两种判定入口:桌面客户端由 Agent 根据“智能小 e 客户端”“小 E”、`XiaoE`、`xiaoe-client` 等明确上下文判断,并传入 `--runtime-agent xiaoe`;网页端沿用原有环境变量规则,成对的 `XIAOE_USER_TOKEN` + `XIAOE_DOMAIN` 会被识别为 XiaoE。工作目录、客户端文件、内置 Node.js、历史登录、路径变量或单个凭据变量都不能单独用于判定。判定为 XiaoE 后,Agent 显式执行 `weaver-work-cli auth xiaoe`。
63
76
 
64
77
  CLI 依次尝试成对的平台凭据、npm 包自带的 `scripts/xiaoe_env.py` 兼容路径、宿主 `xiaoeUserData/tokens.py`、桌面 XiaoE 客户端本地会话和 `WEAVER_XIAOE_*` ETEAMSID 映射。客户端会话优先读取 `XIAOE_USER_SETTINGS_PATH`,再从 `XIAOE_ROBOT_DATA_ROOT` / `XIAOE_ROBOT_ROOT` 查找,最后回退 macOS `~/Library/Application Support/XiaoE/Robots/<id>/user_settings.json` 或 Windows `%LOCALAPPDATA%/XiaoE/Robots/<id>/user_settings.json`。这些变量和文件只用于定位凭据,不能用于识别宿主。`XIAOE_DOMAIN` 是 XiaoE/erpa 换票服务地址,不是 E10 登录地址。
65
78
 
66
- E10 目标地址按“显式 `--base-url` → 专用 `WEAVER_XIAOE_*` E10 配置/映射 → 当前 profile → `https://www.e-cology.com.cn`”解析。凭证可用时,CLI 直接保存登录态,保存的 `agentType` 固定为 `XiaoE`。统一登录失败时,所有操作系统都返回 `authentication/xiaoe_credential_unavailable`,不启动浏览器 OAuth。需要浏览器授权时必须另行显式执行 `auth login`。
79
+ E10 目标地址按“显式 `--base-url` → 专用 `WEAVER_XIAOE_*` E10 配置/映射 → 当前 profile → `https://www.e-cology.com.cn`”解析。凭证可用时,CLI 直接保存登录态,保存的 `agentType` 固定为 `XiaoE`。统一登录失败时,所有操作系统都返回 `authentication/xiaoe_credential_unavailable`(若失败全程都是网络错误则返回 `authentication/xiaoe_network_unavailable`,提示“暂时无法连接 E10,请稍后重试”并标记为可重试),不启动浏览器 OAuth。需要浏览器授权时必须另行显式执行 `auth login`。
67
80
 
68
81
  脚本兼容链路会先自动发现桌面 XiaoE 客户端内置 Python(macOS 应用包与 Windows 按用户/全局安装均支持),再回退到系统 `python3`、`/usr/bin/python3`、`python`;Windows 的系统回退顺序为 `python`、`python3`、`py`。可用 `WEAVER_XIAOE_TOKEN_SCRIPT_PYTHON` 精确指定解释器,用 `WEAVER_XIAOE_TOKEN_SCRIPT_PATH` 指定桌面宿主脚本路径(旧名 `XIAOE_TOKEN_SCRIPT_PYTHON` / `XIAOE_TOKEN_SCRIPT_PATH` 仍兼容)。CLI 自带的 `xiaoe_env.py` 位于 npm 包 `scripts/`,不会放入 `weaver-e10-shared` Skill;Skill 包禁止携带或直接执行 Token 脚本。`XIAOE_` 是平台保留前缀,本 CLI 的自定义变量统一使用 `WEAVER_XIAOE_*`。
69
82
 
70
83
  `auth xiaoe` 会先打印不含凭证的 preflight 摘要,给出 `authMode=xiaoe`、`credentialSourceDetected`、`attempted`、各凭据源检测结果和目标 `baseUrl`。进入脚本分支时会打印 `Trying XiaoE token script credential...`;进入内置 Node 会话分支时会打印 `Trying built-in XiaoE client session credential...`。成功结果和后续 `auth status` 会显示 `credentialSourceStep`、`credentialSourceType`、`credentialSourceLabel`。
71
84
 
85
+ XiaoE 换票结果中的 `expiryTimes` 按 Unix 毫秒时间戳持久化。宿主脚本未返回该字段时,CLI 与 XiaoE `tokens.py` 保持一致,按换票成功时间加 2 小时生成。业务命令加载会话后或长进程每次请求前发现当前时间达到 `expiryTimes` 时,会先静默重新换票;换票失败则停止本次业务请求,不会继续发送已知过期的 ETEAMSID。
86
+
87
+ 小 e 换票接口、`teamsCheck` 与本地会话探测都带 15 秒超时(含读响应体)。超时按网络错误处理(`causeCode=ETIMEDOUT`),不会再出现某一步没有上限、把整条命令挂死的情况;`auth status` 之类的富化请求超时后只是放弃更新信息,不影响命令本身。
88
+
72
89
  业务命令缺少可读取的本地会话时,若当前运行时已通过 `XIAOE_*`、`--runtime-agent xiaoe` 等标记识别为 XiaoE,公共会话加载层会先静默尝试统一登录,成功后继续业务操作。失败时返回 `authentication/xiaoe_credential_unavailable`,并明确提示已尝试自动获取。显式 `--auth` 不触发此恢复;未识别到 XiaoE 的首次认证仍需显式选择登录方式。`auth status --no-check` 等本地状态查询不会主动登录。已有 XiaoE 会话被 E10 接口明确拒绝为失效时,公共请求运行时会根据持久化会话的 `agentType` / `loginSource` 静默换票并重放原请求一次;这条路径不依赖 shared Skill、Agent、`XIAOE_*` 或 `--runtime-agent xiaoe`。它不会打印中间登录步骤,不会自动打开浏览器,也不会对流式请求、网络错误、`partial` / `write_uncertain` 做重放。`--runtime-agent xiaoe` 表示当前运行时身份,不携带凭据。WorkBuddy、Codex 及其他智能体首次认证使用 `auth login --base-url <url> --agent_type <agent_type>` 的浏览器 OAuth 流程。
73
90
 
74
91
  无法使用浏览器回调时,可以用 `auth set` 直接写入浏览器中复制到的
75
92
  `ETEAMSID`。命令会调用 `teamsCheck` 解析当前用户、租户和组织信息,并写入
76
93
  E10 兼容的 auth 文件。
77
94
 
95
+ 静默恢复失败时,`authentication/xiaoe_credential_unavailable` 会带 `details` 以便定位而不必复现:`attemptedSteps` 按序记录评估过的凭证通道及结果(如 `platform_token:missing`、`bundled_env_script:failed`、`token_script:disabled`、`environment_map:empty`、`e10_session:failed`),`failures` 按发生顺序保留每一次失败的阶段(`platform_token` / `bundled_env_script` / `token_script` / `client_session` / `teams_check` / `e10_session`)、类别(`network` / `http` / `credential`)以及网络错误的系统错误码 `causeCode`(取自 `error.cause.code`,如 `ECONNREFUSED`、`ETIMEDOUT`)和 HTTP 错误的状态码 `httpStatus`,`lastError` 是最后一条真实原因(已对已知凭据脱敏并截断到 300 字符),并附带解析出的 `baseUrl`、`clientType`、`platformCredentialDetected`、整体归类 `errorKind` 与最后失败阶段 `failureStage`;若票其实换到了、但按 `expiryTimes` 判定为已过期,会额外带 `resultSessionExpired: true`。当且仅当所有失败都是网络错误时,错误改为 `authentication/xiaoe_network_unavailable`、`retryable: true`,文案换成“暂时无法连接 E10,请稍后重试”(此时登录态并未被验证,提示用户重新登录属于误导)。这条路径默认依然完全无输出,需要看每一步的过程日志时给业务命令加 `--verbose`(经 stderr 以 `[debug]` 前缀输出;`--json` 下完全不输出)。
96
+
97
+ 网页端若返回 `details.reason=host_credential_not_injected`,表示沙箱仍带 `XIAOE_CLIENT_TYPE=cloud` 标记,但宿主注入的平台凭据在启动子进程时丢失。这不是 E10 登录损坏,也不能通过重试或浏览器 OAuth 自愈;沙箱启动器必须保留宿主环境并只定向覆盖 `WEAVER_WORK_CLI_AUTH_ROOT` 等测试变量,不得用 `env -i`、空环境字典或不包含 XiaoE 平台凭据的白名单启动 CLI。凭据值不得写入命令、日志或错误详情。
98
+
78
99
  `auth whoami` 默认读取本地缓存,不发网络请求;`auth whoami --live` 会调用
79
100
  `teamsCheck` 获取实时信息。`auth export-weaver-env` 会输出
80
101
  `WEAVER_BASE_URL`、`WEAVER_ETEAMSID`、`WEAVER_COOKIE`、`WEAVER_USER_AGENT` 和
@@ -381,6 +381,14 @@ dist/weaver-e10-<module>-skill.zip
381
381
 
382
382
  打包单个业务模块时会自动包含 `weaver-e10-shared`。zip 用于平台导入、离线分发或版本归档;本机日常安装优先使用 `weaver-work-cli skills install <module>`。
383
383
 
384
+ 若目标环境已装有共享 skill、只需分发业务模块本身,加 `--no-shared`(脚本位置参数之后):
385
+
386
+ ```bash
387
+ node scripts/package-skill.mjs yepiaotong dist/weaver-e10-yepiaotong-only.zip --no-shared
388
+ ```
389
+
390
+ 此时产物内只有业务模块目录,`../weaver-e10-shared/` 的相对引用需由目标环境自行提供。
391
+
384
392
  ## 10. 安装新生成的业务模块 Skill
385
393
 
386
394
  检测通过并得到用户确认后安装:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "weaver-work-cli",
3
- "version": "0.1.39",
3
+ "version": "0.1.42",
4
4
  "description": "面向泛微工作工具链的可扩展 TypeScript CLI 基础框架(E10 业票通等能力)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 把仓库里的 weaver-e10-meeting 技能铺到小E 的 user-skills 目录(一键恢复)。
4
+ *
5
+ * 背景(2026-11-04):小E 的「更新 skill」会从平台技能库拉 2.11.0 覆盖本地,
6
+ * 而且有一次直接把 `user-skills/weaver-e10-meeting` 主目录删了(只剩 .backup-*),
7
+ * 导致模型读到旧版本、按旧规则把用户推去页面手工建会。
8
+ *
9
+ * 用法:node scripts/install-skill-to-xiaoe.mjs
10
+ * 做的事:
11
+ * 1. 找 AppData/Local/xiaoeUserData/userdata/<id>/user-skills;
12
+ * 2. 复制仓库 skills/weaver-e10-meeting 全部文件过去;
13
+ * 3. 保留/恢复 .skill-id(优先原文件 → 备份目录 → base.json 的 id);
14
+ * 4. 把 base.json 里该技能的 version 同步成 SKILL.md frontmatter 的版本。
15
+ */
16
+ import { existsSync, readFileSync, readdirSync, statSync, copyFileSync, mkdirSync, writeFileSync } from 'node:fs';
17
+ import path from 'node:path';
18
+ import { fileURLToPath } from 'node:url';
19
+
20
+ const here = path.dirname(fileURLToPath(import.meta.url));
21
+ const repoRoot = path.resolve(here, '..');
22
+ const skillSrc = path.join(repoRoot, 'skills', 'weaver-e10-meeting');
23
+ const SKILL_NAME = 'weaver-e10-meeting';
24
+
25
+ const localAppData = process.env.LOCALAPPDATA || path.join(process.env.USERPROFILE || '', 'AppData', 'Local');
26
+ const userdataRoot = path.join(localAppData, 'xiaoeUserData', 'userdata');
27
+ if (!existsSync(userdataRoot)) {
28
+ console.error(`找不到小E 数据目录:${userdataRoot}`);
29
+ process.exit(1);
30
+ }
31
+
32
+ const version = (() => {
33
+ const text = readFileSync(path.join(skillSrc, 'SKILL.md'), 'utf8').replace(/\r\n/g, '\n');
34
+ const m = text.match(/^version:\s*(.+)$/m);
35
+ return m ? m[1].trim() : '';
36
+ })();
37
+
38
+ let installed = 0;
39
+ // 2026-11-04 实测:小E 真正加载的是**租户级** `tenant-skills`(优先级更高),
40
+ // `user-skills` 那份会被平台「更新 skill」重置回 2.11.0,所以两个目录都要铺。
41
+ for (const scope of ['tenant-skills', 'user-skills']) {
42
+ for (const userDir of readdirSync(userdataRoot)) {
43
+ const skillsRoot = path.join(userdataRoot, userDir, scope);
44
+ if (!existsSync(skillsRoot)) continue;
45
+ installInto(skillsRoot);
46
+ }
47
+ }
48
+
49
+ function installInto(skillsRoot) {
50
+ const target = path.join(skillsRoot, SKILL_NAME);
51
+
52
+ // 1) 保留原 .skill-id;没有就从备份目录找;再没有就从 base.json 的条目取
53
+ let skillId = '';
54
+ try {
55
+ skillId = readFileSync(path.join(target, '.skill-id'), 'utf8').trim();
56
+ } catch { /* 主目录被删过就没有 */ }
57
+ if (!skillId) {
58
+ const backup = readdirSync(skillsRoot).find((name) => name.startsWith('.backup') && name.includes('meeting'));
59
+ if (backup) {
60
+ try {
61
+ skillId = readFileSync(path.join(skillsRoot, backup, '.skill-id'), 'utf8').trim();
62
+ } catch { /* ignore */ }
63
+ }
64
+ }
65
+ const baseJsonPath = path.join(skillsRoot, 'base.json');
66
+ let base = null;
67
+ if (existsSync(baseJsonPath)) {
68
+ try {
69
+ base = JSON.parse(readFileSync(baseJsonPath, 'utf8'));
70
+ const entry = (base.skills ?? []).find((s) => s.name === SKILL_NAME);
71
+ if (!skillId) skillId = String(entry?.id ?? '');
72
+ } catch { /* ignore */ }
73
+ }
74
+
75
+ // 2) 复制技能文件
76
+ const copyDir = (rel) => {
77
+ const srcDir = path.join(skillSrc, rel);
78
+ const dstDir = path.join(target, rel);
79
+ mkdirSync(dstDir, { recursive: true });
80
+ for (const name of readdirSync(srcDir)) {
81
+ const src = path.join(srcDir, name);
82
+ const dst = path.join(dstDir, name);
83
+ if (statSync(src).isDirectory()) copyDir(rel ? `${rel}/${name}` : name);
84
+ else copyFileSync(src, dst);
85
+ }
86
+ };
87
+ copyDir('');
88
+
89
+ // 3) 写回 .skill-id
90
+ if (skillId) writeFileSync(path.join(target, '.skill-id'), skillId, 'utf8');
91
+
92
+ // 4) 同步 base.json 版本
93
+ if (base) {
94
+ const entry = (base.skills ?? []).find((s) => s.name === SKILL_NAME);
95
+ if (entry) {
96
+ entry.version = version;
97
+ entry.updateTime = Date.now();
98
+ writeFileSync(baseJsonPath, JSON.stringify(base, null, 2), 'utf8');
99
+ }
100
+ }
101
+
102
+ installed += 1;
103
+ console.log(`已铺装:${target}(version=${version},skillId=${skillId || '未取到'})`);
104
+ }
105
+ if (installed === 0) console.error('没有找到可铺装的 user-skills 目录');
@@ -0,0 +1,234 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * weaver-work-cli 会议 MCP 服务器(stdio 传输,零依赖)。
4
+ *
5
+ * 把 CLI 的会议 operation 封装成 MCP tools,供小E / WorkBuddy 等宿主以 MCP 方式调用:
6
+ * {"mcpServers": {"weaver-meeting": {"command": "node", "args": ["<本文件路径>"]}}}
7
+ *
8
+ * 设计原则(2026-11-03 与用户对齐):
9
+ * - **不重新实现业务**:tools/call 内部直接 spawn 现有 CLI(`meeting run <op> --input-json`),
10
+ * 防呆闸门(timeConfirmed/roomConfirmed/confirm)、登录态、占用缓存、流程记忆全部原样继承;
11
+ * - **工具少而清晰**:MCP 工具发现靠模型读 tool schema,工具越多越乱 —— 只暴露 3 个高频动作;
12
+ * - **零依赖**:MCP stdio 就是 JSON-RPC 2.0(每行一个 JSON),手写握手即可,不引 SDK
13
+ * (私服有坏包前科,bundle 链路也不动)。
14
+ *
15
+ * 手工自测:
16
+ * printf '%s\n%s\n%s\n' \
17
+ * '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"t","version":"0"}}}' \
18
+ * '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
19
+ * '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | node scripts/mcp-meeting.mjs
20
+ */
21
+
22
+ import { spawn } from 'node:child_process';
23
+ import { createInterface } from 'node:readline';
24
+ import { fileURLToPath } from 'node:url';
25
+ import path from 'node:path';
26
+ import { existsSync } from 'node:fs';
27
+
28
+ const SERVER_INFO = { name: 'weaver-meeting', version: '1.0.0' };
29
+ const PROTOCOL_VERSION = '2024-11-05';
30
+
31
+ // CLI 入口:优先同目录的 dist(打包后 scripts/ 与 dist/ 同级),找不到再试仓库根
32
+ const here = path.dirname(fileURLToPath(import.meta.url));
33
+ const candidates = [
34
+ path.resolve(here, '..', 'dist', 'index.js'),
35
+ path.resolve(here, '..', '..', 'dist', 'index.js'),
36
+ ];
37
+ const CLI_ENTRY = candidates.find((p) => existsSync(p));
38
+ if (!CLI_ENTRY) {
39
+ console.error(JSON.stringify({ error: `找不到 CLI 入口,试过:${candidates.join(', ')}` }));
40
+ process.exit(1);
41
+ }
42
+
43
+ /** 调用现有 CLI:一行 JSON 进,一行 JSON 出。 */
44
+ async function callCli(operation, input) {
45
+ return new Promise((resolve) => {
46
+ const child = spawn(process.execPath, [
47
+ CLI_ENTRY, '--json', 'meeting', 'run', operation, '--input-json', JSON.stringify(input ?? {}),
48
+ ], { windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'] });
49
+ let stdout = '';
50
+ let stderr = '';
51
+ child.stdout.on('data', (chunk) => { stdout += String(chunk); });
52
+ child.stderr.on('data', (chunk) => { stderr += String(chunk); });
53
+ child.on('close', () => {
54
+ try {
55
+ resolve(JSON.parse(stdout));
56
+ } catch {
57
+ resolve({
58
+ ok: false,
59
+ error: { type: 'mcp', message: `CLI 输出不是 JSON(stderr: ${stderr.slice(0, 200)};stdout: ${stdout.slice(0, 200)})` },
60
+ });
61
+ }
62
+ });
63
+ child.on('error', (error) => {
64
+ resolve({ ok: false, error: { type: 'mcp', message: `CLI 启动失败:${error.message}` } });
65
+ });
66
+ });
67
+ }
68
+
69
+ /** 把 CLI 的返回压成 MCP text content(大 JSON 直接塞给模型会撑上下文,这里挑关键域)。 */
70
+ function summarize(result) {
71
+ const data = result?.data ?? {};
72
+ const brief = {
73
+ ok: result?.ok === true,
74
+ ...(result?.ok ? {} : { error: result?.error }),
75
+ status: data.status,
76
+ meetingId: data.meetingId ?? undefined,
77
+ requestId: data.requestId ?? undefined,
78
+ workflowPending: data.workflowPending,
79
+ message: typeof data.message === 'string' ? data.message.slice(0, 400) : undefined,
80
+ // 选项类返回(时段/流程/会议室挑选)必须原样带给模型 —— 用户要在选项里点选
81
+ options: Array.isArray(data.options) ? data.options.slice(0, 6) : undefined,
82
+ timings: data.timings,
83
+ };
84
+ return { content: [{ type: 'text', text: JSON.stringify(brief, null, 1) }] };
85
+ }
86
+
87
+ // ---------------------------------------------------------------------------
88
+ // 工具清单:3 个高频动作,schema 直接搬 CLI 入参的精简版(描述要自足,模型只看得到这里)
89
+ // ---------------------------------------------------------------------------
90
+ const TOOLS = [
91
+ {
92
+ name: 'meeting_book_room',
93
+ description: '预订会议室(泛微 E10 EB 版):发起建会流程并**服务端直提**,不弹流程表单。'
94
+ + '时间/会议室必须来自用户原话或在候选里点选的结果——'
95
+ + '时间要传 timeConfirmed: true、会议室要传 roomConfirmed: true 才会真正提交,否则返回候选让用户挑。'
96
+ + 'submit=false 时只做预检与推荐(不提交、不弹表单);submit=true 直接提交流程(同样不弹表单)。',
97
+ inputSchema: {
98
+ type: 'object',
99
+ properties: {
100
+ mt_subject: { type: 'string', description: '会议名称/主题(必填)' },
101
+ begin_datetime: { type: 'string', description: '开始时间 yyyy-MM-dd HH:mm(必填,须来自用户确认)' },
102
+ end_datetime: { type: 'string', description: '结束时间 yyyy-MM-dd HH:mm' },
103
+ timeConfirmed: { type: 'boolean', description: '用户原话明确了时间、或在候选中点选后才传 true' },
104
+ address: { type: 'string', description: '会议室 id 或名称' },
105
+ roomConfirmed: { type: 'boolean', description: '用户明确指定该会议室、或点选后才传 true' },
106
+ mt_type: { type: 'string', description: '会议类型名称(流程表单必填项)' },
107
+ extraFields: { type: 'object', description: '流程表单的其他必填字段(按字段标签传,如 {"会议内容":"..."})' },
108
+ submit: { type: 'boolean', description: 'false=只出方案不提交(默认);true=直接提交流程(不弹表单)' },
109
+ },
110
+ required: ['mt_subject', 'begin_datetime'],
111
+ },
112
+ },
113
+ {
114
+ name: 'meeting_room_list',
115
+ description: '查询会议室列表(EB 版,含状态)。可按人数/关键词过滤。',
116
+ inputSchema: {
117
+ type: 'object',
118
+ properties: {
119
+ keyword: { type: 'string', description: '会议室名称关键词' },
120
+ pageSize: { type: 'number', description: '每页条数,默认 20' },
121
+ },
122
+ },
123
+ },
124
+ {
125
+ name: 'meeting_room_usage',
126
+ description: '查询某天某会议室(或不指定则全部会议室)的占用明细,用于回答"这个会议室明天有没有空"。',
127
+ inputSchema: {
128
+ type: 'object',
129
+ properties: {
130
+ day: { type: 'string', description: '日期 yyyy-MM-dd(必填)' },
131
+ address: { type: 'string', description: '会议室 id;不传 = 返回当天全部会议室占用' },
132
+ },
133
+ required: ['day'],
134
+ },
135
+ },
136
+ ];
137
+
138
+ async function handleToolCall(name, args) {
139
+ if (name === 'meeting_book_room') {
140
+ const input = {
141
+ // ⛔ CLI 的语义键是 mt_name(FIELD_ALIASES 里「会议名称/会议主题/主题」都挂在它下面),
142
+ // mt_subject 不是合法入参 —— MCP 层做一次转换,别把模型给的名称弄丢。
143
+ mt_name: args.mt_subject ?? args.mt_name,
144
+ begin_datetime: args.begin_datetime,
145
+ ...(args.end_datetime ? { end_datetime: args.end_datetime } : {}),
146
+ ...(args.timeConfirmed ? { timeConfirmed: true } : {}),
147
+ ...(args.address ? { address: args.address } : {}),
148
+ ...(args.roomConfirmed ? { roomConfirmed: true } : {}),
149
+ ...(args.mt_type ? { mt_type: args.mt_type } : {}),
150
+ ...(args.extraFields && typeof args.extraFields === 'object' ? { extraFields: args.extraFields } : {}),
151
+ // MCP 口径(2026-11-03 用户确认):预约会议 = 直提流程,**永不弹流程表单**;
152
+ // 提交必须 confirm + submit_mode:direct,预检则不带 confirm(CLI 返回方案,同样不弹表单)。
153
+ ...(args.submit === true ? { confirm: true, submit_mode: 'direct' } : {}),
154
+ };
155
+ return summarize(await callCli('meeting.eb.meeting.create.flow.quick', input));
156
+ }
157
+ if (name === 'meeting_room_list') {
158
+ return summarize(await callCli('meeting.eb.room.list', {
159
+ ...(args.keyword ? { keyword: args.keyword } : {}),
160
+ ...(args.pageSize ? { pageSize: args.pageSize } : {}),
161
+ }));
162
+ }
163
+ if (name === 'meeting_room_usage') {
164
+ const day = String(args.day ?? '').slice(0, 10);
165
+ const input = args.address
166
+ ? { beginDatetime: `${day} 00:00`, endDatetime: `${day} 23:59`, address: args.address }
167
+ : { begindatetime: `${day} 00:00`, enddatetime: `${day} 23:59`, pageSize: 200 };
168
+ const op = args.address ? 'meeting.eb.conflict.room' : 'meeting.eb.roomUsage.list';
169
+ return summarize(await callCli(op, input));
170
+ }
171
+ return { content: [{ type: 'text', text: `未知工具:${name}` }], isError: true };
172
+ }
173
+
174
+ // ---------------------------------------------------------------------------
175
+ // JSON-RPC over stdio(每行一个消息)
176
+ // ---------------------------------------------------------------------------
177
+ const rl = createInterface({ input: process.stdin });
178
+ const send = (message) => process.stdout.write(`${JSON.stringify(message)}\n`);
179
+ // stdin 关闭(宿主不再发消息)时要等在途的 tools/call 跑完再退——CLI 调用要十几秒,不能被杀
180
+ let pendingCalls = 0;
181
+ let stdinClosed = false;
182
+
183
+ rl.on('line', (line) => {
184
+ const text = line.trim();
185
+ if (text === '') return;
186
+ let message;
187
+ try {
188
+ message = JSON.parse(text);
189
+ } catch {
190
+ return; // 非 JSON 行(人话日志)直接忽略
191
+ }
192
+ const { id, method, params } = message ?? {};
193
+ if (method === 'initialize') {
194
+ send({
195
+ jsonrpc: '2.0', id,
196
+ result: {
197
+ protocolVersion: PROTOCOL_VERSION,
198
+ capabilities: { tools: { listChanged: false } },
199
+ serverInfo: SERVER_INFO,
200
+ },
201
+ });
202
+ return;
203
+ }
204
+ if (method === 'notifications/initialized' || (method ?? '').startsWith('notifications/')) return;
205
+ if (method === 'tools/list') {
206
+ send({ jsonrpc: '2.0', id, result: { tools: TOOLS } });
207
+ return;
208
+ }
209
+ if (method === 'tools/call') {
210
+ pendingCalls += 1;
211
+ handleToolCall(String(params?.name ?? ''), params?.arguments ?? {})
212
+ .then((result) => send({ jsonrpc: '2.0', id, result }))
213
+ .catch((error) => send({
214
+ jsonrpc: '2.0', id,
215
+ result: { content: [{ type: 'text', text: `工具执行异常:${error.message}` }], isError: true },
216
+ }))
217
+ .finally(() => {
218
+ pendingCalls -= 1;
219
+ if (stdinClosed && pendingCalls === 0) process.exit(0);
220
+ });
221
+ return;
222
+ }
223
+ if (method === 'ping') {
224
+ send({ jsonrpc: '2.0', id, result: {} });
225
+ return;
226
+ }
227
+ if (id !== undefined) {
228
+ send({ jsonrpc: '2.0', id, error: { code: -32601, message: `method not found: ${method}` } });
229
+ }
230
+ });
231
+ rl.on('close', () => {
232
+ if (pendingCalls === 0) process.exit(0);
233
+ stdinClosed = true; // 在途调用完成后自行退出(见 tools/call 的 finally)
234
+ });
@@ -15,7 +15,9 @@ const packageJsonPath = path.join(repositoryRoot, 'package.json')
15
15
  const sharedSkillName = 'weaver-e10-shared'
16
16
  const skillPrefix = 'weaver-e10-'
17
17
  const legacySkillPrefix = 'weaver-work-cli-'
18
- const [requestedSkillArg, outputArg] = process.argv.slice(2)
18
+ const rawArgs = process.argv.slice(2)
19
+ const includeShared = !rawArgs.includes('--no-shared')
20
+ const [requestedSkillArg, outputArg] = rawArgs.filter((arg) => !arg.startsWith('--'))
19
21
 
20
22
  function sha256(value) {
21
23
  return createHash('sha256').update(value).digest('hex')
@@ -59,7 +61,7 @@ async function resolveSkillNames() {
59
61
  if (!requestedSkill) return allSkills
60
62
  if (!allSkills.includes(requestedSkill)) throw new Error(`未知 Skill:${requestedSkill}`)
61
63
  const names = []
62
- if (requestedSkill !== sharedSkillName && allSkills.includes(sharedSkillName)) names.push(sharedSkillName)
64
+ if (includeShared && requestedSkill !== sharedSkillName && allSkills.includes(sharedSkillName)) names.push(sharedSkillName)
63
65
  names.push(requestedSkill)
64
66
  return names
65
67
  }
@@ -249,6 +249,30 @@
249
249
  "表单分页",
250
250
  "表单详情"
251
251
  ],
252
+ "weaver-e10-recruit-stage": [
253
+ "招聘",
254
+ "招聘助手",
255
+ "招聘启事",
256
+ "招聘岗位",
257
+ "JD",
258
+ "岗位JD",
259
+ "职位",
260
+ "简历",
261
+ "简历解析",
262
+ "简历建档",
263
+ "人才",
264
+ "人才库",
265
+ "候选人",
266
+ "人岗匹配",
267
+ "筛选候选人",
268
+ "面试",
269
+ "AI面试",
270
+ "安排面试",
271
+ "面试安排",
272
+ "面试反馈",
273
+ "面试官",
274
+ "催促面试评价"
275
+ ],
252
276
  "weaver-e10-shared": [
253
277
  "安装",
254
278
  "登录",
@@ -0,0 +1,29 @@
1
+ 本业务域用于泛微 E10 的**招聘阶段业务**(招聘启事生成、简历建档与人岗匹配、AI 面试邀约与反馈)。入口 `SKILL.md` 先路由到 `weaver-e10-shared/SKILL.md`,再给出任务编排名、Reference 路由表、固定参数表与执行纪律。业务能力全部由 `weaver-work-cli` 的 `recruit-stage` 模块提供(13 个 operation),具体接口契约与命令参数拆到 `references/`:
2
+
3
+ - `recruit-check-install.md`:第 0 步闸门,按应用标签取 appId,判断招聘服务是否已部署。
4
+ - `recruit-capability-check.md`:运行时能力探测(有哪些菜单/表单/接口),不按版本号硬编码。
5
+ - `recruit-resolve-metadata.md`:租户参数(objId / formId / listId / appId / 菜单 / 字段 id)的 tag 链解析与缓存。
6
+ - `recruit-resolve-creator.md`:创建人、成员、面试官等人员名称到 EB 用户 ID 的解析。
7
+ - `recruit-jd-create.md`:招聘启事/JD 生成到建职位的 `prepare -> apply` 写入流程。
8
+ - `recruit-jd-template.md`:招聘启事与岗位 JD 的企业标准文案模板(可整体替换)。
9
+ - `recruit-resume-parse.md`:简历 OCR 解析(仅在 AI 无法解析原件时兜底)。
10
+ - `recruit-resume-import.md`:简历导入建人才,含附件上传、查重与标签策略。
11
+ - `recruit-search-candidate.md`:按手机号/姓名/邮箱搜索人才库,取 `talentId`。
12
+ - `recruit-list-candidate.md`:应聘者台账(按职位/批次筛选)。
13
+ - `recruit-list-interview.md`:面试管理列表(近 N 天、待反馈)。
14
+ - `recruit-arrange-interview.md`:安排面试的动作链(含 AI 面试方案必填口径)。
15
+ - `recruit-edit-interview-feedback.md`:提交/修改面试反馈的组合写操作。
16
+ - `recruit-urge-feedback.md`:催促面试官填写评价(会触达真人,需用户明确同意)。
17
+ - `recruit-detail-process.md`:应聘过程卡片(辅助,默认不展示)。
18
+ - `recruit-match-candidates.md`:人岗匹配打分口径与候选人评分卡结构。
19
+ - `recruit-output-links.md`:查看类产物的 Markdown 双链接契约。
20
+
21
+ 调优重点:
22
+
23
+ - `weaver-work-cli recruit-stage schema` 是 operation 合约第一信息源,禁止把源文档里的 HTTP 路径当成可直接调用的地址。
24
+ - 字段 id / 枚举 / 菜单 / appId 全部五层上下文运行时解析并缓存,换环境不需要改技能。
25
+ - 写操作只接受 CLI 生成的 continuation,`prepare` 摘要未经用户明确确认不得 `apply`;`apply` 不自动重试。
26
+ - AI 面试的方案(digital_id)与邮箱必填,`prepare` 未带方案时列候选让用户选,绝不自动取第一条。
27
+ - 姓名/手机号模糊命中多人时列候选让用户确认,禁止自动取第一条;命中 0 条时如实说明,不臆造。
28
+ - 产物只用普通 Markdown 链接(viewLink / listLocateLink / talentCardUrl),不用 browsertool 卡片、不用右栏 iframe。
29
+ - 结果为 `partial` / `write_uncertain` 时停止写入,先做只读回查再向用户说明。
@@ -5,7 +5,7 @@ display_name_en: Weaver E10 Calendar
5
5
  description: 泛微E10日程管理的查询与写操作能力,支持创建、查询列表、查询详情、查询总数、更新、删除日程,查询日程类型与紧急程度,以及应用版本检测,通过 weaver-work-cli calendar 命令执行。
6
6
  description_zh: 泛微E10日程管理的查询与写操作能力,支持创建、查询列表、查询详情、查询总数、更新、删除日程,查询日程类型与紧急程度,以及应用版本检测,通过 weaver-work-cli calendar 命令执行。
7
7
  description_en: Weaver E10 calendar capabilities, including create, list, get, count, update and delete schedules, query schedule type and priority dictionaries, and check app version, delivered through the weaver-work-cli calendar command.
8
- version: 1.1.0
8
+ version: 1.2.2
9
9
  author: 泛微网络科技股份有限公司
10
10
  agent_created: true
11
11
  requires:
@@ -60,6 +60,7 @@ weaver-work-cli --json calendar run <operation> --input-json '{"key":"value"}'
60
60
 
61
61
  - **参与人默认带当前人**:未传 `participants` 时,CLI 自动用当前登录用户;额外指定他人时当前人仍默认包含,除非用户明确表示自己不参与。
62
62
  - **时长默认 1 小时**:只传 `start_time` 未传 `end_time` 时,CLI 自动补 `end_time = start_time + 1 小时`。
63
+ - **默认不提醒、不重复**:用户未指定时提醒保持关闭(不传 `remind`),重复为不重复(`NONE`),不要替用户默认开启提醒或重复。
63
64
  - **更新为全量覆盖**:`calendar.update.prepare` 会先查询当前日程详情并合并用户修改,避免遗漏字段。
64
65
  - **列表默认一页**:`page_no`/`page_size` 默认 1/10,不自动翻页。
65
66