weaver-work-cli 0.1.38 → 0.1.39

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 (136) hide show
  1. package/README.md +4 -2
  2. package/dist/chunks/{archive-PDV724YK.js → archive-ENZYBBME.js} +556 -66
  3. package/dist/chunks/{archive-oa-4XE4MNXQ.js → archive-oa-YWLEC5V4.js} +2 -2
  4. package/dist/chunks/{asset-PDL2QE2N.js → asset-OOV6DWPA.js} +2 -2
  5. package/dist/chunks/asset-idle-RE632MY5.js +670 -0
  6. package/dist/chunks/{attachment-content-MDDGOE5E.js → attachment-content-RWN2FCLL.js} +3 -3
  7. package/dist/chunks/{blog-UYR3EUXW.js → blog-PEPOJAL7.js} +2 -2
  8. package/dist/chunks/{caizhilian-LG2X5NMF.js → caizhilian-WYIQDVPJ.js} +2 -2
  9. package/dist/chunks/{calendar-FG4BAZHE.js → calendar-CIARBAOX.js} +2 -2
  10. package/dist/chunks/{chunk-6FTTSA45.js → chunk-36DIFZAH.js} +2 -2
  11. package/dist/chunks/{chunk-UJJD4QWF.js → chunk-BJGXMFGD.js} +2 -2
  12. package/dist/chunks/{chunk-ELYDWBZJ.js → chunk-CQHGNCK2.js} +1 -1
  13. package/dist/chunks/{chunk-XJY7G4DD.js → chunk-EINRJHQ3.js} +3 -3
  14. package/dist/chunks/{chunk-UZZBA6PV.js → chunk-EZGFHJFW.js} +28 -6
  15. package/dist/chunks/{chunk-NI6GIPIM.js → chunk-F2EQXUEE.js} +438 -387
  16. package/dist/chunks/{chunk-VRYHGG6O.js → chunk-GVPJZXJ2.js} +3 -3
  17. package/dist/chunks/{chunk-IZUDA353.js → chunk-HJYVHXUQ.js} +1 -1
  18. package/dist/chunks/{chunk-KKRL3REV.js → chunk-I2HB737U.js} +2 -2
  19. package/dist/chunks/{chunk-NR6RKXPA.js → chunk-K3RUEEOL.js} +4 -2
  20. package/dist/chunks/{chunk-6LTFIFLM.js → chunk-KTCB5R5H.js} +2 -2
  21. package/dist/chunks/{chunk-J7USS3ED.js → chunk-L4N7B7ZD.js} +4 -4
  22. package/dist/chunks/{chunk-CORFRD7Q.js → chunk-MUQUHKPG.js} +2 -2
  23. package/dist/chunks/{chunk-DMV2TOMH.js → chunk-NLK2RZKG.js} +46 -46
  24. package/dist/chunks/{chunk-JSMFPO43.js → chunk-P2DAISYW.js} +1 -1
  25. package/dist/chunks/{chunk-GGJFMNJM.js → chunk-T7JDJJ7H.js} +3 -3
  26. package/dist/chunks/{chunk-OJQUJZQF.js → chunk-XXJOSZTQ.js} +2 -0
  27. package/dist/chunks/{chunk-Z32KWY6G.js → chunk-YS5DPN4T.js} +1 -1
  28. package/dist/chunks/{chunk-EG6ZU444.js → chunk-ZUX3P6BQ.js} +10 -5
  29. package/dist/chunks/{chunk-FUWVHMVV.js → chunk-ZXRNHZTE.js} +2 -2
  30. package/dist/chunks/{conflict-BQZEQ4SP.js → conflict-DRMDOL56.js} +2 -2
  31. package/dist/chunks/{contract-XIRAFTEV.js → contract-73MERZWN.js} +2 -2
  32. package/dist/chunks/{cowork-BLG62BL2.js → cowork-HNGBPD7A.js} +2 -2
  33. package/dist/chunks/{ebuilder-form-NUKG5QW4.js → ebuilder-form-OY6DVNRK.js} +3 -3
  34. package/dist/chunks/{ehr-2STW5ILH.js → ehr-RAQNEQO7.js} +2 -2
  35. package/dist/chunks/{esb-UUDQUNKY.js → esb-6XV7C7YV.js} +4 -4
  36. package/dist/chunks/{fna-6RCY4NU5.js → fna-XTSRB7G7.js} +2 -2
  37. package/dist/chunks/{host-RHM3NPXV.js → host-3F5UM5GN.js} +3 -3
  38. package/dist/chunks/{host-EJZFROU3.js → host-A7J6GDUP.js} +3 -3
  39. package/dist/chunks/{host-FWDOSRH5.js → host-VGPVP7YF.js} +3 -3
  40. package/dist/chunks/{host-7RXEDMAH.js → host-YAQAPYNP.js} +3 -3
  41. package/dist/chunks/{host-UFF33TWJ.js → host-YMBXWFWX.js} +3 -3
  42. package/dist/chunks/{hrm-PKJ6ELSH.js → hrm-TLHKC545.js} +3 -3
  43. package/dist/chunks/{im-YJAXS7CO.js → im-YOUCFMUK.js} +3 -3
  44. package/dist/chunks/{invoice-HWVSXGX6.js → invoice-WNBS2B4C.js} +3 -3
  45. package/dist/chunks/{jiuchuanhui-L7VKILZB.js → jiuchuanhui-XABWS5RN.js} +2 -2
  46. package/dist/chunks/{lazy-dispatch-NMYEIHRH.js → lazy-dispatch-NLZ5UQQI.js} +5 -5
  47. package/dist/chunks/{mail-B42RRU7G.js → mail-LRYMBFNL.js} +2 -2
  48. package/dist/chunks/{meeting-CFYVBJSS.js → meeting-ESXL6MFI.js} +10 -10
  49. package/dist/chunks/{okr-GCLF6V7W.js → okr-EOV65SSF.js} +2 -2
  50. package/dist/chunks/{plan-ZVL7GBRI.js → plan-YFPVKW6Y.js} +2 -2
  51. package/dist/chunks/{project-4YWAAE2K.js → project-MDVZUYQW.js} +2 -2
  52. package/dist/chunks/{registry-EP4VTHZS.js → registry-QCLZEDAP.js} +8 -8
  53. package/dist/chunks/{registry-FRJ6H7BT.js → registry-VT5Y2HLA.js} +4 -4
  54. package/dist/chunks/{registry-SG2PGVCF.js → registry-YX4CSEMD.js} +3 -3
  55. package/dist/chunks/{room-recommend-R3JVUUAC.js → room-recommend-L3MWH4JW.js} +4 -4
  56. package/dist/chunks/{schedule-NIJBTYDO.js → schedule-UASAVDVD.js} +4 -4
  57. package/dist/chunks/{workflow-BB24DFBY.js → workflow-KDGIUCNW.js} +9 -6
  58. package/dist/core/output.js +16 -6
  59. package/dist/index.js +33 -28
  60. package/dist/internal/e10/auth/messages.js +1 -0
  61. package/dist/internal/e10/auth-recovery.js +13 -6
  62. package/dist/internal/e10/context.js +16 -3
  63. package/dist/internal/e10/request-runtime.js +3 -1
  64. package/dist/shortcuts/archive/host.js +2 -0
  65. package/dist/shortcuts/archive/manifest.js +1 -1
  66. package/dist/shortcuts/archive/operations/borrow-list.js +13 -1
  67. package/dist/shortcuts/archive/operations/flow-url.js +1 -1
  68. package/dist/shortcuts/archive/operations/prelib.js +472 -0
  69. package/dist/shortcuts/archive/operations/registry.js +2 -0
  70. package/dist/shortcuts/archive/operations/upload.js +1 -1
  71. package/dist/shortcuts/asset-idle/errors.js +44 -0
  72. package/dist/shortcuts/asset-idle/host.js +161 -0
  73. package/dist/shortcuts/asset-idle/index.js +114 -0
  74. package/dist/shortcuts/asset-idle/manifest.js +159 -0
  75. package/dist/shortcuts/asset-idle/operations/idle.js +47 -0
  76. package/dist/shortcuts/asset-idle/operations/registry.js +33 -0
  77. package/dist/shortcuts/asset-idle/operations/shared.js +142 -0
  78. package/dist/shortcuts/asset-idle/operations/types.js +9 -0
  79. package/dist/shortcuts/asset-idle/operations.js +15 -0
  80. package/dist/shortcuts/index.js +5 -0
  81. package/dist/shortcuts/workflow/host.js +3 -0
  82. package/dist/shortcuts/workflow/index.js +1 -1
  83. package/dist/shortcuts/workflow/operations/form.js +46 -171
  84. package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupRules.js +77 -26
  85. package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupStore.js +6 -0
  86. package/dist/shortcuts/workflow/operations/todoSmartConvert/summaryCache.js +59 -117
  87. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailCache.js +44 -7
  88. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailFetcher.js +37 -29
  89. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +20 -6
  90. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.detail.js +22 -18
  91. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +34 -10
  92. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +4 -2
  93. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +9 -2
  94. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +110 -20
  95. package/docs/_catalog.md +3 -0
  96. package/docs/asset-idle.md +45 -0
  97. package/docs/e10-auth.md +1 -1
  98. package/docs/todo-smart-convert/subgroup-rules.md +1 -1
  99. package/package.json +1 -1
  100. package/scripts/package-skill.mjs +2 -0
  101. package/skill-template/business-info.json +14 -1
  102. package/skill-template/domains/asset-idle.md +13 -0
  103. package/skill-template/domains/wenshuding.md +3 -0
  104. package/skills/weaver-e10-archive-oa/SKILL.md +1 -0
  105. package/skills/weaver-e10-archive-oa/references/my-borrow.md +49 -0
  106. package/skills/weaver-e10-asset-idle/SKILL.md +73 -0
  107. package/skills/weaver-e10-asset-idle/references/idle-list.md +62 -0
  108. package/skills/weaver-e10-asset-idle/references/idle-stats-and-charts.md +65 -0
  109. package/skills/weaver-e10-asset-idle/references/source-manifest.json +193 -0
  110. package/skills/weaver-e10-asset-idle/references/widget-style.md +205 -0
  111. package/skills/weaver-e10-caizhilian/SKILL.md +29 -11
  112. package/skills/weaver-e10-caizhilian/references/auth-and-install.md +12 -0
  113. package/skills/weaver-e10-caizhilian/references/files.md +1 -1
  114. package/skills/weaver-e10-caizhilian/references/setting-encrypt.md +1 -1
  115. package/skills/weaver-e10-caizhilian/references/source-manifest.json +45 -45
  116. package/skills/weaver-e10-cowork/SKILL.md +2 -0
  117. package/skills/weaver-e10-jucailin/SKILL.md +2 -0
  118. package/skills/weaver-e10-jucailin/references/recruit-read.md +2 -0
  119. package/skills/weaver-e10-jucailin/references/recruit-write.md +1 -1
  120. package/skills/weaver-e10-mail/SKILL.md +3 -0
  121. package/skills/weaver-e10-shared/SKILL.md +5 -5
  122. package/skills/weaver-e10-shared/references/e10-auth-and-session.md +3 -3
  123. package/skills/weaver-e10-wenshuding/SKILL.md +29 -6
  124. package/skills/weaver-e10-wenshuding/references/archive-borrow-list.md +14 -0
  125. package/skills/weaver-e10-wenshuding/references/archive-download.md +2 -0
  126. package/skills/weaver-e10-wenshuding/references/archive-flow.md +1 -1
  127. package/skills/weaver-e10-wenshuding/references/archive-prelib-arrange.md +76 -0
  128. package/skills/weaver-e10-wenshuding/references/archive-prelib-list.md +107 -0
  129. package/skills/weaver-e10-wenshuding/references/archive-prelib-open.md +59 -0
  130. package/skills/weaver-e10-wenshuding/references/archive-upload.md +4 -1
  131. package/skills/weaver-e10-wenshuding/references/source-manifest.json +108 -65
  132. package/skills/weaver-e10-workflow/SKILL.md +5 -2
  133. package/skills/weaver-e10-workflow/aigroup/default.json +154 -19
  134. package/skills/weaver-e10-workflow/references/todo-smart-convert.md +59 -27
  135. package/skills/weaver-e10-workflow/tools/todo-serve.cjs +113 -25
  136. package/skills/weaver-e10-workflow/tools/todo-summary.cjs +292 -42
@@ -15,7 +15,7 @@ import {
15
15
  } from "./chunk-FMPJJYYI.js";
16
16
  import {
17
17
  stringifyForStdout
18
- } from "./chunk-EG6ZU444.js";
18
+ } from "./chunk-ZUX3P6BQ.js";
19
19
  import {
20
20
  stateRoot
21
21
  } from "./chunk-AJ62BGAW.js";
@@ -24,7 +24,7 @@ import {
24
24
  createFetchTimingSink,
25
25
  hasXiaoEEnv,
26
26
  runWithFetchTiming
27
- } from "./chunk-OJQUJZQF.js";
27
+ } from "./chunk-XXJOSZTQ.js";
28
28
 
29
29
  // src/shortcuts/workflow/operations/form.ts
30
30
  import { randomUUID } from "node:crypto";
@@ -5079,17 +5079,47 @@ async function runWorkflowSearch(args, env) {
5079
5079
  var TEXTAREA_COMPONENTS = /* @__PURE__ */ new Set(["textarea", "richtext", "editor", "html", "htmltext"]);
5080
5080
  var SELECT_COMPONENTS = /* @__PURE__ */ new Set(["select", "selectmultiple", "radiobox", "checkbox", "radio", "multiselect"]);
5081
5081
  var BROWSER_COMPONENTS = /* @__PURE__ */ new Set([
5082
+ // 人员 / 组织类
5082
5083
  "employee",
5083
5084
  "department",
5084
5085
  "subcompany",
5085
5086
  "jobtitle",
5086
5087
  "job",
5087
- "relatebrowser",
5088
- "browser",
5089
- "workflow",
5088
+ "employeeorganization",
5089
+ "employeeshare",
5090
+ "employeeauthshare",
5091
+ "odocreceivecomponent",
5092
+ // 关联类型(设计器「表单组件 / 关联类型」面板)
5090
5093
  "ebuilder",
5094
+ "mainline",
5095
+ "project",
5096
+ "task",
5097
+ "document",
5098
+ "workflow",
5099
+ "formcomponent",
5091
5100
  "customer",
5092
- "project"
5101
+ "customercomponent",
5102
+ "cluecomponent",
5103
+ "ordercomponent",
5104
+ "contactcomponent",
5105
+ "productioncomponent",
5106
+ "contractcomponent",
5107
+ "activitycomponent",
5108
+ "competitorcomponent",
5109
+ "kpiflowcomponent",
5110
+ "workreportcomponent",
5111
+ "attendcomponent",
5112
+ "agendacomponent",
5113
+ "chancecomponent",
5114
+ "relatebrowser",
5115
+ "relateodoc",
5116
+ "relatetag",
5117
+ "relateintegrate",
5118
+ "modulecomponent",
5119
+ "paas",
5120
+ "quotecomponent",
5121
+ "drivingrecord",
5122
+ "browser"
5093
5123
  ]);
5094
5124
  var NON_INPUT_COMPONENTS = /* @__PURE__ */ new Set([
5095
5125
  "paragraph",
@@ -5448,8 +5478,7 @@ function extractFields(layoutData, requiredMap, disableEditMap, displayMap) {
5448
5478
  const name = String(option.name ?? option.content ?? "").trim();
5449
5479
  if (optionId && name) options.push({ id: optionId, name });
5450
5480
  }
5451
- const componentBase = normalized.replace(/component$/, "");
5452
- const isBrowser = Object.keys(browserType).length > 0 || BROWSER_COMPONENTS.has(normalized) || BROWSER_COMPONENTS.has(componentBase);
5481
+ const isBrowser = Object.keys(browserType).length > 0 || BROWSER_COMPONENTS.has(normalized);
5453
5482
  const isSelect = SELECT_COMPONENTS.has(normalized) || options.length > 0;
5454
5483
  result.push({
5455
5484
  id: fieldId,
@@ -6379,24 +6408,6 @@ async function buildCreateFormData(workflowId, env, options = {}) {
6379
6408
  if (compsFieldIds.size && !String(f.subFormId ?? "").trim() && !compsFieldIds.has(fid)) continue;
6380
6409
  visibleFields.push(f);
6381
6410
  }
6382
- const hiddenBySubform = /* @__PURE__ */ new Map();
6383
- for (const f of fields) {
6384
- const fid = String(f.id ?? "");
6385
- const sid = String(f.subFormId ?? "").trim();
6386
- if (!sid || !hiddenCellIds.has(fid)) continue;
6387
- hiddenBySubform.set(sid, (hiddenBySubform.get(sid) || 0) + 1);
6388
- }
6389
- const survivingSubforms = new Set(
6390
- visibleFields.map((f) => String(f.subFormId ?? "").trim()).filter(Boolean)
6391
- );
6392
- const invisibleSubformWarnings = [];
6393
- for (const [sid, count] of hiddenBySubform) {
6394
- if (survivingSubforms.has(sid)) continue;
6395
- invisibleSubformWarnings.push(
6396
- `\u660E\u7EC6\u8868 ${sid} \u7684 ${count} \u4E2A\u5B57\u6BB5\u5168\u90E8\u88AB\u5224\u4E3A\u300C\u4E0D\u53EF\u89C1\u300D\uFF08\u8BE5\u660E\u7EC6\u8868\u6240\u5728\u7684\u884C/\u5217\u5728\u8868\u5355\u5E03\u5C40\u91CC\u662F\u9690\u85CF\u7684\uFF09\uFF0C\u56E0\u6B64\u6CA1\u6709\u51FA\u73B0\u5728\u5B57\u6BB5\u6E05\u5355\u91CC\u3002\u8981\u4E48\u5728\u8868\u5355\u8BBE\u8BA1\u5668\u91CC\u628A\u660E\u7EC6\u8868\u632A\u5230\u53EF\u89C1\u884C\uFF0C\u8981\u4E48\u53D6\u6D88\u9690\u85CF\u5B83\u6240\u5728\u7684\u884C/\u5217\uFF0C\u7136\u540E\u91CD\u65B0\u8F7D\u5165\u8868\u5355\u3002`
6397
- );
6398
- }
6399
- let layoutWarning = invisibleSubformWarnings.length ? invisibleSubformWarnings.join("\uFF1B") : null;
6400
6411
  const defaults = normalizeDefaults(layoutData.defaultDetails);
6401
6412
  const systemFieldValues = _normalizeSystemFieldValues(layoutData.businessOperatorObj);
6402
6413
  let linkageActions = Array.isArray(layoutData.linkageActions) ? layoutData.linkageActions : [];
@@ -6438,33 +6449,6 @@ async function buildCreateFormData(workflowId, env, options = {}) {
6438
6449
  }
6439
6450
  }
6440
6451
  const folderOptionValues = _mainValueMap(defaults);
6441
- const conditionalHiddenSubforms = /* @__PURE__ */ new Set();
6442
- const conditionalMainFields = /* @__PURE__ */ new Set();
6443
- const conditionalHints = collectDetailShowLinkages(layoutData.viewLinkages, fields);
6444
- const fieldShowIds = collectFieldShowLinkageIds(layoutData.viewLinkages);
6445
- for (const fid of Array.from(mainHidden)) {
6446
- if (!fieldShowIds.has(fid)) continue;
6447
- if (hiddenCellIds.has(fid)) continue;
6448
- const target = visibleFields.find((f) => String(f.id ?? "") === fid);
6449
- if (!target) continue;
6450
- conditionalMainFields.add(fid);
6451
- mainHidden.delete(fid);
6452
- invisibleSubformWarnings.push(
6453
- `\u5B57\u6BB5\u300C${target.name}\u300D(${fid}) \u56E0\u663E\u793A\u8054\u52A8\u9690\u85CF\uFF08\u8BE5\u5B57\u6BB5\u672C\u8EAB\u662F\u89E6\u53D1\u5B57\u6BB5\uFF09\uFF0C\u5DF2\u7167\u5E38\u4E0B\u53D1\u5E76\u6807 conditional: true`
6454
- );
6455
- }
6456
- for (const sid of Array.from(hiddenSubforms)) {
6457
- const hint = conditionalHints.get(sid);
6458
- if (!hint) continue;
6459
- const usable = visibleFields.some((f) => String(f.subFormId ?? "") === sid && !hiddenCellIds.has(String(f.id ?? "")));
6460
- if (!usable) continue;
6461
- conditionalHiddenSubforms.add(sid);
6462
- hiddenSubforms.delete(sid);
6463
- invisibleSubformWarnings.push(
6464
- `\u660E\u7EC6\u8868 ${sid}${hint.tableName ? `\uFF08${hint.tableName}\uFF09` : ""} \u56E0\u663E\u793A\u8054\u52A8\u9690\u85CF\uFF0C\u89E6\u53D1\u5B57\u6BB5\uFF1A${hint.triggerNames.join("\u3001") || hint.triggerIds.join("\u3001")}\u3002\u8BE5\u8868\u5B57\u6BB5\u5DF2\u7167\u5E38\u4E0B\u53D1\uFF08\u6807 conditional: true\uFF09\uFF0C\u628A\u89E6\u53D1\u5B57\u6BB5\u586B\u4E0A\u540E\u8868\u5355\u91CC\u5C31\u4F1A\u663E\u793A\uFF1B\u4E0D\u8981\u56DE\u300C\u8868\u5355\u91CC\u6CA1\u6709\u8FD9\u5F20\u660E\u7EC6\u8868\u300D\u3002`
6465
- );
6466
- }
6467
- layoutWarning = invisibleSubformWarnings.length ? invisibleSubformWarnings.join("\uFF1B") : null;
6468
6452
  for (const field of visibleFields) {
6469
6453
  const fieldId = String(field.id ?? "");
6470
6454
  const subFormId = String(field.subFormId ?? "");
@@ -6525,8 +6509,6 @@ async function buildCreateFormData(workflowId, env, options = {}) {
6525
6509
  } else if (slimSubFormId) {
6526
6510
  item.subFormId = slimSubFormId;
6527
6511
  }
6528
- if (slimSubFormId && conditionalHiddenSubforms.has(slimSubFormId)) item.conditional = true;
6529
- if (!slimSubFormId && conditionalMainFields.has(String(field.id ?? ""))) item.conditional = true;
6530
6512
  item.componentKey = field.componentKey;
6531
6513
  const initialValue = initialValueByFieldId.get(String(field.id ?? ""));
6532
6514
  if (initialValue !== void 0) item.initialValue = initialValue;
@@ -6660,8 +6642,6 @@ async function buildCreateFormData(workflowId, env, options = {}) {
6660
6642
  },
6661
6643
  systemFieldWarning: minorWarning,
6662
6644
  requiredInfoWarning: requiredInfoWarningText(context),
6663
- // 明细表整表不可见时的告警(见 layoutWarning 注释):有值时**不要**回"表单里没有这张明细表"。
6664
- layoutWarning,
6665
6645
  // 原 Python 把完整 context 落盘;此处通过 continuation 承载,返回结构保持文档契约。
6666
6646
  continuation: token
6667
6647
  }
@@ -7782,50 +7762,6 @@ function mergeLinkageDetails(merged, linkageDetails) {
7782
7762
  function emptyLinkageVisibility() {
7783
7763
  return [/* @__PURE__ */ new Set(), {}, {}, {}];
7784
7764
  }
7785
- function collectFieldShowLinkageIds(linkages) {
7786
- const out = /* @__PURE__ */ new Set();
7787
- if (!Array.isArray(linkages)) return out;
7788
- for (const rule of linkages) {
7789
- const details = Array.isArray(rule?.linkageDetails) ? rule.linkageDetails : [];
7790
- for (const detail of details) {
7791
- if (!detail || typeof detail !== "object") continue;
7792
- if (String(detail.linkageObj ?? "") !== "field") continue;
7793
- if (String(detail.linkageProp ?? "") !== "show") continue;
7794
- const fid = String(detail.linkageValue ?? "").trim();
7795
- if (fid) out.add(fid);
7796
- }
7797
- }
7798
- return out;
7799
- }
7800
- function collectDetailShowLinkages(linkages, fields) {
7801
- const out = /* @__PURE__ */ new Map();
7802
- if (!Array.isArray(linkages)) return out;
7803
- const list = Array.isArray(fields) ? fields : [];
7804
- const nameOf = (id) => {
7805
- for (const f of list) {
7806
- if (String(f?.id ?? "") === id) return String(f?.name ?? id);
7807
- }
7808
- return id;
7809
- };
7810
- for (const rule of linkages) {
7811
- const details = Array.isArray(rule?.linkageDetails) ? rule.linkageDetails : [];
7812
- for (const detail of details) {
7813
- if (!detail || typeof detail !== "object") continue;
7814
- if (String(detail.linkageObj ?? "") !== "detail") continue;
7815
- if (String(detail.linkageProp ?? "") !== "show") continue;
7816
- const sid = String(detail.linkageValue ?? "").trim();
7817
- if (!sid) continue;
7818
- const conds = Array.isArray(rule?.condition?.conditionDetails) ? rule.condition.conditionDetails : [];
7819
- const triggerIds = conds.map((c) => String(c?.targetId ?? "").trim()).filter(Boolean);
7820
- out.set(sid, {
7821
- triggerIds,
7822
- triggerNames: triggerIds.map(nameOf),
7823
- tableName: nameOf(sid) === sid ? "" : nameOf(sid)
7824
- });
7825
- }
7826
- }
7827
- return out;
7828
- }
7829
7765
  function computeLinkageVisibility(linkages, entries, defaults, linkageDetails, systemFieldValues, fields) {
7830
7766
  const hiddenSubforms = /* @__PURE__ */ new Set();
7831
7767
  const rowHidden = {};
@@ -8322,7 +8258,8 @@ var XIAOE_FILL_FORM_SDK_OPTIONS = {
8322
8258
  };
8323
8259
  var XIAOE_INITIAL_VALUES_MULTI_SEPARATOR = ",";
8324
8260
  var XIAOE_INITIAL_VALUES_ROW_SEPARATOR = ";";
8325
- function xiaoEUrlParamScalar(value) {
8261
+ var XIAOE_BROWSER_ID_PREFIX = "##";
8262
+ function xiaoEUrlParamScalar(value, prefixBrowserId = false) {
8326
8263
  if (value === null || value === void 0) return "";
8327
8264
  if (typeof value === "object") {
8328
8265
  const obj = value;
@@ -8330,18 +8267,19 @@ function xiaoEUrlParamScalar(value) {
8330
8267
  const picked = obj[key];
8331
8268
  if (picked === null || picked === void 0) continue;
8332
8269
  const text = String(picked).trim();
8333
- if (text) return text;
8270
+ if (!text) continue;
8271
+ return prefixBrowserId ? `${XIAOE_BROWSER_ID_PREFIX}${text}` : text;
8334
8272
  }
8335
8273
  return "";
8336
8274
  }
8337
8275
  return String(value).trim();
8338
8276
  }
8339
- function xiaoEUrlParamValue(value) {
8277
+ function xiaoEUrlParamValue(value, prefixBrowserId = false) {
8340
8278
  if (value === null || value === void 0) return "";
8341
8279
  if (Array.isArray(value)) {
8342
- return value.map((item) => xiaoEUrlParamScalar(item)).filter(Boolean).join(XIAOE_INITIAL_VALUES_MULTI_SEPARATOR);
8280
+ return value.map((item) => xiaoEUrlParamScalar(item, prefixBrowserId)).filter(Boolean).join(XIAOE_INITIAL_VALUES_MULTI_SEPARATOR);
8343
8281
  }
8344
- return xiaoEUrlParamScalar(value);
8282
+ return xiaoEUrlParamScalar(value, prefixBrowserId);
8345
8283
  }
8346
8284
  function editablePreviewForXiaoE(preview, fields, visibility) {
8347
8285
  const fieldById = /* @__PURE__ */ new Map();
@@ -8366,14 +8304,19 @@ function editablePreviewForXiaoE(preview, fields, visibility) {
8366
8304
  }
8367
8305
  return kept;
8368
8306
  }
8369
- function xiaoECustomParams(preview) {
8307
+ function xiaoECustomParams(preview, fields) {
8370
8308
  const ordered = [];
8371
8309
  const mainValues = /* @__PURE__ */ new Map();
8372
8310
  const detailValues = /* @__PURE__ */ new Map();
8311
+ const browserFieldIds = /* @__PURE__ */ new Set();
8312
+ for (const field of toArray(fields)) {
8313
+ const id = String(field?.id ?? "").trim();
8314
+ if (id && field?.isBrowser) browserFieldIds.add(id);
8315
+ }
8373
8316
  for (const item of toArray(preview)) {
8374
8317
  const fieldId = String(item?.fieldId ?? "").trim();
8375
8318
  if (!fieldId) continue;
8376
- const text = xiaoEUrlParamValue(item?.value);
8319
+ const text = xiaoEUrlParamValue(item?.value, browserFieldIds.has(fieldId));
8377
8320
  if (!text) continue;
8378
8321
  const isDetail = item?.dataIndex !== void 0 && item?.dataIndex !== null;
8379
8322
  if (!isDetail) {
@@ -8528,8 +8471,7 @@ async function runCreateRequest(args, env, options = {}) {
8528
8471
  }
8529
8472
  const [details, valueAmbiguities, preview] = await resolveEntryValues(env, entries, context.layout.form_id);
8530
8473
  const merged = mergeDetails(context.defaults || [], details);
8531
- const forceServerSubmit = args.forceServerSubmit === true;
8532
- const isXiaoE = forceServerSubmit ? false : hasXiaoEEnv(env.ctx.env, env.ctx.getGlobalOptions?.());
8474
+ const isXiaoE = hasXiaoEEnv(env.ctx.env, env.ctx.getGlobalOptions?.());
8533
8475
  const linkageDetails = isXiaoE ? [] : await runFieldLinkage(env, linkageContextFromPayload(context), entries, null, merged, false, context.defaults || []);
8534
8476
  const merged2 = fillDetailDefaultsByRow(
8535
8477
  mergeLinkageDetails(merged, linkageDetails),
@@ -8658,7 +8600,7 @@ async function runCreateRequest(args, env, options = {}) {
8658
8600
  baseUrl: xiaoEBaseUrl,
8659
8601
  title: String(context.workflow?.name ?? ""),
8660
8602
  workflowId: String(context.workflow?.id ?? context.runtime?.workflow_id ?? ""),
8661
- customParams: xiaoECustomParams(fillPreview)
8603
+ customParams: xiaoECustomParams(fillPreview, fields)
8662
8604
  })
8663
8605
  });
8664
8606
  }
@@ -10392,90 +10334,30 @@ import { existsSync as existsSync3, readFileSync } from "node:fs";
10392
10334
  import { join as join2 } from "node:path";
10393
10335
 
10394
10336
  // src/shortcuts/workflow/operations/todoSmartConvert/summaryCache.ts
10395
- import { existsSync as existsSync2, readdirSync, statSync } from "node:fs";
10337
+ import { existsSync as existsSync2 } from "node:fs";
10396
10338
  import { chmod as chmod2, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
10397
- import { homedir as homedir2 } from "node:os";
10398
10339
  import { join, resolve as resolve2 } from "node:path";
10399
- var SKILL_DIR_NAME = "weaver-e10-workflow";
10400
10340
  var CACHE_DIR_NAME = "cache";
10401
- var AGENT_HOME_DIRS = [".workbuddy", ".claude", ".codebuddy", ".codex", ".cursor", ".gemini"];
10402
10341
  var SUMMARY_CACHE_FILE_NAME = "todo-summary-cache.json";
10403
10342
  var SUMMARY_CACHE_VERSION = 2;
10404
10343
  function uniqueDirs(dirs) {
10405
- return [...new Set(dirs.filter(Boolean))];
10406
- }
10407
- function stateCacheDir(ctx) {
10408
- return resolve2(stateRoot(ctx), CACHE_DIR_NAME);
10409
- }
10410
- function discoverThisSkillDirs(home) {
10411
- const marker = join("references", "todo-smart-convert.md");
10412
- const found = [];
10413
- for (const agent of AGENT_HOME_DIRS) {
10414
- const root = join(home, agent, "skills");
10415
- const entries = (() => {
10416
- try {
10417
- return readdirSync(root, { withFileTypes: true });
10418
- } catch {
10419
- return [];
10420
- }
10421
- })();
10422
- for (const entry of entries) {
10423
- if (!entry.isDirectory()) continue;
10424
- const dir = join(root, entry.name);
10425
- if (existsSync2(join(dir, marker))) found.push(dir);
10426
- }
10427
- }
10428
- return found;
10344
+ return [...new Set(dirs.filter((dir) => Boolean(dir)))];
10429
10345
  }
10430
- function mtimeOf(file) {
10431
- try {
10432
- return statSync(file).mtimeMs;
10433
- } catch {
10434
- return 0;
10435
- }
10436
- }
10437
- function rankSkillDirs(dirs) {
10438
- const scored = dirs.map((dir, index) => ({
10439
- dir,
10440
- index,
10441
- hasCache: existsSync2(join(dir, CACHE_DIR_NAME, SUMMARY_CACHE_FILE_NAME)) ? 1 : 0,
10442
- cacheMtime: mtimeOf(join(dir, CACHE_DIR_NAME, SUMMARY_CACHE_FILE_NAME)),
10443
- hasMarker: existsSync2(join(dir, "references", "todo-smart-convert.md")) ? 1 : 0,
10444
- skillMtime: mtimeOf(join(dir, "SKILL.md"))
10445
- }));
10446
- scored.sort(
10447
- (a, b) => b.hasCache - a.hasCache || b.cacheMtime - a.cacheMtime || b.hasMarker - a.hasMarker || b.skillMtime - a.skillMtime || a.index - b.index
10448
- );
10449
- return scored.map((item) => item.dir);
10346
+ function resolveSkillDir() {
10347
+ const explicit = process.env.WEAVER_WORK_CLI_SKILL_DIR?.trim();
10348
+ return explicit ? resolve2(explicit) : null;
10450
10349
  }
10451
10350
  function cacheRoots(ctx) {
10452
- const fallback = stateCacheDir(ctx);
10453
- const explicitCache = process.env.WEAVER_WORK_CLI_CACHE_DIR?.trim();
10454
- if (explicitCache) {
10455
- const dir = resolve2(explicitCache);
10456
- return { preferred: dir, fallback: dir, inSkillDir: false, skillDir: null };
10457
- }
10458
- const home = homedir2();
10459
- const explicitSkill = process.env.WEAVER_WORK_CLI_SKILL_DIR?.trim();
10460
- const candidates = [];
10461
- if (explicitSkill) candidates.push(resolve2(explicitSkill));
10462
- for (const agent of AGENT_HOME_DIRS) {
10463
- candidates.push(join(home, agent, "skills", SKILL_DIR_NAME));
10464
- }
10465
- candidates.push(...discoverThisSkillDirs(home));
10466
- const installed = uniqueDirs(candidates).filter((dir) => existsSync2(join(dir, "SKILL.md")));
10467
- const [skillDir] = rankSkillDirs(installed);
10468
- if (skillDir) {
10469
- return {
10470
- preferred: join(skillDir, CACHE_DIR_NAME),
10471
- fallback,
10472
- inSkillDir: true,
10473
- skillDir
10474
- };
10351
+ void ctx;
10352
+ const skillDir = resolveSkillDir();
10353
+ if (!skillDir) {
10354
+ return { preferred: null, fallback: null, inSkillDir: false, skillDir: null, refused: true };
10475
10355
  }
10476
- return { preferred: fallback, fallback, inSkillDir: false, skillDir: null };
10356
+ const cacheDir = join(skillDir, CACHE_DIR_NAME);
10357
+ return { preferred: cacheDir, fallback: cacheDir, inSkillDir: true, skillDir, refused: false };
10477
10358
  }
10478
10359
  async function readCacheFile(roots, fileName) {
10360
+ if (roots.refused || !roots.preferred) return null;
10479
10361
  for (const dir of uniqueDirs([roots.preferred, roots.fallback])) {
10480
10362
  const file = join(dir, fileName);
10481
10363
  if (!existsSync2(file)) continue;
@@ -10488,6 +10370,7 @@ async function readCacheFile(roots, fileName) {
10488
10370
  return null;
10489
10371
  }
10490
10372
  async function writeCacheFile(roots, fileName, payload) {
10373
+ if (roots.refused || !roots.preferred) return null;
10491
10374
  for (const dir of uniqueDirs([roots.preferred, roots.fallback])) {
10492
10375
  const file = join(dir, fileName);
10493
10376
  try {
@@ -10507,9 +10390,14 @@ function summaryCacheKey(requestId, lastFeedBackDateTime) {
10507
10390
  const stamp = String(lastFeedBackDateTime ?? "").trim();
10508
10391
  return `${requestId}__${stamp}`;
10509
10392
  }
10510
- function entryMatchesMaxChars(entry, maxChars) {
10511
- if (maxChars === void 0) return true;
10512
- return (entry.maxChars ?? 50) === maxChars;
10393
+ function promptTagOf(prompt) {
10394
+ return String(prompt ?? "").trim();
10395
+ }
10396
+ function entryMatches(entry, maxChars, pk, dv) {
10397
+ if (maxChars !== void 0 && (entry.maxChars ?? 50) !== maxChars) return false;
10398
+ if (pk !== void 0 && (entry.pk ?? "") !== pk) return false;
10399
+ if (entry.dv !== void 0 && entry.dv !== dv) return false;
10400
+ return true;
10513
10401
  }
10514
10402
  function normalizeSummaryEntry(raw) {
10515
10403
  if (!raw || typeof raw !== "object") return null;
@@ -10517,7 +10405,15 @@ function normalizeSummaryEntry(raw) {
10517
10405
  if (typeof entry.summary !== "string" || !entry.summary.trim()) return null;
10518
10406
  if (typeof entry.cachedAt !== "number" || !Number.isFinite(entry.cachedAt)) return null;
10519
10407
  const maxChars = typeof entry.maxChars === "number" && Number.isFinite(entry.maxChars) ? entry.maxChars : void 0;
10520
- return { summary: entry.summary, cachedAt: entry.cachedAt, ...maxChars === void 0 ? {} : { maxChars } };
10408
+ const pk = typeof entry.pk === "string" && entry.pk !== "" ? entry.pk : void 0;
10409
+ const dv = typeof entry.dv === "string" && entry.dv !== "" ? entry.dv : void 0;
10410
+ return {
10411
+ summary: entry.summary,
10412
+ cachedAt: entry.cachedAt,
10413
+ ...maxChars === void 0 ? {} : { maxChars },
10414
+ ...pk === void 0 ? {} : { pk },
10415
+ ...dv === void 0 ? {} : { dv }
10416
+ };
10521
10417
  }
10522
10418
  async function openSummaryCache(ctx) {
10523
10419
  const roots = cacheRoots(ctx);
@@ -10554,27 +10450,29 @@ async function openSummaryCache(ctx) {
10554
10450
  misses: 0,
10555
10451
  pruned,
10556
10452
  dirty: false,
10557
- get(requestId, lastFeedBackDateTime, maxChars) {
10453
+ get(requestId, lastFeedBackDateTime, maxChars, pk, dv) {
10558
10454
  const key = summaryCacheKey(requestId, lastFeedBackDateTime);
10559
10455
  const entry = entries.get(key);
10560
- if (entry && now - entry.cachedAt <= SUMMARY_CACHE_TTL_MS && entryMatchesMaxChars(entry, maxChars)) {
10456
+ if (entry && now - entry.cachedAt <= SUMMARY_CACHE_TTL_MS && entryMatches(entry, maxChars, pk, dv)) {
10561
10457
  cache.hits += 1;
10562
10458
  return entry.summary;
10563
10459
  }
10564
10460
  cache.misses += 1;
10565
10461
  return null;
10566
10462
  },
10567
- has(requestId, lastFeedBackDateTime, maxChars) {
10463
+ has(requestId, lastFeedBackDateTime, maxChars, pk, dv) {
10568
10464
  const entry = entries.get(summaryCacheKey(requestId, lastFeedBackDateTime));
10569
- return entry !== void 0 && entryMatchesMaxChars(entry, maxChars);
10465
+ return entry !== void 0 && entryMatches(entry, maxChars, pk, dv);
10570
10466
  },
10571
- set(requestId, lastFeedBackDateTime, summary, maxChars) {
10467
+ set(requestId, lastFeedBackDateTime, summary, maxChars, pk, dv) {
10572
10468
  const text = String(summary ?? "").trim();
10573
10469
  if (!requestId || !text) return false;
10574
10470
  entries.set(summaryCacheKey(requestId, lastFeedBackDateTime), {
10575
10471
  summary: text,
10576
10472
  cachedAt: Date.now(),
10577
- ...maxChars === void 0 ? {} : { maxChars }
10473
+ ...maxChars === void 0 ? {} : { maxChars },
10474
+ ...pk === void 0 || pk === "" ? {} : { pk },
10475
+ ...dv === void 0 || dv === "" ? {} : { dv }
10578
10476
  });
10579
10477
  dirty = true;
10580
10478
  cache.dirty = true;
@@ -10626,7 +10524,8 @@ var FALLBACK_DEFAULTS = {
10626
10524
  requestSummaryPrompt: "",
10627
10525
  summaryMaxChars: 150,
10628
10526
  groupSummaryMaxChars: 100,
10629
- groupSummaryTail: "\u53EF\u5C55\u5F00\u9010\u6761\u67E5\u770B\u6216\u76F4\u63A5\u6C47\u603B\u5904\u7406"
10527
+ groupSummaryTail: "\u53EF\u5C55\u5F00\u9010\u6761\u67E5\u770B\u6216\u76F4\u63A5\u6C47\u603B\u5904\u7406",
10528
+ excludeOriginFormDataFields: []
10630
10529
  };
10631
10530
  function emptyRuleFile(error = null) {
10632
10531
  return {
@@ -10655,14 +10554,33 @@ function validateFocusKeyword(raw, index) {
10655
10554
  if (raw.length !== 3) return `focusKeyword[${index}] \u5FC5\u987B\u662F [\u6307\u6807, \u7B97\u5B50, \u503C] \u4E09\u5143\u7EC4`;
10656
10555
  return null;
10657
10556
  }
10557
+ function validateExcludeFields(raw, where) {
10558
+ if (raw === void 0) return null;
10559
+ if (typeof raw === "string") {
10560
+ return raw.trim() === "" ? `${where} \u4E0D\u80FD\u662F\u7A7A\u5B57\u7B26\u4E32\uFF08\u4E0D\u6392\u9664\u5C31\u522B\u7ED9\u8FD9\u4E2A\u952E\uFF09` : null;
10561
+ }
10562
+ if (!Array.isArray(raw)) return `${where} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4`;
10563
+ for (const item of raw) {
10564
+ if (typeof item !== "string" || item.trim() === "") return `${where} \u7684\u6BCF\u4E00\u9879\u90FD\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`;
10565
+ }
10566
+ return null;
10567
+ }
10658
10568
  function validateRuleFile(raw) {
10659
10569
  const errors = [];
10660
10570
  const file = raw;
10661
10571
  if (!file || typeof file !== "object") return ["\u89C4\u5219\u6587\u4EF6\u5FC5\u987B\u662F JSON \u5BF9\u8C61"];
10572
+ if (file.schemaVersion !== void 0 && file.schemaVersion !== 2 && file.schemaVersion !== 3) {
10573
+ errors.push(`schemaVersion \u53EA\u652F\u6301 2 \u6216 3\uFF0C\u6536\u5230 ${JSON.stringify(file.schemaVersion ?? null)}`);
10574
+ }
10662
10575
  if (!Array.isArray(file.rules)) {
10663
10576
  errors.push("rules \u5FC5\u987B\u662F\u6570\u7EC4");
10664
10577
  return errors;
10665
10578
  }
10579
+ const defaultsExclude = validateExcludeFields(
10580
+ file.defaults?.excludeOriginFormDataFields,
10581
+ "defaults.excludeOriginFormDataFields"
10582
+ );
10583
+ if (defaultsExclude) errors.push(defaultsExclude);
10666
10584
  const seen = /* @__PURE__ */ new Set();
10667
10585
  file.rules.forEach((rule, index) => {
10668
10586
  if (!rule || typeof rule !== "object") {
@@ -10684,6 +10602,13 @@ function validateRuleFile(raw) {
10684
10602
  if (rule.summaryMaxChars !== void 0 && (typeof rule.summaryMaxChars !== "number" || rule.summaryMaxChars <= 0)) {
10685
10603
  errors.push(`rules[${index}].summaryMaxChars \u5FC5\u987B\u662F\u6B63\u6570`);
10686
10604
  }
10605
+ const excludeReason = validateExcludeFields(rule.excludeOriginFormDataFields, `rules[${index}].excludeOriginFormDataFields`);
10606
+ if (excludeReason) errors.push(excludeReason);
10607
+ if (rule.summaryRequiredFields !== void 0) {
10608
+ if (!Array.isArray(rule.summaryRequiredFields) || rule.summaryRequiredFields.length === 0 || rule.summaryRequiredFields.some((f) => typeof f !== "string" || !f.trim() || f.trim().length > 50) || rule.summaryRequiredFields.length > 20) {
10609
+ errors.push(`rules[${index}].summaryRequiredFields \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32\u6570\u7EC4\uFF081~20 \u9879\u3001\u6BCF\u9879 1~50 \u5B57\uFF09`);
10610
+ }
10611
+ }
10687
10612
  const groupRule = rule.aiGroup?.groupRule;
10688
10613
  if (groupRule) {
10689
10614
  if (typeof groupRule.focus !== "boolean") errors.push(`rules[${index}].aiGroup.groupRule.focus \u5FC5\u987B\u662F\u5E03\u5C14`);
@@ -10737,29 +10662,28 @@ function loadRuleFile(file) {
10737
10662
  return { file: parsed, error: null };
10738
10663
  }
10739
10664
  function aigroupDir(ctx) {
10740
- const explicit = process.env.WEAVER_WORK_CLI_AIGROUP_DIR?.trim();
10741
- if (explicit) return join2(explicit);
10742
- const roots = cacheRoots(ctx);
10743
- return roots.skillDir ? join2(roots.skillDir, AIGROUP_DIR_NAME) : join2(stateRoot(ctx), AIGROUP_DIR_NAME);
10665
+ const skillDir = resolveSkillDir();
10666
+ return skillDir ? join2(skillDir, AIGROUP_DIR_NAME) : null;
10744
10667
  }
10745
10668
  function aigroupUserDir(ctx) {
10746
- const explicit = process.env.WEAVER_WORK_CLI_AIGROUP_DIR?.trim();
10747
- if (explicit) return join2(explicit);
10748
- return join2(stateRoot(ctx), AIGROUP_DIR_NAME);
10669
+ return aigroupDir(ctx);
10749
10670
  }
10750
10671
  function loadRules(options = {}) {
10751
- const dir = options.dir ?? aigroupDir(options.ctx);
10752
- const userDir = options.dir ?? aigroupUserDir(options.ctx);
10753
10672
  const warnings = [];
10673
+ const dir = options.dir ?? aigroupDir(options.ctx);
10674
+ if (!dir) {
10675
+ warnings.push("\u65E0\u5F53\u524D skill \u4E0A\u4E0B\u6587\uFF08WEAVER_WORK_CLI_SKILL_DIR \u672A\u8BBE\u7F6E\uFF09\uFF1Aaigroup \u89C4\u5219\u672A\u52A0\u8F7D\uFF0C\u6309\u65E0\u89C4\u5219\u5904\u7406");
10676
+ return { file: emptyRuleFile(null).file, warnings, dir: null };
10677
+ }
10754
10678
  const base = loadRuleFile(join2(dir, DEFAULT_RULE_FILE));
10755
10679
  if (base.error) warnings.push(base.error);
10756
10680
  const rules = [...base.file.rules];
10757
- const userIntentFile = join2(userDir, USER_INTENT_RULE_FILE);
10758
- const legacyIntentFile = join2(dir, USER_INTENT_RULE_FILE);
10681
+ const userIntentFile = join2(dir, USER_INTENT_RULE_FILE);
10682
+ const legacyIntentFile = join2(stateRoot(options.ctx), AIGROUP_DIR_NAME, USER_INTENT_RULE_FILE);
10759
10683
  let intentFile = userIntentFile;
10760
10684
  if (!options.dir && !existsSync3(userIntentFile) && existsSync3(legacyIntentFile)) {
10761
10685
  intentFile = legacyIntentFile;
10762
- 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`);
10686
+ warnings.push(`\u7528\u6237\u610F\u56FE\u4ECD\u8BFB\u81EA CLI \u72B6\u6001\u76EE\u5F55\uFF08${legacyIntentFile}\uFF09\uFF1A\u65B0\u4F4D\u7F6E\u662F ${userIntentFile}\uFF0C\u91CD\u65B0\u6267\u884C aigroup set \u5373\u53EF\u8FC1\u79FB`);
10763
10687
  }
10764
10688
  const intent = loadRuleFile(intentFile);
10765
10689
  if (intent.error) {
@@ -10821,12 +10745,13 @@ function resolveRule(file, workflowName) {
10821
10745
  summaryMaxChars: raw.summaryMaxChars ?? defaults.summaryMaxChars,
10822
10746
  groupSummaryMaxChars: defaults.groupSummaryMaxChars,
10823
10747
  groupSummaryTail: defaults.groupSummaryTail,
10748
+ // 显式给 `[]` = 规则级覆盖(清空 defaults 的清单);未给才落 defaults
10749
+ excludeOriginFormDataFields: raw.excludeOriginFormDataFields === void 0 ? defaults.excludeOriginFormDataFields : asStringArray3(raw.excludeOriginFormDataFields) ?? [],
10824
10750
  aiGroup: raw.aiGroup ? {
10825
10751
  groupSummary: {
10826
10752
  needAI: groupSummary?.needAI ?? false,
10827
10753
  ...groupSummary?.prompt === void 0 ? {} : { prompt: groupSummary.prompt },
10828
10754
  ...groupSummary?.template === void 0 ? {} : { template: groupSummary.template },
10829
- maxChars: defaults.groupSummaryMaxChars,
10830
10755
  tail: defaults.groupSummaryTail
10831
10756
  },
10832
10757
  groupRule: groupRule ?? EMPTY_GROUP_RULE
@@ -10953,6 +10878,15 @@ function resetActiveRules() {
10953
10878
  activeFile = null;
10954
10879
  activeDir = null;
10955
10880
  }
10881
+ function excludeFieldsFor(workflowName) {
10882
+ return activeRuleFor(workflowName)?.excludeOriginFormDataFields ?? [];
10883
+ }
10884
+ function excludeTagOf(fields) {
10885
+ return [...fields].join("");
10886
+ }
10887
+ function excludeTagFor(workflowName) {
10888
+ return excludeTagOf(excludeFieldsFor(workflowName));
10889
+ }
10956
10890
 
10957
10891
  // src/shortcuts/workflow/operations/todoSmartConvert/todoListRows.ts
10958
10892
  var DISPLAY_ROW_FIELDS = [
@@ -11013,6 +10947,107 @@ function projectDisplayRows(response) {
11013
10947
  return projected;
11014
10948
  }
11015
10949
 
10950
+ // src/shortcuts/workflow/operations/todoSmartConvert/todoDetailCache.ts
10951
+ var DETAIL_CACHE_FILE_NAME = "todo-detail-cache.json";
10952
+ var DETAIL_CACHE_TTL_MS = SUMMARY_CACHE_TTL_MS;
10953
+ var DETAIL_CACHE_PRUNE_INTERVAL_MS = SUMMARY_CACHE_PRUNE_INTERVAL_MS;
10954
+ var DETAIL_CACHE_ENTRY_VERSION = 3;
10955
+ function detailCacheKey(requestId, lastFeedBackDateTime) {
10956
+ const stamp = String(lastFeedBackDateTime ?? "").trim();
10957
+ return `${requestId}__${stamp}`;
10958
+ }
10959
+ function detailMaterialTagOf(entry) {
10960
+ const basic = entry.basicInfo ?? {};
10961
+ const basicKeys = Object.keys(basic).sort();
10962
+ const material = JSON.stringify([
10963
+ basicKeys.map((key) => [key, basic[key]]),
10964
+ (entry.fields ?? []).map((field) => [field.fieldName, field.value])
10965
+ ]);
10966
+ let hash = 5381;
10967
+ for (let i = 0; i < material.length; i += 1) hash = (hash << 5) + hash + material.charCodeAt(i) >>> 0;
10968
+ return hash.toString(16);
10969
+ }
10970
+ function normalizeEntry(raw) {
10971
+ if (!raw || typeof raw !== "object") return null;
10972
+ const value = raw;
10973
+ if (value.v !== DETAIL_CACHE_ENTRY_VERSION) return null;
10974
+ if (typeof value.cachedAt !== "number" || !Number.isFinite(value.cachedAt)) return null;
10975
+ if (typeof value.excludeTag !== "string") return null;
10976
+ const basicInfo = {};
10977
+ if (value.basicInfo && typeof value.basicInfo === "object") {
10978
+ for (const [key, item] of Object.entries(value.basicInfo)) {
10979
+ if (typeof item === "string") basicInfo[key] = item;
10980
+ }
10981
+ }
10982
+ const fields = Array.isArray(value.fields) ? value.fields.filter((item) => Boolean(item) && typeof item.fieldName === "string" && typeof item.value === "string").map((item) => ({ fieldName: item.fieldName, value: item.value })) : [];
10983
+ const metrics = value.metrics && typeof value.metrics === "object" ? value.metrics : {};
10984
+ return {
10985
+ v: DETAIL_CACHE_ENTRY_VERSION,
10986
+ basicInfo,
10987
+ fields,
10988
+ metrics,
10989
+ excludeTag: value.excludeTag,
10990
+ cachedAt: value.cachedAt
10991
+ };
10992
+ }
10993
+ async function openDetailCache(ctx) {
10994
+ const roots = cacheRoots(ctx);
10995
+ const stored = await readCacheFile(roots, DETAIL_CACHE_FILE_NAME);
10996
+ const now = Date.now();
10997
+ const entries = /* @__PURE__ */ new Map();
10998
+ let prunedAt = 0;
10999
+ let loaded = 0;
11000
+ let pruned = 0;
11001
+ if (stored) {
11002
+ try {
11003
+ const parsed = JSON.parse(stored.text);
11004
+ prunedAt = typeof parsed.prunedAt === "number" ? parsed.prunedAt : 0;
11005
+ for (const [key, raw] of Object.entries(parsed.entries ?? {})) {
11006
+ const entry = normalizeEntry(raw);
11007
+ if (!entry) continue;
11008
+ if (now - entry.cachedAt > DETAIL_CACHE_TTL_MS) {
11009
+ pruned += 1;
11010
+ continue;
11011
+ }
11012
+ entries.set(key, entry);
11013
+ loaded += 1;
11014
+ }
11015
+ } catch {
11016
+ }
11017
+ }
11018
+ const cache = {
11019
+ file: stored?.file ?? null,
11020
+ pruned: 0,
11021
+ loaded,
11022
+ get(requestId, lastFeedBackDateTime) {
11023
+ const entry = entries.get(detailCacheKey(requestId, lastFeedBackDateTime));
11024
+ if (!entry) return null;
11025
+ if (Date.now() - entry.cachedAt > DETAIL_CACHE_TTL_MS) return null;
11026
+ return entry;
11027
+ },
11028
+ has(requestId, lastFeedBackDateTime) {
11029
+ return cache.get(requestId, lastFeedBackDateTime) !== null;
11030
+ },
11031
+ set(requestId, lastFeedBackDateTime, entry) {
11032
+ if (!requestId) return false;
11033
+ entries.set(detailCacheKey(requestId, lastFeedBackDateTime), { ...entry, cachedAt: Date.now() });
11034
+ return true;
11035
+ },
11036
+ async save() {
11037
+ const shouldPrune = pruned > 0 && Date.now() - prunedAt > DETAIL_CACHE_PRUNE_INTERVAL_MS;
11038
+ const payload = {
11039
+ prunedAt: shouldPrune ? Date.now() : prunedAt,
11040
+ entries: Object.fromEntries(entries)
11041
+ };
11042
+ const file = await writeCacheFile(roots, DETAIL_CACHE_FILE_NAME, JSON.stringify(payload));
11043
+ if (file) cache.file = file;
11044
+ if (shouldPrune) cache.pruned = pruned;
11045
+ return file;
11046
+ }
11047
+ };
11048
+ return cache;
11049
+ }
11050
+
11016
11051
  // src/shortcuts/workflow/operations/todoSmartConvert/detailFieldRules.ts
11017
11052
  function normalizeDetailFieldName(raw) {
11018
11053
  return String(raw ?? "").replace(/<[^>]*>/g, " ").replace(/[【】[\]()()]/g, "").replace(/\s+/g, "").trim();
@@ -11230,7 +11265,8 @@ function renderGroupSummaryTemplate(input) {
11230
11265
  var DETAIL_BATCH_CONCURRENCY = 10;
11231
11266
  var DETAIL_BATCH_TIMEOUT_MS = 1e4;
11232
11267
  var DETAIL_BATCH_RETRIES = 1;
11233
- var DETAIL_BATCH_FIELD_LIMIT = 12;
11268
+ var DETAIL_MATERIAL_FIELD_LIMIT = 200;
11269
+ var DETAIL_MATERIAL_VALUE_LIMIT = 500;
11234
11270
  var HTML_ENTITIES = {
11235
11271
  amp: "&",
11236
11272
  lt: "<",
@@ -11319,6 +11355,9 @@ async function fetchOneDetail(env, requestId, userId, options) {
11319
11355
  const normalized = normalizeDetailResponse(response);
11320
11356
  const base = normalized?.basicInfo ?? {};
11321
11357
  const rawFields = Array.isArray(normalized?.formData?.fields) ? normalized.formData.fields : [];
11358
+ const basicInfo = Object.fromEntries(
11359
+ Object.entries(base).filter(([key]) => key !== "requestTitle" && key !== "flowName")
11360
+ );
11322
11361
  const usableFields = dropDistributionDetailFields(rawFields);
11323
11362
  const internalMessage = isInternalMessageDetail(
11324
11363
  base.workflowName,
@@ -11328,25 +11367,19 @@ async function fetchOneDetail(env, requestId, userId, options) {
11328
11367
  ...field,
11329
11368
  value: cleanFieldText(String(field?.value ?? ""))
11330
11369
  }));
11331
- const picked = internalMessage ? pickInternalMessageFieldPairs(cleanedFields, { creatorName: base.creatorName, createdAt: base.createdAt }) : selectSummaryFields(cleanedFields, options.fieldLimit ?? DETAIL_BATCH_FIELD_LIMIT, void 0, { fullValue: true });
11332
- const summaryFields = picked.map((field) => ({
11370
+ const excludeFields = excludeFieldsFor(base.workflowName);
11371
+ const excludeSet = new Set(excludeFields.map((name) => normalizeDetailFieldName(name)));
11372
+ const picked = (internalMessage ? pickInternalMessageFieldPairs(cleanedFields, base) : cleanedFields.filter((field) => !excludeSet.has(normalizeDetailFieldName(field?.fieldName)))).slice(0, DETAIL_MATERIAL_FIELD_LIMIT).map((field) => ({
11333
11373
  fieldName: String(field?.fieldName ?? "").trim(),
11334
- value: String(field?.value ?? "")
11374
+ value: String(field?.value ?? "").slice(0, DETAIL_MATERIAL_VALUE_LIMIT)
11335
11375
  })).filter((field) => field.fieldName && field.value);
11336
11376
  const metrics = extractRowMetrics(usableFields);
11337
11377
  return {
11338
11378
  requestId,
11339
- basicInfo: {
11340
- requestTitle: String(base.requestTitle ?? ""),
11341
- workflowName: String(base.workflowName ?? ""),
11342
- creatorName: String(base.creatorName ?? ""),
11343
- createdAt: String(base.createdAt ?? ""),
11344
- currentNode: String(base.currentNode ?? ""),
11345
- requestLevel: String(base.requestLevel ?? ""),
11346
- flowStatus: String(base.flowStatus ?? "")
11347
- },
11348
- summaryFields,
11349
- contextAvailable: summaryFields.length > 0,
11379
+ basicInfo,
11380
+ formFields: picked,
11381
+ contextAvailable: picked.length > 0,
11382
+ excludeTag: excludeTagOf(excludeFields),
11350
11383
  metrics
11351
11384
  };
11352
11385
  }
@@ -11398,17 +11431,10 @@ async function fetchRequestDetailsBatch(env, requestIds, options = {}) {
11398
11431
  failures.push({ requestId, error: reason });
11399
11432
  details.set(requestId, {
11400
11433
  requestId,
11401
- basicInfo: {
11402
- requestTitle: "",
11403
- workflowName: "",
11404
- creatorName: "",
11405
- createdAt: "",
11406
- currentNode: "",
11407
- requestLevel: "",
11408
- flowStatus: ""
11409
- },
11410
- summaryFields: [],
11434
+ basicInfo: {},
11435
+ formFields: [],
11411
11436
  contextAvailable: false,
11437
+ excludeTag: "",
11412
11438
  metrics: {},
11413
11439
  error: reason
11414
11440
  });
@@ -11431,90 +11457,11 @@ async function fetchRequestDetailsBatch(env, requestIds, options = {}) {
11431
11457
  };
11432
11458
  }
11433
11459
 
11434
- // src/shortcuts/workflow/operations/todoSmartConvert/todoDetailCache.ts
11435
- var DETAIL_CACHE_FILE_NAME = "todo-detail-cache.json";
11436
- var DETAIL_CACHE_TTL_MS = SUMMARY_CACHE_TTL_MS;
11437
- var DETAIL_CACHE_PRUNE_INTERVAL_MS = SUMMARY_CACHE_PRUNE_INTERVAL_MS;
11438
- function detailCacheKey(requestId, lastFeedBackDateTime) {
11439
- const stamp = String(lastFeedBackDateTime ?? "").trim();
11440
- return `${requestId}__${stamp}`;
11441
- }
11442
- function normalizeEntry(raw) {
11443
- if (!raw || typeof raw !== "object") return null;
11444
- const value = raw;
11445
- if (typeof value.cachedAt !== "number" || !Number.isFinite(value.cachedAt)) return null;
11446
- if (typeof value.context !== "string") return null;
11447
- const fields = Array.isArray(value.fields) ? value.fields.filter((item) => Boolean(item) && typeof item.fieldName === "string" && typeof item.value === "string").map((item) => ({ fieldName: item.fieldName, value: item.value })) : [];
11448
- const metrics = value.metrics && typeof value.metrics === "object" ? value.metrics : {};
11449
- return {
11450
- context: value.context,
11451
- contextAvailable: value.contextAvailable === true,
11452
- metrics,
11453
- fields,
11454
- cachedAt: value.cachedAt
11455
- };
11456
- }
11457
- async function openDetailCache(ctx) {
11458
- const roots = cacheRoots(ctx);
11459
- const stored = await readCacheFile(roots, DETAIL_CACHE_FILE_NAME);
11460
- const now = Date.now();
11461
- const entries = /* @__PURE__ */ new Map();
11462
- let prunedAt = 0;
11463
- let loaded = 0;
11464
- let pruned = 0;
11465
- if (stored) {
11466
- try {
11467
- const parsed = JSON.parse(stored.text);
11468
- prunedAt = typeof parsed.prunedAt === "number" ? parsed.prunedAt : 0;
11469
- for (const [key, raw] of Object.entries(parsed.entries ?? {})) {
11470
- const entry = normalizeEntry(raw);
11471
- if (!entry) continue;
11472
- if (now - entry.cachedAt > DETAIL_CACHE_TTL_MS) {
11473
- pruned += 1;
11474
- continue;
11475
- }
11476
- entries.set(key, entry);
11477
- loaded += 1;
11478
- }
11479
- } catch {
11480
- }
11481
- }
11482
- const cache = {
11483
- file: stored?.file ?? null,
11484
- pruned: 0,
11485
- loaded,
11486
- get(requestId, lastFeedBackDateTime) {
11487
- const entry = entries.get(detailCacheKey(requestId, lastFeedBackDateTime));
11488
- if (!entry) return null;
11489
- if (Date.now() - entry.cachedAt > DETAIL_CACHE_TTL_MS) return null;
11490
- return entry;
11491
- },
11492
- has(requestId, lastFeedBackDateTime) {
11493
- return cache.get(requestId, lastFeedBackDateTime) !== null;
11494
- },
11495
- set(requestId, lastFeedBackDateTime, entry) {
11496
- if (!requestId) return false;
11497
- entries.set(detailCacheKey(requestId, lastFeedBackDateTime), { ...entry, cachedAt: Date.now() });
11498
- return true;
11499
- },
11500
- async save() {
11501
- const shouldPrune = pruned > 0 && Date.now() - prunedAt > DETAIL_CACHE_PRUNE_INTERVAL_MS;
11502
- const payload = {
11503
- prunedAt: shouldPrune ? Date.now() : prunedAt,
11504
- entries: Object.fromEntries(entries)
11505
- };
11506
- const file = await writeCacheFile(roots, DETAIL_CACHE_FILE_NAME, JSON.stringify(payload));
11507
- if (file) cache.file = file;
11508
- if (shouldPrune) cache.pruned = pruned;
11509
- return file;
11510
- }
11511
- };
11512
- return cache;
11513
- }
11514
-
11515
11460
  // src/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.detail.ts
11516
11461
  function contextOfDetail(detail) {
11517
- return detail.summaryFields.map((field) => `${field.fieldName}\uFF1A${field.value}`).join("\uFF1B");
11462
+ const basicLines = Object.entries(detail.basicInfo ?? {}).filter(([, value]) => String(value ?? "").trim() !== "").map(([key, value]) => `${key}:${String(value).trim()}`);
11463
+ const fieldLines = (detail.formFields ?? []).map((field) => `${field.fieldName}:${field.value}`);
11464
+ return [...basicLines, ...fieldLines].join("\n");
11518
11465
  }
11519
11466
  var EMPTY_DETAIL_STATS = {
11520
11467
  requested: 0,
@@ -11526,8 +11473,6 @@ var EMPTY_DETAIL_STATS = {
11526
11473
  concurrency: 0,
11527
11474
  durationMs: 0
11528
11475
  };
11529
- var DETAIL_MATERIAL_FIELD_LIMIT = 8;
11530
- var DETAIL_MATERIAL_VALUE_LIMIT = 80;
11531
11476
  function stampsOfRows(rows) {
11532
11477
  const stamps = /* @__PURE__ */ new Map();
11533
11478
  for (const row of rows) {
@@ -11540,7 +11485,7 @@ function stampsOfRows(rows) {
11540
11485
  return stamps;
11541
11486
  }
11542
11487
  function materialFieldsOf(detail) {
11543
- return detail.summaryFields.filter((field) => field.value.length <= 200).slice(0, DETAIL_MATERIAL_FIELD_LIMIT).map((field) => ({ fieldName: field.fieldName, value: field.value.slice(0, DETAIL_MATERIAL_VALUE_LIMIT) }));
11488
+ return detail.formFields.map((field) => ({ fieldName: field.fieldName, value: field.value }));
11544
11489
  }
11545
11490
  async function fetchDetailFacts(env, requestIds, args, stamps) {
11546
11491
  const unique = [...new Set(requestIds.filter(Boolean))];
@@ -11554,13 +11499,13 @@ async function fetchDetailFacts(env, requestIds, args, stamps) {
11554
11499
  const missing = [];
11555
11500
  for (const requestId of unique) {
11556
11501
  const hit = cache.get(requestId, stamps?.get(requestId));
11557
- if (!hit) {
11502
+ if (!hit || hit.excludeTag !== excludeTagFor(hit.basicInfo.workflowName ?? "")) {
11558
11503
  missing.push(requestId);
11559
11504
  continue;
11560
11505
  }
11561
11506
  facts.set(requestId, {
11562
- context: hit.context,
11563
- contextAvailable: hit.contextAvailable,
11507
+ context: contextOfDetail({ basicInfo: hit.basicInfo, formFields: hit.fields }),
11508
+ contextAvailable: hit.fields.length > 0,
11564
11509
  metrics: hit.metrics,
11565
11510
  fields: hit.fields
11566
11511
  });
@@ -11578,7 +11523,7 @@ async function fetchDetailFacts(env, requestIds, args, stamps) {
11578
11523
  for (const [requestId, detail] of details) {
11579
11524
  const fact = {
11580
11525
  context: contextOfDetail(detail),
11581
- contextAvailable: detail.summaryFields.length > 0,
11526
+ contextAvailable: detail.formFields.length > 0,
11582
11527
  metrics: detail.metrics ?? {},
11583
11528
  fields: materialFieldsOf(detail)
11584
11529
  };
@@ -11587,10 +11532,11 @@ async function fetchDetailFacts(env, requestIds, args, stamps) {
11587
11532
  if (fact.contextAvailable) stats.contextAvailable += 1;
11588
11533
  else stats.contextEmpty += 1;
11589
11534
  if (cache.set(requestId, stamps?.get(requestId), {
11590
- context: fact.context,
11591
- contextAvailable: fact.contextAvailable,
11535
+ v: DETAIL_CACHE_ENTRY_VERSION,
11536
+ basicInfo: detail.basicInfo,
11592
11537
  metrics: fact.metrics,
11593
- fields: fact.fields
11538
+ fields: fact.fields,
11539
+ excludeTag: detail.excludeTag
11594
11540
  })) written += 1;
11595
11541
  }
11596
11542
  } catch (error) {
@@ -12071,16 +12017,32 @@ async function collectRawTodos(args, env) {
12071
12017
  });
12072
12018
  wfIdGroup = grouped.wfIdGroup ?? [];
12073
12019
  const summaryCache = await openSummaryCache(env.ctx);
12074
- const collectSummaryMaxChars = readBoundedInt(
12075
- args.summaryMaxChars,
12076
- "summaryMaxChars",
12077
- DEFAULT_REQUEST_SUMMARY_MAX,
12078
- 10,
12079
- 500
12080
- );
12020
+ const collectMaxCharsByGroup = /* @__PURE__ */ new Map();
12021
+ const collectMaxCharsFor = (workflowName) => {
12022
+ const key = workflowName ?? "";
12023
+ const hit = collectMaxCharsByGroup.get(key);
12024
+ if (hit !== void 0) return hit;
12025
+ const value = readBoundedInt(
12026
+ args.summaryMaxChars ?? activeRuleFor(key)?.summaryMaxChars,
12027
+ "summaryMaxChars",
12028
+ DEFAULT_REQUEST_SUMMARY_MAX,
12029
+ 10,
12030
+ 500
12031
+ );
12032
+ collectMaxCharsByGroup.set(key, value);
12033
+ return value;
12034
+ };
12081
12035
  const cachedSummaryIds = /* @__PURE__ */ new Set();
12036
+ const detailCacheForTag = await openDetailCache(env.ctx);
12082
12037
  for (const row of items) {
12083
- const cached = summaryCache.get(row.requestId, row.lastFeedBackDateTime, collectSummaryMaxChars);
12038
+ const detailEntry = detailCacheForTag.get(row.requestId, row.lastFeedBackDateTime);
12039
+ const cached = summaryCache.get(
12040
+ row.requestId,
12041
+ row.lastFeedBackDateTime,
12042
+ collectMaxCharsFor(row.workflowName),
12043
+ promptTagOf(activeRuleFor(row.workflowName ?? "")?.requestSummaryPrompt ?? ""),
12044
+ detailEntry ? detailMaterialTagOf(detailEntry) : void 0
12045
+ );
12084
12046
  if (!cached) continue;
12085
12047
  row.summary = cached;
12086
12048
  cachedSummaryIds.add(row.requestId);
@@ -12157,7 +12119,7 @@ async function collectRawTodos(args, env) {
12157
12119
  }
12158
12120
  if (!summaryCache.inSkillDir) {
12159
12121
  warnings.push(
12160
- "\u6CA1\u6709\u627E\u5230\u672C\u673A Agent \u7684 weaver-e10-workflow skill \u76EE\u5F55\uFF0C\u6458\u8981\u7F13\u5B58\u5DF2\u9000\u56DE CLI \u72B6\u6001\u76EE\u5F55\uFF1B\u5982\u9700\u7F13\u5B58\u843D\u5728 skill \u76EE\u5F55\uFF0C\u53EF\u7528 WEAVER_WORK_CLI_SKILL_DIR \u6307\u5B9A"
12122
+ "\u65E0\u5F53\u524D skill \u4E0A\u4E0B\u6587\uFF08WEAVER_WORK_CLI_SKILL_DIR \u672A\u8BBE\u7F6E\uFF09\uFF1A\u6458\u8981\u7F13\u5B58\u4E0E aigroup \u89C4\u5219\u5747\u672A\u8BFB\u5199\uFF0C\u672C\u6B21\u6309\u300C\u4ECE\u672A\u751F\u6210\u8FC7\u300D\u8D70\u5B9E\u65F6\u903B\u8F91\uFF1B\u8BF7\u7ECF skill \u7684 tools \u811A\u672C\u8C03\u7528"
12161
12123
  );
12162
12124
  }
12163
12125
  }
@@ -12444,12 +12406,23 @@ async function runSmartGroup(args, env, options = {}) {
12444
12406
  );
12445
12407
  const skipDetail = args.withDetailContext === false;
12446
12408
  const summaryCache = await openSummaryCache(env.ctx);
12409
+ const detailCacheForTag = skipDetail ? null : await openDetailCache(env.ctx);
12410
+ const materialTagOfRow = (requestId, stamp) => {
12411
+ const entry = detailCacheForTag?.get(requestId, stamp);
12412
+ return entry ? detailMaterialTagOf(entry) : void 0;
12413
+ };
12447
12414
  const cachedIds = /* @__PURE__ */ new Set();
12448
12415
  const allRows = [];
12449
12416
  for (const group of groups) {
12450
12417
  for (const row of group.requestDatas ?? []) {
12451
12418
  allRows.push(row);
12452
- if (summaryCache.get(row.requestId, row.lastFeedBackDateTime, summaryMaxChars)) cachedIds.add(row.requestId);
12419
+ if (summaryCache.get(
12420
+ row.requestId,
12421
+ row.lastFeedBackDateTime,
12422
+ summaryMaxChars,
12423
+ promptTagOf(activeRuleFor(group.title)?.requestSummaryPrompt ?? ""),
12424
+ materialTagOfRow(row.requestId, row.lastFeedBackDateTime)
12425
+ )) cachedIds.add(row.requestId);
12453
12426
  }
12454
12427
  }
12455
12428
  const detailIds = [...new Set(allRows.map((row) => row.requestId).filter(Boolean))];
@@ -12699,6 +12672,21 @@ async function runSmartGroup(args, env, options = {}) {
12699
12672
  function needAiSummary(workflowName) {
12700
12673
  return activeRuleFor(workflowName)?.needSummary ?? true;
12701
12674
  }
12675
+ function requestMaxCharsFor(args, workflowName) {
12676
+ return readBoundedInt(
12677
+ args.summaryMaxChars ?? activeRuleFor(workflowName)?.summaryMaxChars,
12678
+ "summaryMaxChars",
12679
+ DEFAULT_REQUEST_SUMMARY_MAX3,
12680
+ 10,
12681
+ 500
12682
+ );
12683
+ }
12684
+ function requestPromptFor(workflowName) {
12685
+ return (activeRuleFor(workflowName)?.requestSummaryPrompt ?? "").trim();
12686
+ }
12687
+ function distinctBatchMaxChars(batches) {
12688
+ return [...new Set(batches.map((batch) => batch.suggestedMaxChars))].sort((left, right) => left - right);
12689
+ }
12702
12690
  var DEFAULT_MAX_CHARS_PER_BATCH = 24e3;
12703
12691
  var DEFAULT_MAX_ITEMS_PER_BATCH = 100;
12704
12692
  var DEFAULT_REQUEST_SUMMARY_MAX3 = 50;
@@ -12869,20 +12857,35 @@ async function runSummaryContext(args, env, prefetched) {
12869
12857
  const units = collectSummaryUnits(groups);
12870
12858
  const skippedSatisfaction = groups.filter((group) => !needAiSummary(group.title)).reduce((sum, group) => sum + rowsOfGroup(group).length, 0);
12871
12859
  const requestIds = [...new Set(units.flatMap((unit) => unit.rows.map((row) => row.requestId)))].filter(Boolean);
12872
- const summaryMaxChars = readBoundedInt(
12873
- args.summaryMaxChars,
12874
- "summaryMaxChars",
12875
- DEFAULT_REQUEST_SUMMARY_MAX3,
12876
- 10,
12877
- 500
12878
- );
12879
12860
  const summaryCache = await openSummaryCache(env.ctx);
12861
+ const detailCacheForTag = await openDetailCache(env.ctx);
12862
+ const materialTagOfRow = (requestId, stamp) => {
12863
+ const entry = detailCacheForTag.get(requestId, stamp);
12864
+ return entry ? detailMaterialTagOf(entry) : void 0;
12865
+ };
12880
12866
  let prefilled = 0;
12881
12867
  const prefilledIds = /* @__PURE__ */ new Set();
12882
12868
  const needsDetail = [];
12869
+ const workflowTitleByRequest = /* @__PURE__ */ new Map();
12883
12870
  for (const unit of units) {
12871
+ if (unit.groupId === "priority") continue;
12884
12872
  for (const row of unit.rows) {
12885
- const cached = summaryCache.get(row.requestId, row.lastFeedBackDateTime, summaryMaxChars);
12873
+ if (row.requestId && !workflowTitleByRequest.has(row.requestId)) {
12874
+ workflowTitleByRequest.set(row.requestId, unit.groupTitle);
12875
+ }
12876
+ }
12877
+ }
12878
+ const ruleNameForRow = (unit, row) => unit.groupId === "priority" ? workflowTitleByRequest.get(row.requestId ?? "") ?? unit.groupTitle : unit.groupTitle;
12879
+ for (const unit of units) {
12880
+ for (const row of unit.rows) {
12881
+ const name = ruleNameForRow(unit, row);
12882
+ const cached = summaryCache.get(
12883
+ row.requestId,
12884
+ row.lastFeedBackDateTime,
12885
+ requestMaxCharsFor(args, name),
12886
+ promptTagOf(requestPromptFor(name)),
12887
+ materialTagOfRow(row.requestId, row.lastFeedBackDateTime)
12888
+ );
12886
12889
  if (cached) {
12887
12890
  row.summary = cached;
12888
12891
  prefilled += 1;
@@ -12901,13 +12904,17 @@ async function runSummaryContext(args, env, prefetched) {
12901
12904
  let contextEmpty = 0;
12902
12905
  let titleCopied = 0;
12903
12906
  const claimed = /* @__PURE__ */ new Set();
12904
- for (const unit of units) {
12907
+ const orderedUnits = [...units].sort(
12908
+ (a, b) => Number(a.groupId === "priority") - Number(b.groupId === "priority")
12909
+ );
12910
+ for (const unit of orderedUnits) {
12905
12911
  let bucket = [];
12906
12912
  let chars = 0;
12907
12913
  let seq = 0;
12908
12914
  const flush = () => {
12909
12915
  if (bucket.length === 0) return;
12910
12916
  seq += 1;
12917
+ const firstName = ruleNameForRow(unit, { requestId: bucket[0].requestId });
12911
12918
  batches.push({
12912
12919
  batchId: `${unit.subGroupId}#${seq}`,
12913
12920
  groupId: unit.groupId,
@@ -12918,7 +12925,8 @@ async function runSummaryContext(args, env, prefetched) {
12918
12925
  charCount: chars,
12919
12926
  kind: unit.kind,
12920
12927
  ...unit.kind === "internal-message" ? { hint: INTERNAL_MESSAGE_SUMMARY_HINT } : {},
12921
- suggestedMaxChars: summaryMaxChars,
12928
+ ...requestPromptFor(firstName) ? { prompt: requestPromptFor(firstName) } : {},
12929
+ suggestedMaxChars: requestMaxCharsFor(args, firstName),
12922
12930
  items: bucket
12923
12931
  });
12924
12932
  bucket = [];
@@ -12989,8 +12997,8 @@ async function runSummaryContext(args, env, prefetched) {
12989
12997
  titleCopied,
12990
12998
  /** 本地摘要命中、跳过 AI 的条数 */
12991
12999
  prefilled,
12992
- /** 单条摘要的目标字数(默认 50,可由 summaryMaxChars 覆盖) */
12993
- suggestedMaxChars: summaryMaxChars,
13000
+ /** 单条摘要的目标字数:口径一致时给数字,各组口径不同时给 distinct 列表 */
13001
+ ...distinctBatchMaxChars(batches).length === 1 ? { suggestedMaxChars: distinctBatchMaxChars(batches)[0] } : { suggestedMaxCharsList: distinctBatchMaxChars(batches) },
12994
13002
  /** 内部留言类批次:摘要要按「最低推理强度」写 */
12995
13003
  internalMessageBatches: batches.filter((batch) => batch.kind === "internal-message").length,
12996
13004
  skippedSatisfaction,
@@ -13054,16 +13062,30 @@ function readAiSummaries(value) {
13054
13062
  async function runSummary(args, env) {
13055
13063
  const groups = await readFinalGroups(args, env);
13056
13064
  const summaries = readAiSummaries(args.aiSummaries);
13057
- const summaryMaxChars = readBoundedInt(
13058
- args.summaryMaxChars,
13059
- "summaryMaxChars",
13060
- DEFAULT_REQUEST_SUMMARY_MAX3,
13061
- 10,
13062
- 500
13063
- );
13065
+ const maxCharsByGroup = /* @__PURE__ */ new Map();
13066
+ const maxCharsFor = (workflowName) => {
13067
+ const hit = maxCharsByGroup.get(workflowName);
13068
+ if (hit !== void 0) return hit;
13069
+ const value = requestMaxCharsFor(args, workflowName);
13070
+ maxCharsByGroup.set(workflowName, value);
13071
+ return value;
13072
+ };
13064
13073
  const summaryCache = await openSummaryCache(env.ctx);
13074
+ const detailCacheForTag = await openDetailCache(env.ctx);
13075
+ const materialTagOfRow = (requestId, stamp) => {
13076
+ const entry = detailCacheForTag.get(requestId, stamp);
13077
+ return entry ? detailMaterialTagOf(entry) : void 0;
13078
+ };
13065
13079
  let cacheWritten = 0;
13066
13080
  let titleSummary = 0;
13081
+ const wfTitleByRequest = /* @__PURE__ */ new Map();
13082
+ for (const group of groups) {
13083
+ if (group.topPriority) continue;
13084
+ for (const row of rowsOfGroup(group)) {
13085
+ if (row?.requestId && !wfTitleByRequest.has(row.requestId)) wfTitleByRequest.set(row.requestId, group.title);
13086
+ }
13087
+ }
13088
+ const ruleNameForGroup = (group, row) => group.topPriority ? wfTitleByRequest.get(row?.requestId ?? "") ?? group.title : group.title;
13067
13089
  for (const group of groups) {
13068
13090
  if (!needAiSummary(group.title)) {
13069
13091
  for (const row of rowsOfGroup(group)) {
@@ -13075,7 +13097,14 @@ async function runSummary(args, env) {
13075
13097
  }
13076
13098
  for (const row of rowsOfGroup(group)) {
13077
13099
  if (!row?.requestId || (row.summary ?? "").trim()) continue;
13078
- const cached = summaryCache.get(row.requestId, row.lastFeedBackDateTime, summaryMaxChars);
13100
+ const name = ruleNameForGroup(group, row);
13101
+ const cached = summaryCache.get(
13102
+ row.requestId,
13103
+ row.lastFeedBackDateTime,
13104
+ maxCharsFor(name),
13105
+ promptTagOf(requestPromptFor(name)),
13106
+ materialTagOfRow(row.requestId, row.lastFeedBackDateTime)
13107
+ );
13079
13108
  if (cached) {
13080
13109
  row.summary = cached;
13081
13110
  }
@@ -13103,7 +13132,7 @@ async function runSummary(args, env) {
13103
13132
  let titleKept = 0;
13104
13133
  let prefilledKept = 0;
13105
13134
  const countedIds = /* @__PURE__ */ new Set();
13106
- const applyAll = (rows) => {
13135
+ const applyAll = (rows, meta) => {
13107
13136
  for (const row of rows) {
13108
13137
  const summary = summaries.get(row.requestId) ?? "";
13109
13138
  const firstTime = !row.requestId || !countedIds.has(row.requestId);
@@ -13118,9 +13147,9 @@ async function runSummary(args, env) {
13118
13147
  if (summary) {
13119
13148
  if (firstTime) {
13120
13149
  filled += 1;
13121
- if (summary.length > summaryMaxChars) tooLong += 1;
13150
+ if (summary.length > meta(row).maxChars) tooLong += 1;
13122
13151
  }
13123
- if (summaryCache.set(row.requestId, row.lastFeedBackDateTime, summary, summaryMaxChars)) cacheWritten += 1;
13152
+ if (summaryCache.set(row.requestId, row.lastFeedBackDateTime, summary, meta(row).maxChars, meta(row).pk, materialTagOfRow(row.requestId, row.lastFeedBackDateTime))) cacheWritten += 1;
13124
13153
  } else if (firstTime) {
13125
13154
  empty += 1;
13126
13155
  }
@@ -13130,17 +13159,28 @@ async function runSummary(args, env) {
13130
13159
  for (const group of groups) {
13131
13160
  if (!needAiSummary(group.title)) continue;
13132
13161
  if (group.topPriority) {
13133
- applyAll(rowsOfGroup(group));
13162
+ applyAll(rowsOfGroup(group), (row) => {
13163
+ const name = ruleNameForGroup(group, row);
13164
+ return { maxChars: maxCharsFor(name), pk: promptTagOf(requestPromptFor(name)) };
13165
+ });
13134
13166
  continue;
13135
13167
  }
13136
13168
  for (const item of group.displayItems) {
13137
13169
  if (item.type === "group") {
13138
- applyAll(item.requestDatas);
13170
+ applyAll(item.requestDatas, (row) => {
13171
+ const name = ruleNameForGroup(group, row);
13172
+ return { maxChars: maxCharsFor(name), pk: promptTagOf(requestPromptFor(name)) };
13173
+ });
13139
13174
  continue;
13140
13175
  }
13141
- applyAll([item.requestData]);
13176
+ applyAll([item.requestData], (row) => {
13177
+ const name = ruleNameForGroup(group, row);
13178
+ return { maxChars: maxCharsFor(name), pk: promptTagOf(requestPromptFor(name)) };
13179
+ });
13142
13180
  }
13143
13181
  }
13182
+ const usedMaxChars = [...new Set(maxCharsByGroup.values())].sort((left, right) => left - right);
13183
+ const maxCharsHint = usedMaxChars.length > 0 ? usedMaxChars.join("/") : String(DEFAULT_REQUEST_SUMMARY_MAX3);
13144
13184
  if (empty > 0) {
13145
13185
  warnings.push(`\u6709 ${empty} \u6761\u6CA1\u6709\u62FF\u5230 AI \u6458\u8981\uFF0Csummary \u4FDD\u6301\u7A7A\u4E32\uFF08\u672A\u7528\u6807\u9898\u515C\u5E95\u3001\u672A\u7F16\u9020\uFF09`);
13146
13186
  }
@@ -13149,7 +13189,7 @@ async function runSummary(args, env) {
13149
13189
  }
13150
13190
  if (tooLong > 0) {
13151
13191
  warnings.push(
13152
- `\u6709 ${tooLong} \u6761\u6458\u8981\u8D85\u8FC7\u76EE\u6807\u957F\u5EA6 ${summaryMaxChars} \u5B57\uFF08\u53EF\u6309\u7528\u6237\u53E3\u5F84\u8C03\u6574\uFF09\uFF0C\u5DF2\u539F\u6837\u4FDD\u7559\uFF1B\u5982\u9700\u63A7\u5236\u957F\u5EA6\u8BF7\u91CD\u8DD1\u6A21\u578B\u4FA7\uFF08CLI \u4E0D\u6539\u5199\u6587\u6848\uFF09`
13192
+ `\u6709 ${tooLong} \u6761\u6458\u8981\u8D85\u8FC7\u76EE\u6807\u957F\u5EA6 ${maxCharsHint} \u5B57\uFF08\u53EF\u6309\u7528\u6237\u53E3\u5F84\u8C03\u6574\uFF09\uFF0C\u5DF2\u539F\u6837\u4FDD\u7559\uFF1B\u5982\u9700\u63A7\u5236\u957F\u5EA6\u8BF7\u91CD\u8DD1\u6A21\u578B\u4FA7\uFF08CLI \u4E0D\u6539\u5199\u6587\u6848\uFF09`
13153
13193
  );
13154
13194
  }
13155
13195
  if (prefilledKept > 0) {
@@ -13174,8 +13214,8 @@ async function runSummary(args, env) {
13174
13214
  meta: {
13175
13215
  summarized: filled,
13176
13216
  empty,
13177
- /** 单条摘要的目标字数(默认 50,可由 summaryMaxChars 覆盖) */
13178
- suggestedMaxChars: summaryMaxChars,
13217
+ /** 单条摘要的目标字数:各组口径一致时给数字,不一致时给 distinct 列表 */
13218
+ ...usedMaxChars.length === 1 ? { suggestedMaxChars: usedMaxChars[0] } : { suggestedMaxCharsList: usedMaxChars },
13179
13219
  titleCopied: titleKept,
13180
13220
  /** 本地摘要缓存命中、未重新生成的条数 */
13181
13221
  prefilled: prefilledKept,
@@ -13194,6 +13234,22 @@ async function runSummary(args, env) {
13194
13234
  var INTERNAL_MESSAGE_SUMMARY_HINT2 = "\u5185\u90E8\u7559\u8A00\uFF1A\u53EA\u6309\u539F\u6587\u76F4\u63A5\u6982\u62EC\u300C\u8C01\u8BF4\u4E86\u4EC0\u4E48\u300D\uFF0C\u4E0D\u8981\u8FC7\u5EA6\u89E3\u8BFB\u3001\u4E0D\u8981\u63A8\u6D4B\u52A8\u673A\u6216\u5F71\u54CD\uFF0C\u4E25\u683C\u6309\u672C\u6279 suggestedMaxChars \u63A7\u5236\u5B57\u6570";
13195
13235
  var GROUP_SUMMARY_TAIL = GROUP_SUMMARY_TAIL_TEXT;
13196
13236
  var DEFAULT_GROUP_SUMMARY_MAX = 100;
13237
+ function makeGroupMaxCharsResolver(args) {
13238
+ const cache = /* @__PURE__ */ new Map();
13239
+ return (workflowName) => {
13240
+ const hit = cache.get(workflowName);
13241
+ if (hit !== void 0) return hit;
13242
+ const value = readBoundedInt(
13243
+ args.groupSummaryMaxChars ?? activeRuleFor(workflowName)?.groupSummaryMaxChars,
13244
+ "groupSummaryMaxChars",
13245
+ DEFAULT_GROUP_SUMMARY_MAX,
13246
+ 20,
13247
+ 1e3
13248
+ );
13249
+ cache.set(workflowName, value);
13250
+ return value;
13251
+ };
13252
+ }
13197
13253
  var GROUP_AMOUNT_PATTERNS = [
13198
13254
  /[¥¥]\s*(\d[\d,]*(?:\.\d{1,2})?)/u,
13199
13255
  /(\d[\d,]*(?:\.\d{1,2})?)\s*元/u
@@ -13212,7 +13268,7 @@ function createrPhraseOf(creators) {
13212
13268
  if (creators.length <= 3) return `\u7531${creators.join("\u3001")} \u53D1\u8D77`;
13213
13269
  return `\u7531${creators.slice(0, 3).join("\u3001")} \u7B49 ${creators.length} \u4EBA\u53D1\u8D77`;
13214
13270
  }
13215
- function collectGroupSummaryBatches(groups, isCtxEmpty, maxChars = DEFAULT_GROUP_SUMMARY_MAX) {
13271
+ function collectGroupSummaryBatches(groups, isCtxEmpty, maxCharsFor = () => DEFAULT_GROUP_SUMMARY_MAX) {
13216
13272
  const batches = [];
13217
13273
  for (const group of groups) {
13218
13274
  if (group.topPriority) continue;
@@ -13241,6 +13297,7 @@ function collectGroupSummaryBatches(groups, isCtxEmpty, maxChars = DEFAULT_GROUP
13241
13297
  if (amount !== null) amounts.push(amount);
13242
13298
  }
13243
13299
  const amountReliable = items.length >= 2 && amounts.length === items.length;
13300
+ const groupPrompt = (activeRuleFor(group.title)?.aiGroup?.groupSummary?.prompt ?? "").trim();
13244
13301
  batches.push({
13245
13302
  groupId: sub.id,
13246
13303
  parentGroupId: group.id,
@@ -13250,7 +13307,8 @@ function collectGroupSummaryBatches(groups, isCtxEmpty, maxChars = DEFAULT_GROUP
13250
13307
  totalCount: allRows.length,
13251
13308
  kind,
13252
13309
  ...kind === "internal-message" ? { hint: INTERNAL_MESSAGE_SUMMARY_HINT2 } : {},
13253
- suggestedMaxChars: maxChars,
13310
+ ...groupPrompt ? { prompt: groupPrompt } : {},
13311
+ suggestedMaxChars: maxCharsFor(group.title),
13254
13312
  ...emptySkipped > 0 ? { emptySkipped } : {},
13255
13313
  items,
13256
13314
  stats: {
@@ -13295,14 +13353,9 @@ async function loadCtxEmptyPredicate(env, groups, args = {}) {
13295
13353
  async function runGroupSummaryContext(args, env) {
13296
13354
  const groups = await readFinalGroups(args, env);
13297
13355
  const { isCtxEmpty, warnings: emptyWarnings } = await loadCtxEmptyPredicate(env, groups, args);
13298
- const groupSummaryMaxChars = readBoundedInt(
13299
- args.groupSummaryMaxChars,
13300
- "groupSummaryMaxChars",
13301
- DEFAULT_GROUP_SUMMARY_MAX,
13302
- 20,
13303
- 1e3
13304
- );
13305
- const batches = collectGroupSummaryBatches(groups, isCtxEmpty, groupSummaryMaxChars);
13356
+ const groupMaxCharsFor = makeGroupMaxCharsResolver(args);
13357
+ const batches = collectGroupSummaryBatches(groups, isCtxEmpty, groupMaxCharsFor);
13358
+ const distinctChars = [...new Set(batches.map((batch) => batch.suggestedMaxChars))].sort((left, right) => left - right);
13306
13359
  const totalCount = totalTodoCount(groups);
13307
13360
  const warnings = [...emptyWarnings];
13308
13361
  const skippedEmpty = batches.reduce((sum, batch) => sum + (batch.emptySkipped ?? 0), 0);
@@ -13338,7 +13391,7 @@ async function runGroupSummaryContext(args, env) {
13338
13391
  /** CLI 固定文案的汇总项个数(不进批次,`smartGroup` 阶段已写好) */
13339
13392
  deterministicGroups,
13340
13393
  tail: GROUP_SUMMARY_TAIL,
13341
- suggestedMaxChars: groupSummaryMaxChars
13394
+ ...distinctChars.length === 1 ? { suggestedMaxChars: distinctChars[0] } : { suggestedMaxCharsList: distinctChars }
13342
13395
  }
13343
13396
  },
13344
13397
  warnings
@@ -13389,14 +13442,9 @@ async function runGroupSummary(args, env) {
13389
13442
  const groups = await readFinalGroups(args, env);
13390
13443
  const summaries = readAiGroupSummaries(args.aiGroupSummaries);
13391
13444
  const { isCtxEmpty, warnings: emptyWarnings } = await loadCtxEmptyPredicate(env, groups, args);
13392
- const groupSummaryMaxChars = readBoundedInt(
13393
- args.groupSummaryMaxChars,
13394
- "groupSummaryMaxChars",
13395
- DEFAULT_GROUP_SUMMARY_MAX,
13396
- 20,
13397
- 1e3
13398
- );
13399
- const batches = collectGroupSummaryBatches(groups, isCtxEmpty, groupSummaryMaxChars);
13445
+ const groupMaxCharsFor = makeGroupMaxCharsResolver(args);
13446
+ const batches = collectGroupSummaryBatches(groups, isCtxEmpty, groupMaxCharsFor);
13447
+ const distinctChars = [...new Set(batches.map((batch) => batch.suggestedMaxChars))].sort((left, right) => left - right);
13400
13448
  const knownGroupIds = new Set(batches.map((batch) => batch.groupId));
13401
13449
  for (const groupId of summaries.keys()) {
13402
13450
  if (!knownGroupIds.has(groupId)) {
@@ -13417,6 +13465,7 @@ async function runGroupSummary(args, env) {
13417
13465
  for (const group of groups) {
13418
13466
  if (group.topPriority) continue;
13419
13467
  const kind = detectBusinessKind(group.title);
13468
+ const groupMaxChars = groupMaxCharsFor(group.title);
13420
13469
  for (const sub of groupItemsOf(group)) {
13421
13470
  if (isDeterministicGroupKind(kind)) {
13422
13471
  if ((sub.summary ?? "").trim() === "") {
@@ -13428,7 +13477,7 @@ async function runGroupSummary(args, env) {
13428
13477
  }
13429
13478
  filled += 1;
13430
13479
  summarizedGroupCount += 1;
13431
- if (summary2.length > groupSummaryMaxChars) tooLong += 1;
13480
+ if (summary2.length > groupMaxChars) tooLong += 1;
13432
13481
  const batch2 = batches.find((item) => item.groupId === sub.id);
13433
13482
  if (batch2 && batch2.stats.createrPhrase && !summary2.includes(batch2.stats.createrPhrase)) {
13434
13483
  missingCreater += 1;
@@ -13447,7 +13496,7 @@ async function runGroupSummary(args, env) {
13447
13496
  }
13448
13497
  filled += 1;
13449
13498
  summarizedGroupCount += 1;
13450
- if (summary.length > groupSummaryMaxChars) tooLong += 1;
13499
+ if (summary.length > groupMaxChars) tooLong += 1;
13451
13500
  const batch = batches.find((item) => item.groupId === sub.id);
13452
13501
  if (batch && batch.stats.createrPhrase && !summary.includes(batch.stats.createrPhrase)) {
13453
13502
  missingCreater += 1;
@@ -13456,7 +13505,7 @@ async function runGroupSummary(args, env) {
13456
13505
  }
13457
13506
  if (empty > 0) warnings.push(`\u6709 ${empty} \u4E2A\u6C47\u603B\u9879\u6CA1\u6709\u62FF\u5230\u7EC4\u6458\u8981\uFF0Csummary \u4FDD\u6301\u7A7A\u4E32\uFF08\u672A\u7F16\u9020\uFF09`);
13458
13507
  if (tooLong > 0) {
13459
- warnings.push(`\u6709 ${tooLong} \u4E2A\u7EC4\u6458\u8981\u8D85\u8FC7\u5EFA\u8BAE\u7684 ${groupSummaryMaxChars} \u5B57\uFF0C\u5DF2\u539F\u6837\u4FDD\u7559\uFF08CLI \u4E0D\u6539\u5199\u6587\u6848\uFF09`);
13508
+ warnings.push(`\u6709 ${tooLong} \u4E2A\u7EC4\u6458\u8981\u8D85\u8FC7\u5EFA\u8BAE\u7684 ${distinctChars.length > 0 ? distinctChars.join("/") : DEFAULT_GROUP_SUMMARY_MAX} \u5B57\uFF0C\u5DF2\u539F\u6837\u4FDD\u7559\uFF08CLI \u4E0D\u6539\u5199\u6587\u6848\uFF09`);
13460
13509
  }
13461
13510
  if (missingCreater > 0) {
13462
13511
  warnings.push(
@@ -13560,8 +13609,10 @@ var inputSchema = schemaOf({
13560
13609
  groupFocus: { type: "string" },
13561
13610
  maxCharsPerBatch: { type: "integer", minimum: 500, maximum: 2e5, default: 24e3 },
13562
13611
  maxItemsPerBatch: { type: "integer", minimum: 1, maximum: 500, default: 100 },
13563
- summaryMaxChars: { type: "integer", minimum: 10, maximum: 500, default: 50 },
13564
- groupSummaryMaxChars: { type: "integer", minimum: 20, maximum: 1e3, default: 100 },
13612
+ // 字数口径不设 schema 默认:默认值来自 aigroup 规则(default.json 的 defaults),
13613
+ // 入参只在用户当轮明确给口径时覆盖规则(2026-10-30 用户要求「摘要规则必须从 JSON 取」)。
13614
+ summaryMaxChars: { type: "integer", minimum: 10, maximum: 500 },
13615
+ groupSummaryMaxChars: { type: "integer", minimum: 20, maximum: 1e3 },
13565
13616
  detailConcurrency: { type: "integer", minimum: 1, maximum: 32, default: 10 },
13566
13617
  detailTimeoutMs: { type: "integer", minimum: 1e3, maximum: 6e4, default: 1e4 },
13567
13618
  skillTiming: { type: "object" },