weaver-work-cli 0.1.32 → 0.1.33

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 (185) hide show
  1. package/README.md +2 -2
  2. package/dist/chunks/{archive-UMGX72K6.js → archive-FVFY6GZN.js} +2 -2
  3. package/dist/chunks/{archive-oa-N2IYBLF3.js → archive-oa-NW3OD4UV.js} +2 -2
  4. package/dist/chunks/{asset-GLEGKFG5.js → asset-7QJKMIDV.js} +2 -2
  5. package/dist/chunks/{attachment-content-AQNX5N3S.js → attachment-content-OSAVA6K3.js} +3 -2
  6. package/dist/chunks/{blog-E44OTVDA.js → blog-I7SDPNW4.js} +2 -2
  7. package/dist/chunks/{caizhilian-DQUFZXZL.js → caizhilian-O37ZIQNY.js} +2 -2
  8. package/dist/chunks/{calendar-JKPIRKFD.js → calendar-7KXE4ED3.js} +2 -2
  9. package/dist/chunks/{chunk-4YC43QQ4.js → chunk-2FLWXFVS.js} +4 -4
  10. package/dist/chunks/{chunk-QWY6PGL6.js → chunk-2LV74IWP.js} +361 -56
  11. package/dist/chunks/chunk-3SO6QL6U.js +73 -0
  12. package/dist/chunks/{chunk-DW6AUUKS.js → chunk-6ATGWRZM.js} +6 -4
  13. package/dist/chunks/chunk-BYATLLEF.js +68 -0
  14. package/dist/chunks/chunk-BYBSCN4X.js +932 -0
  15. package/dist/chunks/{chunk-2GA5ZIQL.js → chunk-D223PTXU.js} +1 -0
  16. package/dist/chunks/{chunk-H7J4DC5R.js → chunk-EEWPQE3O.js} +2 -2
  17. package/dist/chunks/{chunk-6RKD4DRZ.js → chunk-GFPXQIY2.js} +2 -2
  18. package/dist/chunks/{chunk-C6R3B2ML.js → chunk-HEL5XTYI.js} +12 -6
  19. package/dist/chunks/{chunk-CVZ2JOSW.js → chunk-IHUYP6LO.js} +1 -1
  20. package/dist/chunks/{chunk-YRVDW4WN.js → chunk-ILMBNVSG.js} +2 -2
  21. package/dist/chunks/{chunk-G3QJULO2.js → chunk-KAS45KNR.js} +1 -1
  22. package/dist/chunks/{chunk-H6XSTSLM.js → chunk-MEEFGWTM.js} +54 -196
  23. package/dist/chunks/{chunk-GCG2NMWR.js → chunk-MQ2I5AA3.js} +4 -2
  24. package/dist/chunks/chunk-NHA62QD7.js +774 -0
  25. package/dist/chunks/{chunk-WKI2FBIQ.js → chunk-OCU4RLHC.js} +641 -309
  26. package/dist/chunks/{chunk-WSKBSQ2U.js → chunk-PRHJGPMA.js} +2 -2
  27. package/dist/chunks/{chunk-6EFWDL7Y.js → chunk-Q6LWB5HX.js} +2 -2
  28. package/dist/chunks/{chunk-IURUFGZK.js → chunk-RBGOMK4Y.js} +50 -33
  29. package/dist/chunks/chunk-VBCFFFGT.js +226 -0
  30. package/dist/chunks/{ebuilder-form-V5FG2EHC.js → chunk-WRRJ4GG2.js} +22 -1148
  31. package/dist/chunks/{chunk-E4Z23GHM.js → chunk-WY74UBJ6.js} +264 -750
  32. package/dist/chunks/conflict-SFNEVJY5.js +21 -0
  33. package/dist/chunks/continuation-RN6PZN2M.js +11 -0
  34. package/dist/chunks/cowork-CKWYHXYB.js +2508 -0
  35. package/dist/chunks/ebuilder-form-KOLJRVZD.js +121 -0
  36. package/dist/chunks/{ehr-HMFY6VIL.js → ehr-WFOC3B4D.js} +1174 -20
  37. package/dist/chunks/{esb-ZYSVB7SG.js → esb-LJZTN663.js} +4 -4
  38. package/dist/chunks/{fna-B7RKPAZD.js → fna-F7QRIIZC.js} +2 -2
  39. package/dist/chunks/{host-45WED2KK.js → host-BCGUVEWX.js} +3 -3
  40. package/dist/chunks/host-BQBRHVR3.js +23 -0
  41. package/dist/chunks/{host-I4Z6BFYX.js → host-DGE2TZD4.js} +3 -3
  42. package/dist/chunks/{host-KNZ52LJZ.js → host-KXPTEWFS.js} +3 -3
  43. package/dist/chunks/{host-OCH2BCCV.js → host-VQ6JJXGQ.js} +3 -3
  44. package/dist/chunks/{hrm-2KAZGUHI.js → hrm-NI6XAKW5.js} +3 -3
  45. package/dist/chunks/{im-ACJJWH4U.js → im-7TRTF3KT.js} +88 -12
  46. package/dist/chunks/{invoice-ZK3WCX2U.js → invoice-AOXWJKYT.js} +3 -3
  47. package/dist/chunks/{jiuchuanhui-5PQD3IL2.js → jiuchuanhui-7NQWEZAW.js} +2 -2
  48. package/dist/chunks/{lazy-dispatch-JQXBW3GM.js → lazy-dispatch-RNS4EE4S.js} +4 -4
  49. package/dist/chunks/{mail-S2HDDXO2.js → mail-VDHJAB4O.js} +3 -3
  50. package/dist/chunks/{meeting-QVN3I37L.js → meeting-GA7XCNNP.js} +214 -43
  51. package/dist/chunks/{okr-QNG4VC2Q.js → okr-TQIRERPQ.js} +2 -2
  52. package/dist/chunks/operations-5QL3AECO.js +11 -0
  53. package/dist/chunks/{plan-A25EMW6U.js → plan-4RY4LN2P.js} +2 -2
  54. package/dist/chunks/{project-G6XV66DZ.js → project-D6XT2OC5.js} +2 -2
  55. package/dist/chunks/{registry-DC6KR3NH.js → registry-JHRIDQ3A.js} +4 -4
  56. package/dist/chunks/{registry-2VLUAESA.js → registry-OZSMDVPP.js} +2 -2
  57. package/dist/chunks/{registry-TI3CIUXF.js → registry-QKMI43Q6.js} +8 -6
  58. package/dist/chunks/{registry-7C5UMIPL.js → registry-VOGKFFTR.js} +2 -2
  59. package/dist/chunks/{room-recommend-WRTHO6Y2.js → room-recommend-D4EUOOWY.js} +4 -3
  60. package/dist/chunks/{schedule-KFIITGSK.js → schedule-XPFBHPCV.js} +4 -3
  61. package/dist/chunks/{workflow-DJ7SYWAF.js → workflow-HLBZRWIY.js} +172 -6
  62. package/dist/index.js +30 -25
  63. package/dist/internal/e10/auth-recovery.js +14 -4
  64. package/dist/shortcuts/contract/host.js +34 -59
  65. package/dist/shortcuts/cowork/continuation.js +70 -0
  66. package/dist/shortcuts/cowork/errors.js +59 -0
  67. package/dist/shortcuts/cowork/host.js +172 -0
  68. package/dist/shortcuts/cowork/index.js +166 -0
  69. package/dist/shortcuts/cowork/manifest.js +65 -0
  70. package/dist/shortcuts/cowork/operations/discuss-write.js +277 -0
  71. package/dist/shortcuts/cowork/operations/item-write.js +380 -0
  72. package/dist/shortcuts/cowork/operations/member-write.js +283 -0
  73. package/dist/shortcuts/cowork/operations/permission-write.js +286 -0
  74. package/dist/shortcuts/cowork/operations/read.js +423 -0
  75. package/dist/shortcuts/cowork/operations/registry.js +39 -0
  76. package/dist/shortcuts/cowork/operations/review-write.js +157 -0
  77. package/dist/shortcuts/cowork/operations/shared.js +215 -0
  78. package/dist/shortcuts/cowork/operations/types.js +24 -0
  79. package/dist/shortcuts/cowork/operations.js +19 -0
  80. package/dist/shortcuts/ehr/host.js +4 -1
  81. package/dist/shortcuts/ehr/operations/recruit-candidate-import.js +757 -0
  82. package/dist/shortcuts/ehr/operations/recruit-position.js +367 -0
  83. package/dist/shortcuts/ehr/operations/recruit-stats.js +133 -0
  84. package/dist/shortcuts/ehr/operations/recruit-write.js +8 -16
  85. package/dist/shortcuts/ehr/operations/recruit.js +35 -10
  86. package/dist/shortcuts/ehr/operations/registry.js +6 -0
  87. package/dist/shortcuts/im/diagnostics.js +97 -0
  88. package/dist/shortcuts/im/host.js +58 -31
  89. package/dist/shortcuts/im/index.js +7 -2
  90. package/dist/shortcuts/im/operations/at-mention.js +127 -0
  91. package/dist/shortcuts/im/operations/file-user.js +10 -2
  92. package/dist/shortcuts/im/operations/group-read.js +26 -5
  93. package/dist/shortcuts/im/operations/group-write.js +35 -28
  94. package/dist/shortcuts/im/operations/msg-sync.js +7 -2
  95. package/dist/shortcuts/im/operations/msg-write.js +76 -10
  96. package/dist/shortcuts/im/operations/quote-mention.js +119 -0
  97. package/dist/shortcuts/im/operations/session.js +1 -1
  98. package/dist/shortcuts/im/operations/shared.js +10 -0
  99. package/dist/shortcuts/im/operations/types.js +13 -0
  100. package/dist/shortcuts/index.js +5 -0
  101. package/dist/shortcuts/mail/host.js +4 -1
  102. package/dist/shortcuts/meeting/host.js +27 -34
  103. package/dist/shortcuts/meeting/operations/create.js +4 -1
  104. package/dist/shortcuts/meeting/operations/eb/catalog.js +5 -0
  105. package/dist/shortcuts/meeting/operations/eb/conflict.js +78 -7
  106. package/dist/shortcuts/meeting/operations/eb/create-flow.js +168 -26
  107. package/dist/shortcuts/meeting/operations/eb/factory.js +69 -1
  108. package/dist/shortcuts/meeting/operations/eb/index.js +16 -3
  109. package/dist/shortcuts/meeting/operations/eb/room-recommend.js +14 -3
  110. package/dist/shortcuts/meeting/operations/eb-fallback.js +159 -0
  111. package/dist/shortcuts/meeting/operations/env.js +93 -46
  112. package/dist/shortcuts/meeting/operations/form-fields.js +110 -0
  113. package/dist/shortcuts/meeting/operations/registry.js +2 -0
  114. package/dist/shortcuts/meeting/operations/standard-guard.js +71 -0
  115. package/dist/shortcuts/meeting/operations.js +16 -0
  116. package/dist/shortcuts/workflow/index.js +110 -1
  117. package/dist/shortcuts/workflow/operations/form.js +24 -3
  118. package/dist/shortcuts/workflow/operations/read.js +104 -23
  119. package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupRules.js +448 -0
  120. package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupStore.js +106 -0
  121. package/dist/shortcuts/workflow/operations/todoSmartConvert/businessRules.js +47 -0
  122. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +30 -23
  123. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.core.js +1 -0
  124. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.group.js +1 -0
  125. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +2 -1
  126. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +2 -4
  127. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +138 -181
  128. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +12 -7
  129. package/docs/e10-auth.md +1 -1
  130. package/docs/im.md +8 -1
  131. package/docs/todo-smart-convert/README.md +1 -1
  132. package/docs/todo-smart-convert/data-contract.md +2 -2
  133. package/docs/todo-smart-convert/subgroup-rules.md +6 -0
  134. package/package.json +1 -1
  135. package/skill-template/domains/yimiaoban.md +3 -3
  136. package/skill-template/skill-template.md +1 -1
  137. package/skills/weaver-e10-blog/SKILL.md +5 -5
  138. package/skills/weaver-e10-caizhilian/SKILL.md +5 -5
  139. package/skills/weaver-e10-calendar/SKILL.md +5 -5
  140. package/skills/weaver-e10-esb/SKILL.md +5 -5
  141. package/skills/weaver-e10-hrm/SKILL.md +5 -5
  142. package/skills/weaver-e10-jinchengda/SKILL.md +2 -2
  143. package/skills/weaver-e10-jiuchuanhui/SKILL.md +5 -5
  144. package/skills/weaver-e10-jucailin/SKILL.md +18 -12
  145. package/skills/weaver-e10-jucailin/references/recruit-create.md +104 -0
  146. package/skills/weaver-e10-mail/SKILL.md +5 -5
  147. package/skills/weaver-e10-meeting/SKILL.md +171 -25
  148. package/skills/weaver-e10-meeting/references/meeting-eb.md +4 -3
  149. package/skills/weaver-e10-meeting/references/meeting-queries.md +9 -6
  150. package/skills/weaver-e10-meeting/references/meeting-verification.md +8 -6
  151. package/skills/weaver-e10-meeting.zip +0 -0
  152. package/skills/weaver-e10-okr/SKILL.md +5 -5
  153. package/skills/weaver-e10-okr/references/source-manifest.json +3 -3
  154. package/skills/weaver-e10-plan/SKILL.md +5 -5
  155. package/skills/weaver-e10-shared/SKILL.md +12 -12
  156. package/skills/weaver-e10-shared/references/e10-auth-and-session.md +4 -4
  157. package/skills/weaver-e10-wenshuding/SKILL.md +5 -5
  158. package/skills/weaver-e10-workflow/SKILL.md +29 -5
  159. package/skills/weaver-e10-workflow/aigroup/default.json +88 -0
  160. package/skills/weaver-e10-workflow/references/todo-smart-convert.md +66 -14
  161. package/skills/weaver-e10-workflow/references/workflow-agent-entry.md +1 -1
  162. package/skills/weaver-e10-workflow/references/workflow-memory.md +1 -1
  163. package/skills/weaver-e10-workflow/references/workflow-query.md +12 -10
  164. package/skills/weaver-e10-workflow/references/workflow-view.md +2 -2
  165. package/skills/weaver-e10-workflow/tools/todo-serve.cjs +239 -0
  166. package/skills/weaver-e10-workflow/{scripts → tools}/todo-summary.cjs +218 -28
  167. package/skills/weaver-e10-yepiaotong/SKILL.md +10 -8
  168. package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +7 -7
  169. package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +10 -10
  170. package/skills/weaver-e10-yepiaotong/references/reim-examples.md +40 -37
  171. package/skills/weaver-e10-yepiaotong/references/reim-expense-subject-rules.md +4 -4
  172. package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +27 -38
  173. package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +4 -4
  174. package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +37 -29
  175. package/skills/weaver-e10-yimiaoban/SKILL.md +156 -33
  176. package/skills/weaver-e10-yimiaoban/references/ding-write.md +1 -1
  177. package/skills/weaver-e10-yimiaoban/references/error-codes.md +5 -1
  178. package/skills/weaver-e10-yimiaoban/references/group-read.md +5 -1
  179. package/skills/weaver-e10-yimiaoban/references/group-write.md +6 -4
  180. package/skills/weaver-e10-yimiaoban/references/msg-read.md +1 -0
  181. package/skills/weaver-e10-yimiaoban/references/msg-write.md +34 -2
  182. package/skills/weaver-e10-yimiaoban/references/safety-boundaries.md +5 -2
  183. package/skills/weaver-e10-yimiaoban/references/source-manifest.json +79 -58
  184. package/skills/weaver-e10-yimiaoban/references/user-remind.md +2 -2
  185. package/skills/weaver-e10-ziguanjia/SKILL.md +5 -5
@@ -22,7 +22,7 @@ import {
22
22
  import {
23
23
  E10_REAUTH_GUIDANCE,
24
24
  hasXiaoEEnv
25
- } from "./chunk-2GA5ZIQL.js";
25
+ } from "./chunk-D223PTXU.js";
26
26
 
27
27
  // src/shortcuts/workflow/operations/form.ts
28
28
  import { randomUUID } from "node:crypto";
@@ -2030,7 +2030,7 @@ var workflowSearch = {
2030
2030
  }, env, { json: "last_search.json", md: "last_search.md" })), startedAt);
2031
2031
  }
2032
2032
  };
2033
- var SMART_GROUPING_MIN_OA_VERSION = [10, 0, 9909, 1];
2033
+ var SMART_GROUPING_MIN_OA_VERSION = [10, 0, 9807, 1];
2034
2034
  function formatOaVersion(tuple) {
2035
2035
  const [a, b, c, d] = tuple;
2036
2036
  return `${a}.${b}.${c}.${String(d).padStart(2, "0")}`;
@@ -4839,11 +4839,25 @@ function formatHistoryFieldValue(raw, field) {
4839
4839
  }
4840
4840
  return stringifyDetailValue(raw);
4841
4841
  }
4842
+ var SAAS_COLOGY_BASE_URL = "https://www.e-cology.com.cn";
4843
+ function isSaasCologyBaseUrl(baseUrl) {
4844
+ const normalize = (value) => String(value ?? "").trim().replace(/\/+$/u, "").toLowerCase();
4845
+ return normalize(baseUrl) === SAAS_COLOGY_BASE_URL;
4846
+ }
4847
+ async function isSaasCologyEnv(env) {
4848
+ try {
4849
+ const session = await env.host.getSession();
4850
+ return isSaasCologyBaseUrl(session?.baseUrl);
4851
+ } catch {
4852
+ return false;
4853
+ }
4854
+ }
4842
4855
  async function fetchHistoryListSnapshot(env, options = {}) {
4843
4856
  try {
4844
4857
  const now = /* @__PURE__ */ new Date();
4845
4858
  const start = new Date(now.getTime() - HISTORY_LOOKBACK_DAYS * 24 * 60 * 60 * 1e3);
4846
4859
  const historyWorkflowId = String(options.workflowId ?? "").trim();
4860
+ const addDisableCheckUserPermission = await isSaasCologyEnv(env);
4847
4861
  const listResponse = await env.host.workflowRequest({
4848
4862
  method: "POST",
4849
4863
  path: WORKFLOW_ENDPOINTS.MINE_LIST,
@@ -4855,7 +4869,9 @@ async function fetchHistoryListSnapshot(env, options = {}) {
4855
4869
  dimension: "mine",
4856
4870
  flowSpareType: 1,
4857
4871
  outType: 0,
4858
- needIutData: false
4872
+ needIutData: false,
4873
+ // SaaS 公有云环境写死带上(见 `SAAS_COLOGY_BASE_URL`);其余环境不带此键。
4874
+ ...addDisableCheckUserPermission ? { disableCheckUserPermission: "1" } : {}
4859
4875
  },
4860
4876
  // `needParseData: true`:让服务端把日期等字段直接解析成可读文本(`displayData`),
4861
4877
  // 客户端不再自己转。
@@ -4944,7 +4960,31 @@ async function pickUniqueMineWorkflow(candidates, env) {
4944
4960
  return null;
4945
4961
  }
4946
4962
  }
4947
- async function buildHistoryRequestData(env, fields, targets, options = {}, prefetchedList) {
4963
+ function prefetchHistoryDetails(env, listed) {
4964
+ const requestIds = listed?.requestIds ?? [];
4965
+ if (!requestIds.length) return Promise.resolve([]);
4966
+ return (async () => {
4967
+ const session = await env.host.getSession();
4968
+ return Promise.all(requestIds.map(async (requestId) => {
4969
+ const payload = {
4970
+ requestId,
4971
+ isGetRequestBaseInfo: false,
4972
+ isGetRequestLog: false,
4973
+ isGetFormData: true,
4974
+ isReadRequest: false
4975
+ };
4976
+ if (session.userId) payload.userId = session.userId;
4977
+ const response = await env.host.workflowRequest({
4978
+ method: "POST",
4979
+ path: WORKFLOW_ENDPOINTS.REQUEST_DETAIL,
4980
+ operation: "workflow.createRequest.history.detail",
4981
+ body: payload
4982
+ });
4983
+ return detailDataOf(response);
4984
+ }));
4985
+ })();
4986
+ }
4987
+ async function buildHistoryRequestData(env, fields, targets, options = {}, prefetchedList, prefetchedDetails) {
4948
4988
  const targetList = toArray(targets).filter((item) => !item?.systemField && String(item?.id ?? "").trim()).map((item) => ({ id: String(item.id).trim(), name: String(item.name ?? item.id) }));
4949
4989
  if (!targetList.length && !options.allFormFields) return null;
4950
4990
  const fieldMeta = /* @__PURE__ */ new Map();
@@ -4956,7 +4996,7 @@ async function buildHistoryRequestData(env, fields, targets, options = {}, prefe
4956
4996
  const items = listed.items;
4957
4997
  const requestIds = listed.requestIds;
4958
4998
  const session = await env.host.getSession();
4959
- const details = await Promise.all(requestIds.map(async (requestId) => {
4999
+ const details = prefetchedDetails ? await prefetchedDetails : await Promise.all(requestIds.map(async (requestId) => {
4960
5000
  const payload = {
4961
5001
  requestId,
4962
5002
  isGetRequestBaseInfo: false,
@@ -4973,6 +5013,7 @@ async function buildHistoryRequestData(env, fields, targets, options = {}, prefe
4973
5013
  });
4974
5014
  return detailDataOf(response);
4975
5015
  }));
5016
+ if (!details) return null;
4976
5017
  const result = [];
4977
5018
  for (let index = 0; index < details.length; index += 1) {
4978
5019
  const data = details[index] || {};
@@ -5307,6 +5348,7 @@ function parseTenantSetting(data) {
5307
5348
  return { max_size_mb: maxSizeMb, format_mode: whitesEnable ? "white" : "black", formats };
5308
5349
  }
5309
5350
  function buildLayoutRequest(workflowId, runtime, frame) {
5351
+ const isEbForm = String(frame.relate_type ?? "").trim() === "WEA_EBUILDER";
5310
5352
  const custom = {
5311
5353
  permissionType: frame.permission_type,
5312
5354
  requestId: runtime.request_id,
@@ -5322,6 +5364,7 @@ function buildLayoutRequest(workflowId, runtime, frame) {
5322
5364
  mobile: false,
5323
5365
  formId: frame.form_id,
5324
5366
  source: "view",
5367
+ ...isEbForm ? { bridgeService: "ebuilder" } : {},
5325
5368
  isAgent: false,
5326
5369
  beAgentId: "0",
5327
5370
  hideSysFieldArea: true,
@@ -5336,7 +5379,7 @@ function buildLayoutRequest(workflowId, runtime, frame) {
5336
5379
  terminalType: "PC",
5337
5380
  formId: frame.form_id,
5338
5381
  ...nodePermissionEnabled && permissionId ? { permissionId } : {},
5339
- module: "workflow",
5382
+ module: isEbForm ? "ebuildercard" : "workflow",
5340
5383
  customParam: custom,
5341
5384
  cacheUid: randomUUID(),
5342
5385
  newLayout: frame.new_layout,
@@ -6238,6 +6281,9 @@ async function buildCreateFormData(workflowId, env) {
6238
6281
  const query = { workflowId, isCreate: 1, ...AJAX_QUERY };
6239
6282
  const body = { workflowId, isCreate: 1, isMobile: 0 };
6240
6283
  const historyListSnapshot = fetchHistoryListSnapshot(env, { workflowId }).catch(() => null);
6284
+ const historyDetails = historyListSnapshot.then(async (snapshot) => snapshot && snapshot.requestIds.length ? prefetchHistoryDetails(env, snapshot) : null);
6285
+ historyDetails.catch(() => {
6286
+ });
6241
6287
  const isXiaoE = hasXiaoEEnv(env.ctx.env, env.ctx.getGlobalOptions?.());
6242
6288
  const basePromise = requestJson(env, "POST", FORM_ENDPOINTS.loadBase, query, body, { tolerateBusinessError: true }).then((value) => ({ ok: true, value })).catch((error) => ({ ok: false, error }));
6243
6289
  const framePromise = requestJson(env, "POST", FORM_ENDPOINTS.loadFrame, query, body).then((value) => ({ ok: true, value })).catch((error) => ({ ok: false, error }));
@@ -6462,7 +6508,9 @@ async function buildCreateFormData(workflowId, env) {
6462
6508
  historyRequiredFieldIds.map((id) => ({ id, name: String((fieldsById.get(id) || {}).name ?? id) })),
6463
6509
  { allFormFields: true, workflowId },
6464
6510
  // 本命令开头就已并发发起的列表请求:这里只补「详情」那几步(P2)。
6465
- historyListSnapshot
6511
+ historyListSnapshot,
6512
+ // 明细也已在列表返回时就发出去(与 layout 并行),这里只等它回来、按本表单字段组装。
6513
+ historyDetails
6466
6514
  ) : null;
6467
6515
  const session = await getSessionContext(env);
6468
6516
  const context = {
@@ -10104,6 +10152,7 @@ function rowFromAny(raw) {
10104
10152
  "lastfeedbacktime",
10105
10153
  "lastFeedbackTime"
10106
10154
  ]) ?? "",
10155
+ ...pick(["planFinishDatetime", "planfinishdatetime"]) ? { planFinishDatetime: pick(["planFinishDatetime", "planfinishdatetime"]) } : {},
10107
10156
  summary: pick(["summary"]),
10108
10157
  workflowName: pick(["workflowName", "workflowname", "workflowTypeName"], true),
10109
10158
  receivedTime: pick(["receivedTime", "receivedtime", "receivedatetime", "operatedatetime", "stayStartAt"]),
@@ -10179,64 +10228,9 @@ function readBoundedInt(value, name, fallback, min, max) {
10179
10228
  return parsed;
10180
10229
  }
10181
10230
 
10182
- // src/shortcuts/workflow/operations/todoSmartConvert/todoListRows.ts
10183
- var DISPLAY_ROW_FIELDS = [
10184
- // 定位键
10185
- "requestId",
10186
- "requestid",
10187
- "workflowid",
10188
- "workflowId",
10189
- "userMasterId",
10190
- "userid",
10191
- "isremark",
10192
- "isremarktype",
10193
- "nodeid",
10194
- "currentNodeId",
10195
- // 状态位
10196
- "overdue",
10197
- "userOverTime",
10198
- "requestlevel",
10199
- "requestLevelShow",
10200
- "requestlevelShow",
10201
- "requestlevelTitle",
10202
- // 展示字段
10203
- "requestnamehtml",
10204
- "requestnameTitle",
10205
- "requestnametitle",
10206
- "requestname",
10207
- "creater",
10208
- "creatername",
10209
- "creatorName",
10210
- "workflowname",
10211
- "workflowName",
10212
- "workflowTypeName",
10213
- "requestmark",
10214
- "flowstatusShow",
10215
- "receivedatetime",
10216
- "operatedatetime",
10217
- // 最后反馈时间:`getTodoListData.displayData` 里的原始键是全小写,大小写变体一并保留。
10218
- "lastfeedbackdatetime",
10219
- "lastFeedbackDateTime"
10220
- ];
10221
- function projectDisplayRows(response) {
10222
- const record = responseData(response);
10223
- const raw = record?.data?.displayData ?? record?.displayData ?? [];
10224
- const rows = Array.isArray(raw) ? raw : [];
10225
- const projected = [];
10226
- for (const row of rows) {
10227
- if (!row || typeof row !== "object" || Array.isArray(row)) continue;
10228
- const source = row;
10229
- const picked = {};
10230
- for (const key of DISPLAY_ROW_FIELDS) {
10231
- const value = source[key];
10232
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
10233
- picked[key] = value;
10234
- }
10235
- }
10236
- if (Object.keys(picked).length > 0) projected.push(picked);
10237
- }
10238
- return projected;
10239
- }
10231
+ // src/shortcuts/workflow/operations/todoSmartConvert/aigroupRules.ts
10232
+ import { existsSync as existsSync3, readFileSync } from "node:fs";
10233
+ import { join as join2 } from "node:path";
10240
10234
 
10241
10235
  // src/shortcuts/workflow/operations/todoSmartConvert/summaryCache.ts
10242
10236
  import { existsSync as existsSync2, readdirSync, statSync } from "node:fs";
@@ -10449,6 +10443,417 @@ async function openSummaryCache(ctx) {
10449
10443
  return cache;
10450
10444
  }
10451
10445
 
10446
+ // src/shortcuts/workflow/operations/todoSmartConvert/aigroupRules.ts
10447
+ var AIGROUP_DIR_NAME = "aigroup";
10448
+ var DEFAULT_RULE_FILE = "default.json";
10449
+ var USER_INTENT_RULE_FILE = "user-intents.json";
10450
+ var FOCUS_OPERATORS = [
10451
+ "\u7B49\u4E8E",
10452
+ "\u4E0D\u7B49\u4E8E",
10453
+ "\u662F",
10454
+ "\u4E0D\u662F",
10455
+ "\u5927\u4E8E",
10456
+ "\u5C0F\u4E8E",
10457
+ "\u5C0F\u4E8E\u7B49\u4E8E",
10458
+ "\u5927\u4E8E\u7B49\u4E8E",
10459
+ "\u4ECB\u4E8E",
10460
+ "\u5305\u542B"
10461
+ ];
10462
+ var MAX_GROUPING_PROMPT_CHARS = 500;
10463
+ var EMPTY_GROUP_RULE = { focus: false };
10464
+ var FALLBACK_DEFAULTS = {
10465
+ weight: 999,
10466
+ needSummary: true,
10467
+ requestSummaryPrompt: "",
10468
+ summaryMaxChars: 150,
10469
+ groupSummaryMaxChars: 100,
10470
+ groupSummaryTail: "\u53EF\u5C55\u5F00\u9010\u6761\u67E5\u770B\u6216\u76F4\u63A5\u6C47\u603B\u5904\u7406"
10471
+ };
10472
+ function emptyRuleFile(error = null) {
10473
+ return {
10474
+ file: { schemaVersion: 2, defaults: FALLBACK_DEFAULTS, rules: [] },
10475
+ error
10476
+ };
10477
+ }
10478
+ function asStringArray3(value) {
10479
+ if (typeof value === "string") return [value];
10480
+ if (!Array.isArray(value)) return null;
10481
+ const items = value.map((item) => String(item ?? "").trim()).filter((item) => item !== "");
10482
+ return items.length > 0 ? items : null;
10483
+ }
10484
+ function isOperator(value) {
10485
+ return typeof value === "string" && FOCUS_OPERATORS.includes(value);
10486
+ }
10487
+ function validateFocusKeyword(raw, index) {
10488
+ if (!Array.isArray(raw)) return `focusKeyword[${index}] \u5FC5\u987B\u662F\u6570\u7EC4`;
10489
+ const [metric, op] = raw;
10490
+ if (typeof metric !== "string" || !metric.trim()) return `focusKeyword[${index}] \u7684\u6307\u6807\u540D\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`;
10491
+ if (!isOperator(op)) return `focusKeyword[${index}] \u7684\u7B97\u5B50\u300C${String(op)}\u300D\u4E0D\u652F\u6301\uFF08\u53EF\u7528\uFF1A${FOCUS_OPERATORS.join("/")}\uFF09`;
10492
+ if (op === "\u4ECB\u4E8E") {
10493
+ if (raw.length !== 4) return `focusKeyword[${index}] \u7528\u300C\u4ECB\u4E8E\u300D\u65F6\u5FC5\u987B\u7ED9 [\u6307\u6807, \u4ECB\u4E8E, \u4E0B\u754C, \u4E0A\u754C]`;
10494
+ return null;
10495
+ }
10496
+ if (raw.length !== 3) return `focusKeyword[${index}] \u5FC5\u987B\u662F [\u6307\u6807, \u7B97\u5B50, \u503C] \u4E09\u5143\u7EC4`;
10497
+ return null;
10498
+ }
10499
+ function validateRuleFile(raw) {
10500
+ const errors = [];
10501
+ const file = raw;
10502
+ if (!file || typeof file !== "object") return ["\u89C4\u5219\u6587\u4EF6\u5FC5\u987B\u662F JSON \u5BF9\u8C61"];
10503
+ if (!Array.isArray(file.rules)) {
10504
+ errors.push("rules \u5FC5\u987B\u662F\u6570\u7EC4");
10505
+ return errors;
10506
+ }
10507
+ const seen = /* @__PURE__ */ new Set();
10508
+ file.rules.forEach((rule, index) => {
10509
+ if (!rule || typeof rule !== "object") {
10510
+ errors.push(`rules[${index}] \u5FC5\u987B\u662F\u5BF9\u8C61`);
10511
+ return;
10512
+ }
10513
+ const names = asStringArray3(rule.workflowName);
10514
+ if (!names) {
10515
+ errors.push(`rules[${index}].workflowName \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32\u6216\u975E\u7A7A\u6570\u7EC4`);
10516
+ return;
10517
+ }
10518
+ for (const name of names) {
10519
+ if (seen.has(name)) errors.push(`workflowName\u300C${name}\u300D\u5728 rules[${index}] \u91CD\u590D\u51FA\u73B0`);
10520
+ seen.add(name);
10521
+ }
10522
+ if (rule.weight !== void 0 && (typeof rule.weight !== "number" || !Number.isFinite(rule.weight))) {
10523
+ errors.push(`rules[${index}].weight \u5FC5\u987B\u662F\u6570\u5B57`);
10524
+ }
10525
+ if (rule.summaryMaxChars !== void 0 && (typeof rule.summaryMaxChars !== "number" || rule.summaryMaxChars <= 0)) {
10526
+ errors.push(`rules[${index}].summaryMaxChars \u5FC5\u987B\u662F\u6B63\u6570`);
10527
+ }
10528
+ const groupRule = rule.aiGroup?.groupRule;
10529
+ if (groupRule) {
10530
+ if (typeof groupRule.focus !== "boolean") errors.push(`rules[${index}].aiGroup.groupRule.focus \u5FC5\u987B\u662F\u5E03\u5C14`);
10531
+ if (groupRule.focus) {
10532
+ const keywords = groupRule.focusKeyword;
10533
+ if (!Array.isArray(keywords) || keywords.length === 0) {
10534
+ errors.push(`rules[${index}] focus=true \u65F6\u5FC5\u987B\u7ED9 focusKeyword`);
10535
+ } else {
10536
+ keywords.forEach((keyword, k) => {
10537
+ const reason = validateFocusKeyword(keyword, k);
10538
+ if (reason) errors.push(`rules[${index}].${reason}`);
10539
+ });
10540
+ }
10541
+ } else if (groupRule.focusKeyword !== void 0 && groupRule.focusKeyword.length > 0) {
10542
+ errors.push(`rules[${index}] focus=false \u65F6\u4E0D\u5E94\u7ED9 focusKeyword`);
10543
+ }
10544
+ if (groupRule.focus === false && !groupRule.aiContext) {
10545
+ errors.push(`rules[${index}] focus=false \u65F6\u5FC5\u987B\u7ED9 aiContext\uFF08\u6D41\u7A0B\u6807\u9898 / \u6D41\u7A0B\u8BE6\u60C5\uFF09`);
10546
+ }
10547
+ if (groupRule.groupingPrompt !== void 0) {
10548
+ if (groupRule.focus === true) {
10549
+ errors.push(`rules[${index}] focus=true \u65F6\u4E0D\u5E94\u7ED9 groupingPrompt\uFF08\u5B83\u53EA\u4F5C\u7528\u4E8E focus=false \u7684\u8BED\u4E49\u5206\u7EC4\uFF09`);
10550
+ } else if (typeof groupRule.groupingPrompt !== "string" || groupRule.groupingPrompt.trim() === "") {
10551
+ errors.push(`rules[${index}].aiGroup.groupRule.groupingPrompt \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);
10552
+ } else if (groupRule.groupingPrompt.length > MAX_GROUPING_PROMPT_CHARS) {
10553
+ errors.push(
10554
+ `rules[${index}].aiGroup.groupRule.groupingPrompt \u8D85\u8FC7 ${MAX_GROUPING_PROMPT_CHARS} \u5B57\uFF08\u5B83\u4F1A\u539F\u6837\u8FDB\u6A21\u578B\u4E0A\u4E0B\u6587\uFF0C\u8BF7\u7CBE\u7B80\uFF09`
10555
+ );
10556
+ }
10557
+ }
10558
+ }
10559
+ const groupSummary = rule.aiGroup?.groupSummary;
10560
+ if (groupSummary) {
10561
+ if (typeof groupSummary.needAI !== "boolean") errors.push(`rules[${index}].aiGroup.groupSummary.needAI \u5FC5\u987B\u662F\u5E03\u5C14`);
10562
+ if (groupSummary.needAI && !groupSummary.prompt) errors.push(`rules[${index}] groupSummary.needAI=true \u65F6\u5FC5\u987B\u7ED9 prompt`);
10563
+ if (!groupSummary.needAI && !groupSummary.template) errors.push(`rules[${index}] groupSummary.needAI=false \u65F6\u5FC5\u987B\u7ED9 template`);
10564
+ }
10565
+ });
10566
+ return errors;
10567
+ }
10568
+ function loadRuleFile(file) {
10569
+ if (!existsSync3(file)) return emptyRuleFile(`\u89C4\u5219\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${file}`);
10570
+ let parsed;
10571
+ try {
10572
+ parsed = JSON.parse(readFileSync(file, "utf8"));
10573
+ } catch (error) {
10574
+ return emptyRuleFile(`\u89C4\u5219\u6587\u4EF6\u4E0D\u662F\u5408\u6CD5 JSON\uFF1A${file}\uFF08${error.message}\uFF09`);
10575
+ }
10576
+ const errors = validateRuleFile(parsed);
10577
+ if (errors.length > 0) return emptyRuleFile(`\u89C4\u5219\u6587\u4EF6\u6821\u9A8C\u5931\u8D25\uFF1A${errors.join("\uFF1B")}`);
10578
+ return { file: parsed, error: null };
10579
+ }
10580
+ function aigroupDir(ctx) {
10581
+ const explicit = process.env.WEAVER_WORK_CLI_AIGROUP_DIR?.trim();
10582
+ if (explicit) return join2(explicit);
10583
+ const roots = cacheRoots(ctx);
10584
+ return roots.skillDir ? join2(roots.skillDir, AIGROUP_DIR_NAME) : join2(stateRoot(ctx), AIGROUP_DIR_NAME);
10585
+ }
10586
+ function aigroupUserDir(ctx) {
10587
+ const explicit = process.env.WEAVER_WORK_CLI_AIGROUP_DIR?.trim();
10588
+ if (explicit) return join2(explicit);
10589
+ return join2(stateRoot(ctx), AIGROUP_DIR_NAME);
10590
+ }
10591
+ function loadRules(options = {}) {
10592
+ const dir = options.dir ?? aigroupDir(options.ctx);
10593
+ const userDir = options.dir ?? aigroupUserDir(options.ctx);
10594
+ const warnings = [];
10595
+ const base = loadRuleFile(join2(dir, DEFAULT_RULE_FILE));
10596
+ if (base.error) warnings.push(base.error);
10597
+ const rules = [...base.file.rules];
10598
+ const userIntentFile = join2(userDir, USER_INTENT_RULE_FILE);
10599
+ const legacyIntentFile = join2(dir, USER_INTENT_RULE_FILE);
10600
+ let intentFile = userIntentFile;
10601
+ if (!options.dir && !existsSync3(userIntentFile) && existsSync3(legacyIntentFile)) {
10602
+ intentFile = legacyIntentFile;
10603
+ warnings.push(`\u7528\u6237\u610F\u56FE\u4ECD\u8BFB\u81EA skill \u76EE\u5F55\uFF08${legacyIntentFile}\uFF09\uFF1A\u65B0\u4F4D\u7F6E\u662F ${userIntentFile}\uFF0C\u91CD\u65B0\u6267\u884C aigroup set \u5373\u53EF\u8FC1\u79FB`);
10604
+ }
10605
+ const intent = loadRuleFile(intentFile);
10606
+ if (intent.error) {
10607
+ if (existsSync3(intentFile)) warnings.push(intent.error);
10608
+ } else {
10609
+ for (const rule of intent.file.rules) {
10610
+ const names = new Set(asStringArray3(rule.workflowName) ?? []);
10611
+ const at = rules.findIndex((item) => (asStringArray3(item.workflowName) ?? []).some((name) => names.has(name)));
10612
+ if (at >= 0 && (asStringArray3(rules[at].workflowName) ?? []).includes("*")) {
10613
+ warnings.push(`\u7528\u6237\u610F\u56FE\u4E0D\u80FD\u8986\u76D6\u901A\u914D\u6761\u76EE\u300C*\u300D\uFF0C\u5DF2\u5FFD\u7565\uFF1A${[...names].join(",")}`);
10614
+ continue;
10615
+ }
10616
+ if (at >= 0) rules[at] = rule;
10617
+ else rules.push(rule);
10618
+ }
10619
+ }
10620
+ return {
10621
+ file: { schemaVersion: base.file.schemaVersion, defaults: { ...FALLBACK_DEFAULTS, ...base.file.defaults }, rules },
10622
+ warnings,
10623
+ dir
10624
+ };
10625
+ }
10626
+ function matchRule(rules, workflowName) {
10627
+ const name = String(workflowName ?? "").trim();
10628
+ const aliasesOf = (rule) => asStringArray3(rule.workflowName) ?? [];
10629
+ const indexOf = /* @__PURE__ */ new Map();
10630
+ rules.forEach((rule, index) => indexOf.set(rule, index));
10631
+ if (name) {
10632
+ const exact = rules.filter((rule) => aliasesOf(rule).includes(name));
10633
+ if (exact.length > 0) {
10634
+ const [rule] = exact;
10635
+ return { rule, matchedBy: "exact", index: indexOf.get(rule) ?? 0 };
10636
+ }
10637
+ const fuzzy = rules.filter((rule) => aliasesOf(rule).some((alias) => alias !== "*" && name.includes(alias)));
10638
+ if (fuzzy.length > 0) {
10639
+ const sorted = [...fuzzy].sort((a, b) => (a.weight ?? FALLBACK_DEFAULTS.weight) - (b.weight ?? FALLBACK_DEFAULTS.weight) || (indexOf.get(a) ?? 0) - (indexOf.get(b) ?? 0));
10640
+ const rule = sorted[0];
10641
+ return { rule, matchedBy: "fuzzy", index: indexOf.get(rule) ?? 0 };
10642
+ }
10643
+ }
10644
+ const fallback = rules.find((rule) => aliasesOf(rule).includes("*"));
10645
+ if (fallback) return { rule: fallback, matchedBy: "default", index: indexOf.get(fallback) ?? 0 };
10646
+ return null;
10647
+ }
10648
+ function resolveRule(file, workflowName) {
10649
+ const matched = matchRule(file.rules, workflowName);
10650
+ if (!matched) return null;
10651
+ const defaults = { ...FALLBACK_DEFAULTS, ...file.defaults };
10652
+ const raw = matched.rule;
10653
+ const groupSummary = raw.aiGroup?.groupSummary;
10654
+ const groupRule = raw.aiGroup?.groupRule;
10655
+ return {
10656
+ matchedBy: matched.matchedBy,
10657
+ rule: {
10658
+ workflowName: asStringArray3(raw.workflowName) ?? [],
10659
+ weight: raw.weight ?? defaults.weight,
10660
+ needSummary: raw.needSummary ?? defaults.needSummary,
10661
+ requestSummaryPrompt: raw.requestSummaryPrompt ?? defaults.requestSummaryPrompt,
10662
+ summaryMaxChars: raw.summaryMaxChars ?? defaults.summaryMaxChars,
10663
+ groupSummaryMaxChars: defaults.groupSummaryMaxChars,
10664
+ groupSummaryTail: defaults.groupSummaryTail,
10665
+ aiGroup: raw.aiGroup ? {
10666
+ groupSummary: {
10667
+ needAI: groupSummary?.needAI ?? false,
10668
+ ...groupSummary?.prompt === void 0 ? {} : { prompt: groupSummary.prompt },
10669
+ ...groupSummary?.template === void 0 ? {} : { template: groupSummary.template },
10670
+ maxChars: defaults.groupSummaryMaxChars,
10671
+ tail: defaults.groupSummaryTail
10672
+ },
10673
+ groupRule: groupRule ?? EMPTY_GROUP_RULE
10674
+ } : null,
10675
+ ruleIndex: matched.index
10676
+ }
10677
+ };
10678
+ }
10679
+ function dateOnly(value) {
10680
+ const pad = (n) => String(n).padStart(2, "0");
10681
+ return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`;
10682
+ }
10683
+ var RELATIVE_DAYS = { \u4ECA\u5929: 0, \u6628\u5929: -1, \u660E\u5929: 1 };
10684
+ function normalizeDateLike(value, now = /* @__PURE__ */ new Date()) {
10685
+ const text = value.trim();
10686
+ if (text in RELATIVE_DAYS) {
10687
+ const date = new Date(now.getTime());
10688
+ date.setDate(date.getDate() + RELATIVE_DAYS[text]);
10689
+ return dateOnly(date);
10690
+ }
10691
+ const matched = /^(\d{4})[-/](\d{1,2})[-/](\d{1,2})/u.exec(text);
10692
+ if (!matched) return null;
10693
+ const [, y, m, d] = matched;
10694
+ return `${y}-${String(m).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
10695
+ }
10696
+ function toNumber(value) {
10697
+ if (typeof value === "number" && Number.isFinite(value)) return value;
10698
+ const text = String(value ?? "").replace(/[,¥¥\s]/gu, "");
10699
+ if (!text) return null;
10700
+ const parsed = Number(text);
10701
+ return Number.isFinite(parsed) ? parsed : null;
10702
+ }
10703
+ function comparableOf(value, now) {
10704
+ if (value === null || value === void 0 || value === "") return null;
10705
+ if (typeof value === "number") return Number.isFinite(value) ? { kind: "number", value } : null;
10706
+ const text = String(value).trim();
10707
+ if (!text) return null;
10708
+ const date = normalizeDateLike(text, now);
10709
+ if (date) return { kind: "date", value: date };
10710
+ const num = toNumber(text);
10711
+ if (num !== null && /^[¥¥]?\s*-?\d[\d,]*(?:\.\d+)?$/.test(text.replace(/\s/gu, ""))) {
10712
+ return { kind: "number", value: num };
10713
+ }
10714
+ return { kind: "text", value: text };
10715
+ }
10716
+ function compare(a, b) {
10717
+ if (a.kind === "number" && b.kind === "number") return a.value - b.value;
10718
+ if (a.kind === "date" && b.kind === "date") return a.value < b.value ? -1 : a.value > b.value ? 1 : 0;
10719
+ if (a.kind === "text" || b.kind === "text") {
10720
+ const left = String(a.value);
10721
+ const right = String(b.value);
10722
+ return left < right ? -1 : left > right ? 1 : 0;
10723
+ }
10724
+ return null;
10725
+ }
10726
+ function evaluateCondition(condition, actual, now = /* @__PURE__ */ new Date()) {
10727
+ const [metric, op, expected, upper] = condition;
10728
+ const left = comparableOf(actual, now);
10729
+ if (!left) return false;
10730
+ const right = comparableOf(expected, now);
10731
+ if (!right) return false;
10732
+ switch (op) {
10733
+ case "\u7B49\u4E8E":
10734
+ case "\u662F":
10735
+ return compare(left, right) === 0;
10736
+ case "\u4E0D\u7B49\u4E8E":
10737
+ case "\u4E0D\u662F":
10738
+ return compare(left, right) !== 0;
10739
+ case "\u5927\u4E8E": {
10740
+ const diff = compare(left, right);
10741
+ return diff !== null && diff > 0;
10742
+ }
10743
+ case "\u5C0F\u4E8E": {
10744
+ const diff = compare(left, right);
10745
+ return diff !== null && diff < 0;
10746
+ }
10747
+ case "\u5927\u4E8E\u7B49\u4E8E": {
10748
+ const diff = compare(left, right);
10749
+ return diff !== null && diff >= 0;
10750
+ }
10751
+ case "\u5C0F\u4E8E\u7B49\u4E8E": {
10752
+ const diff = compare(left, right);
10753
+ return diff !== null && diff <= 0;
10754
+ }
10755
+ case "\u4ECB\u4E8E": {
10756
+ const top = comparableOf(upper, now);
10757
+ if (!top) return false;
10758
+ const low = compare(left, right);
10759
+ const high = compare(left, top);
10760
+ return low !== null && high !== null && low >= 0 && high <= 0;
10761
+ }
10762
+ case "\u5305\u542B":
10763
+ return String(left.value).includes(String(right.value));
10764
+ default:
10765
+ return false;
10766
+ }
10767
+ }
10768
+ function evaluateFocusKeywords(conditions, resolve3, now = /* @__PURE__ */ new Date()) {
10769
+ if (conditions.length === 0) return false;
10770
+ return conditions.every((condition) => evaluateCondition(condition, resolve3(condition[0]), now));
10771
+ }
10772
+ var activeFile = null;
10773
+ var activeDir = null;
10774
+ function primeRules(ctx) {
10775
+ const loaded = loadRules({ ctx });
10776
+ activeFile = loaded.file;
10777
+ activeDir = loaded.dir;
10778
+ return loaded;
10779
+ }
10780
+ function activeRules() {
10781
+ if (!activeFile) {
10782
+ const loaded = loadRules();
10783
+ activeFile = loaded.file;
10784
+ activeDir = loaded.dir;
10785
+ }
10786
+ return activeFile;
10787
+ }
10788
+ function activeRuleFor(workflowName) {
10789
+ const name = String(workflowName ?? "").trim();
10790
+ if (!name) return null;
10791
+ return resolveRule(activeRules(), name)?.rule ?? null;
10792
+ }
10793
+ function resetActiveRules() {
10794
+ activeFile = null;
10795
+ activeDir = null;
10796
+ }
10797
+
10798
+ // src/shortcuts/workflow/operations/todoSmartConvert/todoListRows.ts
10799
+ var DISPLAY_ROW_FIELDS = [
10800
+ // 定位键
10801
+ "requestId",
10802
+ "requestid",
10803
+ "workflowid",
10804
+ "workflowId",
10805
+ "userMasterId",
10806
+ "userid",
10807
+ "isremark",
10808
+ "isremarktype",
10809
+ "nodeid",
10810
+ "currentNodeId",
10811
+ // 状态位
10812
+ "overdue",
10813
+ "userOverTime",
10814
+ "requestlevel",
10815
+ "requestLevelShow",
10816
+ "requestlevelShow",
10817
+ "requestlevelTitle",
10818
+ // 展示字段
10819
+ "requestnamehtml",
10820
+ "requestnameTitle",
10821
+ "requestnametitle",
10822
+ "requestname",
10823
+ "creater",
10824
+ "creatername",
10825
+ "creatorName",
10826
+ "workflowname",
10827
+ "workflowName",
10828
+ "workflowTypeName",
10829
+ "requestmark",
10830
+ "flowstatusShow",
10831
+ "receivedatetime",
10832
+ "operatedatetime",
10833
+ // 最后反馈时间:`getTodoListData.displayData` 里的原始键是全小写,大小写变体一并保留。
10834
+ "lastfeedbackdatetime",
10835
+ "lastFeedbackDateTime"
10836
+ ];
10837
+ function projectDisplayRows(response) {
10838
+ const record = responseData(response);
10839
+ const raw = record?.data?.displayData ?? record?.displayData ?? [];
10840
+ const rows = Array.isArray(raw) ? raw : [];
10841
+ const projected = [];
10842
+ for (const row of rows) {
10843
+ if (!row || typeof row !== "object" || Array.isArray(row)) continue;
10844
+ const source = row;
10845
+ const picked = {};
10846
+ for (const key of DISPLAY_ROW_FIELDS) {
10847
+ const value = source[key];
10848
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
10849
+ picked[key] = value;
10850
+ }
10851
+ }
10852
+ if (Object.keys(picked).length > 0) projected.push(picked);
10853
+ }
10854
+ return projected;
10855
+ }
10856
+
10452
10857
  // src/shortcuts/workflow/operations/todoSmartConvert/detailFieldRules.ts
10453
10858
  function normalizeDetailFieldName(raw) {
10454
10859
  return String(raw ?? "").replace(/<[^>]*>/g, " ").replace(/[【】[\]()()]/g, "").replace(/\s+/g, "").trim();
@@ -10491,19 +10896,10 @@ function pickInternalMessageFieldPairs(fields, basicInfo = {}) {
10491
10896
  }
10492
10897
 
10493
10898
  // src/shortcuts/workflow/operations/todoSmartConvert/businessRules.ts
10494
- var BUSINESS_KIND_LABEL = {
10495
- leave: "\u8BF7\u5047\u7C7B",
10496
- finance: "\u8D22\u52A1\u7C7B",
10497
- "internal-message": "\u5185\u90E8\u7559\u8A00\u7C7B",
10498
- satisfaction: "\u6EE1\u610F\u5EA6\u7C7B",
10499
- "issue-support": "\u5BA2\u6237\u95EE\u9898\u652F\u6301\u7C7B",
10500
- other: "\u5176\u4ED6\u7C7B"
10501
- };
10502
10899
  var ISSUE_SUPPORT_WORKFLOW_NAMES = [
10503
10900
  "Ecology\u5BA2\u6237\u95EE\u9898\u652F\u6301\u89E3\u51B3\u6D41\u7A0B",
10504
10901
  "E10\u5BA2\u6237\u95EE\u9898\u652F\u6301\u89E3\u51B3\u6D41\u7A0B"
10505
10902
  ];
10506
- var ISSUE_SUPPORT_GROUP_TITLE = "\u5DF2\u8FC7\u671F\u53CA\u4ECA\u5929\u5373\u5C06\u8FC7\u671F\u7684\u6D41\u7A0B";
10507
10903
  var LEAVE_DAY_THRESHOLD = 1;
10508
10904
  var FINANCE_AMOUNT_THRESHOLD = 100;
10509
10905
  var LEAVE_GROUP_TITLE = `${LEAVE_DAY_THRESHOLD}\u5929\u4EE5\u5185`;
@@ -10524,49 +10920,12 @@ function detectBusinessKind(workflowName) {
10524
10920
  function isDeterministicGroupKind(kind) {
10525
10921
  return kind === "leave" || kind === "finance" || kind === "issue-support";
10526
10922
  }
10527
- var INTENT_RULES = [
10528
- {
10529
- id: "leave",
10530
- label: "\u8BF7\u5047\u7EF4\u5EA6",
10531
- match: /请假|休假|年假|调休|病假|事假|婚假|产假|陪产|丧假|探亲|工伤|哺乳|假别|假期|假种|天数/u,
10532
- kinds: ["leave"]
10533
- },
10534
- {
10535
- id: "finance",
10536
- label: "\u8D22\u52A1\u7EF4\u5EA6",
10537
- match: /报销|费用|金额|发票|差旅|借款|付款|请款|科目|票据|对公|核销/u,
10538
- kinds: ["finance"]
10539
- },
10540
- {
10541
- id: "issue-support",
10542
- label: "\u95EE\u9898\u652F\u6301\u7EF4\u5EA6",
10543
- match: /问题|模块|处理阶段|客户问题|工单|支持/u,
10544
- kinds: ["issue-support"]
10545
- },
10546
- {
10547
- id: "generic",
10548
- label: "\u901A\u7528\u7EF4\u5EA6",
10549
- match: /客户|发起人|创建人|提交人|时间|日期|紧急|等级|优先级|主题|标题|类型|类别|状态|节点|内容/u,
10550
- kinds: ["internal-message", "other"]
10551
- }
10552
- ];
10553
- function intentAppliesToKind(focus, kind) {
10554
- const text = String(focus ?? "").trim();
10555
- if (!text || kind === "satisfaction") return false;
10556
- const specific = INTENT_RULES.filter((rule) => rule.id !== "generic" && rule.match.test(text));
10557
- if (specific.length > 0) return specific.some((rule) => rule.kinds.includes(kind));
10558
- const generic = INTENT_RULES.find((rule) => rule.id === "generic");
10559
- return generic ? generic.kinds.includes(kind) : false;
10560
- }
10561
10923
  function requestSummaryStrategy(kind) {
10562
10924
  return kind === "satisfaction" ? "title" : "ai";
10563
10925
  }
10564
10926
  function needsRequestSummary(kind) {
10565
10927
  return requestSummaryStrategy(kind) === "ai";
10566
10928
  }
10567
- function usesTitleSummary(kind) {
10568
- return requestSummaryStrategy(kind) === "title";
10569
- }
10570
10929
  var LEAVE_TYPE_FIELD_PATTERN = /^(?:假别|假类|请假类型|请假类别|假期类型|假期类别|休假类型|休假类别)$/u;
10571
10930
  var LEAVE_DAYS_FIELD_PATTERN = /^(?:(?:请假|休假|假期|调休)(?:天数|时长|合计)|(?:请假|休假|假期|调休)?天数|天数合计|合计天数|总天数|时长)$/u;
10572
10931
  var AMOUNT_FIELD_PATTERN = /^(?:人民币金额|报销金额|报销总金额|实报金额|实际支付金额|申请金额|付款金额|借款金额|请款金额|总金额|金额合计|合计金额|费用合计|小写金额|总价|价税合计|金额|合计|总计)(?:[((]元[))])?$/u;
@@ -10687,32 +11046,25 @@ function uniqueTexts(values) {
10687
11046
  return result;
10688
11047
  }
10689
11048
  var GROUP_SUMMARY_TAIL_TEXT = "\u53EF\u5C55\u5F00\u9010\u6761\u67E5\u770B\u6216\u76F4\u63A5\u6C47\u603B\u5904\u7406";
10690
- function creatorClauseOf(creators) {
10691
- const all = normalizeCreators(creators);
10692
- const shown = all.slice(0, 3);
10693
- if (shown.length === 0) return "";
10694
- return `\u7531${shown.join("\u3001")}${all.length > 2 ? "\u7B49" : ""}\u53D1\u8D77\u3002`;
10695
- }
10696
- function formatLeaveGroupSummary(input) {
10697
- const allTypes = uniqueTexts(input.leaveTypes);
10698
- const types = allTypes.slice(0, 3);
10699
- const typeCount = allTypes.length > 0 ? allTypes.length : 1;
10700
- const typeText = types.length > 0 ? `${typeCount}\u7C7B\u5047\u522B\uFF08${types.join("\u3001")}${allTypes.length > types.length ? "\u7B49" : ""}\uFF09` : `${typeCount}\u7C7B\u5047\u522B`;
10701
- return `\u5171${input.count}\u6761\uFF0C\u6DB5\u76D6${typeText}\uFF0C${creatorClauseOf(input.creators)}${GROUP_SUMMARY_TAIL_TEXT}`;
10702
- }
10703
- function formatFinanceGroupSummary(input) {
10704
- const allCategories = uniqueTexts(input.categories);
10705
- const categories = allCategories.slice(0, 3);
10706
- const categoryText = allCategories.length > 0 ? `${allCategories.length}\u7C7B\u8D39\u7528\uFF08${categories.join("\u3001")}${allCategories.length > categories.length ? "\u7B49" : ""}\uFF09` : "1\u7C7B\u8D39\u7528";
10707
- const sum = `\xA5${formatNumber(input.sum)}`;
10708
- return `\u5355\u7B14 \xA5${formatNumber(input.min)} ~ \xA5${formatNumber(input.max)}\uFF0C\u5408\u8BA1 ${sum}\uFF0C\u6DB5\u76D6${categoryText}\uFF0C${creatorClauseOf(input.creators)}${GROUP_SUMMARY_TAIL_TEXT}`;
10709
- }
10710
- function formatIssueSupportGroupSummary(input) {
10711
- const allCreators = normalizeCreators(input.creators);
10712
- const shown = allCreators.slice(0, 3);
10713
- const creatorText = shown.length > 0 ? `\u7531 ${shown.join("\u3001")}${allCreators.length > shown.length ? " \u7B49" : ""} ${allCreators.length} \u4EBA\u53D1\u8D77\uFF0C` : "";
10714
- const restText = input.restCount > 0 ? `\u5176\u4F59 ${input.restCount} \u6761\u6309\u5355\u6761\u5C55\u793A\uFF0C` : "";
10715
- return `\u542B ${input.count} \u6761\u5DF2\u8FC7\u671F\u6216\u4ECA\u65E5\u5230\u671F\u7684\u95EE\u9898\u6D41\u7A0B\uFF0C${creatorText}${restText}${GROUP_SUMMARY_TAIL_TEXT}`;
11049
+ function renderGroupSummaryTemplate(input) {
11050
+ let text = String(input.template ?? "");
11051
+ if (!text.trim()) return "";
11052
+ const allCategories = uniqueTexts(input.categories ?? []);
11053
+ const shownCategories = allCategories.slice(0, 3);
11054
+ const categoryCount = allCategories.length > 0 ? allCategories.length : 1;
11055
+ const categories = shownCategories.length > 0 ? `${shownCategories.join("\u3001")}${allCategories.length > shownCategories.length ? "\u7B49" : ""}` : "";
11056
+ const allCreators = normalizeCreators(input.creators ?? []);
11057
+ const shownCreators = allCreators.slice(0, 3);
11058
+ const creators = shownCreators.length > 0 ? `\u7531${shownCreators.join("\u3001")}${allCreators.length > 2 ? "\u7B49" : ""}` : "";
11059
+ if (!creators) {
11060
+ text = text.replace(/\{\{creators\}\}发起[。,]/gu, "");
11061
+ }
11062
+ if (!categories) {
11063
+ text = text.replace(/(\{\{categories\}\})/gu, "");
11064
+ }
11065
+ const amounts = (input.amounts ?? []).filter((value) => typeof value === "number" && Number.isFinite(value));
11066
+ const replaced = text.replace(/\{\{count\}\}/gu, String(input.count)).replace(/\{\{restCount\}\}/gu, String(input.restCount ?? 0)).replace(/\{\{categoryCount\}\}/gu, String(categoryCount)).replace(/\{\{categories\}\}/gu, categories).replace(/\{\{min\}\}/gu, amounts.length > 0 ? formatNumber(Math.min(...amounts)) : "").replace(/\{\{max\}\}/gu, amounts.length > 0 ? formatNumber(Math.max(...amounts)) : "").replace(/\{\{sum\}\}/gu, amounts.length > 0 ? formatNumber(Number(amounts.reduce((total, value) => total + value, 0).toFixed(2))) : "").replace(/\{\{creators\}\}/gu, creators).replace(/\{\{tail\}\}/gu, input.tail);
11067
+ return replaced.replace(/¥(\s*)/gu, "").replace(/\s*,\s*,/gu, "\uFF0C").trim();
10716
11068
  }
10717
11069
 
10718
11070
  // src/shortcuts/workflow/operations/todoSmartConvert/todoDetailFetcher.ts
@@ -11126,9 +11478,6 @@ var URGENT_PATTERN = /紧急/u;
11126
11478
  var PRIORITY_GROUP_ID = "priority";
11127
11479
  var PRIORITY_GROUP_TITLE = "\u5EFA\u8BAE\u4F18\u5148\u5904\u7406\u7684\u6D41\u7A0B";
11128
11480
  var GROUP_MIN_ITEMS_FOR_SUBGROUP = 3;
11129
- function focusAppliesToKind(focus, kind) {
11130
- return intentAppliesToKind(focus, kind);
11131
- }
11132
11481
  function timeOf(value) {
11133
11482
  if (!value) return void 0;
11134
11483
  const text = value.trim();
@@ -11235,6 +11584,7 @@ function toRequestData(row) {
11235
11584
  creater: row.creater,
11236
11585
  createrName: row.createrName,
11237
11586
  lastFeedBackDateTime: row.lastFeedBackDateTime,
11587
+ ...row.planFinishDatetime ? { planFinishDatetime: row.planFinishDatetime } : {},
11238
11588
  summary: row.summary ?? ""
11239
11589
  };
11240
11590
  }
@@ -11586,7 +11936,7 @@ async function collectRawTodos(args, env) {
11586
11936
  const focusText = typeof args.groupFocus === "string" ? args.groupFocus.trim() : "";
11587
11937
  const fieldsById = /* @__PURE__ */ new Map();
11588
11938
  if (focusText) {
11589
- const targetRows = wfIdGroup.filter((group) => !group.topPriority && focusAppliesToKind(focusText, detectBusinessKind(group.title))).flatMap((group) => group.requestDatas ?? []);
11939
+ const targetRows = wfIdGroup.filter((group) => !group.topPriority && activeRuleFor(group.title)?.aiGroup?.groupRule.aiContext === "\u6D41\u7A0B\u8BE6\u60C5").flatMap((group) => group.requestDatas ?? []);
11590
11940
  const targetIds = [...new Set(targetRows.map((row) => row.requestId).filter(Boolean))];
11591
11941
  if (targetIds.length > 0) {
11592
11942
  const { facts, stats } = await fetchDetailFacts(env, targetIds, args, stampsOfRows(targetRows));
@@ -11602,26 +11952,31 @@ async function collectRawTodos(args, env) {
11602
11952
  };
11603
11953
  }
11604
11954
  }
11605
- groupingBrief = wfIdGroup.map((group) => ({
11606
- groupId: group.id,
11607
- title: group.title,
11608
- count: group.count,
11609
- topPriority: group.topPriority,
11610
- items: (group.requestDatas ?? []).map((row, index) => ({
11611
- idx: index + 1,
11612
- requestId: row.requestId,
11613
- title: row.requestNameTitle ?? "",
11614
- // 客户问题支持类无侧重点时按这两个布尔分组(模型不用自己解析日期文案)
11615
- overdue: isOverdueRow(row),
11616
- expiringToday: isExpiringTodayRow(row),
11617
- ...row.userOverTime ? { userOverTime: row.userOverTime } : {},
11618
- ...row.summary ? { summary: row.summary } : {},
11619
- // `summaryCached:true` = 这条已有本地摘要(按 requestId__lastFeedBackDateTime 命中),
11620
- // 分组仍要做(聚类看标题),但**不要再给它写摘要**。
11621
- ...cachedSummaryIds.has(row.requestId) ? { summaryCached: true } : {},
11622
- ...fieldsById.has(row.requestId) ? { fields: fieldsById.get(row.requestId) } : {}
11623
- }))
11624
- }));
11955
+ groupingBrief = wfIdGroup.map((group) => {
11956
+ const groupRule = activeRuleFor(group.title)?.aiGroup?.groupRule;
11957
+ const groupingPrompt = groupRule && groupRule.focus === false && typeof groupRule.groupingPrompt === "string" ? groupRule.groupingPrompt.trim() : "";
11958
+ return {
11959
+ groupId: group.id,
11960
+ title: group.title,
11961
+ count: group.count,
11962
+ topPriority: group.topPriority,
11963
+ ...groupingPrompt ? { groupingPrompt } : {},
11964
+ items: (group.requestDatas ?? []).map((row, index) => ({
11965
+ idx: index + 1,
11966
+ requestId: row.requestId,
11967
+ title: row.requestNameTitle ?? "",
11968
+ // 客户问题支持类无侧重点时按这两个布尔分组(模型不用自己解析日期文案)
11969
+ overdue: isOverdueRow(row),
11970
+ expiringToday: isExpiringTodayRow(row),
11971
+ ...row.userOverTime ? { userOverTime: row.userOverTime } : {},
11972
+ ...row.summary ? { summary: row.summary } : {},
11973
+ // `summaryCached:true` = 这条已有本地摘要(按 requestId__lastFeedBackDateTime 命中),
11974
+ // 分组仍要做(聚类看标题),但**不要再给它写摘要**。
11975
+ ...cachedSummaryIds.has(row.requestId) ? { summaryCached: true } : {},
11976
+ ...fieldsById.has(row.requestId) ? { fields: fieldsById.get(row.requestId) } : {}
11977
+ }))
11978
+ };
11979
+ });
11625
11980
  const groupingFocus = typeof args.groupFocus === "string" ? args.groupFocus.trim() : "";
11626
11981
  groupInfo = {
11627
11982
  smartSummaryTitle: grouped.smartSummaryTitle,
@@ -11814,11 +12169,11 @@ function readAiGroups(value) {
11814
12169
  if (!record) {
11815
12170
  throw workflowValidationError("ai_groups_invalid", `${label} \u5FC5\u987B\u662F\u5BF9\u8C61 { groupId, title, requestIds }`, { retryAllowed: false });
11816
12171
  }
11817
- const unknownKeys = Object.keys(record).filter((key) => !["groupId", "title", "requestIds", "seq"].includes(key));
12172
+ const unknownKeys = Object.keys(record).filter((key) => !["groupId", "title", "requestIds"].includes(key));
11818
12173
  if (unknownKeys.length > 0) {
11819
12174
  throw workflowValidationError(
11820
12175
  "ai_groups_invalid",
11821
- `${label} \u4E0D\u63A5\u53D7\u5B57\u6BB5\uFF1A${unknownKeys.join(", ")}\uFF1B\u53EA\u652F\u6301 groupId / title / requestIds / seq`,
12176
+ `${label} \u4E0D\u63A5\u53D7\u5B57\u6BB5\uFF1A${unknownKeys.join(", ")}\uFF1B\u53EA\u652F\u6301 groupId / title / requestIds`,
11822
12177
  { retryAllowed: false, details: { unknownKeys } }
11823
12178
  );
11824
12179
  }
@@ -11839,37 +12194,15 @@ function readAiGroups(value) {
11839
12194
  );
11840
12195
  }
11841
12196
  const hasIds = Array.isArray(record.requestIds) && record.requestIds.length > 0;
11842
- const hasSeq = Array.isArray(record.seq) && record.seq.length > 0;
11843
- if (hasIds && hasSeq) {
11844
- throw workflowValidationError(
11845
- "ai_groups_invalid",
11846
- `${label} \u4E0D\u80FD\u540C\u65F6\u7ED9 requestIds \u4E0E seq\uFF1A\u7528 seq\uFF08\u7EC4\u5185\u5E8F\u53F7\uFF0C\u63A8\u8350\uFF09\u6216 requestIds\uFF08\u663E\u5F0F ID\uFF09\u4E8C\u9009\u4E00`,
11847
- { retryAllowed: false }
11848
- );
11849
- }
11850
- if (!hasIds && !hasSeq) {
12197
+ if (!hasIds) {
11851
12198
  throw workflowValidationError(
11852
12199
  "ai_groups_invalid",
11853
- `${label} \u9700\u8981 requestIds \u6216 seq\uFF08\u7EC4\u5185 1-based \u5E8F\u53F7\uFF0C\u89C1 collect \u7684 groupingBrief\uFF09`,
12200
+ `${label} \u5FC5\u987B\u7ED9 requestIds\uFF08\u975E\u7A7A\u7684 requestId \u5B57\u7B26\u4E32\u6570\u7EC4\uFF09`,
11854
12201
  { retryAllowed: false }
11855
12202
  );
11856
12203
  }
11857
- const seqNumbers = [];
11858
- if (hasSeq) {
11859
- for (const item of record.seq) {
11860
- const n = typeof item === "number" ? item : Number(item);
11861
- if (!Number.isInteger(n) || n < 1) {
11862
- throw workflowValidationError(
11863
- "ai_groups_invalid",
11864
- `${label}.seq \u53EA\u63A5\u53D7 \u22651 \u7684\u6574\u6570\u5E8F\u53F7\uFF0C\u6536\u5230 ${String(item)}`,
11865
- { retryAllowed: false }
11866
- );
11867
- }
11868
- seqNumbers.push(n);
11869
- }
11870
- }
11871
12204
  const ids = [];
11872
- for (const item of hasIds ? record.requestIds : []) {
12205
+ for (const item of record.requestIds) {
11873
12206
  const id = typeof item === "string" ? item.trim() : typeof item === "number" ? String(item) : "";
11874
12207
  if (!id) {
11875
12208
  throw workflowValidationError(
@@ -11881,7 +12214,7 @@ function readAiGroups(value) {
11881
12214
  ids.push(id);
11882
12215
  }
11883
12216
  const bucket = map.get(groupId) ?? [];
11884
- bucket.push({ groupId, title, requestIds: [...new Set(ids)], seq: [...new Set(seqNumbers)] });
12217
+ bucket.push({ groupId, title, requestIds: [...new Set(ids)] });
11885
12218
  map.set(groupId, bucket);
11886
12219
  });
11887
12220
  return map;
@@ -11900,34 +12233,21 @@ function ctxEmptyOf(facts) {
11900
12233
  function rowMetricsOf(row, metrics) {
11901
12234
  return metrics?.get(row.requestId) ?? {};
11902
12235
  }
11903
- function deterministicGroupSummary(kind, rows, metrics, restCount = 0) {
11904
- if (!isDeterministicGroupKind(kind)) return null;
11905
- const creators = normalizeCreators(rows.map((row) => row.createrName));
11906
- if (kind === "issue-support") {
11907
- return formatIssueSupportGroupSummary({ count: rows.length, restCount, creators });
12236
+ function metricValueOf(row, metric, sysArg, facts, metrics) {
12237
+ if (sysArg) {
12238
+ const key = Object.keys(row).find((item) => item.toLowerCase() === metric.toLowerCase());
12239
+ return key ? row[key] : void 0;
11908
12240
  }
11909
- if (kind === "leave") {
11910
- const items = rows.map((row) => rowMetricsOf(row, metrics));
11911
- return formatLeaveGroupSummary({
11912
- count: rows.length,
11913
- leaveTypes: items.map((item) => item.leaveType),
11914
- creators
11915
- });
12241
+ const rowMetrics = metrics?.get(row.requestId);
12242
+ if (rowMetrics) {
12243
+ if (/金额|费用|价|合计/u.test(metric) && typeof rowMetrics.amount === "number") return rowMetrics.amount;
12244
+ if (/天数|时长/u.test(metric) && typeof rowMetrics.leaveDays === "number") return rowMetrics.leaveDays;
12245
+ if (/假别|假种|假期/u.test(metric) && typeof rowMetrics.leaveType === "string") return rowMetrics.leaveType;
11916
12246
  }
11917
- if (kind === "finance") {
11918
- const items = rows.map((row) => rowMetricsOf(row, metrics));
11919
- const amounts = items.map((item) => item.amount).filter((value) => typeof value === "number" && value > 0);
11920
- if (amounts.length === 0) return null;
11921
- const sum = Number(amounts.reduce((total, value) => total + value, 0).toFixed(2));
11922
- return formatFinanceGroupSummary({
11923
- min: Math.min(...amounts),
11924
- max: Math.max(...amounts),
11925
- sum,
11926
- categories: items.map((item) => item.feeCategory),
11927
- creators
11928
- });
11929
- }
11930
- return null;
12247
+ const fact = facts?.get(row.requestId);
12248
+ const field = (fact?.fields ?? []).find((item) => String(item.fieldName ?? "").includes(metric));
12249
+ const value = field?.value;
12250
+ return value === void 0 || String(value).trim() === "" ? void 0 : value;
11931
12251
  }
11932
12252
  function totalTodoCount(groups) {
11933
12253
  const seen = /* @__PURE__ */ new Set();
@@ -11995,6 +12315,7 @@ async function runSmartGroup(args, env, options = {}) {
11995
12315
  }
11996
12316
  }
11997
12317
  const warnings = (base.warnings ?? []).filter((text) => !text.startsWith("markdown \u53EA\u5C55\u793A\u524D"));
12318
+ warnings.push(...primeRules(env.ctx).warnings);
11998
12319
  if (skipDetail) {
11999
12320
  warnings.push("withDetailContext=false\uFF1A\u672C\u6B21\u672A\u62C9\u53D6\u4EFB\u4F55\u8BE6\u60C5\u2014\u2014\u8BF7\u5047/\u8D22\u52A1\u9608\u503C\u6539\u4E3A\u6309\u6807\u9898\u8BC6\u522B\u3001\u8DF3\u8FC7\u6574\u7EC4\u7A7A\u5224\u5B9A\uFF0C\u4E5F\u4E0D\u4EA7 summaryBatches");
12000
12321
  } else if (cachedIds.size > 0) {
@@ -12009,7 +12330,7 @@ async function runSmartGroup(args, env, options = {}) {
12009
12330
  topPriority: true,
12010
12331
  title: group.title,
12011
12332
  count: group.count,
12012
- // 只有优先组默认展开,其余分组一律收缩。
12333
+ // 大分组(含优先组)默认展开;只有汇总项(ai二次分组)收缩。
12013
12334
  defaultExpanded: true,
12014
12335
  displayItems: requestItemsOf(group.requestDatas)
12015
12336
  };
@@ -12018,106 +12339,78 @@ async function runSmartGroup(args, env, options = {}) {
12018
12339
  const used = /* @__PURE__ */ new Set();
12019
12340
  const subGroups = [];
12020
12341
  const singles = [];
12021
- const kind = detectBusinessKind(group.title);
12022
- const rawPlans = plans?.get(group.id) ?? [];
12023
- const groupHasFocus = hasFocus && focusAppliesToKind(groupFocus, kind);
12024
- const plansAllowed = groupHasFocus || kind === "internal-message";
12025
- const groupPlans = plansAllowed ? rawPlans : [];
12026
- if (rawPlans.length > 0 && !plansAllowed) {
12027
- warnings.push(hasFocus ? `\u300C${group.title}\u300D\u610F\u56FE\u300C${groupFocus}\u300D\u4E0D\u9002\u7528\u4E8E\u672C\u7C7B\u578B\uFF0C\u5DF2\u5FFD\u7565 aiGroups\uFF0C\u6309\u65E0\u610F\u56FE\u89C4\u5219\u5904\u7406` : `\u300C${group.title}\u300D${BUSINESS_KIND_LABEL[kind]}\u9ED8\u8BA4\u4E0D\u6309\u6807\u9898\u4E8C\u6B21\u5206\u7EC4\uFF0C\u5DF2\u5FFD\u7565 aiGroups\uFF08\u8981\u6309\u4FA7\u91CD\u70B9\u5206\u7EC4\u8BF7\u5728 groupFocus \u91CC\u8BF4\u660E\uFF09`);
12028
- }
12029
12342
  const flatReturn = () => ({
12030
12343
  id: group.id,
12031
12344
  topPriority: false,
12032
12345
  title: group.title,
12033
12346
  count: group.count,
12034
- defaultExpanded: false,
12347
+ defaultExpanded: true,
12035
12348
  displayItems: requestItemsOf(group.requestDatas)
12036
12349
  });
12037
- if (kind === "satisfaction") {
12038
- if (rawPlans.length > 0) warnings.push(`\u300C${group.title}\u300D\u6EE1\u610F\u5EA6\u7C7B\u4E0D\u505A ai\u4E8C\u6B21\u5206\u7EC4\uFF0C\u5DF2\u5FFD\u7565 aiGroups`);
12039
- warnings.push(`\u300C${group.title}\u300D\u5C5E\u4E8E\u6EE1\u610F\u5EA6\u7C7B\uFF0C\u5168\u90E8\u5E73\u94FA\u5355\u6761\uFF1Bsummary \u7531\u6807\u9898\u515C\u5E95\uFF08\u4E0D\u8C03 AI\uFF09`);
12350
+ const rawPlans = plans?.get(group.id) ?? [];
12351
+ const rule = activeRuleFor(group.title);
12352
+ if (!rule?.aiGroup) {
12353
+ if (rawPlans.length > 0) warnings.push(`\u300C${group.title}\u300D\u672A\u914D\u7F6E aiGroup\uFF0C\u5DF2\u5FFD\u7565 aiGroups`);
12354
+ if (!rule?.needSummary) warnings.push(`\u300C${group.title}\u300D\u4E0D\u9700\u8981 AI \u6458\u8981\uFF0Csummary \u7528\u6807\u9898\u515C\u5E95`);
12355
+ warnings.push(`\u300C${group.title}\u300D\u672A\u914D\u7F6E ai\u4E8C\u6B21\u5206\u7EC4\uFF0C${group.requestDatas.length} \u6761\u5E73\u94FA`);
12040
12356
  return flatReturn();
12041
12357
  }
12358
+ const groupRule = rule.aiGroup.groupRule;
12359
+ const focusMode = groupRule.focus === true;
12360
+ const groupPlans = rawPlans;
12042
12361
  if (group.requestDatas.length < GROUP_MIN_ITEMS_FOR_SUBGROUP) {
12043
- if (rawPlans.length > 0) warnings.push(`\u300C${group.title}\u300D\u4E0D\u8DB3 3 \u6761\uFF08\u786C\u95E8\u69DB\uFF09\uFF0C\u5FFD\u7565 aiGroups \u5E76\u5E73\u94FA`);
12362
+ if (rawPlans.length > 0) warnings.push(`\u300C${group.title}\u300D\u4E0D\u8DB3 ${GROUP_MIN_ITEMS_FOR_SUBGROUP} \u6761\uFF08\u786C\u95E8\u69DB\uFF09\uFF0C\u5FFD\u7565 aiGroups \u5E76\u5E73\u94FA`);
12044
12363
  return flatReturn();
12045
12364
  }
12046
- if (groupHasFocus && groupPlans.length === 0 && kind !== "internal-message") {
12047
- warnings.push(`\u300C${group.title}\u300D\u610F\u56FE\u9002\u7528\u4F46\u6A21\u578B\u672A\u7ED9\u672C\u7EC4\u8BA1\u5212\uFF0C\u6309\u65E0\u610F\u56FE\u5904\u7406`);
12048
- }
12049
- if (kind === "internal-message" && groupPlans.length === 0) {
12365
+ if (!focusMode && groupPlans.length === 0) {
12366
+ const groupingPrompt = typeof groupRule.groupingPrompt === "string" ? groupRule.groupingPrompt.trim() : "";
12050
12367
  throw workflowValidationError(
12051
12368
  "ai_groups_required",
12052
- `\u300C${group.title}\u300D\u5C5E\u4E8E\u5185\u90E8\u7559\u8A00\u4E14\u4E0D\u5C11\u4E8E ${GROUP_MIN_ITEMS_FOR_SUBGROUP} \u6761\uFF0C\u5FC5\u987B\u7ED9\u672C\u7EC4 aiGroups\uFF1A` + (groupHasFocus ? `\u7528\u6237\u4FA7\u91CD\u70B9\u300C${groupFocus}\u300D\u9002\u7528\u4E8E\u5185\u90E8\u7559\u8A00\uFF0C\u8BF7\u6309\u4FA7\u91CD\u70B9\u7ED3\u5408\u6D41\u7A0B\u8BE6\u60C5\u6570\u636E\u5206\u7EC4` : "\u5F53\u524D\u6CA1\u6709\u9002\u7528\u4E8E\u5185\u90E8\u7559\u8A00\u7684\u4FA7\u91CD\u70B9\uFF0C\u8BF7**\u6309\u6D41\u7A0B\u6807\u9898**\u5206\u7EC4\uFF08\u540C\u4E3B\u9898\u7684\u901A\u77E5/\u516C\u544A\u5F52\u5230\u540C\u4E00\u5B50\u7EC4\uFF09") + `\uFF1B\u53EF\u7528 groupId\uFF1A${group.id}\uFF0C\u7EC4\u5185\u5E8F\u53F7 1..${group.requestDatas.length}`,
12369
+ `\u300C${group.title}\u300D\u6309\u89C4\u5219\u8981\u6C42\u505A AI \u4E8C\u6B21\u5206\u7EC4\uFF08focus=false\uFF0C\u4E0A\u4E0B\u6587\uFF1A${groupRule.aiContext ?? "\u6D41\u7A0B\u6807\u9898"}\uFF09\uFF0C\u5FC5\u987B\u7ED9\u672C\u7EC4 aiGroups\uFF1B\u53EF\u7528 groupId\uFF1A${group.id}\uFF0CrequestIds \u53D6\u672C\u7EC4 ${group.requestDatas.length} \u6761` + (groupingPrompt ? `\u3002\u5206\u7EC4\u53E3\u5F84\uFF08groupingPrompt\uFF09\uFF1A${groupingPrompt}` : ""),
12053
12370
  {
12054
12371
  retryAllowed: true,
12055
- details: { groupId: group.id, count: group.requestDatas.length, groupFocus: groupHasFocus ? groupFocus : "" }
12372
+ details: {
12373
+ groupId: group.id,
12374
+ count: group.requestDatas.length,
12375
+ aiContext: groupRule.aiContext ?? "",
12376
+ ...groupingPrompt ? { groupingPrompt } : {}
12377
+ }
12056
12378
  }
12057
12379
  );
12058
12380
  }
12059
12381
  if (groupPlans.length === 0) {
12060
- if (kind === "leave" || kind === "finance") {
12061
- const eligible = [];
12062
- let unknown = 0;
12063
- for (const row of group.requestDatas) {
12064
- const metric = rowMetricsOf(row, metrics);
12065
- const value = kind === "leave" ? metric.leaveDays : metric.amount;
12066
- const hit = kind === "leave" ? typeof value === "number" && value <= LEAVE_DAY_THRESHOLD : typeof value === "number" && value > 0 && value <= FINANCE_AMOUNT_THRESHOLD;
12067
- if (hit) eligible.push(row);
12068
- else {
12069
- singles.push(row);
12070
- if (typeof value !== "number") unknown += 1;
12071
- }
12072
- }
12073
- if (eligible.length > 0) {
12074
- subGroups.push({
12075
- title: kind === "leave" ? LEAVE_GROUP_TITLE : FINANCE_GROUP_TITLE,
12076
- requestDatas: eligible
12077
- });
12078
- warnings.push(`\u300C${group.title}\u300D\u6309${kind === "leave" ? "\u8BF7\u5047\u7C7B 1\u5929\u4EE5\u5185" : "\u8D22\u52A1\u7C7B 100\u5143\u4EE5\u5185"}\u786E\u5B9A\u6027\u6C47\u603B\uFF0C\u5176\u4F59\u6761\u76EE\u5E73\u94FA`);
12079
- }
12080
- if (unknown > 0) {
12081
- warnings.push(
12082
- `\u300C${group.title}\u300D\u6709 ${unknown} \u6761\u6D41\u7A0B\u8BE6\u60C5\u6570\u636E\u53D6\u4E0D\u5230${kind === "leave" ? "\u8BF7\u5047\u5929\u6570" : "\u62A5\u9500\u91D1\u989D"}\uFF0C\u4E0D\u505A ai\u4E8C\u6B21\u5206\u7EC4\u3001\u6309\u5355\u6761\u5E73\u94FA`
12083
- );
12084
- }
12085
- } else if (kind === "issue-support") {
12086
- const urgentRows = [];
12087
- const rest = [];
12088
- for (const row of group.requestDatas) {
12089
- if (isExpiredUserOverTime(row.userOverTime) || isExpiringTodayRow(row)) urgentRows.push(row);
12090
- else rest.push(row);
12091
- }
12092
- singles.push(...rest);
12093
- if (urgentRows.length > 0) {
12094
- subGroups.push({ title: ISSUE_SUPPORT_GROUP_TITLE, requestDatas: urgentRows });
12095
- warnings.push(
12096
- `\u300C${group.title}\u300D\u6309\u5BA2\u6237\u95EE\u9898\u652F\u6301\u7C7B\u53E3\u5F84\uFF1A${urgentRows.length} \u6761\u5DF2\u8FC7\u671F\u6216\u4ECA\u65E5\u5230\u671F\uFF0C\u5176\u4F59 ${rest.length} \u6761\u5E73\u94FA`
12097
- );
12098
- } else {
12099
- warnings.push(`\u300C${group.title}\u300D\u6CA1\u6709\u5DF2\u8FC7\u671F\u6216\u4ECA\u65E5\u5230\u671F\u7684\u6761\u76EE\uFF08userOverTime \u672A\u547D\u4E2D\uFF09\uFF0C\u5168\u90E8\u5E73\u94FA`);
12100
- }
12382
+ const conditions = groupRule.focusKeyword ?? [];
12383
+ const sysArg = groupRule.sysArg === true;
12384
+ const hit = [];
12385
+ const missing = /* @__PURE__ */ new Set();
12386
+ for (const row of group.requestDatas) {
12387
+ const resolve3 = (metric) => {
12388
+ const value = metricValueOf(row, metric, sysArg, facts, metrics);
12389
+ if (value === void 0) missing.add(metric);
12390
+ return value;
12391
+ };
12392
+ if (conditions.length > 0 && evaluateFocusKeywords(conditions, resolve3)) hit.push(row);
12393
+ else singles.push(row);
12394
+ }
12395
+ const conditionText = conditions.map((condition) => condition.join(" ")).join(" \u4E14 ");
12396
+ const title = groupRule.groupTitle?.trim() || conditionText || "\u6C47\u603B";
12397
+ if (hit.length > 0) {
12398
+ subGroups.push({ title, requestDatas: hit });
12399
+ warnings.push(
12400
+ `\u300C${group.title}\u300D\u6309\u89C4\u5219\u300C${title}\u300D\u547D\u4E2D ${hit.length} \u6761\uFF08${conditionText}\uFF09\uFF0C\u5176\u4F59 ${group.requestDatas.length - hit.length} \u6761\u5E73\u94FA`
12401
+ );
12101
12402
  } else {
12102
- singles.push(...group.requestDatas);
12103
- warnings.push(`\u300C${group.title}\u300D\u9ED8\u8BA4\u4E0D\u505A ai\u4E8C\u6B21\u5206\u7EC4\uFF0C${group.requestDatas.length} \u6761\u5E73\u94FA`);
12403
+ warnings.push(`\u300C${group.title}\u300D\u89C4\u5219\u300C${title}\u300D\u547D\u4E2D 0 \u6761${conditionText ? `\uFF08${conditionText}\uFF09` : ""}\uFF0C\u5168\u90E8\u5E73\u94FA`);
12404
+ }
12405
+ if (missing.size > 0) {
12406
+ warnings.push(`\u300C${group.title}\u300D\u6307\u6807\u53D6\u4E0D\u5230\uFF1A${[...missing].join("\u3001")}\uFF0C\u76F8\u5173\u6761\u76EE\u6309\u5355\u6761\u5E73\u94FA\uFF1B\u8BF7\u68C0\u67E5\u89C4\u5219\u91CC\u7684\u6307\u6807\u540D`);
12104
12407
  }
12105
12408
  } else {
12106
- const reservedTitle = kind === "leave" ? LEAVE_GROUP_TITLE : kind === "finance" ? FINANCE_GROUP_TITLE : "";
12409
+ const reservedTitle = groupRule.groupTitle ?? "";
12107
12410
  const droppedByThreshold = [];
12108
12411
  for (const plan of groupPlans) {
12109
12412
  const datas = [];
12110
- const planRequestIds = plan.requestIds.length > 0 ? plan.requestIds : plan.seq.map((n) => {
12111
- const row = group.requestDatas[n - 1];
12112
- if (!row) {
12113
- throw workflowValidationError(
12114
- "ai_group_seq_out_of_range",
12115
- `aiGroups \u7ED9\u300C${group.title}\u300D\u7684 seq \u91CC\u6709 ${n}\uFF0C\u4F46\u8BE5\u7EC4\u53EA\u6709 ${group.requestDatas.length} \u6761\uFF08\u5E8F\u53F7\u4ECE 1 \u5F00\u59CB\uFF09`,
12116
- { retryAllowed: true, details: { groupId: group.id, seq: n, count: group.requestDatas.length } }
12117
- );
12118
- }
12119
- return row.requestId;
12120
- });
12413
+ const planRequestIds = plan.requestIds;
12121
12414
  for (const requestId of planRequestIds) {
12122
12415
  const data = byRequestId.get(requestId);
12123
12416
  if (!data) {
@@ -12141,11 +12434,11 @@ async function runSmartGroup(args, env, options = {}) {
12141
12434
  if (reservedTitle && plan.title === reservedTitle) {
12142
12435
  const kept2 = [];
12143
12436
  const dropped = [];
12437
+ const conditions = groupRule.focusKeyword ?? [];
12438
+ const sysArg = groupRule.sysArg === true;
12144
12439
  for (const row of datas) {
12145
- const metric = rowMetricsOf(row, metrics);
12146
- const value = kind === "leave" ? metric.leaveDays : metric.amount;
12147
- const hit = kind === "leave" ? typeof value === "number" && value <= LEAVE_DAY_THRESHOLD : typeof value === "number" && value > 0 && value <= FINANCE_AMOUNT_THRESHOLD;
12148
- (hit ? kept2 : dropped).push(row);
12440
+ const resolve3 = (metric) => metricValueOf(row, metric, sysArg, facts, metrics);
12441
+ (conditions.length > 0 && evaluateFocusKeywords(conditions, resolve3) ? kept2 : dropped).push(row);
12149
12442
  }
12150
12443
  if (dropped.length > 0) {
12151
12444
  droppedByThreshold.push(...dropped);
@@ -12173,8 +12466,38 @@ async function runSmartGroup(args, env, options = {}) {
12173
12466
  singles.push(...uncovered);
12174
12467
  warnings.push(`\u300C${group.title}\u300D\u6709 ${uncovered.length} \u6761\u672A\u88AB AI \u5206\u7EC4\uFF0C\u6309\u5355\u6761\u5E73\u94FA\uFF08\u4E0D\u9020 other \u5B50\u7EC4\uFF09`);
12175
12468
  }
12469
+ if (focusMode && subGroups.length > 1) {
12470
+ const sorted = [...subGroups].sort((a, b) => b.requestDatas.length - a.requestDatas.length);
12471
+ const [keep] = sorted;
12472
+ const dropped = sorted.slice(1);
12473
+ const droppedCount = dropped.reduce((sum, sub) => sum + sub.requestDatas.length, 0);
12474
+ for (const sub of dropped) singles.push(...sub.requestDatas);
12475
+ subGroups.length = 0;
12476
+ subGroups.push(keep);
12477
+ warnings.push(
12478
+ `\u300C${group.title}\u300D\u4FA7\u91CD\u70B9\u4EA7\u51FA ${sorted.length} \u4E2A\u5B50\u7EC4\uFF0C\u6309\u89C4\u5219\u53EA\u4FDD\u7559\u6761\u6570\u6700\u591A\u7684\u300C${keep.title}\u300D\uFF08${keep.requestDatas.length} \u6761\uFF09\uFF0C\u5176\u4F59 ${droppedCount} \u6761\u6539\u5355\u6761\u5E73\u94FA`
12479
+ );
12480
+ }
12176
12481
  }
12177
- if (!groupHasFocus) subGroups.sort((a, b) => b.requestDatas.length - a.requestDatas.length);
12482
+ const renderSubGroupSummary = (sub) => {
12483
+ const groupSummary = rule.aiGroup?.groupSummary;
12484
+ if (!groupSummary || groupSummary.needAI || !groupSummary.template) return "";
12485
+ if (groupRule.groupTitle && sub.title !== groupRule.groupTitle) return "";
12486
+ const rows = sub.requestDatas;
12487
+ const items = rows.map((row) => rowMetricsOf(row, metrics));
12488
+ const amounts = items.map((item) => item.amount).filter((value) => typeof value === "number" && value > 0);
12489
+ if (groupSummary.template.includes("{{min}}") && amounts.length === 0) return "";
12490
+ return renderGroupSummaryTemplate({
12491
+ template: groupSummary.template,
12492
+ tail: groupSummary.tail,
12493
+ count: rows.length,
12494
+ restCount: singles.length,
12495
+ categories: items.map((item) => item.leaveType ?? item.feeCategory),
12496
+ amounts,
12497
+ creators: rows.map((row) => row.createrName)
12498
+ });
12499
+ };
12500
+ if (!focusMode) subGroups.sort((a, b) => b.requestDatas.length - a.requestDatas.length);
12178
12501
  const groupItems = subGroups.map((sub, index) => ({
12179
12502
  // 键顺序照新目标结构:type → id → title → count → summary → defaultExpanded → requestDatas
12180
12503
  type: "group",
@@ -12182,7 +12505,7 @@ async function runSmartGroup(args, env, options = {}) {
12182
12505
  title: sub.title,
12183
12506
  count: sub.requestDatas.length,
12184
12507
  // 组摘要口径不变(Q4):只有 CLI 自己造的三类固定组用固定文案;AI 子组一律留空交 groupSummary。
12185
- summary: kind === "leave" && sub.title === LEAVE_GROUP_TITLE || kind === "finance" && sub.title === FINANCE_GROUP_TITLE || kind === "issue-support" && sub.title === ISSUE_SUPPORT_GROUP_TITLE ? deterministicGroupSummary(kind, sub.requestDatas, metrics, singles.length) ?? "" : "",
12508
+ summary: renderSubGroupSummary(sub),
12186
12509
  // 汇总项自身默认收缩(与大分组的展开状态互相独立)
12187
12510
  defaultExpanded: false,
12188
12511
  requestDatas: sub.requestDatas
@@ -12192,7 +12515,8 @@ async function runSmartGroup(args, env, options = {}) {
12192
12515
  topPriority: false,
12193
12516
  title: group.title,
12194
12517
  count: group.count,
12195
- defaultExpanded: false,
12518
+ // 大分组默认展开(与汇总项自身的收缩状态互相独立)
12519
+ defaultExpanded: true,
12196
12520
  // 汇总项在前、单独条目在后。
12197
12521
  displayItems: [...groupItems, ...requestItemsOf(singles)]
12198
12522
  };
@@ -12213,6 +12537,9 @@ async function runSmartGroup(args, env, options = {}) {
12213
12537
  }
12214
12538
 
12215
12539
  // src/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.ts
12540
+ function needAiSummary(workflowName) {
12541
+ return activeRuleFor(workflowName)?.needSummary ?? true;
12542
+ }
12216
12543
  var DEFAULT_MAX_CHARS_PER_BATCH = 24e3;
12217
12544
  var DEFAULT_MAX_ITEMS_PER_BATCH = 100;
12218
12545
  var DEFAULT_REQUEST_SUMMARY_MAX3 = 50;
@@ -12319,7 +12646,7 @@ function validateFinalGroups(value) {
12319
12646
  (sum, item) => sum + (item.type === "group" ? item.requestDatas.length : 1),
12320
12647
  0
12321
12648
  );
12322
- return topPriority ? { id, topPriority: true, title, count, defaultExpanded: true, displayItems } : { id, topPriority: false, title, count, defaultExpanded: false, displayItems };
12649
+ return topPriority ? { id, topPriority: true, title, count, defaultExpanded: true, displayItems } : { id, topPriority: false, title, count, defaultExpanded: true, displayItems };
12323
12650
  });
12324
12651
  }
12325
12652
  async function readFinalGroups(args, env) {
@@ -12340,7 +12667,7 @@ function collectSummaryUnits(groups) {
12340
12667
  const units = [];
12341
12668
  for (const group of groups) {
12342
12669
  if (group.topPriority) {
12343
- if (!needsRequestSummary(detectBusinessKind(group.title))) continue;
12670
+ if (!needAiSummary(group.title)) continue;
12344
12671
  units.push({
12345
12672
  groupId: group.id,
12346
12673
  groupTitle: group.title,
@@ -12381,7 +12708,7 @@ function collectSummaryUnits(groups) {
12381
12708
  async function runSummaryContext(args, env, prefetched) {
12382
12709
  const groups = await readFinalGroups(args, env);
12383
12710
  const units = collectSummaryUnits(groups);
12384
- const skippedSatisfaction = groups.filter((group) => usesTitleSummary(detectBusinessKind(group.title))).reduce((sum, group) => sum + rowsOfGroup(group).length, 0);
12711
+ const skippedSatisfaction = groups.filter((group) => !needAiSummary(group.title)).reduce((sum, group) => sum + rowsOfGroup(group).length, 0);
12385
12712
  const requestIds = [...new Set(units.flatMap((unit) => unit.rows.map((row) => row.requestId)))].filter(Boolean);
12386
12713
  const summaryMaxChars = readBoundedInt(
12387
12714
  args.summaryMaxChars,
@@ -12579,7 +12906,7 @@ async function runSummary(args, env) {
12579
12906
  let cacheWritten = 0;
12580
12907
  let titleSummary = 0;
12581
12908
  for (const group of groups) {
12582
- if (usesTitleSummary(detectBusinessKind(group.title))) {
12909
+ if (!needAiSummary(group.title)) {
12583
12910
  for (const row of rowsOfGroup(group)) {
12584
12911
  if ((row.summary ?? "").trim()) continue;
12585
12912
  row.summary = row.requestNameTitle ?? "";
@@ -12642,7 +12969,7 @@ async function runSummary(args, env) {
12642
12969
  }
12643
12970
  };
12644
12971
  for (const group of groups) {
12645
- if (!needsRequestSummary(detectBusinessKind(group.title))) continue;
12972
+ if (!needAiSummary(group.title)) continue;
12646
12973
  if (group.topPriority) {
12647
12974
  applyAll(rowsOfGroup(group));
12648
12975
  continue;
@@ -12669,7 +12996,7 @@ async function runSummary(args, env) {
12669
12996
  if (prefilledKept > 0) {
12670
12997
  warnings.push(`\u6709 ${prefilledKept} \u6761\u6CBF\u7528\u672C\u5730\u6458\u8981\u7F13\u5B58\uFF08\u672A\u91CD\u65B0\u751F\u6210\uFF09`);
12671
12998
  }
12672
- const titleSummaryCount = groups.filter((group) => usesTitleSummary(detectBusinessKind(group.title))).reduce((sum, group) => sum + rowsOfGroup(group).length, 0);
12999
+ const titleSummaryCount = groups.filter((group) => !needAiSummary(group.title)).reduce((sum, group) => sum + rowsOfGroup(group).length, 0);
12673
13000
  if (titleSummaryCount > 0) {
12674
13001
  warnings.push(`\u6709 ${titleSummaryCount} \u6761\u6EE1\u610F\u5EA6\u7C7B\u5F85\u529E\u4E0D\u8C03\u7528 AI\uFF0Csummary \u76F4\u63A5\u4F7F\u7528\u6761\u76EE\u6807\u9898\uFF08\u4FDD\u8BC1\u975E\u7A7A\uFF09`);
12675
13002
  }
@@ -12837,7 +13164,7 @@ async function runGroupSummaryContext(args, env) {
12837
13164
  "\u672C\u6B21\u6CA1\u6709\u9700\u8981 AI \u5199\u7EC4\u6458\u8981\u7684\u6C47\u603B\u9879\uFF1A\u6240\u6709\u4E8C\u6B21\u5206\u7EC4\u6C47\u603B\u9879\u7684\u7EC4\u6458\u8981\u5747\u7531 CLI \u56FA\u5B9A\u751F\u6210"
12838
13165
  );
12839
13166
  }
12840
- const deterministicGroups = groups.filter((group) => !group.topPriority && isDeterministicGroupKind(detectBusinessKind(group.title))).reduce((sum, group) => sum + groupItemsOf(group).length, 0);
13167
+ const deterministicGroups = groups.filter((group) => !group.topPriority && activeRuleFor(group.title)?.aiGroup?.groupSummary.needAI === false).reduce((sum, group) => sum + groupItemsOf(group).length, 0);
12841
13168
  return {
12842
13169
  data: {
12843
13170
  smartSummaryTitle: readSmartSummaryTitle(args, `\u60A8\u5F53\u524D\u6709 ${totalCount} \u6761\u5F85\u529E\uFF0C\u6E05\u5355\u5982\u4E0B\uFF1A`),
@@ -13011,18 +13338,16 @@ var inputSchema = schemaOf({
13011
13338
  },
13012
13339
  aiGroups: {
13013
13340
  type: "array",
13014
- description: "smartGroup \u7684\u4E8C\u6B21\u5206\u7EC4\u8BA1\u5212\u3002\u6BCF\u9879\u5FC5\u987B\u63D0\u4F9B groupId\u3001title\uFF0C\u4EE5\u53CA requestIds \u4E0E seq \u4E8C\u9009\u4E00\u3002",
13341
+ description: "smartGroup \u7684\u4E8C\u6B21\u5206\u7EC4\u8BA1\u5212\u3002\u6BCF\u9879\u5FC5\u987B\u63D0\u4F9B groupId\u3001title\u3001requestIds\u3002",
13015
13342
  items: {
13016
13343
  type: "object",
13017
13344
  additionalProperties: false,
13018
13345
  properties: {
13019
13346
  groupId: { type: "string" },
13020
13347
  title: { type: "string" },
13021
- requestIds: { type: "array", minItems: 1, items: { type: "string" } },
13022
- seq: { type: "array", minItems: 1, items: { type: "integer", minimum: 1 } }
13348
+ requestIds: { type: "array", minItems: 1, items: { type: "string" } }
13023
13349
  },
13024
- required: ["groupId", "title"],
13025
- oneOf: [{ required: ["requestIds"] }, { required: ["seq"] }]
13350
+ required: ["groupId", "title", "requestIds"]
13026
13351
  }
13027
13352
  },
13028
13353
  aiSummaries: {
@@ -15600,6 +15925,13 @@ export {
15600
15925
  asObject,
15601
15926
  assertNoForbiddenKeys,
15602
15927
  compactStdoutPaths,
15928
+ USER_INTENT_RULE_FILE,
15929
+ emptyRuleFile,
15930
+ validateRuleFile,
15931
+ loadRuleFile,
15932
+ aigroupUserDir,
15933
+ loadRules,
15934
+ resetActiveRules,
15603
15935
  workflowOperationDefinitions,
15604
15936
  getWorkflowOperation,
15605
15937
  hasWorkflowOperation