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
@@ -6,6 +6,9 @@ import { workflowManifest } from './manifest.js';
6
6
  import { executeWorkflowOperation } from './operations.js';
7
7
  import { workflowValidationError } from './errors.js';
8
8
  import { compactStdoutPaths } from './stdout-compact.js';
9
+ import { join } from 'node:path';
10
+ import { loadRules, resetActiveRules } from './operations/todoSmartConvert/aigroupRules.js';
11
+ import { clearUserIntents, readRawUserIntents, readUserIntents, saveUserIntents, } from './operations/todoSmartConvert/aigroupStore.js';
9
12
  function asOptions(value) {
10
13
  return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
11
14
  }
@@ -114,6 +117,53 @@ async function executeAndPrint(ctx, operation, input) {
114
117
  process.exitCode = isCliError(error) ? error.exitCode : ExitCode.GeneralError;
115
118
  }
116
119
  }
120
+ /**
121
+ * 目录里的 `fields` 只取 `inputSchema.properties` 的键名,供 agent 判断「这个字段存不存在」。
122
+ *
123
+ * ★ 2026-10-28:整份 manifest 实测 65,748 B,超过 stdout 预算(`DEFAULT_RESULT_THRESHOLD_BYTES`
124
+ * = 24 KB)后,公共输出层按 `COMPACT_TIERS` 第一档把 `operations` 截到 10 条 —— 26 个 operation 里
125
+ * 排在后面的(`createRequest` 之后,含 `workflow.todoSmartConvert`)在 stdout 上完全不可见,
126
+ * 且没有任何「还有 16 条」的提示。此处改为默认编目形态(约 15 KB,26 条全可见),
127
+ * 完整 inputSchema 用 `--operation` 单取,整份完整 manifest 用 `--full`。
128
+ */
129
+ function fieldNamesOf(inputSchema) {
130
+ const properties = inputSchema.properties;
131
+ if (!properties || typeof properties !== 'object' || Array.isArray(properties))
132
+ return [];
133
+ return Object.keys(properties);
134
+ }
135
+ function manifestIndex() {
136
+ return {
137
+ schemaVersion: workflowManifest.schemaVersion,
138
+ name: workflowManifest.name,
139
+ title: workflowManifest.title,
140
+ version: workflowManifest.version,
141
+ host: workflowManifest.host,
142
+ status: workflowManifest.status,
143
+ sourceSkill: workflowManifest.sourceSkill,
144
+ capabilities: workflowManifest.capabilities,
145
+ operationCount: workflowManifest.operations.length,
146
+ operations: workflowManifest.operations.map((definition) => ({
147
+ name: definition.name,
148
+ resource: definition.resource,
149
+ summary: definition.summary,
150
+ ...(definition.capability ? { capability: definition.capability } : {}),
151
+ risk: definition.risk,
152
+ ...(definition.requiresConfirmation ? { requiresConfirmation: true } : {}),
153
+ fields: fieldNamesOf(definition.inputSchema),
154
+ })),
155
+ withheldOperations: workflowManifest.withheldOperations,
156
+ operationsHint: '默认只列 operation 与字段名;字段类型、枚举和填写口径用 `workflow schema --operation <name>` 单取,整份完整 manifest 用 `workflow schema --full`。',
157
+ };
158
+ }
159
+ function findOperationContract(name) {
160
+ const full = name.startsWith('workflow.') ? name : `workflow.${name}`;
161
+ const matched = workflowManifest.operations.find((definition) => definition.name === full);
162
+ if (!matched) {
163
+ throw workflowValidationError('operation_unknown', `流程模块不支持操作:${name}`);
164
+ }
165
+ return matched;
166
+ }
117
167
  function withJsonInputOptions(command) {
118
168
  command
119
169
  .option('--input <path>', 'JSON input file, or - for stdin')
@@ -130,8 +180,67 @@ export const workflowShortcut = {
130
180
  .description('泛微E10流程智能助手(待办/已办/我发起/全部、详情、操作、批量、发起、修改)');
131
181
  workflow.command('schema')
132
182
  .description('Print workflow operation manifest for agents')
183
+ .option('--operation <name>', 'print one operation with its full inputSchema')
184
+ .option('--full', 'print the whole manifest (about 65 KB; stdout may be trimmed)')
185
+ .action(action((ctx, options) => {
186
+ const opts = asOptions(options);
187
+ const requested = String(opts.operation ?? '').trim();
188
+ if (requested && opts.full === true) {
189
+ throw workflowValidationError('option_conflict', '不能同时传 --operation 和 --full');
190
+ }
191
+ if (opts.full === true) {
192
+ ctx.output.write(workflowManifest, { json: true });
193
+ return;
194
+ }
195
+ if (requested) {
196
+ ctx.output.write(findOperationContract(requested), { json: true });
197
+ return;
198
+ }
199
+ ctx.output.write(manifestIndex(), { json: true });
200
+ }));
201
+ /**
202
+ * ai二次分组规则库:`<skill>/aigroup/default.json`(系统只读)+ CLI 状态目录下的
203
+ * `aigroup/user-intents.json`(用户意图,不随 skill 分发)。
204
+ * 意图由模型理解、但**落盘必须结构化**:这里统一做校验 + 按 workflowName 整条覆盖。
205
+ */
206
+ const aigroup = workflow
207
+ .command('aigroup')
208
+ .description('ai二次分组规则库(默认规则 + 用户意图)');
209
+ aigroup.command('show')
210
+ .description('Print effective ai-group rules (default merged with user intents)')
211
+ .option('--raw', 'also print user-intents.json as stored on disk')
212
+ .action(action((ctx, options) => {
213
+ const opts = asOptions(options);
214
+ const loaded = loadRules({ ctx: ctx });
215
+ const user = readUserIntents({ ctx: ctx });
216
+ ctx.output.write({
217
+ dir: loaded.dir,
218
+ defaultFile: join(loaded.dir, 'default.json'),
219
+ userIntentFile: user.file,
220
+ userIntentExists: user.exists,
221
+ userIntentError: user.error,
222
+ defaults: loaded.file.defaults,
223
+ rules: loaded.file.rules,
224
+ userRules: user.rules,
225
+ warnings: loaded.warnings,
226
+ ...(opts.raw === true && user.exists ? { rawUserIntents: readRawUserIntents(user.file) } : {}),
227
+ }, { json: true });
228
+ }));
229
+ withJsonInputOptions(aigroup.command('set')
230
+ .description('Save user-intent rules: validated, whole-entry replace by workflowName')
231
+ .action(action(async (ctx, options) => {
232
+ const payload = await inputFrom(options);
233
+ const result = saveUserIntents(payload, { ctx: ctx });
234
+ // 同一进程内后续命令要看到新规则,避免读到旧的进程内缓存
235
+ resetActiveRules();
236
+ ctx.output.write(result, { json: true });
237
+ })));
238
+ aigroup.command('clear')
239
+ .description('Empty user-intent rules (default.json is never touched)')
133
240
  .action(action((ctx) => {
134
- ctx.output.write(workflowManifest, { json: true });
241
+ const file = clearUserIntents({ ctx: ctx });
242
+ resetActiveRules();
243
+ ctx.output.write({ cleared: true, file }, { json: true });
135
244
  }));
136
245
  withJsonInputOptions(workflow.command('run')
137
246
  .description('Run a workflow operation with JSON input')
@@ -24,8 +24,9 @@ import { resolveSignRemark } from './sign-input.js';
24
24
  import { compactStdoutPaths } from '../stdout-compact.js';
25
25
  import { continuationReplayError } from '../continuation.js';
26
26
  import { writeStateFileBestEffort } from '../state.js';
27
- import { buildHistoryRequestData, fetchHistoryListSnapshot, filterHistoryRequestData, pickUniqueMineWorkflow } from './read.js';
27
+ import { buildHistoryRequestData, fetchHistoryListSnapshot, filterHistoryRequestData, pickUniqueMineWorkflow, prefetchHistoryDetails } from './read.js';
28
28
  import { hasXiaoEEnv } from '../../../internal/e10/auth/xiaoe.js';
29
+ import { createFetchTimingSink, runWithFetchTiming } from '../../../internal/e10/fetch-timing.js';
29
30
  import { buildChatSceneInput, formatLocalNow, requestFormFill } from './chatscene.js';
30
31
  // ---------------------------------------------------------------------------
31
32
  // 常量(与 Python 源逐条对齐)
@@ -448,6 +449,12 @@ function parseTenantSetting(data) {
448
449
  * 只读字段 35→0);不带时拿到的才是表单设计级的真实属性。
449
450
  */
450
451
  function buildLayoutRequest(workflowId, runtime, frame) {
452
+ // 建模表单(relateType=WEA_EBUILDER)的 `module` 与桥接服务名都不是 workflow:服务端按请求体里的
453
+ // `module` 解析 `@Service("<module>_FormCoreService")`,传 `workflow` 会直接 500「未找到名为
454
+ // FormCoreService 的实例对象」(2026-10-29 e-cology 建模流程 1179913136549412865 实测:只把该值
455
+ // 改成 ebuildercard 即 200,其余 params 逐字不变)。页面同场景传 `module:"ebuildercard"` +
456
+ // `customParam.bridgeService:"ebuilder"`(`loadBaseParam` 顶层也返回 `bridgeService:"ebuilder"`)。
457
+ const isEbForm = String(frame.relate_type ?? '').trim() === 'WEA_EBUILDER';
451
458
  const custom = {
452
459
  permissionType: frame.permission_type,
453
460
  requestId: runtime.request_id,
@@ -463,6 +470,7 @@ function buildLayoutRequest(workflowId, runtime, frame) {
463
470
  mobile: false,
464
471
  formId: frame.form_id,
465
472
  source: 'view',
473
+ ...(isEbForm ? { bridgeService: 'ebuilder' } : {}),
466
474
  isAgent: false,
467
475
  beAgentId: '0',
468
476
  hideSysFieldArea: true,
@@ -478,7 +486,7 @@ function buildLayoutRequest(workflowId, runtime, frame) {
478
486
  terminalType: 'PC',
479
487
  formId: frame.form_id,
480
488
  ...(nodePermissionEnabled && permissionId ? { permissionId } : {}),
481
- module: 'workflow',
489
+ module: isEbForm ? 'ebuildercard' : 'workflow',
482
490
  customParam: custom,
483
491
  cacheUid: randomUUID(),
484
492
  newLayout: frame.new_layout,
@@ -1478,7 +1486,23 @@ async function resolveCreateWorkflow(rawWorkflow, env) {
1478
1486
  // 澄清文案里回显的是**用户原话**(不是切分后的关键词)——用户要能认出自己给的条件
1479
1487
  const queryText = rawTerms.join('、');
1480
1488
  if (!rawTerms.length) {
1481
- throw workflowClarificationError('workflow', '', '要发起哪个流程?请提供该流程的完整名称(或其它可用于检索的关键词)后再继续。');
1489
+ // ★ 2026-10-30 用户裁定:这一档不是「名称没匹配上」,而是**必填入参 `workflow` 根本没给**
1490
+ // (缺键 / 空数组 / 空字符串都算)。原先与「只给了填充词」共用同一句澄清,模型看到的是
1491
+ // 「请提供完整名称」,于是键名写错(如写成 `workflows`、`name`)时不知道自己漏了 `workflow`,
1492
+ // 只会回头把锅甩给用户。现在单独标 `clarificationReason=workflow_required` 并下发
1493
+ // `missingInput` + `requiredInput`,让模型知道「是我少传了入参、要按这个形态补」。
1494
+ throw workflowClarificationError('workflow', '', '要发起哪个流程?请提供该流程的完整名称(或其它可用于检索的关键词)后再继续。', [], {
1495
+ clarificationReason: 'workflow_required',
1496
+ missingInput: ['workflow'],
1497
+ requiredInput: {
1498
+ workflow: {
1499
+ required: true,
1500
+ type: 'string | string[]',
1501
+ description: '要发起的工作流:完整名称、名称关键词,或「名称(ID)」;纯数字按工作流 ID 处理。',
1502
+ example: ['费用报销'],
1503
+ },
1504
+ },
1505
+ });
1482
1506
  }
1483
1507
  // 先做**纯本地**的解析:显式 ID(`名称(ID)` / 纯数字)与名称关键词(一格可含多个,见
1484
1508
  // `splitCreateKeywords`)。这一步不依赖远端结果,于是能先判"到底有没有可用条件"——
@@ -1744,9 +1768,9 @@ function singleExplicitWorkflowId(rawWorkflow) {
1744
1768
  return parsed.id ?? (/^[0-9]+$/.test(terms[0]) ? terms[0] : '');
1745
1769
  }
1746
1770
  /** 表单载入 + 该工作流的记忆:两者只共享 `workflowId`,可以并行。 */
1747
- async function loadCreateFormPack(workflowId, env) {
1771
+ async function loadCreateFormPack(workflowId, env, options = {}) {
1748
1772
  const [{ data }, workflowMemory] = await Promise.all([
1749
- buildCreateFormData(workflowId, env),
1773
+ buildCreateFormData(workflowId, env, options),
1750
1774
  // 记忆读取是 best-effort(内部全 catch),不会把表单载入的错误顶掉。
1751
1775
  fetchWorkflowMemory(workflowId, env),
1752
1776
  ]);
@@ -1832,7 +1856,7 @@ async function resolveIntentFill(pack, userQuestion, baseUrl, env) {
1832
1856
  * 现在返回的就是纯取数结果:`fields` + `historyRequestData` + `systemFields` + 记忆,
1833
1857
  * 由模型自己拼 `data` 后交给 `createRequest`。
1834
1858
  */
1835
- async function prepareCreateFormPayload(args, env) {
1859
+ async function prepareCreateFormPayload(args, env, options = {}) {
1836
1860
  // 会话是**惰性**加载的(`ensureSession` 只在首次调用时填充)。本命令随后会并发发起多个请求,
1837
1861
  // 先在这里显式取一次,避免并发首调各自走一遍会话初始化。
1838
1862
  //
@@ -1851,11 +1875,11 @@ async function prepareCreateFormPayload(args, env) {
1851
1875
  // `commonParam.authInfo` 给出;该 ID 不可用时由载入表单一侧的 `readCreateFormBlock`
1852
1876
  // 抛出**可判别**的澄清(不是把它伪装成"没有匹配到可发起的工作流")。
1853
1877
  target = { id: explicitId, name: '', source: 'workflowId' };
1854
- pack = await loadCreateFormPack(explicitId, env);
1878
+ pack = await loadCreateFormPack(explicitId, env, options);
1855
1879
  }
1856
1880
  else {
1857
1881
  target = await resolveCreateWorkflow(args.workflow, env);
1858
- pack = await loadCreateFormPack(target.id, env);
1882
+ pack = await loadCreateFormPack(target.id, env, options);
1859
1883
  }
1860
1884
  // ★ 2026-10-15 用户裁定:`createForm` 改用**字符口径 20,000** 的**严格档**(见
1861
1885
  // `CREATE_FORM_STDOUT_SAFE_CHARS` / `compactFormOutput` 的 `charBudget`)。
@@ -1947,7 +1971,21 @@ async function commandCreateForm(args, env) {
1947
1971
  * 与旧版的差别只有一处:`workflowId` 由调用方(`resolveCreateWorkflow`)解析好后传进来,
1948
1972
  * 不再是本函数的入参校验点。
1949
1973
  */
1950
- async function buildCreateFormData(workflowId, env) {
1974
+ async function buildCreateFormData(workflowId, env, options = {}) {
1975
+ /**
1976
+ * 明细字段的标记形态(2026-10-30 用户裁定):
1977
+ * - 缺省 `subFormId` —— `createForm` 口径,明细字段带 `subFormId`(`data.details` 的键);
1978
+ * - `isDetail` —— `createRequestDirect` 独有的口径,明细字段带 `isDetail: true`、不再下发 `subFormId`。
1979
+ */
1980
+ const detailMark = options.detailMark === 'isDetail' ? 'isDetail' : 'subFormId';
1981
+ /**
1982
+ * ★ 2026-10-30 用户裁定:`getHistory` 是 `createRequestDirect` 的**隐藏入参**(只在 CLI 实现层支持,
1983
+ * 不进 `inputSchema`、不进 skill)。传 `false` 时「历史发起流程」这一段整块不做 ——
1984
+ * 不发 `getMineListData`(列表)、不发明细,也不要组装;输出里 `historyRequestData` 直接给 `null`。
1985
+ *
1986
+ * 缺省(含 `createForm` 这一侧,它从不传)一律按 `true`,行为与从前一字不差。
1987
+ */
1988
+ const getHistory = options.getHistory !== false;
1951
1989
  const query = { workflowId, isCreate: 1, ...AJAX_QUERY };
1952
1990
  const body = { workflowId, isCreate: 1, isMobile: 0 };
1953
1991
  /**
@@ -1958,7 +1996,23 @@ async function buildCreateFormData(workflowId, env) {
1958
1996
  * `.catch(() => null)` 是必须的:这个 Promise 可能因为表单后续抛错而**没人 await**,
1959
1997
  * 兜住之后就不会留下未处理的拒绝;真要暴露的认证/网络错误由同批的载入请求抛出,不会被吞掉。
1960
1998
  */
1961
- const historyListSnapshot = fetchHistoryListSnapshot(env, { workflowId }).catch(() => null);
1999
+ const historyListSnapshot = getHistory
2000
+ ? fetchHistoryListSnapshot(env, { workflowId }).catch(() => null)
2001
+ : Promise.resolve(null);
2002
+ /**
2003
+ * 明细请求紧跟着**列表**走(2026-10-29 用户口径):它的入参只有 `requestId`(列表给的)与会话
2004
+ * `userId`,与 `getFormLayout` **没有任何参数依赖**;原先排在 layout 之后纯属写法问题,白等约
2005
+ * 100 ms。现在列表一返回就发出去,与 layout 并行;**取值后怎么组装一个字没改**(仍在 layout 之后
2006
+ * 用本表单字段清单做,见下方 `buildHistoryRequestData`)。
2007
+ *
2008
+ * `.catch(() => {})`:表单后续可能先抛错(layout 失败等),这条链就没人 `await` 了 —— 先挂一个
2009
+ * 空处理免得留下未处理的拒绝。真正的认证/网络错误仍由 `buildHistoryRequestData` 里那次 `await`
2010
+ * 决定去留(口径不变)。
2011
+ */
2012
+ const historyDetails = getHistory
2013
+ ? historyListSnapshot.then(async (snapshot) => (snapshot && snapshot.requestIds.length ? prefetchHistoryDetails(env, snapshot) : null))
2014
+ : Promise.resolve(null);
2015
+ historyDetails.catch(() => { });
1962
2016
  // 2026-09-22:这四个接口**彼此没有数据依赖**(入参只需要 workflowId,见各自的 query/body),
1963
2017
  // 真机实测各 171–429 ms、串行合计约 1.1 s;并行后只受最慢的一个约束。
1964
2018
  // `loadMinorInfo` / `tenant/setting` 仍是 best-effort(失败只降级、不阻断),所以各自 catch 成
@@ -2235,12 +2289,20 @@ async function buildCreateFormData(workflowId, env) {
2235
2289
  // 不在当前布局上的字段不下发——模型既填不了也看不到。
2236
2290
  if (!modelFieldIds.has(String(field.id ?? '')))
2237
2291
  continue;
2238
- // 键序 id|name|subFormId|componentKey 是契约;`subFormId` **为空就整个省略**(缺该键=主表字段)
2239
- // —— 主表字段占绝大多数,写 `""` 恒白占一条键(真机 278 字段表单:100 个主表字段 × 22 B ≈ 2.2 KB)。
2292
+ // 明细标记**按命令分档**(2026-10-30 用户裁定:改成 isDetail 只对 `createRequestDirect` 生效):
2293
+ // - `createRequestDirect`:键序 `id|name|isDetail|componentKey`,明细字段带 `isDetail: true`,
2294
+ // 主表字段**整个省略**该键(缺键=主表;恒写 `isDetail:false` 白占体积),且**不下发** `subFormId`;
2295
+ // - `createForm`(默认档):维持原口径,明细字段带 `subFormId`(它就是 `data.details` 的键),
2296
+ // 主表字段省略该键。
2240
2297
  const slimSubFormId = String(field.subFormId ?? '');
2241
2298
  const item = { id: field.id, name: field.name };
2242
- if (slimSubFormId)
2299
+ if (detailMark === 'isDetail') {
2300
+ if (slimSubFormId)
2301
+ item.isDetail = true;
2302
+ }
2303
+ else if (slimSubFormId) {
2243
2304
  item.subFormId = slimSubFormId;
2305
+ }
2244
2306
  item.componentKey = field.componentKey;
2245
2307
  // 表单初始化时就有的值(OA 预填 + onLoadForm 联动带出)——有才出现该键;**没有默认值的字段不带**。
2246
2308
  // CLI 拼 `data` 时会自动并入,模型**不必显式传**;用户本次明确改写了它才按用户说的覆盖(见
@@ -2316,10 +2378,12 @@ async function buildCreateFormData(workflowId, env) {
2316
2378
  ...requiredFieldsList.map((f) => String(f?.id ?? '')),
2317
2379
  ...Object.values(subFormRequired).flatMap((list) => list.map((f) => String(f?.id ?? ''))),
2318
2380
  ].filter(Boolean))];
2319
- const historyCache = fields.length
2381
+ const historyCache = getHistory && fields.length
2320
2382
  ? await buildHistoryRequestData(env, fields, historyRequiredFieldIds.map((id) => ({ id, name: String((fieldsById.get(id) || {}).name ?? id) })), { allFormFields: true, workflowId },
2321
2383
  // 本命令开头就已并发发起的列表请求:这里只补「详情」那几步(P2)。
2322
- historyListSnapshot)
2384
+ historyListSnapshot,
2385
+ // 明细也已在列表返回时就发出去(与 layout 并行),这里只等它回来、按本表单字段组装。
2386
+ historyDetails)
2323
2387
  : null;
2324
2388
  const session = await getSessionContext(env);
2325
2389
  const context = {
@@ -2386,7 +2450,9 @@ async function buildCreateFormData(workflowId, env) {
2386
2450
  // 历史参考值(近一年、非草稿、最近 5 条「我发起的」)——填值前先看它,能直接照用的字段就别去
2387
2451
  // 问用户。字段范围与 `fields` **同一口径**(见 modelFieldIds 注释);完整结果(本表单全部字段)
2388
2452
  // 仍随句柄留给 `createRequest` 用(条件必填要到那边才现身)。
2389
- historyRequestData: filterHistoryRequestData(historyCache, modelFieldIds),
2453
+ // `getHistory:false`(隐藏入参)时整段历史取数没做 ⇒ 这里给 `null`(不是空数组:空数组表示
2454
+ // "查了但没数据",两者含义不同)。
2455
+ historyRequestData: getHistory ? filterHistoryRequestData(historyCache, modelFieldIds) : null,
2390
2456
  systemFields: {
2391
2457
  permissions: minorInfo.permissions || {},
2392
2458
  defaults: context.systemFields.defaults,
@@ -3800,9 +3866,11 @@ async function runFieldLinkage(env, ctx, entries, actionTypes, allDetails, isEdi
3800
3866
  }
3801
3867
  if (!dataList.length && !runDataList.length)
3802
3868
  return [];
3869
+ // 建模表单的联动接口 `module` 是 `ebuilderform`(与布局 / 保存的 `ebuildercard` 不同,真机请求体实证)。
3870
+ const linkageModule = formModuleName(ctx.frame && ctx.frame.relate_type, 'ebuilderform');
3803
3871
  const executeParam = {
3804
3872
  formId: ctx.layout.form_id,
3805
- module: 'workflow',
3873
+ module: linkageModule,
3806
3874
  dataList,
3807
3875
  runDataList,
3808
3876
  moduleDataList: [],
@@ -3846,9 +3914,10 @@ async function runFieldLinkage(env, ctx, entries, actionTypes, allDetails, isEdi
3846
3914
  if (frame.layout_multi_id)
3847
3915
  executeParam.layoutId = frame.layout_multi_id;
3848
3916
  }
3849
- const payload = { formId: ctx.layout.form_id, module: 'workflow', executeParam };
3917
+ const payload = { formId: ctx.layout.form_id, module: linkageModule, executeParam };
3850
3918
  const relateType = (ctx.frame && ctx.frame.relate_type) || '';
3851
- const endpoint = formApiUrl(FORM_ENDPOINTS.fdLinkage, relateType);
3919
+ // 建模表单的联动接口在 `/api/ebuilder/form/` 下,与布局 / 保存的 `/api/ebuilder/flow/` 不同(真机实证)。
3920
+ const endpoint = formApiUrl(FORM_ENDPOINTS.fdLinkage, relateType, '/api/ebuilder/form/');
3852
3921
  const response = await requestJson(env, 'POST', endpoint, AJAX_QUERY, payload);
3853
3922
  // requestJson 内部已解包一层(responseData),此处不可再取 .data
3854
3923
  const data = (response && typeof response === 'object') ? response : null;
@@ -4625,6 +4694,8 @@ function linkageResultNotice(linkageDetails, fields, hiddenSubforms, rowHidden,
4625
4694
  * 的就是与普通链路同一段代码),它们不是必填判定。
4626
4695
  * - 句柄**不消费**:本分支在任何写请求之前返回,同一个 `context` 之后仍可正常重发。
4627
4696
  * - `title` 取**工作流名称**;`src` 与两处 `routerProps_*` 的 `initialEntries` 用**工作流 id**;
4697
+ * `src` 末尾另按 `&<字段id>=<值>` 拼上本次要填的字段(2026-10-30 用户裁定,与下面
4698
+ * `params.customParams` 同一份数据);
4628
4699
  * `params.customParams` 取 `createRequest` **入参**经解析后的字段值(不含表单默认值、不含联动带出的值),
4629
4700
  * 同段 `fieldAssignKeys` 列出这次要填的**全部字段 id**(`,` 连接)。
4630
4701
  */
@@ -4777,10 +4848,31 @@ function xiaoECustomParams(preview) {
4777
4848
  }
4778
4849
  return { values, keys: ordered };
4779
4850
  }
4851
+ /**
4852
+ * `src` 末尾的字段参数(2026-10-30 用户裁定):`&<字段id>=<值>`,与 `params.customParams` 里那份
4853
+ * 字段值**同一份数据、同一顺序**(`fieldAssignKeys` 是元信息,不进 URL)。
4854
+ *
4855
+ * 值**原样拼、不做任何百分号编码**:客户端自己解析这段 query(按 `&` 切键值对、再按 `=` 切第一个
4856
+ * 等号),中文、空格、`,` / `;` / `#` 等都不需要转义,拼出来的字面值必须与 `params.customParams`
4857
+ * 里逐字相同。唯一代价是值本身含 `&` 时会截断——按用户口径以此为准,不在此处兜底改写。
4858
+ */
4859
+ function xiaoESrcFieldQuery(params) {
4860
+ let query = '';
4861
+ for (const fieldId of params.keys) {
4862
+ const text = params.values[fieldId];
4863
+ if (!text)
4864
+ continue;
4865
+ query += `&${fieldId}=${text}`;
4866
+ }
4867
+ return query;
4868
+ }
4780
4869
  /**
4781
4870
  * 渲染 `<browsertool>` 块(该块**整体**就是小e 环境下 `createRequest` 的 `finalMarkdown`)。
4782
4871
  *
4783
4872
  * 除 `title` / `src` / 两处 `routerProps_*` 的 `initialEntries` / `params.customParams` 外全部写死。
4873
+ *
4874
+ * `src` 形如 `…/flowpage/create/<workflowId>?workflowId=<workflowId>&isCreate=1&<字段id>=<值>&…`
4875
+ * —— 末尾的字段参数与 `params.customParams` 同源(2026-10-30 用户裁定)。
4784
4876
  */
4785
4877
  function renderXiaoEFillFormMarkdown(params) {
4786
4878
  const base = String(params.baseUrl ?? '').replace(/\/+$/u, '');
@@ -4793,7 +4885,7 @@ function renderXiaoEFillFormMarkdown(params) {
4793
4885
  arguments: {
4794
4886
  type: 'e10',
4795
4887
  title: String(params.title ?? ''),
4796
- src: `${base}/sp/workflow${createPath}?workflowId=${workflowId}&isCreate=1`,
4888
+ src: `${base}/sp/workflow${createPath}?workflowId=${workflowId}&isCreate=1${xiaoESrcFieldQuery(params.customParams)}`,
4797
4889
  sdkOptions: {
4798
4890
  compName: XIAOE_FILL_FORM_SDK_OPTIONS.compName,
4799
4891
  routerType: XIAOE_FILL_FORM_SDK_OPTIONS.routerType,
@@ -4819,7 +4911,8 @@ function renderXiaoEFillFormMarkdown(params) {
4819
4911
  * - `durationMs` = 命令入口 → 结果产出;
4820
4912
  * - `apiDurations` = 每个接口(并行批次合成一个 key,取墙钟、不叠加);
4821
4913
  * - `apiSlowest` = 每个**真并行**批里谁最慢(`[{ batch, name, ms, items }]`,`ms` 是该接口自身耗时,
4822
- * `items` 是批内每个成员的 `{ name, at, ms }`,按 `ms` 降序);
4914
+ * `items` 是批内每个成员的 `{ name, at, ms, fetchAt, fetchEnd, fetchCost }`,按 `ms` 降序;
4915
+ * `fetchAt`/`fetchEnd`/`fetchCost` 描述其中纯 fetch 那一段);
4823
4916
  * - `authMs` = 登录取凭据(首次会话解析)的墙钟 —— 这一段走 auth 层自己的 fetch、不经
4824
4917
  * `host.workflowRequest`,`apiDurations` 统计不到,单独给一个数才能对上账。
4825
4918
  *
@@ -5448,15 +5541,27 @@ function apiShortName(path) {
5448
5541
  * 给 host 套一层**逐接口计时**(只包请求,不改返回、不吞异常)。
5449
5542
  *
5450
5543
  * `finally` 里落片段:请求失败(超时 / 业务错误 / 抛错)同样要记 —— 恰恰是这类请求最需要看到耗时。
5544
+ *
5545
+ * 片段里除整段耗时外,还记**纯 fetch** 那一段(`fetchMs`,2026-10-30 用户要求):它由
5546
+ * `runWithFetchTiming` 开一个旁路 sink、`E10RequestRuntime` 在 fetch 前后各打一枪得到,
5547
+ * 两条链路都只读不改请求/返回值。
5451
5548
  */
5452
5549
  function withApiTiming(host, spans) {
5453
5550
  const record = async (path, run) => {
5454
5551
  const start = Date.now();
5552
+ const fetchTiming = createFetchTimingSink();
5455
5553
  try {
5456
- return await run();
5554
+ return await runWithFetchTiming(fetchTiming, run);
5457
5555
  }
5458
5556
  finally {
5459
- spans.push({ name: apiShortName(path), start, end: Date.now() });
5557
+ spans.push({
5558
+ name: apiShortName(path),
5559
+ start,
5560
+ end: Date.now(),
5561
+ fetchStart: fetchTiming.fetchStart,
5562
+ fetchEnd: fetchTiming.fetchEnd,
5563
+ fetchMs: fetchTiming.fetchMs,
5564
+ });
5460
5565
  }
5461
5566
  };
5462
5567
  return {
@@ -5485,7 +5590,9 @@ function withApiTiming(host, spans) {
5485
5590
  * - 批内**全是同一个接口**时也不产(如 5 个并发的 `getWorkflowRequest` 取历史详情):请求都一样,
5486
5591
  * "谁最慢"没有区分意义,只有批的墙钟有用(2026-10-22 用户第二轮裁定);
5487
5592
  * - `ms` 取该接口**自身**耗时(`end - start`),不是批墙钟;
5488
- * - 每条另带 `items`:批内**每个**成员的 `{name, at, ms}`(`at` 相对批起点),按 `ms` 降序。
5593
+ * - 每条另带 `items`:批内**每个**成员的 `{name, at, ms, fetchAt, fetchEnd, fetchCost}`(`at` 相对批
5594
+ * 起点;`ms` 自身耗时;`fetchAt`/`fetchEnd` 是其中**纯 fetch**(发出请求 → 收到响应头)的起止偏移、
5595
+ * `fetchCost` 是它的耗时,2026-10-30 用户要求),按 `ms` 降序。
5489
5596
  * 2026-10-26 用户要求:只看最慢项判断不出「优化它值不值」——若批内多个接口耗时接近,
5490
5597
  * 砍掉最慢那个的收益有限,得看整条关键路径的分布;
5491
5598
  * - 顺序=批的时间顺序,与 `apiDurations` 的 key 一一对应。
@@ -5520,13 +5627,17 @@ function summarizeApiSpans(spans) {
5520
5627
  // 批内全是同一个接口 ⇒ 不产最慢项("5 个 getWorkflowRequest 里谁最慢"没有区分意义)。
5521
5628
  if (group.length > 1 && new Set(names).size > 1) {
5522
5629
  const origin = Math.min(...group.map((item) => item.start));
5523
- // 批内逐个成员都留一条(`at` 相对批起点,`ms` 自身耗时),按耗时降序;并列取先开始的
5524
- // (`at` 升序),保证同一份输入每次输出一致。`name`/`ms` 就取这一项。
5630
+ // 批内逐个成员都留一条(`at` 相对批起点,`ms` 自身耗时;`fetchAt`/`fetchEnd` 是其中纯 fetch
5631
+ // 的起止偏移、`fetchCost` 是它自身的耗时),按耗时降序;并列取先开始的(`at` 升序),
5632
+ // 保证同一份输入每次输出一致。`name`/`ms` 就取这一项。
5525
5633
  const items = group
5526
5634
  .map((item) => ({
5527
5635
  name: item.name,
5528
5636
  at: Math.max(0, Math.round(item.start - origin)),
5529
5637
  ms: Math.max(0, Math.round(item.end - item.start)),
5638
+ fetchAt: item.fetchStart === null ? null : Math.max(0, Math.round(item.fetchStart - origin)),
5639
+ fetchEnd: item.fetchEnd === null ? null : Math.max(0, Math.round(item.fetchEnd - origin)),
5640
+ fetchCost: Math.max(0, Math.round(item.fetchMs)),
5530
5641
  }))
5531
5642
  .sort((a, b) => (b.ms - a.ms) || (a.at - b.at));
5532
5643
  slowest.push({ batch: key, name: items[0].name, ms: items[0].ms, items });
@@ -5534,6 +5645,26 @@ function summarizeApiSpans(spans) {
5534
5645
  }
5535
5646
  return { durations, slowest };
5536
5647
  }
5648
+ /**
5649
+ * `createRequestDirect` 的**隐藏入参** `getHistory` 取值(2026-10-30 用户裁定)。
5650
+ *
5651
+ * 只在 CLI 实现层支持:**不写进** `inputSchema`、不写进 skill 文档,模型侧看不到、也没法从
5652
+ * `workflow schema` 里读到;需要时由调用方(桌面端 / 脚本)自己塞进 `--input-json`。
5653
+ *
5654
+ * 口径:缺省、`null`、`undefined`、空串、其它非 `false` 的真值 ⇒ `true`(与从前的行为完全一致);
5655
+ * 只有明确表达"不要"的写法才关掉:`false` / `0` / `"false"` / `"0"`(大小写、首尾空格都不敏感)。
5656
+ * 宽松接受字符串是为了调用方从环境变量或配置里透传时不必先转类型。
5657
+ */
5658
+ function readHiddenGetHistory(value) {
5659
+ if (value === false || value === 0)
5660
+ return false;
5661
+ if (typeof value === 'string') {
5662
+ const text = value.trim().toLowerCase();
5663
+ if (text === 'false' || text === '0')
5664
+ return false;
5665
+ }
5666
+ return true;
5667
+ }
5537
5668
  /**
5538
5669
  * `workflow.createRequestDirect` —— **取数命令**(2026-10-22 用户裁定,语义已变)。
5539
5670
  *
@@ -5555,6 +5686,10 @@ function summarizeApiSpans(spans) {
5555
5686
  * 5. **输出降级**(按 20,000 **字符**,与 `createForm` 同一个宿主口径):
5556
5687
  * 全量超线 ⇒ `historyRequestData` 留空数组(键还在);仍超 ⇒ `userMemory` 留空串(键还在;小e 档没有
5557
5688
  * 这个键,不补);**`fields` 自己也超线时不再裁**(宁大不丢)—— 它是唯一不可省的,砍了这条命令就没有意义。
5689
+ * 6. **隐藏入参 `getHistory`**(2026-10-30 用户裁定):只在实现层支持,**不进 schema、不进 skill**。
5690
+ * 不传 = `true`(原行为);传 `false` 时整段「历史发起流程」取数(`getMineListData` 列表 + 明细)
5691
+ * 一次都不发,输出里 `historyRequestData` 直接是 `null`(不是空数组——空数组的意思是"查了但没数据")。
5692
+ * 这一档也不参与上面的输出降级。
5558
5693
  *
5559
5694
  * ## 耗时
5560
5695
  * 与 `createForm` 完全同口径,全部收在 `timing` 一个桶里:`durationMs`(整条命令)/
@@ -5567,9 +5702,15 @@ async function commandCreateRequestDirect(args, env) {
5567
5702
  // 计时从**命令入口**开始算(含会话解析、工作流消歧、表单载入)。
5568
5703
  const spans = [];
5569
5704
  const timedEnv = { ...env, host: withApiTiming(env.host, spans) };
5705
+ // 隐藏入参(不进 schema / skill):`false` 时不跑「历史发起流程」那段取数。
5706
+ const getHistory = readHiddenGetHistory(args.getHistory);
5570
5707
  // 取数段本身已经不碰 `chatScene`(`createForm` 自 2026-10-23 起不再接 `userQuestion`),
5571
- // 这里不必再置空任何入参。
5572
- const { payload, authMs } = await prepareCreateFormPayload(args, timedEnv);
5708
+ // 这里不必再置空任何入参。`detailMark` 也是**本命令独有**:明细字段标 `isDetail: true`、
5709
+ // 不再下发 `subFormId`(`createForm` 仍走老口径,见 `buildCreateFormData`)。
5710
+ const { payload, authMs } = await prepareCreateFormPayload(args, timedEnv, {
5711
+ getHistory,
5712
+ detailMark: 'isDetail',
5713
+ });
5573
5714
  const contextId = String(payload.contextId ?? '');
5574
5715
  if (!contextId) {
5575
5716
  // `prepareCreateFormPayload` 正常返回时 contextId 必然存在;这里只用来判断
@@ -5604,8 +5745,10 @@ async function commandCreateRequestDirect(args, env) {
5604
5745
  const overLine = () => finalStdoutChars({ ...data, ...reserve }, 'workflow.createRequestDirect') > CREATE_FORM_STDOUT_SAFE_CHARS;
5605
5746
  // 两级降级:先砍历史(留空 key)→ 再砍记忆(留空 key)。`fields` 不参与裁剪。
5606
5747
  // 小e 档没有 `userMemory` 这个键,第二级跳过(不能借"写空串"把它重新加回来)。
5748
+ // `getHistory:false` 时历史那一档本来就没查(值是 `null`)⇒ 不参与降级,否则会把"没查"说成"查了没数据"。
5607
5749
  if (overLine()) {
5608
- data.historyRequestData = [];
5750
+ if (getHistory)
5751
+ data.historyRequestData = [];
5609
5752
  if ('userMemory' in data && overLine())
5610
5753
  data.userMemory = '';
5611
5754
  }
@@ -5628,10 +5771,30 @@ function formatRemark(value) {
5628
5771
  return text;
5629
5772
  return `_weaverMte_<p>${text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')}</p>`;
5630
5773
  }
5774
+ /**
5775
+ * 表单所属模块名:建模表单(`relateType=WEA_EBUILDER`)按接口取自己的 service 名,其余是 `workflow`。
5776
+ *
5777
+ * 服务端按请求体里的 `module` 解析 `@Service("<module>_FormCoreService")`:建模表单传 `workflow`
5778
+ * 会直接 500「未找到名为 FormCoreService 的实例对象」(2026-10-29 e-cology 建模流程实测:只把该值
5779
+ * 改成 `ebuildercard` 即 200)。所以凡是请求体带 `module` 的表单接口(布局 / 附件 / 保存 / 联动)
5780
+ * 都必须按表单类型取值,不能硬编码。
5781
+ *
5782
+ * ⚠️ 建模表单内部**不是同一个值**,必须按接口分别给(均为真机请求体实证):
5783
+ * - `getFormLayout` / `saveFormData` / 附件上传 → `ebuildercard`
5784
+ * - `executeFdLinkage` / `getFormDataAndLayout` → `ebuilderform`
5785
+ *
5786
+ * 注意这两个值**不按目录/同族划分**:`getFormDataAndLayout` 与 `getFormLayout` 同在 `form/core` 下,
5787
+ * 前者是 `ebuilderform`、后者是 `ebuildercard`。所以只能按接口真机样例取值,不能靠推断。
5788
+ */
5789
+ function formModuleName(relateType, ebModule = 'ebuildercard') {
5790
+ return String(relateType ?? '').trim() === 'WEA_EBUILDER' ? ebModule : 'workflow';
5791
+ }
5631
5792
  function buildSaveBody(context, prepared) {
5632
5793
  const runtime = context.runtime;
5794
+ // 顶层 `module` 与 `formData.module` 是同一条判据:建模表单的 saveFormData 也走 ebuilder 的服务。
5795
+ const moduleName = formModuleName(context.frame?.relate_type);
5633
5796
  return {
5634
- module: 'workflow',
5797
+ module: moduleName,
5635
5798
  customParam: {
5636
5799
  isCreate: true,
5637
5800
  requestId: runtime.request_id,
@@ -5649,7 +5812,7 @@ function buildSaveBody(context, prepared) {
5649
5812
  },
5650
5813
  employeeId: runtime.employee_id,
5651
5814
  formData: {
5652
- module: 'workflow',
5815
+ module: moduleName,
5653
5816
  presetDataId: runtime.request_id,
5654
5817
  dataDetails: prepared.dataDetails,
5655
5818
  client: 'pc',
@@ -6150,12 +6313,15 @@ async function runCreateNodeFieldVerification(env, context, switches) {
6150
6313
  // ---------------------------------------------------------------------------
6151
6314
  // editLoad / editPrepare / editSave
6152
6315
  // ---------------------------------------------------------------------------
6153
- function buildEditDataLayoutRequest(requestId, workflowId, nodeId, formId, dataId, layoutMultiId, viewFormNodeId, permissionType, runtime) {
6316
+ function buildEditDataLayoutRequest(requestId, workflowId, nodeId, formId, dataId, layoutMultiId, viewFormNodeId, permissionType, runtime, relateType) {
6154
6317
  return {
6155
6318
  terminalType: 'PC',
6156
6319
  dataId,
6157
6320
  formId,
6158
- module: 'workflow',
6321
+ // 建模表单取 `ebuilderform`(2026-10-30 真机请求体实证),**不是** `ebuildercard`:
6322
+ // 同为 `form/core` 下的接口,`getFormLayout` / `saveFormData` 是 `ebuildercard`,
6323
+ // 本接口与 `executeFdLinkage` 是 `ebuilderform` —— 建模表单内部不能按"同族"推定。
6324
+ module: formModuleName(relateType, 'ebuilderform'),
6159
6325
  newLayout: true,
6160
6326
  cacheUid: null,
6161
6327
  layoutMultiId,
@@ -6229,7 +6395,7 @@ async function commandEditLoad(args, env) {
6229
6395
  tenantSetting = {};
6230
6396
  }
6231
6397
  const dataId = requestId;
6232
- 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));
6398
+ 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));
6233
6399
  const dlData = dlResp;
6234
6400
  if (!dlData || typeof dlData !== 'object')
6235
6401
  throw workflowApiError('format_error', 'getFormDataAndLayout 未返回有效 data');
@@ -6537,8 +6703,10 @@ async function commandEditPrepare(args, env) {
6537
6703
  }
6538
6704
  function buildEditSaveBody(context, prepared) {
6539
6705
  const runtime = context.runtime || {};
6706
+ // 同 `buildSaveBody`:改已有表单时也按表单类型取 module,建模表单要 `ebuildercard`。
6707
+ const moduleName = formModuleName(context.frame?.relate_type);
6540
6708
  return {
6541
- module: 'workflow',
6709
+ module: moduleName,
6542
6710
  customParam: {
6543
6711
  isCreate: false,
6544
6712
  requestId: context.requestId ?? context.request_id,
@@ -6558,7 +6726,7 @@ function buildEditSaveBody(context, prepared) {
6558
6726
  formData: {
6559
6727
  id: context.data_id,
6560
6728
  updateTimeStamp: context.update_time_stamp || '',
6561
- module: 'workflow',
6729
+ module: moduleName,
6562
6730
  dataDelRows: [],
6563
6731
  dataDetails: prepared.dataDetails || [],
6564
6732
  client: 'pc',