weaver-work-cli 0.1.32 → 0.1.36

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 (211) hide show
  1. package/README.md +2 -2
  2. package/dist/chunks/{archive-UMGX72K6.js → archive-XBVH7JU7.js} +2 -2
  3. package/dist/chunks/{archive-oa-N2IYBLF3.js → archive-oa-MZM3EKFQ.js} +2 -2
  4. package/dist/chunks/{asset-GLEGKFG5.js → asset-4XO7UOUW.js} +2 -2
  5. package/dist/chunks/{attachment-content-AQNX5N3S.js → attachment-content-VXSWANAC.js} +3 -2
  6. package/dist/chunks/{blog-E44OTVDA.js → blog-PGZKOPSC.js} +2 -2
  7. package/dist/chunks/{caizhilian-DQUFZXZL.js → caizhilian-BH4ZVGUN.js} +2 -2
  8. package/dist/chunks/{calendar-JKPIRKFD.js → calendar-MXEMTIO4.js} +2 -2
  9. package/dist/chunks/{chunk-QWY6PGL6.js → chunk-2LV74IWP.js} +361 -56
  10. package/dist/chunks/chunk-3SO6QL6U.js +73 -0
  11. package/dist/chunks/chunk-5DQEEGCC.js +229 -0
  12. package/dist/chunks/{chunk-G3QJULO2.js → chunk-6LLJFKJE.js} +1 -1
  13. package/dist/chunks/{chunk-C6R3B2ML.js → chunk-BPE37FPB.js} +35 -7
  14. package/dist/chunks/chunk-BYATLLEF.js +68 -0
  15. package/dist/chunks/chunk-BYBSCN4X.js +932 -0
  16. package/dist/chunks/{chunk-CVZ2JOSW.js → chunk-F746NKNF.js} +1 -1
  17. package/dist/chunks/{chunk-GCG2NMWR.js → chunk-HXJQI5NM.js} +4 -2
  18. package/dist/chunks/{chunk-YRVDW4WN.js → chunk-I6QGIBDM.js} +2 -2
  19. package/dist/chunks/{chunk-H7J4DC5R.js → chunk-JCSN3JGM.js} +2 -2
  20. package/dist/chunks/{chunk-2GA5ZIQL.js → chunk-JNG42JKG.js} +30 -1
  21. package/dist/chunks/{chunk-DW6AUUKS.js → chunk-JUXVYKII.js} +9 -4
  22. package/dist/chunks/{chunk-6RKD4DRZ.js → chunk-JYKABYCV.js} +2 -2
  23. package/dist/chunks/{chunk-6EFWDL7Y.js → chunk-NCOVUAZK.js} +2 -2
  24. package/dist/chunks/{chunk-E4Z23GHM.js → chunk-QHFANTX7.js} +1114 -904
  25. package/dist/chunks/{ebuilder-form-V5FG2EHC.js → chunk-QYGO5EE2.js} +22 -1148
  26. package/dist/chunks/{chunk-IURUFGZK.js → chunk-T72N74ZT.js} +50 -33
  27. package/dist/chunks/{chunk-H6XSTSLM.js → chunk-TC6MZAO3.js} +137 -204
  28. package/dist/chunks/{chunk-WKI2FBIQ.js → chunk-VPUTVEMC.js} +737 -341
  29. package/dist/chunks/{chunk-WSKBSQ2U.js → chunk-VPXOPQJI.js} +2 -2
  30. package/dist/chunks/chunk-WXFPWCXG.js +774 -0
  31. package/dist/chunks/{chunk-4YC43QQ4.js → chunk-XMGSYD6S.js} +4 -4
  32. package/dist/chunks/conflict-JAB2LJEZ.js +21 -0
  33. package/dist/chunks/continuation-RN6PZN2M.js +11 -0
  34. package/dist/chunks/contract-XI2EEIZU.js +9110 -0
  35. package/dist/chunks/cowork-SCPGLBA4.js +2527 -0
  36. package/dist/chunks/ebuilder-form-EYLHNOTA.js +121 -0
  37. package/dist/chunks/{ehr-HMFY6VIL.js → ehr-EAP77IMT.js} +1344 -27
  38. package/dist/chunks/{esb-ZYSVB7SG.js → esb-2TGGXEE7.js} +4 -4
  39. package/dist/chunks/{fna-B7RKPAZD.js → fna-2X7ZE7BU.js} +13 -8
  40. package/dist/chunks/{host-OCH2BCCV.js → host-C6EL2RKL.js} +3 -3
  41. package/dist/chunks/{host-45WED2KK.js → host-I4NRK4MX.js} +3 -3
  42. package/dist/chunks/{host-I4Z6BFYX.js → host-Q4LZGCRU.js} +3 -3
  43. package/dist/chunks/host-UEI5FGDM.js +23 -0
  44. package/dist/chunks/{host-KNZ52LJZ.js → host-XCLDDXKQ.js} +3 -3
  45. package/dist/chunks/{hrm-2KAZGUHI.js → hrm-YXERJM76.js} +3 -3
  46. package/dist/chunks/{im-ACJJWH4U.js → im-A4VZN2TQ.js} +88 -12
  47. package/dist/chunks/{invoice-ZK3WCX2U.js → invoice-2Z6YPMIS.js} +3 -3
  48. package/dist/chunks/{jiuchuanhui-5PQD3IL2.js → jiuchuanhui-AR5GMKZB.js} +2 -2
  49. package/dist/chunks/{lazy-dispatch-JQXBW3GM.js → lazy-dispatch-QXW7P4X3.js} +4 -4
  50. package/dist/chunks/{mail-S2HDDXO2.js → mail-7GZ6CPBJ.js} +45 -24
  51. package/dist/chunks/{meeting-QVN3I37L.js → meeting-3NMGA3MB.js} +278 -43
  52. package/dist/chunks/{okr-QNG4VC2Q.js → okr-BZ6XUOAG.js} +2 -2
  53. package/dist/chunks/operations-5QL3AECO.js +11 -0
  54. package/dist/chunks/{plan-A25EMW6U.js → plan-DR5CMUYP.js} +2 -2
  55. package/dist/chunks/{project-G6XV66DZ.js → project-6J63MK33.js} +2 -2
  56. package/dist/chunks/{registry-DC6KR3NH.js → registry-KDD7DHNK.js} +4 -4
  57. package/dist/chunks/{registry-2VLUAESA.js → registry-OZSMDVPP.js} +2 -2
  58. package/dist/chunks/{registry-7C5UMIPL.js → registry-TKX2E7C7.js} +2 -2
  59. package/dist/chunks/{registry-TI3CIUXF.js → registry-VRTNC6UR.js} +8 -6
  60. package/dist/chunks/{room-recommend-WRTHO6Y2.js → room-recommend-XCWRMB5P.js} +4 -3
  61. package/dist/chunks/{schedule-KFIITGSK.js → schedule-IVBICP32.js} +4 -3
  62. package/dist/chunks/{workflow-DJ7SYWAF.js → workflow-D74NFK3C.js} +179 -6
  63. package/dist/index.js +35 -25
  64. package/dist/internal/e10/auth-recovery.js +14 -4
  65. package/dist/internal/e10/fetch-timing.js +31 -0
  66. package/dist/internal/e10/request-runtime.js +5 -0
  67. package/dist/shortcuts/contract/host.js +34 -59
  68. package/dist/shortcuts/cowork/continuation.js +70 -0
  69. package/dist/shortcuts/cowork/errors.js +59 -0
  70. package/dist/shortcuts/cowork/host.js +180 -0
  71. package/dist/shortcuts/cowork/index.js +166 -0
  72. package/dist/shortcuts/cowork/manifest.js +65 -0
  73. package/dist/shortcuts/cowork/operations/discuss-write.js +277 -0
  74. package/dist/shortcuts/cowork/operations/item-write.js +380 -0
  75. package/dist/shortcuts/cowork/operations/member-write.js +283 -0
  76. package/dist/shortcuts/cowork/operations/permission-write.js +286 -0
  77. package/dist/shortcuts/cowork/operations/read.js +423 -0
  78. package/dist/shortcuts/cowork/operations/registry.js +39 -0
  79. package/dist/shortcuts/cowork/operations/review-write.js +157 -0
  80. package/dist/shortcuts/cowork/operations/shared.js +215 -0
  81. package/dist/shortcuts/cowork/operations/types.js +39 -0
  82. package/dist/shortcuts/cowork/operations.js +19 -0
  83. package/dist/shortcuts/ehr/host.js +4 -1
  84. package/dist/shortcuts/ehr/operations/recruit-candidate-import.js +757 -0
  85. package/dist/shortcuts/ehr/operations/recruit-position.js +367 -0
  86. package/dist/shortcuts/ehr/operations/recruit-stats.js +133 -0
  87. package/dist/shortcuts/ehr/operations/recruit-write.js +43 -16
  88. package/dist/shortcuts/ehr/operations/recruit.js +182 -10
  89. package/dist/shortcuts/ehr/operations/registry.js +6 -0
  90. package/dist/shortcuts/fna/operations/expense-chart.js +19 -7
  91. package/dist/shortcuts/im/diagnostics.js +97 -0
  92. package/dist/shortcuts/im/host.js +58 -31
  93. package/dist/shortcuts/im/index.js +7 -2
  94. package/dist/shortcuts/im/operations/at-mention.js +127 -0
  95. package/dist/shortcuts/im/operations/file-user.js +10 -2
  96. package/dist/shortcuts/im/operations/group-read.js +26 -5
  97. package/dist/shortcuts/im/operations/group-write.js +35 -28
  98. package/dist/shortcuts/im/operations/msg-sync.js +7 -2
  99. package/dist/shortcuts/im/operations/msg-write.js +76 -10
  100. package/dist/shortcuts/im/operations/quote-mention.js +119 -0
  101. package/dist/shortcuts/im/operations/session.js +1 -1
  102. package/dist/shortcuts/im/operations/shared.js +10 -0
  103. package/dist/shortcuts/im/operations/types.js +13 -0
  104. package/dist/shortcuts/index.js +10 -0
  105. package/dist/shortcuts/mail/host.js +12 -1
  106. package/dist/shortcuts/mail/operations/types.js +17 -2
  107. package/dist/shortcuts/meeting/host.js +27 -34
  108. package/dist/shortcuts/meeting/index.js +79 -1
  109. package/dist/shortcuts/meeting/manifest.js +10 -0
  110. package/dist/shortcuts/meeting/operations/create.js +4 -1
  111. package/dist/shortcuts/meeting/operations/eb/catalog.js +10 -0
  112. package/dist/shortcuts/meeting/operations/eb/conflict.js +84 -8
  113. package/dist/shortcuts/meeting/operations/eb/create-flow.js +1195 -140
  114. package/dist/shortcuts/meeting/operations/eb/factory.js +170 -8
  115. package/dist/shortcuts/meeting/operations/eb/index.js +16 -3
  116. package/dist/shortcuts/meeting/operations/eb/room-recommend.js +50 -5
  117. package/dist/shortcuts/meeting/operations/eb-fallback.js +163 -0
  118. package/dist/shortcuts/meeting/operations/env.js +99 -46
  119. package/dist/shortcuts/meeting/operations/form-fields.js +110 -0
  120. package/dist/shortcuts/meeting/operations/invitation.js +79 -20
  121. package/dist/shortcuts/meeting/operations/registry.js +2 -0
  122. package/dist/shortcuts/meeting/operations/standard-guard.js +71 -0
  123. package/dist/shortcuts/meeting/operations.js +16 -0
  124. package/dist/shortcuts/workflow/endpoints.js +8 -3
  125. package/dist/shortcuts/workflow/index.js +110 -1
  126. package/dist/shortcuts/workflow/operations/form.js +204 -36
  127. package/dist/shortcuts/workflow/operations/read.js +104 -23
  128. package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupRules.js +448 -0
  129. package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupStore.js +106 -0
  130. package/dist/shortcuts/workflow/operations/todoSmartConvert/businessRules.js +47 -0
  131. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +30 -23
  132. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.core.js +1 -0
  133. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.group.js +1 -0
  134. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +2 -1
  135. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +2 -4
  136. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +138 -181
  137. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +12 -7
  138. package/dist/shortcuts/workflow/operations.js +23 -1
  139. package/docs/e10-auth.md +1 -1
  140. package/docs/ehr.md +1 -1
  141. package/docs/fna.md +2 -1
  142. package/docs/im.md +8 -1
  143. package/docs/todo-smart-convert/README.md +1 -1
  144. package/docs/todo-smart-convert/data-contract.md +2 -2
  145. package/docs/todo-smart-convert/subgroup-rules.md +6 -0
  146. package/package.json +1 -1
  147. package/skill-template/business-info.json +18 -0
  148. package/skill-template/domains/cowork.md +14 -0
  149. package/skill-template/domains/yimiaoban.md +3 -3
  150. package/skill-template/skill-template.md +1 -1
  151. package/skills/weaver-e10-blog/SKILL.md +5 -5
  152. package/skills/weaver-e10-caizhilian/SKILL.md +5 -5
  153. package/skills/weaver-e10-calendar/SKILL.md +5 -5
  154. package/skills/weaver-e10-cowork/SKILL.md +101 -0
  155. package/skills/weaver-e10-cowork/references/cowork-read.md +90 -0
  156. package/skills/weaver-e10-cowork/references/cowork-write.md +131 -0
  157. package/skills/weaver-e10-cowork/references/safety-boundaries.md +45 -0
  158. package/skills/weaver-e10-esb/SKILL.md +5 -5
  159. package/skills/weaver-e10-hrm/SKILL.md +5 -5
  160. package/skills/weaver-e10-jinchengda/SKILL.md +2 -2
  161. package/skills/weaver-e10-jiuchuanhui/SKILL.md +5 -5
  162. package/skills/weaver-e10-jucailin/SKILL.md +38 -14
  163. package/skills/weaver-e10-jucailin/references/recruit-create.md +104 -0
  164. package/skills/weaver-e10-jucailin/references/recruit-read.md +25 -0
  165. package/skills/weaver-e10-jucailin/references/recruit-write.md +13 -0
  166. package/skills/weaver-e10-jucailin/references/salary.md +15 -11
  167. package/skills/weaver-e10-mail/SKILL.md +17 -14
  168. package/skills/weaver-e10-meeting/SKILL.md +442 -46
  169. package/skills/weaver-e10-meeting/references/meeting-eb.md +135 -3
  170. package/skills/weaver-e10-meeting/references/meeting-invitation.md +28 -2
  171. package/skills/weaver-e10-meeting/references/meeting-queries.md +9 -6
  172. package/skills/weaver-e10-meeting/references/meeting-verification.md +8 -6
  173. package/skills/weaver-e10-meeting.zip +0 -0
  174. package/skills/weaver-e10-okr/SKILL.md +5 -5
  175. package/skills/weaver-e10-okr/references/source-manifest.json +3 -3
  176. package/skills/weaver-e10-plan/SKILL.md +5 -5
  177. package/skills/weaver-e10-qiyecheng/SKILL.md +5 -2
  178. package/skills/weaver-e10-qiyecheng/references/catalog.md +2 -2
  179. package/skills/weaver-e10-qiyecheng/references/expense-chart.md +15 -1
  180. package/skills/weaver-e10-qiyecheng/references/source-manifest.json +22 -21
  181. package/skills/weaver-e10-shared/SKILL.md +12 -12
  182. package/skills/weaver-e10-shared/references/e10-auth-and-session.md +4 -4
  183. package/skills/weaver-e10-wenshuding/SKILL.md +5 -5
  184. package/skills/weaver-e10-workflow/SKILL.md +29 -5
  185. package/skills/weaver-e10-workflow/aigroup/default.json +88 -0
  186. package/skills/weaver-e10-workflow/references/todo-smart-convert.md +66 -14
  187. package/skills/weaver-e10-workflow/references/workflow-agent-entry.md +1 -1
  188. package/skills/weaver-e10-workflow/references/workflow-memory.md +1 -1
  189. package/skills/weaver-e10-workflow/references/workflow-query.md +12 -10
  190. package/skills/weaver-e10-workflow/references/workflow-view.md +2 -2
  191. package/skills/weaver-e10-workflow/tools/todo-serve.cjs +239 -0
  192. package/skills/weaver-e10-workflow/{scripts → tools}/todo-summary.cjs +218 -28
  193. package/skills/weaver-e10-yepiaotong/SKILL.md +10 -8
  194. package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +7 -7
  195. package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +10 -10
  196. package/skills/weaver-e10-yepiaotong/references/reim-examples.md +40 -37
  197. package/skills/weaver-e10-yepiaotong/references/reim-expense-subject-rules.md +4 -4
  198. package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +27 -38
  199. package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +4 -4
  200. package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +37 -29
  201. package/skills/weaver-e10-yimiaoban/SKILL.md +156 -33
  202. package/skills/weaver-e10-yimiaoban/references/ding-write.md +1 -1
  203. package/skills/weaver-e10-yimiaoban/references/error-codes.md +5 -1
  204. package/skills/weaver-e10-yimiaoban/references/group-read.md +5 -1
  205. package/skills/weaver-e10-yimiaoban/references/group-write.md +6 -4
  206. package/skills/weaver-e10-yimiaoban/references/msg-read.md +1 -0
  207. package/skills/weaver-e10-yimiaoban/references/msg-write.md +34 -2
  208. package/skills/weaver-e10-yimiaoban/references/safety-boundaries.md +5 -2
  209. package/skills/weaver-e10-yimiaoban/references/source-manifest.json +79 -58
  210. package/skills/weaver-e10-yimiaoban/references/user-remind.md +2 -2
  211. package/skills/weaver-e10-ziguanjia/SKILL.md +5 -5
@@ -21,8 +21,10 @@ import {
21
21
  } from "./chunk-AJ62BGAW.js";
22
22
  import {
23
23
  E10_REAUTH_GUIDANCE,
24
- hasXiaoEEnv
25
- } from "./chunk-2GA5ZIQL.js";
24
+ createFetchTimingSink,
25
+ hasXiaoEEnv,
26
+ runWithFetchTiming
27
+ } from "./chunk-JNG42JKG.js";
26
28
 
27
29
  // src/shortcuts/workflow/operations/form.ts
28
30
  import { randomUUID } from "node:crypto";
@@ -341,9 +343,9 @@ var FORM_ENDPOINTS = {
341
343
  tenantSetting: "/api/file/tenant/setting"
342
344
  };
343
345
  var AJAX_QUERY = { sf_request_type: "ajax" };
344
- function formApiUrl(path, relateType) {
346
+ function formApiUrl(path, relateType, ebPrefix = "/api/ebuilder/flow/") {
345
347
  if (String(relateType || "").trim() === "WEA_EBUILDER") {
346
- return path.replace("/api/workflow/core/", "/api/ebuilder/flow/");
348
+ return path.replace("/api/workflow/core/", ebPrefix);
347
349
  }
348
350
  return path;
349
351
  }
@@ -2030,7 +2032,7 @@ var workflowSearch = {
2030
2032
  }, env, { json: "last_search.json", md: "last_search.md" })), startedAt);
2031
2033
  }
2032
2034
  };
2033
- var SMART_GROUPING_MIN_OA_VERSION = [10, 0, 9909, 1];
2035
+ var SMART_GROUPING_MIN_OA_VERSION = [10, 0, 9807, 1];
2034
2036
  function formatOaVersion(tuple) {
2035
2037
  const [a, b, c, d] = tuple;
2036
2038
  return `${a}.${b}.${c}.${String(d).padStart(2, "0")}`;
@@ -4839,11 +4841,25 @@ function formatHistoryFieldValue(raw, field) {
4839
4841
  }
4840
4842
  return stringifyDetailValue(raw);
4841
4843
  }
4844
+ var SAAS_COLOGY_BASE_URL = "https://www.e-cology.com.cn";
4845
+ function isSaasCologyBaseUrl(baseUrl) {
4846
+ const normalize = (value) => String(value ?? "").trim().replace(/\/+$/u, "").toLowerCase();
4847
+ return normalize(baseUrl) === SAAS_COLOGY_BASE_URL;
4848
+ }
4849
+ async function isSaasCologyEnv(env) {
4850
+ try {
4851
+ const session = await env.host.getSession();
4852
+ return isSaasCologyBaseUrl(session?.baseUrl);
4853
+ } catch {
4854
+ return false;
4855
+ }
4856
+ }
4842
4857
  async function fetchHistoryListSnapshot(env, options = {}) {
4843
4858
  try {
4844
4859
  const now = /* @__PURE__ */ new Date();
4845
4860
  const start = new Date(now.getTime() - HISTORY_LOOKBACK_DAYS * 24 * 60 * 60 * 1e3);
4846
4861
  const historyWorkflowId = String(options.workflowId ?? "").trim();
4862
+ const addDisableCheckUserPermission = await isSaasCologyEnv(env);
4847
4863
  const listResponse = await env.host.workflowRequest({
4848
4864
  method: "POST",
4849
4865
  path: WORKFLOW_ENDPOINTS.MINE_LIST,
@@ -4855,7 +4871,9 @@ async function fetchHistoryListSnapshot(env, options = {}) {
4855
4871
  dimension: "mine",
4856
4872
  flowSpareType: 1,
4857
4873
  outType: 0,
4858
- needIutData: false
4874
+ needIutData: false,
4875
+ // SaaS 公有云环境写死带上(见 `SAAS_COLOGY_BASE_URL`);其余环境不带此键。
4876
+ ...addDisableCheckUserPermission ? { disableCheckUserPermission: "1" } : {}
4859
4877
  },
4860
4878
  // `needParseData: true`:让服务端把日期等字段直接解析成可读文本(`displayData`),
4861
4879
  // 客户端不再自己转。
@@ -4944,7 +4962,31 @@ async function pickUniqueMineWorkflow(candidates, env) {
4944
4962
  return null;
4945
4963
  }
4946
4964
  }
4947
- async function buildHistoryRequestData(env, fields, targets, options = {}, prefetchedList) {
4965
+ function prefetchHistoryDetails(env, listed) {
4966
+ const requestIds = listed?.requestIds ?? [];
4967
+ if (!requestIds.length) return Promise.resolve([]);
4968
+ return (async () => {
4969
+ const session = await env.host.getSession();
4970
+ return Promise.all(requestIds.map(async (requestId) => {
4971
+ const payload = {
4972
+ requestId,
4973
+ isGetRequestBaseInfo: false,
4974
+ isGetRequestLog: false,
4975
+ isGetFormData: true,
4976
+ isReadRequest: false
4977
+ };
4978
+ if (session.userId) payload.userId = session.userId;
4979
+ const response = await env.host.workflowRequest({
4980
+ method: "POST",
4981
+ path: WORKFLOW_ENDPOINTS.REQUEST_DETAIL,
4982
+ operation: "workflow.createRequest.history.detail",
4983
+ body: payload
4984
+ });
4985
+ return detailDataOf(response);
4986
+ }));
4987
+ })();
4988
+ }
4989
+ async function buildHistoryRequestData(env, fields, targets, options = {}, prefetchedList, prefetchedDetails) {
4948
4990
  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
4991
  if (!targetList.length && !options.allFormFields) return null;
4950
4992
  const fieldMeta = /* @__PURE__ */ new Map();
@@ -4956,7 +4998,7 @@ async function buildHistoryRequestData(env, fields, targets, options = {}, prefe
4956
4998
  const items = listed.items;
4957
4999
  const requestIds = listed.requestIds;
4958
5000
  const session = await env.host.getSession();
4959
- const details = await Promise.all(requestIds.map(async (requestId) => {
5001
+ const details = prefetchedDetails ? await prefetchedDetails : await Promise.all(requestIds.map(async (requestId) => {
4960
5002
  const payload = {
4961
5003
  requestId,
4962
5004
  isGetRequestBaseInfo: false,
@@ -4973,6 +5015,7 @@ async function buildHistoryRequestData(env, fields, targets, options = {}, prefe
4973
5015
  });
4974
5016
  return detailDataOf(response);
4975
5017
  }));
5018
+ if (!details) return null;
4976
5019
  const result = [];
4977
5020
  for (let index = 0; index < details.length; index += 1) {
4978
5021
  const data = details[index] || {};
@@ -5307,6 +5350,7 @@ function parseTenantSetting(data) {
5307
5350
  return { max_size_mb: maxSizeMb, format_mode: whitesEnable ? "white" : "black", formats };
5308
5351
  }
5309
5352
  function buildLayoutRequest(workflowId, runtime, frame) {
5353
+ const isEbForm = String(frame.relate_type ?? "").trim() === "WEA_EBUILDER";
5310
5354
  const custom = {
5311
5355
  permissionType: frame.permission_type,
5312
5356
  requestId: runtime.request_id,
@@ -5322,6 +5366,7 @@ function buildLayoutRequest(workflowId, runtime, frame) {
5322
5366
  mobile: false,
5323
5367
  formId: frame.form_id,
5324
5368
  source: "view",
5369
+ ...isEbForm ? { bridgeService: "ebuilder" } : {},
5325
5370
  isAgent: false,
5326
5371
  beAgentId: "0",
5327
5372
  hideSysFieldArea: true,
@@ -5336,7 +5381,7 @@ function buildLayoutRequest(workflowId, runtime, frame) {
5336
5381
  terminalType: "PC",
5337
5382
  formId: frame.form_id,
5338
5383
  ...nodePermissionEnabled && permissionId ? { permissionId } : {},
5339
- module: "workflow",
5384
+ module: isEbForm ? "ebuildercard" : "workflow",
5340
5385
  customParam: custom,
5341
5386
  cacheUid: randomUUID(),
5342
5387
  newLayout: frame.new_layout,
@@ -5994,7 +6039,20 @@ async function resolveCreateWorkflow(rawWorkflow, env) {
5994
6039
  throw workflowClarificationError(
5995
6040
  "workflow",
5996
6041
  "",
5997
- "\u8981\u53D1\u8D77\u54EA\u4E2A\u6D41\u7A0B\uFF1F\u8BF7\u63D0\u4F9B\u8BE5\u6D41\u7A0B\u7684\u5B8C\u6574\u540D\u79F0\uFF08\u6216\u5176\u5B83\u53EF\u7528\u4E8E\u68C0\u7D22\u7684\u5173\u952E\u8BCD\uFF09\u540E\u518D\u7EE7\u7EED\u3002"
6042
+ "\u8981\u53D1\u8D77\u54EA\u4E2A\u6D41\u7A0B\uFF1F\u8BF7\u63D0\u4F9B\u8BE5\u6D41\u7A0B\u7684\u5B8C\u6574\u540D\u79F0\uFF08\u6216\u5176\u5B83\u53EF\u7528\u4E8E\u68C0\u7D22\u7684\u5173\u952E\u8BCD\uFF09\u540E\u518D\u7EE7\u7EED\u3002",
6043
+ [],
6044
+ {
6045
+ clarificationReason: "workflow_required",
6046
+ missingInput: ["workflow"],
6047
+ requiredInput: {
6048
+ workflow: {
6049
+ required: true,
6050
+ type: "string | string[]",
6051
+ description: "\u8981\u53D1\u8D77\u7684\u5DE5\u4F5C\u6D41\uFF1A\u5B8C\u6574\u540D\u79F0\u3001\u540D\u79F0\u5173\u952E\u8BCD\uFF0C\u6216\u300C\u540D\u79F0(ID)\u300D\uFF1B\u7EAF\u6570\u5B57\u6309\u5DE5\u4F5C\u6D41 ID \u5904\u7406\u3002",
6052
+ example: ["\u8D39\u7528\u62A5\u9500"]
6053
+ }
6054
+ }
6055
+ }
5998
6056
  );
5999
6057
  }
6000
6058
  const explicitIds = /* @__PURE__ */ new Set();
@@ -6164,15 +6222,15 @@ function singleExplicitWorkflowId(rawWorkflow) {
6164
6222
  const parsed = parseNameWithId(terms[0]);
6165
6223
  return parsed.id ?? (/^[0-9]+$/.test(terms[0]) ? terms[0] : "");
6166
6224
  }
6167
- async function loadCreateFormPack(workflowId, env) {
6225
+ async function loadCreateFormPack(workflowId, env, options = {}) {
6168
6226
  const [{ data }, workflowMemory] = await Promise.all([
6169
- buildCreateFormData(workflowId, env),
6227
+ buildCreateFormData(workflowId, env, options),
6170
6228
  // 记忆读取是 best-effort(内部全 catch),不会把表单载入的错误顶掉。
6171
6229
  fetchWorkflowMemory(workflowId, env)
6172
6230
  ]);
6173
6231
  return { data, workflowMemory };
6174
6232
  }
6175
- async function prepareCreateFormPayload(args, env) {
6233
+ async function prepareCreateFormPayload(args, env, options = {}) {
6176
6234
  const authStartedAt = Date.now();
6177
6235
  await env.host.getSession();
6178
6236
  const authMs = Date.now() - authStartedAt;
@@ -6181,10 +6239,10 @@ async function prepareCreateFormPayload(args, env) {
6181
6239
  const explicitId = singleExplicitWorkflowId(args.workflow);
6182
6240
  if (explicitId) {
6183
6241
  target = { id: explicitId, name: "", source: "workflowId" };
6184
- pack = await loadCreateFormPack(explicitId, env);
6242
+ pack = await loadCreateFormPack(explicitId, env, options);
6185
6243
  } else {
6186
6244
  target = await resolveCreateWorkflow(args.workflow, env);
6187
- pack = await loadCreateFormPack(target.id, env);
6245
+ pack = await loadCreateFormPack(target.id, env, options);
6188
6246
  }
6189
6247
  const fullPayload = {
6190
6248
  ...pack.data,
@@ -6234,10 +6292,15 @@ async function commandCreateForm(args, env) {
6234
6292
  };
6235
6293
  return workflowSuccess("workflow.createForm", result);
6236
6294
  }
6237
- async function buildCreateFormData(workflowId, env) {
6295
+ async function buildCreateFormData(workflowId, env, options = {}) {
6296
+ const detailMark = options.detailMark === "isDetail" ? "isDetail" : "subFormId";
6297
+ const getHistory = options.getHistory !== false;
6238
6298
  const query = { workflowId, isCreate: 1, ...AJAX_QUERY };
6239
6299
  const body = { workflowId, isCreate: 1, isMobile: 0 };
6240
- const historyListSnapshot = fetchHistoryListSnapshot(env, { workflowId }).catch(() => null);
6300
+ const historyListSnapshot = getHistory ? fetchHistoryListSnapshot(env, { workflowId }).catch(() => null) : Promise.resolve(null);
6301
+ const historyDetails = getHistory ? historyListSnapshot.then(async (snapshot) => snapshot && snapshot.requestIds.length ? prefetchHistoryDetails(env, snapshot) : null) : Promise.resolve(null);
6302
+ historyDetails.catch(() => {
6303
+ });
6241
6304
  const isXiaoE = hasXiaoEEnv(env.ctx.env, env.ctx.getGlobalOptions?.());
6242
6305
  const basePromise = requestJson(env, "POST", FORM_ENDPOINTS.loadBase, query, body, { tolerateBusinessError: true }).then((value) => ({ ok: true, value })).catch((error) => ({ ok: false, error }));
6243
6306
  const framePromise = requestJson(env, "POST", FORM_ENDPOINTS.loadFrame, query, body).then((value) => ({ ok: true, value })).catch((error) => ({ ok: false, error }));
@@ -6411,7 +6474,11 @@ async function buildCreateFormData(workflowId, env) {
6411
6474
  if (!modelFieldIds.has(String(field.id ?? ""))) continue;
6412
6475
  const slimSubFormId = String(field.subFormId ?? "");
6413
6476
  const item = { id: field.id, name: field.name };
6414
- if (slimSubFormId) item.subFormId = slimSubFormId;
6477
+ if (detailMark === "isDetail") {
6478
+ if (slimSubFormId) item.isDetail = true;
6479
+ } else if (slimSubFormId) {
6480
+ item.subFormId = slimSubFormId;
6481
+ }
6415
6482
  item.componentKey = field.componentKey;
6416
6483
  const initialValue = initialValueByFieldId.get(String(field.id ?? ""));
6417
6484
  if (initialValue !== void 0) item.initialValue = initialValue;
@@ -6446,8 +6513,8 @@ async function buildCreateFormData(workflowId, env) {
6446
6513
  }
6447
6514
  if (String(field.componentKey ?? "").toLowerCase() === "textarea" && field.richEditor) item.componentKey = "RichText";
6448
6515
  if (String(field.format ?? "").trim()) item.format = String(field.format).trim();
6449
- const options = field.options || [];
6450
- if (options.length) item.options = options;
6516
+ const options2 = field.options || [];
6517
+ if (options2.length) item.options = options2;
6451
6518
  slimFields.push(item);
6452
6519
  }
6453
6520
  const fieldsById = /* @__PURE__ */ new Map();
@@ -6456,13 +6523,15 @@ async function buildCreateFormData(workflowId, env) {
6456
6523
  ...requiredFieldsList.map((f) => String(f?.id ?? "")),
6457
6524
  ...Object.values(subFormRequired).flatMap((list) => list.map((f) => String(f?.id ?? "")))
6458
6525
  ].filter(Boolean))];
6459
- const historyCache = fields.length ? await buildHistoryRequestData(
6526
+ const historyCache = getHistory && fields.length ? await buildHistoryRequestData(
6460
6527
  env,
6461
6528
  fields,
6462
6529
  historyRequiredFieldIds.map((id) => ({ id, name: String((fieldsById.get(id) || {}).name ?? id) })),
6463
6530
  { allFormFields: true, workflowId },
6464
6531
  // 本命令开头就已并发发起的列表请求:这里只补「详情」那几步(P2)。
6465
- historyListSnapshot
6532
+ historyListSnapshot,
6533
+ // 明细也已在列表返回时就发出去(与 layout 并行),这里只等它回来、按本表单字段组装。
6534
+ historyDetails
6466
6535
  ) : null;
6467
6536
  const session = await getSessionContext(env);
6468
6537
  const context = {
@@ -6532,7 +6601,9 @@ async function buildCreateFormData(workflowId, env) {
6532
6601
  // 历史参考值(近一年、非草稿、最近 5 条「我发起的」)——填值前先看它,能直接照用的字段就别去
6533
6602
  // 问用户。字段范围与 `fields` **同一口径**(见 modelFieldIds 注释);完整结果(本表单全部字段)
6534
6603
  // 仍随句柄留给 `createRequest` 用(条件必填要到那边才现身)。
6535
- historyRequestData: filterHistoryRequestData(historyCache, modelFieldIds),
6604
+ // `getHistory:false`(隐藏入参)时整段历史取数没做 ⇒ 这里给 `null`(不是空数组:空数组表示
6605
+ // "查了但没数据",两者含义不同)。
6606
+ historyRequestData: getHistory ? filterHistoryRequestData(historyCache, modelFieldIds) : null,
6536
6607
  systemFields: {
6537
6608
  permissions: minorInfo.permissions || {},
6538
6609
  defaults: context.systemFields.defaults,
@@ -7582,9 +7653,10 @@ async function runFieldLinkage(env, ctx, entries, actionTypes, allDetails, isEdi
7582
7653
  }
7583
7654
  }
7584
7655
  if (!dataList.length && !runDataList.length) return [];
7656
+ const linkageModule = formModuleName(ctx.frame && ctx.frame.relate_type, "ebuilderform");
7585
7657
  const executeParam = {
7586
7658
  formId: ctx.layout.form_id,
7587
- module: "workflow",
7659
+ module: linkageModule,
7588
7660
  dataList,
7589
7661
  runDataList,
7590
7662
  moduleDataList: []
@@ -7625,9 +7697,9 @@ async function runFieldLinkage(env, ctx, entries, actionTypes, allDetails, isEdi
7625
7697
  const frame = ctx.frame || {};
7626
7698
  if (frame.layout_multi_id) executeParam.layoutId = frame.layout_multi_id;
7627
7699
  }
7628
- const payload = { formId: ctx.layout.form_id, module: "workflow", executeParam };
7700
+ const payload = { formId: ctx.layout.form_id, module: linkageModule, executeParam };
7629
7701
  const relateType = ctx.frame && ctx.frame.relate_type || "";
7630
- const endpoint = formApiUrl(FORM_ENDPOINTS.fdLinkage, relateType);
7702
+ const endpoint = formApiUrl(FORM_ENDPOINTS.fdLinkage, relateType, "/api/ebuilder/form/");
7631
7703
  const response = await requestJson(env, "POST", endpoint, AJAX_QUERY, payload);
7632
7704
  const data = response && typeof response === "object" ? response : null;
7633
7705
  const linkageList = data && typeof data === "object" ? data.linkageDataList : null;
@@ -8234,6 +8306,15 @@ function xiaoECustomParams(preview) {
8234
8306
  }
8235
8307
  return { values, keys: ordered };
8236
8308
  }
8309
+ function xiaoESrcFieldQuery(params) {
8310
+ let query = "";
8311
+ for (const fieldId of params.keys) {
8312
+ const text = params.values[fieldId];
8313
+ if (!text) continue;
8314
+ query += `&${fieldId}=${text}`;
8315
+ }
8316
+ return query;
8317
+ }
8237
8318
  function renderXiaoEFillFormMarkdown(params) {
8238
8319
  const base = String(params.baseUrl ?? "").replace(/\/+$/u, "");
8239
8320
  const workflowId = String(params.workflowId ?? "").trim();
@@ -8245,7 +8326,7 @@ function renderXiaoEFillFormMarkdown(params) {
8245
8326
  arguments: {
8246
8327
  type: "e10",
8247
8328
  title: String(params.title ?? ""),
8248
- src: `${base}/sp/workflow${createPath}?workflowId=${workflowId}&isCreate=1`,
8329
+ src: `${base}/sp/workflow${createPath}?workflowId=${workflowId}&isCreate=1${xiaoESrcFieldQuery(params.customParams)}`,
8249
8330
  sdkOptions: {
8250
8331
  compName: XIAOE_FILL_FORM_SDK_OPTIONS.compName,
8251
8332
  routerType: XIAOE_FILL_FORM_SDK_OPTIONS.routerType,
@@ -8728,10 +8809,18 @@ function apiShortName(path) {
8728
8809
  function withApiTiming(host, spans) {
8729
8810
  const record = async (path, run) => {
8730
8811
  const start = Date.now();
8812
+ const fetchTiming = createFetchTimingSink();
8731
8813
  try {
8732
- return await run();
8814
+ return await runWithFetchTiming(fetchTiming, run);
8733
8815
  } finally {
8734
- spans.push({ name: apiShortName(path), start, end: Date.now() });
8816
+ spans.push({
8817
+ name: apiShortName(path),
8818
+ start,
8819
+ end: Date.now(),
8820
+ fetchStart: fetchTiming.fetchStart,
8821
+ fetchEnd: fetchTiming.fetchEnd,
8822
+ fetchMs: fetchTiming.fetchMs
8823
+ });
8735
8824
  }
8736
8825
  };
8737
8826
  return {
@@ -8770,18 +8859,33 @@ function summarizeApiSpans(spans) {
8770
8859
  const items = group.map((item) => ({
8771
8860
  name: item.name,
8772
8861
  at: Math.max(0, Math.round(item.start - origin)),
8773
- ms: Math.max(0, Math.round(item.end - item.start))
8862
+ ms: Math.max(0, Math.round(item.end - item.start)),
8863
+ fetchAt: item.fetchStart === null ? null : Math.max(0, Math.round(item.fetchStart - origin)),
8864
+ fetchEnd: item.fetchEnd === null ? null : Math.max(0, Math.round(item.fetchEnd - origin)),
8865
+ fetchCost: Math.max(0, Math.round(item.fetchMs))
8774
8866
  })).sort((a, b) => b.ms - a.ms || a.at - b.at);
8775
8867
  slowest.push({ batch: key, name: items[0].name, ms: items[0].ms, items });
8776
8868
  }
8777
8869
  }
8778
8870
  return { durations, slowest };
8779
8871
  }
8872
+ function readHiddenGetHistory(value) {
8873
+ if (value === false || value === 0) return false;
8874
+ if (typeof value === "string") {
8875
+ const text = value.trim().toLowerCase();
8876
+ if (text === "false" || text === "0") return false;
8877
+ }
8878
+ return true;
8879
+ }
8780
8880
  async function commandCreateRequestDirect(args, env) {
8781
8881
  const startedAt = Date.now();
8782
8882
  const spans = [];
8783
8883
  const timedEnv = { ...env, host: withApiTiming(env.host, spans) };
8784
- const { payload, authMs } = await prepareCreateFormPayload(args, timedEnv);
8884
+ const getHistory = readHiddenGetHistory(args.getHistory);
8885
+ const { payload, authMs } = await prepareCreateFormPayload(args, timedEnv, {
8886
+ getHistory,
8887
+ detailMark: "isDetail"
8888
+ });
8785
8889
  const contextId = String(payload.contextId ?? "");
8786
8890
  if (!contextId) {
8787
8891
  throw workflowValidationError("context_missing", "\u8868\u5355\u8F7D\u5165\u672A\u4EA7\u51FA\u53EF\u7528\u53E5\u67C4\uFF0C\u8BF7\u91CD\u8BD5");
@@ -8808,7 +8912,7 @@ async function commandCreateRequestDirect(args, env) {
8808
8912
  "workflow.createRequestDirect"
8809
8913
  ) > CREATE_FORM_STDOUT_SAFE_CHARS;
8810
8914
  if (overLine()) {
8811
- data.historyRequestData = [];
8915
+ if (getHistory) data.historyRequestData = [];
8812
8916
  if ("userMemory" in data && overLine()) data.userMemory = "";
8813
8917
  }
8814
8918
  return workflowSuccess("workflow.createRequestDirect", {
@@ -8828,10 +8932,14 @@ function formatRemark(value) {
8828
8932
  if (text.startsWith("_weaverMte_")) return text;
8829
8933
  return `_weaverMte_<p>${text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")}</p>`;
8830
8934
  }
8935
+ function formModuleName(relateType, ebModule = "ebuildercard") {
8936
+ return String(relateType ?? "").trim() === "WEA_EBUILDER" ? ebModule : "workflow";
8937
+ }
8831
8938
  function buildSaveBody(context, prepared) {
8832
8939
  const runtime = context.runtime;
8940
+ const moduleName = formModuleName(context.frame?.relate_type);
8833
8941
  return {
8834
- module: "workflow",
8942
+ module: moduleName,
8835
8943
  customParam: {
8836
8944
  isCreate: true,
8837
8945
  requestId: runtime.request_id,
@@ -8849,7 +8957,7 @@ function buildSaveBody(context, prepared) {
8849
8957
  },
8850
8958
  employeeId: runtime.employee_id,
8851
8959
  formData: {
8852
- module: "workflow",
8960
+ module: moduleName,
8853
8961
  presetDataId: runtime.request_id,
8854
8962
  dataDetails: prepared.dataDetails,
8855
8963
  client: "pc",
@@ -9226,12 +9334,15 @@ async function runCreateNodeFieldVerification(env, context, switches) {
9226
9334
  result.passed = !result.blocked;
9227
9335
  return result;
9228
9336
  }
9229
- function buildEditDataLayoutRequest(requestId, workflowId, nodeId, formId, dataId, layoutMultiId, viewFormNodeId, permissionType, runtime) {
9337
+ function buildEditDataLayoutRequest(requestId, workflowId, nodeId, formId, dataId, layoutMultiId, viewFormNodeId, permissionType, runtime, relateType) {
9230
9338
  return {
9231
9339
  terminalType: "PC",
9232
9340
  dataId,
9233
9341
  formId,
9234
- module: "workflow",
9342
+ // 建模表单取 `ebuilderform`(2026-10-30 真机请求体实证),**不是** `ebuildercard`:
9343
+ // 同为 `form/core` 下的接口,`getFormLayout` / `saveFormData` 是 `ebuildercard`,
9344
+ // 本接口与 `executeFdLinkage` 是 `ebuilderform` —— 建模表单内部不能按"同族"推定。
9345
+ module: formModuleName(relateType, "ebuilderform"),
9235
9346
  newLayout: true,
9236
9347
  cacheUid: null,
9237
9348
  layoutMultiId,
@@ -9301,7 +9412,7 @@ async function commandEditLoad(args, env) {
9301
9412
  tenantSetting = {};
9302
9413
  }
9303
9414
  const dataId = requestId;
9304
- const dlResp = await requestJson(env, "POST", formApiUrl(FORM_ENDPOINTS.formDataAndLayout, frame.relate_type), { formId: frame.form_id, dataId, ...AJAX_QUERY }, buildEditDataLayoutRequest(requestId, workflowId, runtime.node_id, frame.form_id, dataId, frame.layout_multi_id, frame.view_form_node_id, frame.permission_type, runtime));
9415
+ const dlResp = await requestJson(env, "POST", formApiUrl(FORM_ENDPOINTS.formDataAndLayout, frame.relate_type), { formId: frame.form_id, dataId, ...AJAX_QUERY }, buildEditDataLayoutRequest(requestId, workflowId, runtime.node_id, frame.form_id, dataId, frame.layout_multi_id, frame.view_form_node_id, frame.permission_type, runtime, frame.relate_type));
9305
9416
  const dlData = dlResp;
9306
9417
  if (!dlData || typeof dlData !== "object") throw workflowApiError("format_error", "getFormDataAndLayout \u672A\u8FD4\u56DE\u6709\u6548 data");
9307
9418
  const vrc = Array.isArray(dlData.viewRelateConfig) ? dlData.viewRelateConfig : [];
@@ -9547,8 +9658,9 @@ async function commandEditPrepare(args, env) {
9547
9658
  }
9548
9659
  function buildEditSaveBody(context, prepared) {
9549
9660
  const runtime = context.runtime || {};
9661
+ const moduleName = formModuleName(context.frame?.relate_type);
9550
9662
  return {
9551
- module: "workflow",
9663
+ module: moduleName,
9552
9664
  customParam: {
9553
9665
  isCreate: false,
9554
9666
  requestId: context.requestId ?? context.request_id,
@@ -9568,7 +9680,7 @@ function buildEditSaveBody(context, prepared) {
9568
9680
  formData: {
9569
9681
  id: context.data_id,
9570
9682
  updateTimeStamp: context.update_time_stamp || "",
9571
- module: "workflow",
9683
+ module: moduleName,
9572
9684
  dataDelRows: [],
9573
9685
  dataDetails: prepared.dataDetails || [],
9574
9686
  client: "pc",
@@ -10104,6 +10216,7 @@ function rowFromAny(raw) {
10104
10216
  "lastfeedbacktime",
10105
10217
  "lastFeedbackTime"
10106
10218
  ]) ?? "",
10219
+ ...pick(["planFinishDatetime", "planfinishdatetime"]) ? { planFinishDatetime: pick(["planFinishDatetime", "planfinishdatetime"]) } : {},
10107
10220
  summary: pick(["summary"]),
10108
10221
  workflowName: pick(["workflowName", "workflowname", "workflowTypeName"], true),
10109
10222
  receivedTime: pick(["receivedTime", "receivedtime", "receivedatetime", "operatedatetime", "stayStartAt"]),
@@ -10179,64 +10292,9 @@ function readBoundedInt(value, name, fallback, min, max) {
10179
10292
  return parsed;
10180
10293
  }
10181
10294
 
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
- }
10295
+ // src/shortcuts/workflow/operations/todoSmartConvert/aigroupRules.ts
10296
+ import { existsSync as existsSync3, readFileSync } from "node:fs";
10297
+ import { join as join2 } from "node:path";
10240
10298
 
10241
10299
  // src/shortcuts/workflow/operations/todoSmartConvert/summaryCache.ts
10242
10300
  import { existsSync as existsSync2, readdirSync, statSync } from "node:fs";
@@ -10449,6 +10507,417 @@ async function openSummaryCache(ctx) {
10449
10507
  return cache;
10450
10508
  }
10451
10509
 
10510
+ // src/shortcuts/workflow/operations/todoSmartConvert/aigroupRules.ts
10511
+ var AIGROUP_DIR_NAME = "aigroup";
10512
+ var DEFAULT_RULE_FILE = "default.json";
10513
+ var USER_INTENT_RULE_FILE = "user-intents.json";
10514
+ var FOCUS_OPERATORS = [
10515
+ "\u7B49\u4E8E",
10516
+ "\u4E0D\u7B49\u4E8E",
10517
+ "\u662F",
10518
+ "\u4E0D\u662F",
10519
+ "\u5927\u4E8E",
10520
+ "\u5C0F\u4E8E",
10521
+ "\u5C0F\u4E8E\u7B49\u4E8E",
10522
+ "\u5927\u4E8E\u7B49\u4E8E",
10523
+ "\u4ECB\u4E8E",
10524
+ "\u5305\u542B"
10525
+ ];
10526
+ var MAX_GROUPING_PROMPT_CHARS = 500;
10527
+ var EMPTY_GROUP_RULE = { focus: false };
10528
+ var FALLBACK_DEFAULTS = {
10529
+ weight: 999,
10530
+ needSummary: true,
10531
+ requestSummaryPrompt: "",
10532
+ summaryMaxChars: 150,
10533
+ groupSummaryMaxChars: 100,
10534
+ groupSummaryTail: "\u53EF\u5C55\u5F00\u9010\u6761\u67E5\u770B\u6216\u76F4\u63A5\u6C47\u603B\u5904\u7406"
10535
+ };
10536
+ function emptyRuleFile(error = null) {
10537
+ return {
10538
+ file: { schemaVersion: 2, defaults: FALLBACK_DEFAULTS, rules: [] },
10539
+ error
10540
+ };
10541
+ }
10542
+ function asStringArray3(value) {
10543
+ if (typeof value === "string") return [value];
10544
+ if (!Array.isArray(value)) return null;
10545
+ const items = value.map((item) => String(item ?? "").trim()).filter((item) => item !== "");
10546
+ return items.length > 0 ? items : null;
10547
+ }
10548
+ function isOperator(value) {
10549
+ return typeof value === "string" && FOCUS_OPERATORS.includes(value);
10550
+ }
10551
+ function validateFocusKeyword(raw, index) {
10552
+ if (!Array.isArray(raw)) return `focusKeyword[${index}] \u5FC5\u987B\u662F\u6570\u7EC4`;
10553
+ const [metric, op] = raw;
10554
+ if (typeof metric !== "string" || !metric.trim()) return `focusKeyword[${index}] \u7684\u6307\u6807\u540D\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`;
10555
+ if (!isOperator(op)) return `focusKeyword[${index}] \u7684\u7B97\u5B50\u300C${String(op)}\u300D\u4E0D\u652F\u6301\uFF08\u53EF\u7528\uFF1A${FOCUS_OPERATORS.join("/")}\uFF09`;
10556
+ if (op === "\u4ECB\u4E8E") {
10557
+ if (raw.length !== 4) return `focusKeyword[${index}] \u7528\u300C\u4ECB\u4E8E\u300D\u65F6\u5FC5\u987B\u7ED9 [\u6307\u6807, \u4ECB\u4E8E, \u4E0B\u754C, \u4E0A\u754C]`;
10558
+ return null;
10559
+ }
10560
+ if (raw.length !== 3) return `focusKeyword[${index}] \u5FC5\u987B\u662F [\u6307\u6807, \u7B97\u5B50, \u503C] \u4E09\u5143\u7EC4`;
10561
+ return null;
10562
+ }
10563
+ function validateRuleFile(raw) {
10564
+ const errors = [];
10565
+ const file = raw;
10566
+ if (!file || typeof file !== "object") return ["\u89C4\u5219\u6587\u4EF6\u5FC5\u987B\u662F JSON \u5BF9\u8C61"];
10567
+ if (!Array.isArray(file.rules)) {
10568
+ errors.push("rules \u5FC5\u987B\u662F\u6570\u7EC4");
10569
+ return errors;
10570
+ }
10571
+ const seen = /* @__PURE__ */ new Set();
10572
+ file.rules.forEach((rule, index) => {
10573
+ if (!rule || typeof rule !== "object") {
10574
+ errors.push(`rules[${index}] \u5FC5\u987B\u662F\u5BF9\u8C61`);
10575
+ return;
10576
+ }
10577
+ const names = asStringArray3(rule.workflowName);
10578
+ if (!names) {
10579
+ errors.push(`rules[${index}].workflowName \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32\u6216\u975E\u7A7A\u6570\u7EC4`);
10580
+ return;
10581
+ }
10582
+ for (const name of names) {
10583
+ if (seen.has(name)) errors.push(`workflowName\u300C${name}\u300D\u5728 rules[${index}] \u91CD\u590D\u51FA\u73B0`);
10584
+ seen.add(name);
10585
+ }
10586
+ if (rule.weight !== void 0 && (typeof rule.weight !== "number" || !Number.isFinite(rule.weight))) {
10587
+ errors.push(`rules[${index}].weight \u5FC5\u987B\u662F\u6570\u5B57`);
10588
+ }
10589
+ if (rule.summaryMaxChars !== void 0 && (typeof rule.summaryMaxChars !== "number" || rule.summaryMaxChars <= 0)) {
10590
+ errors.push(`rules[${index}].summaryMaxChars \u5FC5\u987B\u662F\u6B63\u6570`);
10591
+ }
10592
+ const groupRule = rule.aiGroup?.groupRule;
10593
+ if (groupRule) {
10594
+ if (typeof groupRule.focus !== "boolean") errors.push(`rules[${index}].aiGroup.groupRule.focus \u5FC5\u987B\u662F\u5E03\u5C14`);
10595
+ if (groupRule.focus) {
10596
+ const keywords = groupRule.focusKeyword;
10597
+ if (!Array.isArray(keywords) || keywords.length === 0) {
10598
+ errors.push(`rules[${index}] focus=true \u65F6\u5FC5\u987B\u7ED9 focusKeyword`);
10599
+ } else {
10600
+ keywords.forEach((keyword, k) => {
10601
+ const reason = validateFocusKeyword(keyword, k);
10602
+ if (reason) errors.push(`rules[${index}].${reason}`);
10603
+ });
10604
+ }
10605
+ } else if (groupRule.focusKeyword !== void 0 && groupRule.focusKeyword.length > 0) {
10606
+ errors.push(`rules[${index}] focus=false \u65F6\u4E0D\u5E94\u7ED9 focusKeyword`);
10607
+ }
10608
+ if (groupRule.focus === false && !groupRule.aiContext) {
10609
+ errors.push(`rules[${index}] focus=false \u65F6\u5FC5\u987B\u7ED9 aiContext\uFF08\u6D41\u7A0B\u6807\u9898 / \u6D41\u7A0B\u8BE6\u60C5\uFF09`);
10610
+ }
10611
+ if (groupRule.groupingPrompt !== void 0) {
10612
+ if (groupRule.focus === true) {
10613
+ 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`);
10614
+ } else if (typeof groupRule.groupingPrompt !== "string" || groupRule.groupingPrompt.trim() === "") {
10615
+ errors.push(`rules[${index}].aiGroup.groupRule.groupingPrompt \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);
10616
+ } else if (groupRule.groupingPrompt.length > MAX_GROUPING_PROMPT_CHARS) {
10617
+ errors.push(
10618
+ `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`
10619
+ );
10620
+ }
10621
+ }
10622
+ }
10623
+ const groupSummary = rule.aiGroup?.groupSummary;
10624
+ if (groupSummary) {
10625
+ if (typeof groupSummary.needAI !== "boolean") errors.push(`rules[${index}].aiGroup.groupSummary.needAI \u5FC5\u987B\u662F\u5E03\u5C14`);
10626
+ if (groupSummary.needAI && !groupSummary.prompt) errors.push(`rules[${index}] groupSummary.needAI=true \u65F6\u5FC5\u987B\u7ED9 prompt`);
10627
+ if (!groupSummary.needAI && !groupSummary.template) errors.push(`rules[${index}] groupSummary.needAI=false \u65F6\u5FC5\u987B\u7ED9 template`);
10628
+ }
10629
+ });
10630
+ return errors;
10631
+ }
10632
+ function loadRuleFile(file) {
10633
+ if (!existsSync3(file)) return emptyRuleFile(`\u89C4\u5219\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${file}`);
10634
+ let parsed;
10635
+ try {
10636
+ parsed = JSON.parse(readFileSync(file, "utf8"));
10637
+ } catch (error) {
10638
+ return emptyRuleFile(`\u89C4\u5219\u6587\u4EF6\u4E0D\u662F\u5408\u6CD5 JSON\uFF1A${file}\uFF08${error.message}\uFF09`);
10639
+ }
10640
+ const errors = validateRuleFile(parsed);
10641
+ if (errors.length > 0) return emptyRuleFile(`\u89C4\u5219\u6587\u4EF6\u6821\u9A8C\u5931\u8D25\uFF1A${errors.join("\uFF1B")}`);
10642
+ return { file: parsed, error: null };
10643
+ }
10644
+ function aigroupDir(ctx) {
10645
+ const explicit = process.env.WEAVER_WORK_CLI_AIGROUP_DIR?.trim();
10646
+ if (explicit) return join2(explicit);
10647
+ const roots = cacheRoots(ctx);
10648
+ return roots.skillDir ? join2(roots.skillDir, AIGROUP_DIR_NAME) : join2(stateRoot(ctx), AIGROUP_DIR_NAME);
10649
+ }
10650
+ function aigroupUserDir(ctx) {
10651
+ const explicit = process.env.WEAVER_WORK_CLI_AIGROUP_DIR?.trim();
10652
+ if (explicit) return join2(explicit);
10653
+ return join2(stateRoot(ctx), AIGROUP_DIR_NAME);
10654
+ }
10655
+ function loadRules(options = {}) {
10656
+ const dir = options.dir ?? aigroupDir(options.ctx);
10657
+ const userDir = options.dir ?? aigroupUserDir(options.ctx);
10658
+ const warnings = [];
10659
+ const base = loadRuleFile(join2(dir, DEFAULT_RULE_FILE));
10660
+ if (base.error) warnings.push(base.error);
10661
+ const rules = [...base.file.rules];
10662
+ const userIntentFile = join2(userDir, USER_INTENT_RULE_FILE);
10663
+ const legacyIntentFile = join2(dir, USER_INTENT_RULE_FILE);
10664
+ let intentFile = userIntentFile;
10665
+ if (!options.dir && !existsSync3(userIntentFile) && existsSync3(legacyIntentFile)) {
10666
+ intentFile = legacyIntentFile;
10667
+ 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`);
10668
+ }
10669
+ const intent = loadRuleFile(intentFile);
10670
+ if (intent.error) {
10671
+ if (existsSync3(intentFile)) warnings.push(intent.error);
10672
+ } else {
10673
+ for (const rule of intent.file.rules) {
10674
+ const names = new Set(asStringArray3(rule.workflowName) ?? []);
10675
+ const at = rules.findIndex((item) => (asStringArray3(item.workflowName) ?? []).some((name) => names.has(name)));
10676
+ if (at >= 0 && (asStringArray3(rules[at].workflowName) ?? []).includes("*")) {
10677
+ warnings.push(`\u7528\u6237\u610F\u56FE\u4E0D\u80FD\u8986\u76D6\u901A\u914D\u6761\u76EE\u300C*\u300D\uFF0C\u5DF2\u5FFD\u7565\uFF1A${[...names].join(",")}`);
10678
+ continue;
10679
+ }
10680
+ if (at >= 0) rules[at] = rule;
10681
+ else rules.push(rule);
10682
+ }
10683
+ }
10684
+ return {
10685
+ file: { schemaVersion: base.file.schemaVersion, defaults: { ...FALLBACK_DEFAULTS, ...base.file.defaults }, rules },
10686
+ warnings,
10687
+ dir
10688
+ };
10689
+ }
10690
+ function matchRule(rules, workflowName) {
10691
+ const name = String(workflowName ?? "").trim();
10692
+ const aliasesOf = (rule) => asStringArray3(rule.workflowName) ?? [];
10693
+ const indexOf = /* @__PURE__ */ new Map();
10694
+ rules.forEach((rule, index) => indexOf.set(rule, index));
10695
+ if (name) {
10696
+ const exact = rules.filter((rule) => aliasesOf(rule).includes(name));
10697
+ if (exact.length > 0) {
10698
+ const [rule] = exact;
10699
+ return { rule, matchedBy: "exact", index: indexOf.get(rule) ?? 0 };
10700
+ }
10701
+ const fuzzy = rules.filter((rule) => aliasesOf(rule).some((alias) => alias !== "*" && name.includes(alias)));
10702
+ if (fuzzy.length > 0) {
10703
+ const sorted = [...fuzzy].sort((a, b) => (a.weight ?? FALLBACK_DEFAULTS.weight) - (b.weight ?? FALLBACK_DEFAULTS.weight) || (indexOf.get(a) ?? 0) - (indexOf.get(b) ?? 0));
10704
+ const rule = sorted[0];
10705
+ return { rule, matchedBy: "fuzzy", index: indexOf.get(rule) ?? 0 };
10706
+ }
10707
+ }
10708
+ const fallback = rules.find((rule) => aliasesOf(rule).includes("*"));
10709
+ if (fallback) return { rule: fallback, matchedBy: "default", index: indexOf.get(fallback) ?? 0 };
10710
+ return null;
10711
+ }
10712
+ function resolveRule(file, workflowName) {
10713
+ const matched = matchRule(file.rules, workflowName);
10714
+ if (!matched) return null;
10715
+ const defaults = { ...FALLBACK_DEFAULTS, ...file.defaults };
10716
+ const raw = matched.rule;
10717
+ const groupSummary = raw.aiGroup?.groupSummary;
10718
+ const groupRule = raw.aiGroup?.groupRule;
10719
+ return {
10720
+ matchedBy: matched.matchedBy,
10721
+ rule: {
10722
+ workflowName: asStringArray3(raw.workflowName) ?? [],
10723
+ weight: raw.weight ?? defaults.weight,
10724
+ needSummary: raw.needSummary ?? defaults.needSummary,
10725
+ requestSummaryPrompt: raw.requestSummaryPrompt ?? defaults.requestSummaryPrompt,
10726
+ summaryMaxChars: raw.summaryMaxChars ?? defaults.summaryMaxChars,
10727
+ groupSummaryMaxChars: defaults.groupSummaryMaxChars,
10728
+ groupSummaryTail: defaults.groupSummaryTail,
10729
+ aiGroup: raw.aiGroup ? {
10730
+ groupSummary: {
10731
+ needAI: groupSummary?.needAI ?? false,
10732
+ ...groupSummary?.prompt === void 0 ? {} : { prompt: groupSummary.prompt },
10733
+ ...groupSummary?.template === void 0 ? {} : { template: groupSummary.template },
10734
+ maxChars: defaults.groupSummaryMaxChars,
10735
+ tail: defaults.groupSummaryTail
10736
+ },
10737
+ groupRule: groupRule ?? EMPTY_GROUP_RULE
10738
+ } : null,
10739
+ ruleIndex: matched.index
10740
+ }
10741
+ };
10742
+ }
10743
+ function dateOnly(value) {
10744
+ const pad = (n) => String(n).padStart(2, "0");
10745
+ return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`;
10746
+ }
10747
+ var RELATIVE_DAYS = { \u4ECA\u5929: 0, \u6628\u5929: -1, \u660E\u5929: 1 };
10748
+ function normalizeDateLike(value, now = /* @__PURE__ */ new Date()) {
10749
+ const text = value.trim();
10750
+ if (text in RELATIVE_DAYS) {
10751
+ const date = new Date(now.getTime());
10752
+ date.setDate(date.getDate() + RELATIVE_DAYS[text]);
10753
+ return dateOnly(date);
10754
+ }
10755
+ const matched = /^(\d{4})[-/](\d{1,2})[-/](\d{1,2})/u.exec(text);
10756
+ if (!matched) return null;
10757
+ const [, y, m, d] = matched;
10758
+ return `${y}-${String(m).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
10759
+ }
10760
+ function toNumber(value) {
10761
+ if (typeof value === "number" && Number.isFinite(value)) return value;
10762
+ const text = String(value ?? "").replace(/[,¥¥\s]/gu, "");
10763
+ if (!text) return null;
10764
+ const parsed = Number(text);
10765
+ return Number.isFinite(parsed) ? parsed : null;
10766
+ }
10767
+ function comparableOf(value, now) {
10768
+ if (value === null || value === void 0 || value === "") return null;
10769
+ if (typeof value === "number") return Number.isFinite(value) ? { kind: "number", value } : null;
10770
+ const text = String(value).trim();
10771
+ if (!text) return null;
10772
+ const date = normalizeDateLike(text, now);
10773
+ if (date) return { kind: "date", value: date };
10774
+ const num = toNumber(text);
10775
+ if (num !== null && /^[¥¥]?\s*-?\d[\d,]*(?:\.\d+)?$/.test(text.replace(/\s/gu, ""))) {
10776
+ return { kind: "number", value: num };
10777
+ }
10778
+ return { kind: "text", value: text };
10779
+ }
10780
+ function compare(a, b) {
10781
+ if (a.kind === "number" && b.kind === "number") return a.value - b.value;
10782
+ if (a.kind === "date" && b.kind === "date") return a.value < b.value ? -1 : a.value > b.value ? 1 : 0;
10783
+ if (a.kind === "text" || b.kind === "text") {
10784
+ const left = String(a.value);
10785
+ const right = String(b.value);
10786
+ return left < right ? -1 : left > right ? 1 : 0;
10787
+ }
10788
+ return null;
10789
+ }
10790
+ function evaluateCondition(condition, actual, now = /* @__PURE__ */ new Date()) {
10791
+ const [metric, op, expected, upper] = condition;
10792
+ const left = comparableOf(actual, now);
10793
+ if (!left) return false;
10794
+ const right = comparableOf(expected, now);
10795
+ if (!right) return false;
10796
+ switch (op) {
10797
+ case "\u7B49\u4E8E":
10798
+ case "\u662F":
10799
+ return compare(left, right) === 0;
10800
+ case "\u4E0D\u7B49\u4E8E":
10801
+ case "\u4E0D\u662F":
10802
+ return compare(left, right) !== 0;
10803
+ case "\u5927\u4E8E": {
10804
+ const diff = compare(left, right);
10805
+ return diff !== null && diff > 0;
10806
+ }
10807
+ case "\u5C0F\u4E8E": {
10808
+ const diff = compare(left, right);
10809
+ return diff !== null && diff < 0;
10810
+ }
10811
+ case "\u5927\u4E8E\u7B49\u4E8E": {
10812
+ const diff = compare(left, right);
10813
+ return diff !== null && diff >= 0;
10814
+ }
10815
+ case "\u5C0F\u4E8E\u7B49\u4E8E": {
10816
+ const diff = compare(left, right);
10817
+ return diff !== null && diff <= 0;
10818
+ }
10819
+ case "\u4ECB\u4E8E": {
10820
+ const top = comparableOf(upper, now);
10821
+ if (!top) return false;
10822
+ const low = compare(left, right);
10823
+ const high = compare(left, top);
10824
+ return low !== null && high !== null && low >= 0 && high <= 0;
10825
+ }
10826
+ case "\u5305\u542B":
10827
+ return String(left.value).includes(String(right.value));
10828
+ default:
10829
+ return false;
10830
+ }
10831
+ }
10832
+ function evaluateFocusKeywords(conditions, resolve3, now = /* @__PURE__ */ new Date()) {
10833
+ if (conditions.length === 0) return false;
10834
+ return conditions.every((condition) => evaluateCondition(condition, resolve3(condition[0]), now));
10835
+ }
10836
+ var activeFile = null;
10837
+ var activeDir = null;
10838
+ function primeRules(ctx) {
10839
+ const loaded = loadRules({ ctx });
10840
+ activeFile = loaded.file;
10841
+ activeDir = loaded.dir;
10842
+ return loaded;
10843
+ }
10844
+ function activeRules() {
10845
+ if (!activeFile) {
10846
+ const loaded = loadRules();
10847
+ activeFile = loaded.file;
10848
+ activeDir = loaded.dir;
10849
+ }
10850
+ return activeFile;
10851
+ }
10852
+ function activeRuleFor(workflowName) {
10853
+ const name = String(workflowName ?? "").trim();
10854
+ if (!name) return null;
10855
+ return resolveRule(activeRules(), name)?.rule ?? null;
10856
+ }
10857
+ function resetActiveRules() {
10858
+ activeFile = null;
10859
+ activeDir = null;
10860
+ }
10861
+
10862
+ // src/shortcuts/workflow/operations/todoSmartConvert/todoListRows.ts
10863
+ var DISPLAY_ROW_FIELDS = [
10864
+ // 定位键
10865
+ "requestId",
10866
+ "requestid",
10867
+ "workflowid",
10868
+ "workflowId",
10869
+ "userMasterId",
10870
+ "userid",
10871
+ "isremark",
10872
+ "isremarktype",
10873
+ "nodeid",
10874
+ "currentNodeId",
10875
+ // 状态位
10876
+ "overdue",
10877
+ "userOverTime",
10878
+ "requestlevel",
10879
+ "requestLevelShow",
10880
+ "requestlevelShow",
10881
+ "requestlevelTitle",
10882
+ // 展示字段
10883
+ "requestnamehtml",
10884
+ "requestnameTitle",
10885
+ "requestnametitle",
10886
+ "requestname",
10887
+ "creater",
10888
+ "creatername",
10889
+ "creatorName",
10890
+ "workflowname",
10891
+ "workflowName",
10892
+ "workflowTypeName",
10893
+ "requestmark",
10894
+ "flowstatusShow",
10895
+ "receivedatetime",
10896
+ "operatedatetime",
10897
+ // 最后反馈时间:`getTodoListData.displayData` 里的原始键是全小写,大小写变体一并保留。
10898
+ "lastfeedbackdatetime",
10899
+ "lastFeedbackDateTime"
10900
+ ];
10901
+ function projectDisplayRows(response) {
10902
+ const record = responseData(response);
10903
+ const raw = record?.data?.displayData ?? record?.displayData ?? [];
10904
+ const rows = Array.isArray(raw) ? raw : [];
10905
+ const projected = [];
10906
+ for (const row of rows) {
10907
+ if (!row || typeof row !== "object" || Array.isArray(row)) continue;
10908
+ const source = row;
10909
+ const picked = {};
10910
+ for (const key of DISPLAY_ROW_FIELDS) {
10911
+ const value = source[key];
10912
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
10913
+ picked[key] = value;
10914
+ }
10915
+ }
10916
+ if (Object.keys(picked).length > 0) projected.push(picked);
10917
+ }
10918
+ return projected;
10919
+ }
10920
+
10452
10921
  // src/shortcuts/workflow/operations/todoSmartConvert/detailFieldRules.ts
10453
10922
  function normalizeDetailFieldName(raw) {
10454
10923
  return String(raw ?? "").replace(/<[^>]*>/g, " ").replace(/[【】[\]()()]/g, "").replace(/\s+/g, "").trim();
@@ -10491,19 +10960,10 @@ function pickInternalMessageFieldPairs(fields, basicInfo = {}) {
10491
10960
  }
10492
10961
 
10493
10962
  // 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
10963
  var ISSUE_SUPPORT_WORKFLOW_NAMES = [
10503
10964
  "Ecology\u5BA2\u6237\u95EE\u9898\u652F\u6301\u89E3\u51B3\u6D41\u7A0B",
10504
10965
  "E10\u5BA2\u6237\u95EE\u9898\u652F\u6301\u89E3\u51B3\u6D41\u7A0B"
10505
10966
  ];
10506
- var ISSUE_SUPPORT_GROUP_TITLE = "\u5DF2\u8FC7\u671F\u53CA\u4ECA\u5929\u5373\u5C06\u8FC7\u671F\u7684\u6D41\u7A0B";
10507
10967
  var LEAVE_DAY_THRESHOLD = 1;
10508
10968
  var FINANCE_AMOUNT_THRESHOLD = 100;
10509
10969
  var LEAVE_GROUP_TITLE = `${LEAVE_DAY_THRESHOLD}\u5929\u4EE5\u5185`;
@@ -10524,49 +10984,12 @@ function detectBusinessKind(workflowName) {
10524
10984
  function isDeterministicGroupKind(kind) {
10525
10985
  return kind === "leave" || kind === "finance" || kind === "issue-support";
10526
10986
  }
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
10987
  function requestSummaryStrategy(kind) {
10562
10988
  return kind === "satisfaction" ? "title" : "ai";
10563
10989
  }
10564
10990
  function needsRequestSummary(kind) {
10565
10991
  return requestSummaryStrategy(kind) === "ai";
10566
10992
  }
10567
- function usesTitleSummary(kind) {
10568
- return requestSummaryStrategy(kind) === "title";
10569
- }
10570
10993
  var LEAVE_TYPE_FIELD_PATTERN = /^(?:假别|假类|请假类型|请假类别|假期类型|假期类别|休假类型|休假类别)$/u;
10571
10994
  var LEAVE_DAYS_FIELD_PATTERN = /^(?:(?:请假|休假|假期|调休)(?:天数|时长|合计)|(?:请假|休假|假期|调休)?天数|天数合计|合计天数|总天数|时长)$/u;
10572
10995
  var AMOUNT_FIELD_PATTERN = /^(?:人民币金额|报销金额|报销总金额|实报金额|实际支付金额|申请金额|付款金额|借款金额|请款金额|总金额|金额合计|合计金额|费用合计|小写金额|总价|价税合计|金额|合计|总计)(?:[((]元[))])?$/u;
@@ -10687,32 +11110,25 @@ function uniqueTexts(values) {
10687
11110
  return result;
10688
11111
  }
10689
11112
  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}`;
11113
+ function renderGroupSummaryTemplate(input) {
11114
+ let text = String(input.template ?? "");
11115
+ if (!text.trim()) return "";
11116
+ const allCategories = uniqueTexts(input.categories ?? []);
11117
+ const shownCategories = allCategories.slice(0, 3);
11118
+ const categoryCount = allCategories.length > 0 ? allCategories.length : 1;
11119
+ const categories = shownCategories.length > 0 ? `${shownCategories.join("\u3001")}${allCategories.length > shownCategories.length ? "\u7B49" : ""}` : "";
11120
+ const allCreators = normalizeCreators(input.creators ?? []);
11121
+ const shownCreators = allCreators.slice(0, 3);
11122
+ const creators = shownCreators.length > 0 ? `\u7531${shownCreators.join("\u3001")}${allCreators.length > 2 ? "\u7B49" : ""}` : "";
11123
+ if (!creators) {
11124
+ text = text.replace(/\{\{creators\}\}发起[。,]/gu, "");
11125
+ }
11126
+ if (!categories) {
11127
+ text = text.replace(/(\{\{categories\}\})/gu, "");
11128
+ }
11129
+ const amounts = (input.amounts ?? []).filter((value) => typeof value === "number" && Number.isFinite(value));
11130
+ 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);
11131
+ return replaced.replace(/¥(\s*)/gu, "").replace(/\s*,\s*,/gu, "\uFF0C").trim();
10716
11132
  }
10717
11133
 
10718
11134
  // src/shortcuts/workflow/operations/todoSmartConvert/todoDetailFetcher.ts
@@ -11126,9 +11542,6 @@ var URGENT_PATTERN = /紧急/u;
11126
11542
  var PRIORITY_GROUP_ID = "priority";
11127
11543
  var PRIORITY_GROUP_TITLE = "\u5EFA\u8BAE\u4F18\u5148\u5904\u7406\u7684\u6D41\u7A0B";
11128
11544
  var GROUP_MIN_ITEMS_FOR_SUBGROUP = 3;
11129
- function focusAppliesToKind(focus, kind) {
11130
- return intentAppliesToKind(focus, kind);
11131
- }
11132
11545
  function timeOf(value) {
11133
11546
  if (!value) return void 0;
11134
11547
  const text = value.trim();
@@ -11235,6 +11648,7 @@ function toRequestData(row) {
11235
11648
  creater: row.creater,
11236
11649
  createrName: row.createrName,
11237
11650
  lastFeedBackDateTime: row.lastFeedBackDateTime,
11651
+ ...row.planFinishDatetime ? { planFinishDatetime: row.planFinishDatetime } : {},
11238
11652
  summary: row.summary ?? ""
11239
11653
  };
11240
11654
  }
@@ -11586,7 +12000,7 @@ async function collectRawTodos(args, env) {
11586
12000
  const focusText = typeof args.groupFocus === "string" ? args.groupFocus.trim() : "";
11587
12001
  const fieldsById = /* @__PURE__ */ new Map();
11588
12002
  if (focusText) {
11589
- const targetRows = wfIdGroup.filter((group) => !group.topPriority && focusAppliesToKind(focusText, detectBusinessKind(group.title))).flatMap((group) => group.requestDatas ?? []);
12003
+ const targetRows = wfIdGroup.filter((group) => !group.topPriority && activeRuleFor(group.title)?.aiGroup?.groupRule.aiContext === "\u6D41\u7A0B\u8BE6\u60C5").flatMap((group) => group.requestDatas ?? []);
11590
12004
  const targetIds = [...new Set(targetRows.map((row) => row.requestId).filter(Boolean))];
11591
12005
  if (targetIds.length > 0) {
11592
12006
  const { facts, stats } = await fetchDetailFacts(env, targetIds, args, stampsOfRows(targetRows));
@@ -11602,26 +12016,31 @@ async function collectRawTodos(args, env) {
11602
12016
  };
11603
12017
  }
11604
12018
  }
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
- }));
12019
+ groupingBrief = wfIdGroup.map((group) => {
12020
+ const groupRule = activeRuleFor(group.title)?.aiGroup?.groupRule;
12021
+ const groupingPrompt = groupRule && groupRule.focus === false && typeof groupRule.groupingPrompt === "string" ? groupRule.groupingPrompt.trim() : "";
12022
+ return {
12023
+ groupId: group.id,
12024
+ title: group.title,
12025
+ count: group.count,
12026
+ topPriority: group.topPriority,
12027
+ ...groupingPrompt ? { groupingPrompt } : {},
12028
+ items: (group.requestDatas ?? []).map((row, index) => ({
12029
+ idx: index + 1,
12030
+ requestId: row.requestId,
12031
+ title: row.requestNameTitle ?? "",
12032
+ // 客户问题支持类无侧重点时按这两个布尔分组(模型不用自己解析日期文案)
12033
+ overdue: isOverdueRow(row),
12034
+ expiringToday: isExpiringTodayRow(row),
12035
+ ...row.userOverTime ? { userOverTime: row.userOverTime } : {},
12036
+ ...row.summary ? { summary: row.summary } : {},
12037
+ // `summaryCached:true` = 这条已有本地摘要(按 requestId__lastFeedBackDateTime 命中),
12038
+ // 分组仍要做(聚类看标题),但**不要再给它写摘要**。
12039
+ ...cachedSummaryIds.has(row.requestId) ? { summaryCached: true } : {},
12040
+ ...fieldsById.has(row.requestId) ? { fields: fieldsById.get(row.requestId) } : {}
12041
+ }))
12042
+ };
12043
+ });
11625
12044
  const groupingFocus = typeof args.groupFocus === "string" ? args.groupFocus.trim() : "";
11626
12045
  groupInfo = {
11627
12046
  smartSummaryTitle: grouped.smartSummaryTitle,
@@ -11814,11 +12233,11 @@ function readAiGroups(value) {
11814
12233
  if (!record) {
11815
12234
  throw workflowValidationError("ai_groups_invalid", `${label} \u5FC5\u987B\u662F\u5BF9\u8C61 { groupId, title, requestIds }`, { retryAllowed: false });
11816
12235
  }
11817
- const unknownKeys = Object.keys(record).filter((key) => !["groupId", "title", "requestIds", "seq"].includes(key));
12236
+ const unknownKeys = Object.keys(record).filter((key) => !["groupId", "title", "requestIds"].includes(key));
11818
12237
  if (unknownKeys.length > 0) {
11819
12238
  throw workflowValidationError(
11820
12239
  "ai_groups_invalid",
11821
- `${label} \u4E0D\u63A5\u53D7\u5B57\u6BB5\uFF1A${unknownKeys.join(", ")}\uFF1B\u53EA\u652F\u6301 groupId / title / requestIds / seq`,
12240
+ `${label} \u4E0D\u63A5\u53D7\u5B57\u6BB5\uFF1A${unknownKeys.join(", ")}\uFF1B\u53EA\u652F\u6301 groupId / title / requestIds`,
11822
12241
  { retryAllowed: false, details: { unknownKeys } }
11823
12242
  );
11824
12243
  }
@@ -11839,37 +12258,15 @@ function readAiGroups(value) {
11839
12258
  );
11840
12259
  }
11841
12260
  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) {
12261
+ if (!hasIds) {
11844
12262
  throw workflowValidationError(
11845
12263
  "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`,
12264
+ `${label} \u5FC5\u987B\u7ED9 requestIds\uFF08\u975E\u7A7A\u7684 requestId \u5B57\u7B26\u4E32\u6570\u7EC4\uFF09`,
11847
12265
  { retryAllowed: false }
11848
12266
  );
11849
12267
  }
11850
- if (!hasIds && !hasSeq) {
11851
- throw workflowValidationError(
11852
- "ai_groups_invalid",
11853
- `${label} \u9700\u8981 requestIds \u6216 seq\uFF08\u7EC4\u5185 1-based \u5E8F\u53F7\uFF0C\u89C1 collect \u7684 groupingBrief\uFF09`,
11854
- { retryAllowed: false }
11855
- );
11856
- }
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
12268
  const ids = [];
11872
- for (const item of hasIds ? record.requestIds : []) {
12269
+ for (const item of record.requestIds) {
11873
12270
  const id = typeof item === "string" ? item.trim() : typeof item === "number" ? String(item) : "";
11874
12271
  if (!id) {
11875
12272
  throw workflowValidationError(
@@ -11881,7 +12278,7 @@ function readAiGroups(value) {
11881
12278
  ids.push(id);
11882
12279
  }
11883
12280
  const bucket = map.get(groupId) ?? [];
11884
- bucket.push({ groupId, title, requestIds: [...new Set(ids)], seq: [...new Set(seqNumbers)] });
12281
+ bucket.push({ groupId, title, requestIds: [...new Set(ids)] });
11885
12282
  map.set(groupId, bucket);
11886
12283
  });
11887
12284
  return map;
@@ -11900,34 +12297,21 @@ function ctxEmptyOf(facts) {
11900
12297
  function rowMetricsOf(row, metrics) {
11901
12298
  return metrics?.get(row.requestId) ?? {};
11902
12299
  }
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 });
11908
- }
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
- });
12300
+ function metricValueOf(row, metric, sysArg, facts, metrics) {
12301
+ if (sysArg) {
12302
+ const key = Object.keys(row).find((item) => item.toLowerCase() === metric.toLowerCase());
12303
+ return key ? row[key] : void 0;
11916
12304
  }
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
- });
12305
+ const rowMetrics = metrics?.get(row.requestId);
12306
+ if (rowMetrics) {
12307
+ if (/金额|费用|价|合计/u.test(metric) && typeof rowMetrics.amount === "number") return rowMetrics.amount;
12308
+ if (/天数|时长/u.test(metric) && typeof rowMetrics.leaveDays === "number") return rowMetrics.leaveDays;
12309
+ if (/假别|假种|假期/u.test(metric) && typeof rowMetrics.leaveType === "string") return rowMetrics.leaveType;
11929
12310
  }
11930
- return null;
12311
+ const fact = facts?.get(row.requestId);
12312
+ const field = (fact?.fields ?? []).find((item) => String(item.fieldName ?? "").includes(metric));
12313
+ const value = field?.value;
12314
+ return value === void 0 || String(value).trim() === "" ? void 0 : value;
11931
12315
  }
11932
12316
  function totalTodoCount(groups) {
11933
12317
  const seen = /* @__PURE__ */ new Set();
@@ -11995,6 +12379,7 @@ async function runSmartGroup(args, env, options = {}) {
11995
12379
  }
11996
12380
  }
11997
12381
  const warnings = (base.warnings ?? []).filter((text) => !text.startsWith("markdown \u53EA\u5C55\u793A\u524D"));
12382
+ warnings.push(...primeRules(env.ctx).warnings);
11998
12383
  if (skipDetail) {
11999
12384
  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
12385
  } else if (cachedIds.size > 0) {
@@ -12009,7 +12394,7 @@ async function runSmartGroup(args, env, options = {}) {
12009
12394
  topPriority: true,
12010
12395
  title: group.title,
12011
12396
  count: group.count,
12012
- // 只有优先组默认展开,其余分组一律收缩。
12397
+ // 大分组(含优先组)默认展开;只有汇总项(ai二次分组)收缩。
12013
12398
  defaultExpanded: true,
12014
12399
  displayItems: requestItemsOf(group.requestDatas)
12015
12400
  };
@@ -12018,106 +12403,78 @@ async function runSmartGroup(args, env, options = {}) {
12018
12403
  const used = /* @__PURE__ */ new Set();
12019
12404
  const subGroups = [];
12020
12405
  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
12406
  const flatReturn = () => ({
12030
12407
  id: group.id,
12031
12408
  topPriority: false,
12032
12409
  title: group.title,
12033
12410
  count: group.count,
12034
- defaultExpanded: false,
12411
+ defaultExpanded: true,
12035
12412
  displayItems: requestItemsOf(group.requestDatas)
12036
12413
  });
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`);
12414
+ const rawPlans = plans?.get(group.id) ?? [];
12415
+ const rule = activeRuleFor(group.title);
12416
+ if (!rule?.aiGroup) {
12417
+ if (rawPlans.length > 0) warnings.push(`\u300C${group.title}\u300D\u672A\u914D\u7F6E aiGroup\uFF0C\u5DF2\u5FFD\u7565 aiGroups`);
12418
+ if (!rule?.needSummary) warnings.push(`\u300C${group.title}\u300D\u4E0D\u9700\u8981 AI \u6458\u8981\uFF0Csummary \u7528\u6807\u9898\u515C\u5E95`);
12419
+ warnings.push(`\u300C${group.title}\u300D\u672A\u914D\u7F6E ai\u4E8C\u6B21\u5206\u7EC4\uFF0C${group.requestDatas.length} \u6761\u5E73\u94FA`);
12040
12420
  return flatReturn();
12041
12421
  }
12422
+ const groupRule = rule.aiGroup.groupRule;
12423
+ const focusMode = groupRule.focus === true;
12424
+ const groupPlans = rawPlans;
12042
12425
  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`);
12426
+ 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
12427
  return flatReturn();
12045
12428
  }
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) {
12429
+ if (!focusMode && groupPlans.length === 0) {
12430
+ const groupingPrompt = typeof groupRule.groupingPrompt === "string" ? groupRule.groupingPrompt.trim() : "";
12050
12431
  throw workflowValidationError(
12051
12432
  "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}`,
12433
+ `\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
12434
  {
12054
12435
  retryAllowed: true,
12055
- details: { groupId: group.id, count: group.requestDatas.length, groupFocus: groupHasFocus ? groupFocus : "" }
12436
+ details: {
12437
+ groupId: group.id,
12438
+ count: group.requestDatas.length,
12439
+ aiContext: groupRule.aiContext ?? "",
12440
+ ...groupingPrompt ? { groupingPrompt } : {}
12441
+ }
12056
12442
  }
12057
12443
  );
12058
12444
  }
12059
12445
  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
- }
12446
+ const conditions = groupRule.focusKeyword ?? [];
12447
+ const sysArg = groupRule.sysArg === true;
12448
+ const hit = [];
12449
+ const missing = /* @__PURE__ */ new Set();
12450
+ for (const row of group.requestDatas) {
12451
+ const resolve3 = (metric) => {
12452
+ const value = metricValueOf(row, metric, sysArg, facts, metrics);
12453
+ if (value === void 0) missing.add(metric);
12454
+ return value;
12455
+ };
12456
+ if (conditions.length > 0 && evaluateFocusKeywords(conditions, resolve3)) hit.push(row);
12457
+ else singles.push(row);
12458
+ }
12459
+ const conditionText = conditions.map((condition) => condition.join(" ")).join(" \u4E14 ");
12460
+ const title = groupRule.groupTitle?.trim() || conditionText || "\u6C47\u603B";
12461
+ if (hit.length > 0) {
12462
+ subGroups.push({ title, requestDatas: hit });
12463
+ warnings.push(
12464
+ `\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`
12465
+ );
12101
12466
  } 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`);
12467
+ warnings.push(`\u300C${group.title}\u300D\u89C4\u5219\u300C${title}\u300D\u547D\u4E2D 0 \u6761${conditionText ? `\uFF08${conditionText}\uFF09` : ""}\uFF0C\u5168\u90E8\u5E73\u94FA`);
12468
+ }
12469
+ if (missing.size > 0) {
12470
+ 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
12471
  }
12105
12472
  } else {
12106
- const reservedTitle = kind === "leave" ? LEAVE_GROUP_TITLE : kind === "finance" ? FINANCE_GROUP_TITLE : "";
12473
+ const reservedTitle = groupRule.groupTitle ?? "";
12107
12474
  const droppedByThreshold = [];
12108
12475
  for (const plan of groupPlans) {
12109
12476
  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
- });
12477
+ const planRequestIds = plan.requestIds;
12121
12478
  for (const requestId of planRequestIds) {
12122
12479
  const data = byRequestId.get(requestId);
12123
12480
  if (!data) {
@@ -12141,11 +12498,11 @@ async function runSmartGroup(args, env, options = {}) {
12141
12498
  if (reservedTitle && plan.title === reservedTitle) {
12142
12499
  const kept2 = [];
12143
12500
  const dropped = [];
12501
+ const conditions = groupRule.focusKeyword ?? [];
12502
+ const sysArg = groupRule.sysArg === true;
12144
12503
  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);
12504
+ const resolve3 = (metric) => metricValueOf(row, metric, sysArg, facts, metrics);
12505
+ (conditions.length > 0 && evaluateFocusKeywords(conditions, resolve3) ? kept2 : dropped).push(row);
12149
12506
  }
12150
12507
  if (dropped.length > 0) {
12151
12508
  droppedByThreshold.push(...dropped);
@@ -12173,8 +12530,38 @@ async function runSmartGroup(args, env, options = {}) {
12173
12530
  singles.push(...uncovered);
12174
12531
  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
12532
  }
12533
+ if (focusMode && subGroups.length > 1) {
12534
+ const sorted = [...subGroups].sort((a, b) => b.requestDatas.length - a.requestDatas.length);
12535
+ const [keep] = sorted;
12536
+ const dropped = sorted.slice(1);
12537
+ const droppedCount = dropped.reduce((sum, sub) => sum + sub.requestDatas.length, 0);
12538
+ for (const sub of dropped) singles.push(...sub.requestDatas);
12539
+ subGroups.length = 0;
12540
+ subGroups.push(keep);
12541
+ warnings.push(
12542
+ `\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`
12543
+ );
12544
+ }
12176
12545
  }
12177
- if (!groupHasFocus) subGroups.sort((a, b) => b.requestDatas.length - a.requestDatas.length);
12546
+ const renderSubGroupSummary = (sub) => {
12547
+ const groupSummary = rule.aiGroup?.groupSummary;
12548
+ if (!groupSummary || groupSummary.needAI || !groupSummary.template) return "";
12549
+ if (groupRule.groupTitle && sub.title !== groupRule.groupTitle) return "";
12550
+ const rows = sub.requestDatas;
12551
+ const items = rows.map((row) => rowMetricsOf(row, metrics));
12552
+ const amounts = items.map((item) => item.amount).filter((value) => typeof value === "number" && value > 0);
12553
+ if (groupSummary.template.includes("{{min}}") && amounts.length === 0) return "";
12554
+ return renderGroupSummaryTemplate({
12555
+ template: groupSummary.template,
12556
+ tail: groupSummary.tail,
12557
+ count: rows.length,
12558
+ restCount: singles.length,
12559
+ categories: items.map((item) => item.leaveType ?? item.feeCategory),
12560
+ amounts,
12561
+ creators: rows.map((row) => row.createrName)
12562
+ });
12563
+ };
12564
+ if (!focusMode) subGroups.sort((a, b) => b.requestDatas.length - a.requestDatas.length);
12178
12565
  const groupItems = subGroups.map((sub, index) => ({
12179
12566
  // 键顺序照新目标结构:type → id → title → count → summary → defaultExpanded → requestDatas
12180
12567
  type: "group",
@@ -12182,7 +12569,7 @@ async function runSmartGroup(args, env, options = {}) {
12182
12569
  title: sub.title,
12183
12570
  count: sub.requestDatas.length,
12184
12571
  // 组摘要口径不变(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) ?? "" : "",
12572
+ summary: renderSubGroupSummary(sub),
12186
12573
  // 汇总项自身默认收缩(与大分组的展开状态互相独立)
12187
12574
  defaultExpanded: false,
12188
12575
  requestDatas: sub.requestDatas
@@ -12192,7 +12579,8 @@ async function runSmartGroup(args, env, options = {}) {
12192
12579
  topPriority: false,
12193
12580
  title: group.title,
12194
12581
  count: group.count,
12195
- defaultExpanded: false,
12582
+ // 大分组默认展开(与汇总项自身的收缩状态互相独立)
12583
+ defaultExpanded: true,
12196
12584
  // 汇总项在前、单独条目在后。
12197
12585
  displayItems: [...groupItems, ...requestItemsOf(singles)]
12198
12586
  };
@@ -12213,6 +12601,9 @@ async function runSmartGroup(args, env, options = {}) {
12213
12601
  }
12214
12602
 
12215
12603
  // src/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.ts
12604
+ function needAiSummary(workflowName) {
12605
+ return activeRuleFor(workflowName)?.needSummary ?? true;
12606
+ }
12216
12607
  var DEFAULT_MAX_CHARS_PER_BATCH = 24e3;
12217
12608
  var DEFAULT_MAX_ITEMS_PER_BATCH = 100;
12218
12609
  var DEFAULT_REQUEST_SUMMARY_MAX3 = 50;
@@ -12319,7 +12710,7 @@ function validateFinalGroups(value) {
12319
12710
  (sum, item) => sum + (item.type === "group" ? item.requestDatas.length : 1),
12320
12711
  0
12321
12712
  );
12322
- return topPriority ? { id, topPriority: true, title, count, defaultExpanded: true, displayItems } : { id, topPriority: false, title, count, defaultExpanded: false, displayItems };
12713
+ return topPriority ? { id, topPriority: true, title, count, defaultExpanded: true, displayItems } : { id, topPriority: false, title, count, defaultExpanded: true, displayItems };
12323
12714
  });
12324
12715
  }
12325
12716
  async function readFinalGroups(args, env) {
@@ -12340,7 +12731,7 @@ function collectSummaryUnits(groups) {
12340
12731
  const units = [];
12341
12732
  for (const group of groups) {
12342
12733
  if (group.topPriority) {
12343
- if (!needsRequestSummary(detectBusinessKind(group.title))) continue;
12734
+ if (!needAiSummary(group.title)) continue;
12344
12735
  units.push({
12345
12736
  groupId: group.id,
12346
12737
  groupTitle: group.title,
@@ -12381,7 +12772,7 @@ function collectSummaryUnits(groups) {
12381
12772
  async function runSummaryContext(args, env, prefetched) {
12382
12773
  const groups = await readFinalGroups(args, env);
12383
12774
  const units = collectSummaryUnits(groups);
12384
- const skippedSatisfaction = groups.filter((group) => usesTitleSummary(detectBusinessKind(group.title))).reduce((sum, group) => sum + rowsOfGroup(group).length, 0);
12775
+ const skippedSatisfaction = groups.filter((group) => !needAiSummary(group.title)).reduce((sum, group) => sum + rowsOfGroup(group).length, 0);
12385
12776
  const requestIds = [...new Set(units.flatMap((unit) => unit.rows.map((row) => row.requestId)))].filter(Boolean);
12386
12777
  const summaryMaxChars = readBoundedInt(
12387
12778
  args.summaryMaxChars,
@@ -12579,7 +12970,7 @@ async function runSummary(args, env) {
12579
12970
  let cacheWritten = 0;
12580
12971
  let titleSummary = 0;
12581
12972
  for (const group of groups) {
12582
- if (usesTitleSummary(detectBusinessKind(group.title))) {
12973
+ if (!needAiSummary(group.title)) {
12583
12974
  for (const row of rowsOfGroup(group)) {
12584
12975
  if ((row.summary ?? "").trim()) continue;
12585
12976
  row.summary = row.requestNameTitle ?? "";
@@ -12642,7 +13033,7 @@ async function runSummary(args, env) {
12642
13033
  }
12643
13034
  };
12644
13035
  for (const group of groups) {
12645
- if (!needsRequestSummary(detectBusinessKind(group.title))) continue;
13036
+ if (!needAiSummary(group.title)) continue;
12646
13037
  if (group.topPriority) {
12647
13038
  applyAll(rowsOfGroup(group));
12648
13039
  continue;
@@ -12669,7 +13060,7 @@ async function runSummary(args, env) {
12669
13060
  if (prefilledKept > 0) {
12670
13061
  warnings.push(`\u6709 ${prefilledKept} \u6761\u6CBF\u7528\u672C\u5730\u6458\u8981\u7F13\u5B58\uFF08\u672A\u91CD\u65B0\u751F\u6210\uFF09`);
12671
13062
  }
12672
- const titleSummaryCount = groups.filter((group) => usesTitleSummary(detectBusinessKind(group.title))).reduce((sum, group) => sum + rowsOfGroup(group).length, 0);
13063
+ const titleSummaryCount = groups.filter((group) => !needAiSummary(group.title)).reduce((sum, group) => sum + rowsOfGroup(group).length, 0);
12673
13064
  if (titleSummaryCount > 0) {
12674
13065
  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
13066
  }
@@ -12837,7 +13228,7 @@ async function runGroupSummaryContext(args, env) {
12837
13228
  "\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
13229
  );
12839
13230
  }
12840
- const deterministicGroups = groups.filter((group) => !group.topPriority && isDeterministicGroupKind(detectBusinessKind(group.title))).reduce((sum, group) => sum + groupItemsOf(group).length, 0);
13231
+ const deterministicGroups = groups.filter((group) => !group.topPriority && activeRuleFor(group.title)?.aiGroup?.groupSummary.needAI === false).reduce((sum, group) => sum + groupItemsOf(group).length, 0);
12841
13232
  return {
12842
13233
  data: {
12843
13234
  smartSummaryTitle: readSmartSummaryTitle(args, `\u60A8\u5F53\u524D\u6709 ${totalCount} \u6761\u5F85\u529E\uFF0C\u6E05\u5355\u5982\u4E0B\uFF1A`),
@@ -13011,18 +13402,16 @@ var inputSchema = schemaOf({
13011
13402
  },
13012
13403
  aiGroups: {
13013
13404
  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",
13405
+ description: "smartGroup \u7684\u4E8C\u6B21\u5206\u7EC4\u8BA1\u5212\u3002\u6BCF\u9879\u5FC5\u987B\u63D0\u4F9B groupId\u3001title\u3001requestIds\u3002",
13015
13406
  items: {
13016
13407
  type: "object",
13017
13408
  additionalProperties: false,
13018
13409
  properties: {
13019
13410
  groupId: { type: "string" },
13020
13411
  title: { type: "string" },
13021
- requestIds: { type: "array", minItems: 1, items: { type: "string" } },
13022
- seq: { type: "array", minItems: 1, items: { type: "integer", minimum: 1 } }
13412
+ requestIds: { type: "array", minItems: 1, items: { type: "string" } }
13023
13413
  },
13024
- required: ["groupId", "title"],
13025
- oneOf: [{ required: ["requestIds"] }, { required: ["seq"] }]
13414
+ required: ["groupId", "title", "requestIds"]
13026
13415
  }
13027
13416
  },
13028
13417
  aiSummaries: {
@@ -15600,6 +15989,13 @@ export {
15600
15989
  asObject,
15601
15990
  assertNoForbiddenKeys,
15602
15991
  compactStdoutPaths,
15992
+ USER_INTENT_RULE_FILE,
15993
+ emptyRuleFile,
15994
+ validateRuleFile,
15995
+ loadRuleFile,
15996
+ aigroupUserDir,
15997
+ loadRules,
15998
+ resetActiveRules,
15603
15999
  workflowOperationDefinitions,
15604
16000
  getWorkflowOperation,
15605
16001
  hasWorkflowOperation