weaver-work-cli 0.1.33 → 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 (100) hide show
  1. package/dist/chunks/{archive-FVFY6GZN.js → archive-XBVH7JU7.js} +2 -2
  2. package/dist/chunks/{archive-oa-NW3OD4UV.js → archive-oa-MZM3EKFQ.js} +2 -2
  3. package/dist/chunks/{asset-7QJKMIDV.js → asset-4XO7UOUW.js} +2 -2
  4. package/dist/chunks/{attachment-content-OSAVA6K3.js → attachment-content-VXSWANAC.js} +3 -3
  5. package/dist/chunks/{blog-I7SDPNW4.js → blog-PGZKOPSC.js} +2 -2
  6. package/dist/chunks/{caizhilian-O37ZIQNY.js → caizhilian-BH4ZVGUN.js} +2 -2
  7. package/dist/chunks/{calendar-7KXE4ED3.js → calendar-MXEMTIO4.js} +2 -2
  8. package/dist/chunks/{chunk-VBCFFFGT.js → chunk-5DQEEGCC.js} +4 -1
  9. package/dist/chunks/{chunk-KAS45KNR.js → chunk-6LLJFKJE.js} +1 -1
  10. package/dist/chunks/{chunk-HEL5XTYI.js → chunk-BPE37FPB.js} +26 -4
  11. package/dist/chunks/{chunk-IHUYP6LO.js → chunk-F746NKNF.js} +1 -1
  12. package/dist/chunks/{chunk-MQ2I5AA3.js → chunk-HXJQI5NM.js} +2 -2
  13. package/dist/chunks/{chunk-ILMBNVSG.js → chunk-I6QGIBDM.js} +2 -2
  14. package/dist/chunks/{chunk-EEWPQE3O.js → chunk-JCSN3JGM.js} +2 -2
  15. package/dist/chunks/{chunk-D223PTXU.js → chunk-JNG42JKG.js} +29 -1
  16. package/dist/chunks/{chunk-6ATGWRZM.js → chunk-JUXVYKII.js} +4 -1
  17. package/dist/chunks/{chunk-GFPXQIY2.js → chunk-JYKABYCV.js} +2 -2
  18. package/dist/chunks/{chunk-Q6LWB5HX.js → chunk-NCOVUAZK.js} +2 -2
  19. package/dist/chunks/{chunk-WY74UBJ6.js → chunk-QHFANTX7.js} +900 -204
  20. package/dist/chunks/{chunk-WRRJ4GG2.js → chunk-QYGO5EE2.js} +2 -2
  21. package/dist/chunks/{chunk-RBGOMK4Y.js → chunk-T72N74ZT.js} +2 -2
  22. package/dist/chunks/{chunk-MEEFGWTM.js → chunk-TC6MZAO3.js} +84 -9
  23. package/dist/chunks/{chunk-OCU4RLHC.js → chunk-VPUTVEMC.js} +98 -34
  24. package/dist/chunks/{chunk-PRHJGPMA.js → chunk-VPXOPQJI.js} +2 -2
  25. package/dist/chunks/{chunk-NHA62QD7.js → chunk-WXFPWCXG.js} +3 -3
  26. package/dist/chunks/{chunk-2FLWXFVS.js → chunk-XMGSYD6S.js} +4 -4
  27. package/dist/chunks/{conflict-SFNEVJY5.js → conflict-JAB2LJEZ.js} +2 -2
  28. package/dist/chunks/contract-XI2EEIZU.js +9110 -0
  29. package/dist/chunks/{cowork-CKWYHXYB.js → cowork-SCPGLBA4.js} +44 -25
  30. package/dist/chunks/{ebuilder-form-KOLJRVZD.js → ebuilder-form-EYLHNOTA.js} +3 -3
  31. package/dist/chunks/{ehr-WFOC3B4D.js → ehr-EAP77IMT.js} +172 -9
  32. package/dist/chunks/{esb-LJZTN663.js → esb-2TGGXEE7.js} +4 -4
  33. package/dist/chunks/{fna-F7QRIIZC.js → fna-2X7ZE7BU.js} +13 -8
  34. package/dist/chunks/{host-VQ6JJXGQ.js → host-C6EL2RKL.js} +3 -3
  35. package/dist/chunks/{host-BCGUVEWX.js → host-I4NRK4MX.js} +3 -3
  36. package/dist/chunks/{host-DGE2TZD4.js → host-Q4LZGCRU.js} +3 -3
  37. package/dist/chunks/{host-BQBRHVR3.js → host-UEI5FGDM.js} +3 -3
  38. package/dist/chunks/{host-KXPTEWFS.js → host-XCLDDXKQ.js} +3 -3
  39. package/dist/chunks/{hrm-NI6XAKW5.js → hrm-YXERJM76.js} +3 -3
  40. package/dist/chunks/{im-7TRTF3KT.js → im-A4VZN2TQ.js} +3 -3
  41. package/dist/chunks/{invoice-AOXWJKYT.js → invoice-2Z6YPMIS.js} +3 -3
  42. package/dist/chunks/{jiuchuanhui-7NQWEZAW.js → jiuchuanhui-AR5GMKZB.js} +2 -2
  43. package/dist/chunks/{lazy-dispatch-RNS4EE4S.js → lazy-dispatch-QXW7P4X3.js} +4 -4
  44. package/dist/chunks/{mail-VDHJAB4O.js → mail-7GZ6CPBJ.js} +44 -23
  45. package/dist/chunks/{meeting-GA7XCNNP.js → meeting-3NMGA3MB.js} +74 -10
  46. package/dist/chunks/{okr-TQIRERPQ.js → okr-BZ6XUOAG.js} +2 -2
  47. package/dist/chunks/{plan-4RY4LN2P.js → plan-DR5CMUYP.js} +2 -2
  48. package/dist/chunks/{project-D6XT2OC5.js → project-6J63MK33.js} +2 -2
  49. package/dist/chunks/{registry-JHRIDQ3A.js → registry-KDD7DHNK.js} +4 -4
  50. package/dist/chunks/{registry-VOGKFFTR.js → registry-TKX2E7C7.js} +2 -2
  51. package/dist/chunks/{registry-QKMI43Q6.js → registry-VRTNC6UR.js} +8 -8
  52. package/dist/chunks/{room-recommend-D4EUOOWY.js → room-recommend-XCWRMB5P.js} +4 -4
  53. package/dist/chunks/{schedule-XPFBHPCV.js → schedule-IVBICP32.js} +4 -4
  54. package/dist/chunks/{workflow-HLBZRWIY.js → workflow-D74NFK3C.js} +11 -4
  55. package/dist/index.js +31 -26
  56. package/dist/internal/e10/fetch-timing.js +31 -0
  57. package/dist/internal/e10/request-runtime.js +5 -0
  58. package/dist/shortcuts/cowork/host.js +8 -0
  59. package/dist/shortcuts/cowork/operations/types.js +17 -2
  60. package/dist/shortcuts/ehr/operations/recruit-write.js +35 -0
  61. package/dist/shortcuts/ehr/operations/recruit.js +147 -0
  62. package/dist/shortcuts/fna/operations/expense-chart.js +19 -7
  63. package/dist/shortcuts/index.js +5 -0
  64. package/dist/shortcuts/mail/host.js +8 -0
  65. package/dist/shortcuts/mail/operations/types.js +17 -2
  66. package/dist/shortcuts/meeting/index.js +79 -1
  67. package/dist/shortcuts/meeting/manifest.js +10 -0
  68. package/dist/shortcuts/meeting/operations/eb/catalog.js +5 -0
  69. package/dist/shortcuts/meeting/operations/eb/conflict.js +6 -1
  70. package/dist/shortcuts/meeting/operations/eb/create-flow.js +1047 -134
  71. package/dist/shortcuts/meeting/operations/eb/factory.js +101 -7
  72. package/dist/shortcuts/meeting/operations/eb/room-recommend.js +36 -2
  73. package/dist/shortcuts/meeting/operations/eb-fallback.js +4 -0
  74. package/dist/shortcuts/meeting/operations/env.js +6 -0
  75. package/dist/shortcuts/meeting/operations/invitation.js +79 -20
  76. package/dist/shortcuts/workflow/endpoints.js +8 -3
  77. package/dist/shortcuts/workflow/operations/form.js +181 -34
  78. package/dist/shortcuts/workflow/operations.js +23 -1
  79. package/docs/ehr.md +1 -1
  80. package/docs/fna.md +2 -1
  81. package/package.json +1 -1
  82. package/skill-template/business-info.json +18 -0
  83. package/skill-template/domains/cowork.md +14 -0
  84. package/skills/weaver-e10-cowork/SKILL.md +101 -0
  85. package/skills/weaver-e10-cowork/references/cowork-read.md +90 -0
  86. package/skills/weaver-e10-cowork/references/cowork-write.md +131 -0
  87. package/skills/weaver-e10-cowork/references/safety-boundaries.md +45 -0
  88. package/skills/weaver-e10-jucailin/SKILL.md +21 -3
  89. package/skills/weaver-e10-jucailin/references/recruit-read.md +25 -0
  90. package/skills/weaver-e10-jucailin/references/recruit-write.md +13 -0
  91. package/skills/weaver-e10-jucailin/references/salary.md +15 -11
  92. package/skills/weaver-e10-mail/SKILL.md +12 -9
  93. package/skills/weaver-e10-meeting/SKILL.md +284 -34
  94. package/skills/weaver-e10-meeting/references/meeting-eb.md +131 -0
  95. package/skills/weaver-e10-meeting/references/meeting-invitation.md +28 -2
  96. package/skills/weaver-e10-meeting.zip +0 -0
  97. package/skills/weaver-e10-qiyecheng/SKILL.md +5 -2
  98. package/skills/weaver-e10-qiyecheng/references/catalog.md +2 -2
  99. package/skills/weaver-e10-qiyecheng/references/expense-chart.md +15 -1
  100. package/skills/weaver-e10-qiyecheng/references/source-manifest.json +22 -21
@@ -26,6 +26,7 @@ import { continuationReplayError } from '../continuation.js';
26
26
  import { writeStateFileBestEffort } from '../state.js';
27
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 源逐条对齐)
@@ -1485,7 +1486,23 @@ async function resolveCreateWorkflow(rawWorkflow, env) {
1485
1486
  // 澄清文案里回显的是**用户原话**(不是切分后的关键词)——用户要能认出自己给的条件
1486
1487
  const queryText = rawTerms.join('、');
1487
1488
  if (!rawTerms.length) {
1488
- 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
+ });
1489
1506
  }
1490
1507
  // 先做**纯本地**的解析:显式 ID(`名称(ID)` / 纯数字)与名称关键词(一格可含多个,见
1491
1508
  // `splitCreateKeywords`)。这一步不依赖远端结果,于是能先判"到底有没有可用条件"——
@@ -1751,9 +1768,9 @@ function singleExplicitWorkflowId(rawWorkflow) {
1751
1768
  return parsed.id ?? (/^[0-9]+$/.test(terms[0]) ? terms[0] : '');
1752
1769
  }
1753
1770
  /** 表单载入 + 该工作流的记忆:两者只共享 `workflowId`,可以并行。 */
1754
- async function loadCreateFormPack(workflowId, env) {
1771
+ async function loadCreateFormPack(workflowId, env, options = {}) {
1755
1772
  const [{ data }, workflowMemory] = await Promise.all([
1756
- buildCreateFormData(workflowId, env),
1773
+ buildCreateFormData(workflowId, env, options),
1757
1774
  // 记忆读取是 best-effort(内部全 catch),不会把表单载入的错误顶掉。
1758
1775
  fetchWorkflowMemory(workflowId, env),
1759
1776
  ]);
@@ -1839,7 +1856,7 @@ async function resolveIntentFill(pack, userQuestion, baseUrl, env) {
1839
1856
  * 现在返回的就是纯取数结果:`fields` + `historyRequestData` + `systemFields` + 记忆,
1840
1857
  * 由模型自己拼 `data` 后交给 `createRequest`。
1841
1858
  */
1842
- async function prepareCreateFormPayload(args, env) {
1859
+ async function prepareCreateFormPayload(args, env, options = {}) {
1843
1860
  // 会话是**惰性**加载的(`ensureSession` 只在首次调用时填充)。本命令随后会并发发起多个请求,
1844
1861
  // 先在这里显式取一次,避免并发首调各自走一遍会话初始化。
1845
1862
  //
@@ -1858,11 +1875,11 @@ async function prepareCreateFormPayload(args, env) {
1858
1875
  // `commonParam.authInfo` 给出;该 ID 不可用时由载入表单一侧的 `readCreateFormBlock`
1859
1876
  // 抛出**可判别**的澄清(不是把它伪装成"没有匹配到可发起的工作流")。
1860
1877
  target = { id: explicitId, name: '', source: 'workflowId' };
1861
- pack = await loadCreateFormPack(explicitId, env);
1878
+ pack = await loadCreateFormPack(explicitId, env, options);
1862
1879
  }
1863
1880
  else {
1864
1881
  target = await resolveCreateWorkflow(args.workflow, env);
1865
- pack = await loadCreateFormPack(target.id, env);
1882
+ pack = await loadCreateFormPack(target.id, env, options);
1866
1883
  }
1867
1884
  // ★ 2026-10-15 用户裁定:`createForm` 改用**字符口径 20,000** 的**严格档**(见
1868
1885
  // `CREATE_FORM_STDOUT_SAFE_CHARS` / `compactFormOutput` 的 `charBudget`)。
@@ -1954,7 +1971,21 @@ async function commandCreateForm(args, env) {
1954
1971
  * 与旧版的差别只有一处:`workflowId` 由调用方(`resolveCreateWorkflow`)解析好后传进来,
1955
1972
  * 不再是本函数的入参校验点。
1956
1973
  */
1957
- 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;
1958
1989
  const query = { workflowId, isCreate: 1, ...AJAX_QUERY };
1959
1990
  const body = { workflowId, isCreate: 1, isMobile: 0 };
1960
1991
  /**
@@ -1965,7 +1996,9 @@ async function buildCreateFormData(workflowId, env) {
1965
1996
  * `.catch(() => null)` 是必须的:这个 Promise 可能因为表单后续抛错而**没人 await**,
1966
1997
  * 兜住之后就不会留下未处理的拒绝;真要暴露的认证/网络错误由同批的载入请求抛出,不会被吞掉。
1967
1998
  */
1968
- const historyListSnapshot = fetchHistoryListSnapshot(env, { workflowId }).catch(() => null);
1999
+ const historyListSnapshot = getHistory
2000
+ ? fetchHistoryListSnapshot(env, { workflowId }).catch(() => null)
2001
+ : Promise.resolve(null);
1969
2002
  /**
1970
2003
  * 明细请求紧跟着**列表**走(2026-10-29 用户口径):它的入参只有 `requestId`(列表给的)与会话
1971
2004
  * `userId`,与 `getFormLayout` **没有任何参数依赖**;原先排在 layout 之后纯属写法问题,白等约
@@ -1976,7 +2009,9 @@ async function buildCreateFormData(workflowId, env) {
1976
2009
  * 空处理免得留下未处理的拒绝。真正的认证/网络错误仍由 `buildHistoryRequestData` 里那次 `await`
1977
2010
  * 决定去留(口径不变)。
1978
2011
  */
1979
- const historyDetails = historyListSnapshot.then(async (snapshot) => (snapshot && snapshot.requestIds.length ? prefetchHistoryDetails(env, snapshot) : null));
2012
+ const historyDetails = getHistory
2013
+ ? historyListSnapshot.then(async (snapshot) => (snapshot && snapshot.requestIds.length ? prefetchHistoryDetails(env, snapshot) : null))
2014
+ : Promise.resolve(null);
1980
2015
  historyDetails.catch(() => { });
1981
2016
  // 2026-09-22:这四个接口**彼此没有数据依赖**(入参只需要 workflowId,见各自的 query/body),
1982
2017
  // 真机实测各 171–429 ms、串行合计约 1.1 s;并行后只受最慢的一个约束。
@@ -2254,12 +2289,20 @@ async function buildCreateFormData(workflowId, env) {
2254
2289
  // 不在当前布局上的字段不下发——模型既填不了也看不到。
2255
2290
  if (!modelFieldIds.has(String(field.id ?? '')))
2256
2291
  continue;
2257
- // 键序 id|name|subFormId|componentKey 是契约;`subFormId` **为空就整个省略**(缺该键=主表字段)
2258
- // —— 主表字段占绝大多数,写 `""` 恒白占一条键(真机 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
+ // 主表字段省略该键。
2259
2297
  const slimSubFormId = String(field.subFormId ?? '');
2260
2298
  const item = { id: field.id, name: field.name };
2261
- if (slimSubFormId)
2299
+ if (detailMark === 'isDetail') {
2300
+ if (slimSubFormId)
2301
+ item.isDetail = true;
2302
+ }
2303
+ else if (slimSubFormId) {
2262
2304
  item.subFormId = slimSubFormId;
2305
+ }
2263
2306
  item.componentKey = field.componentKey;
2264
2307
  // 表单初始化时就有的值(OA 预填 + onLoadForm 联动带出)——有才出现该键;**没有默认值的字段不带**。
2265
2308
  // CLI 拼 `data` 时会自动并入,模型**不必显式传**;用户本次明确改写了它才按用户说的覆盖(见
@@ -2335,7 +2378,7 @@ async function buildCreateFormData(workflowId, env) {
2335
2378
  ...requiredFieldsList.map((f) => String(f?.id ?? '')),
2336
2379
  ...Object.values(subFormRequired).flatMap((list) => list.map((f) => String(f?.id ?? ''))),
2337
2380
  ].filter(Boolean))];
2338
- const historyCache = fields.length
2381
+ const historyCache = getHistory && fields.length
2339
2382
  ? await buildHistoryRequestData(env, fields, historyRequiredFieldIds.map((id) => ({ id, name: String((fieldsById.get(id) || {}).name ?? id) })), { allFormFields: true, workflowId },
2340
2383
  // 本命令开头就已并发发起的列表请求:这里只补「详情」那几步(P2)。
2341
2384
  historyListSnapshot,
@@ -2407,7 +2450,9 @@ async function buildCreateFormData(workflowId, env) {
2407
2450
  // 历史参考值(近一年、非草稿、最近 5 条「我发起的」)——填值前先看它,能直接照用的字段就别去
2408
2451
  // 问用户。字段范围与 `fields` **同一口径**(见 modelFieldIds 注释);完整结果(本表单全部字段)
2409
2452
  // 仍随句柄留给 `createRequest` 用(条件必填要到那边才现身)。
2410
- historyRequestData: filterHistoryRequestData(historyCache, modelFieldIds),
2453
+ // `getHistory:false`(隐藏入参)时整段历史取数没做 ⇒ 这里给 `null`(不是空数组:空数组表示
2454
+ // "查了但没数据",两者含义不同)。
2455
+ historyRequestData: getHistory ? filterHistoryRequestData(historyCache, modelFieldIds) : null,
2411
2456
  systemFields: {
2412
2457
  permissions: minorInfo.permissions || {},
2413
2458
  defaults: context.systemFields.defaults,
@@ -3821,9 +3866,11 @@ async function runFieldLinkage(env, ctx, entries, actionTypes, allDetails, isEdi
3821
3866
  }
3822
3867
  if (!dataList.length && !runDataList.length)
3823
3868
  return [];
3869
+ // 建模表单的联动接口 `module` 是 `ebuilderform`(与布局 / 保存的 `ebuildercard` 不同,真机请求体实证)。
3870
+ const linkageModule = formModuleName(ctx.frame && ctx.frame.relate_type, 'ebuilderform');
3824
3871
  const executeParam = {
3825
3872
  formId: ctx.layout.form_id,
3826
- module: 'workflow',
3873
+ module: linkageModule,
3827
3874
  dataList,
3828
3875
  runDataList,
3829
3876
  moduleDataList: [],
@@ -3867,9 +3914,10 @@ async function runFieldLinkage(env, ctx, entries, actionTypes, allDetails, isEdi
3867
3914
  if (frame.layout_multi_id)
3868
3915
  executeParam.layoutId = frame.layout_multi_id;
3869
3916
  }
3870
- const payload = { formId: ctx.layout.form_id, module: 'workflow', executeParam };
3917
+ const payload = { formId: ctx.layout.form_id, module: linkageModule, executeParam };
3871
3918
  const relateType = (ctx.frame && ctx.frame.relate_type) || '';
3872
- 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/');
3873
3921
  const response = await requestJson(env, 'POST', endpoint, AJAX_QUERY, payload);
3874
3922
  // requestJson 内部已解包一层(responseData),此处不可再取 .data
3875
3923
  const data = (response && typeof response === 'object') ? response : null;
@@ -4646,6 +4694,8 @@ function linkageResultNotice(linkageDetails, fields, hiddenSubforms, rowHidden,
4646
4694
  * 的就是与普通链路同一段代码),它们不是必填判定。
4647
4695
  * - 句柄**不消费**:本分支在任何写请求之前返回,同一个 `context` 之后仍可正常重发。
4648
4696
  * - `title` 取**工作流名称**;`src` 与两处 `routerProps_*` 的 `initialEntries` 用**工作流 id**;
4697
+ * `src` 末尾另按 `&<字段id>=<值>` 拼上本次要填的字段(2026-10-30 用户裁定,与下面
4698
+ * `params.customParams` 同一份数据);
4649
4699
  * `params.customParams` 取 `createRequest` **入参**经解析后的字段值(不含表单默认值、不含联动带出的值),
4650
4700
  * 同段 `fieldAssignKeys` 列出这次要填的**全部字段 id**(`,` 连接)。
4651
4701
  */
@@ -4798,10 +4848,31 @@ function xiaoECustomParams(preview) {
4798
4848
  }
4799
4849
  return { values, keys: ordered };
4800
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
+ }
4801
4869
  /**
4802
4870
  * 渲染 `<browsertool>` 块(该块**整体**就是小e 环境下 `createRequest` 的 `finalMarkdown`)。
4803
4871
  *
4804
4872
  * 除 `title` / `src` / 两处 `routerProps_*` 的 `initialEntries` / `params.customParams` 外全部写死。
4873
+ *
4874
+ * `src` 形如 `…/flowpage/create/<workflowId>?workflowId=<workflowId>&isCreate=1&<字段id>=<值>&…`
4875
+ * —— 末尾的字段参数与 `params.customParams` 同源(2026-10-30 用户裁定)。
4805
4876
  */
4806
4877
  function renderXiaoEFillFormMarkdown(params) {
4807
4878
  const base = String(params.baseUrl ?? '').replace(/\/+$/u, '');
@@ -4814,7 +4885,7 @@ function renderXiaoEFillFormMarkdown(params) {
4814
4885
  arguments: {
4815
4886
  type: 'e10',
4816
4887
  title: String(params.title ?? ''),
4817
- src: `${base}/sp/workflow${createPath}?workflowId=${workflowId}&isCreate=1`,
4888
+ src: `${base}/sp/workflow${createPath}?workflowId=${workflowId}&isCreate=1${xiaoESrcFieldQuery(params.customParams)}`,
4818
4889
  sdkOptions: {
4819
4890
  compName: XIAOE_FILL_FORM_SDK_OPTIONS.compName,
4820
4891
  routerType: XIAOE_FILL_FORM_SDK_OPTIONS.routerType,
@@ -4840,7 +4911,8 @@ function renderXiaoEFillFormMarkdown(params) {
4840
4911
  * - `durationMs` = 命令入口 → 结果产出;
4841
4912
  * - `apiDurations` = 每个接口(并行批次合成一个 key,取墙钟、不叠加);
4842
4913
  * - `apiSlowest` = 每个**真并行**批里谁最慢(`[{ batch, name, ms, items }]`,`ms` 是该接口自身耗时,
4843
- * `items` 是批内每个成员的 `{ name, at, ms }`,按 `ms` 降序);
4914
+ * `items` 是批内每个成员的 `{ name, at, ms, fetchAt, fetchEnd, fetchCost }`,按 `ms` 降序;
4915
+ * `fetchAt`/`fetchEnd`/`fetchCost` 描述其中纯 fetch 那一段);
4844
4916
  * - `authMs` = 登录取凭据(首次会话解析)的墙钟 —— 这一段走 auth 层自己的 fetch、不经
4845
4917
  * `host.workflowRequest`,`apiDurations` 统计不到,单独给一个数才能对上账。
4846
4918
  *
@@ -5469,15 +5541,27 @@ function apiShortName(path) {
5469
5541
  * 给 host 套一层**逐接口计时**(只包请求,不改返回、不吞异常)。
5470
5542
  *
5471
5543
  * `finally` 里落片段:请求失败(超时 / 业务错误 / 抛错)同样要记 —— 恰恰是这类请求最需要看到耗时。
5544
+ *
5545
+ * 片段里除整段耗时外,还记**纯 fetch** 那一段(`fetchMs`,2026-10-30 用户要求):它由
5546
+ * `runWithFetchTiming` 开一个旁路 sink、`E10RequestRuntime` 在 fetch 前后各打一枪得到,
5547
+ * 两条链路都只读不改请求/返回值。
5472
5548
  */
5473
5549
  function withApiTiming(host, spans) {
5474
5550
  const record = async (path, run) => {
5475
5551
  const start = Date.now();
5552
+ const fetchTiming = createFetchTimingSink();
5476
5553
  try {
5477
- return await run();
5554
+ return await runWithFetchTiming(fetchTiming, run);
5478
5555
  }
5479
5556
  finally {
5480
- 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
+ });
5481
5565
  }
5482
5566
  };
5483
5567
  return {
@@ -5506,7 +5590,9 @@ function withApiTiming(host, spans) {
5506
5590
  * - 批内**全是同一个接口**时也不产(如 5 个并发的 `getWorkflowRequest` 取历史详情):请求都一样,
5507
5591
  * "谁最慢"没有区分意义,只有批的墙钟有用(2026-10-22 用户第二轮裁定);
5508
5592
  * - `ms` 取该接口**自身**耗时(`end - start`),不是批墙钟;
5509
- * - 每条另带 `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` 降序。
5510
5596
  * 2026-10-26 用户要求:只看最慢项判断不出「优化它值不值」——若批内多个接口耗时接近,
5511
5597
  * 砍掉最慢那个的收益有限,得看整条关键路径的分布;
5512
5598
  * - 顺序=批的时间顺序,与 `apiDurations` 的 key 一一对应。
@@ -5541,13 +5627,17 @@ function summarizeApiSpans(spans) {
5541
5627
  // 批内全是同一个接口 ⇒ 不产最慢项("5 个 getWorkflowRequest 里谁最慢"没有区分意义)。
5542
5628
  if (group.length > 1 && new Set(names).size > 1) {
5543
5629
  const origin = Math.min(...group.map((item) => item.start));
5544
- // 批内逐个成员都留一条(`at` 相对批起点,`ms` 自身耗时),按耗时降序;并列取先开始的
5545
- // (`at` 升序),保证同一份输入每次输出一致。`name`/`ms` 就取这一项。
5630
+ // 批内逐个成员都留一条(`at` 相对批起点,`ms` 自身耗时;`fetchAt`/`fetchEnd` 是其中纯 fetch
5631
+ // 的起止偏移、`fetchCost` 是它自身的耗时),按耗时降序;并列取先开始的(`at` 升序),
5632
+ // 保证同一份输入每次输出一致。`name`/`ms` 就取这一项。
5546
5633
  const items = group
5547
5634
  .map((item) => ({
5548
5635
  name: item.name,
5549
5636
  at: Math.max(0, Math.round(item.start - origin)),
5550
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)),
5551
5641
  }))
5552
5642
  .sort((a, b) => (b.ms - a.ms) || (a.at - b.at));
5553
5643
  slowest.push({ batch: key, name: items[0].name, ms: items[0].ms, items });
@@ -5555,6 +5645,26 @@ function summarizeApiSpans(spans) {
5555
5645
  }
5556
5646
  return { durations, slowest };
5557
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
+ }
5558
5668
  /**
5559
5669
  * `workflow.createRequestDirect` —— **取数命令**(2026-10-22 用户裁定,语义已变)。
5560
5670
  *
@@ -5576,6 +5686,10 @@ function summarizeApiSpans(spans) {
5576
5686
  * 5. **输出降级**(按 20,000 **字符**,与 `createForm` 同一个宿主口径):
5577
5687
  * 全量超线 ⇒ `historyRequestData` 留空数组(键还在);仍超 ⇒ `userMemory` 留空串(键还在;小e 档没有
5578
5688
  * 这个键,不补);**`fields` 自己也超线时不再裁**(宁大不丢)—— 它是唯一不可省的,砍了这条命令就没有意义。
5689
+ * 6. **隐藏入参 `getHistory`**(2026-10-30 用户裁定):只在实现层支持,**不进 schema、不进 skill**。
5690
+ * 不传 = `true`(原行为);传 `false` 时整段「历史发起流程」取数(`getMineListData` 列表 + 明细)
5691
+ * 一次都不发,输出里 `historyRequestData` 直接是 `null`(不是空数组——空数组的意思是"查了但没数据")。
5692
+ * 这一档也不参与上面的输出降级。
5579
5693
  *
5580
5694
  * ## 耗时
5581
5695
  * 与 `createForm` 完全同口径,全部收在 `timing` 一个桶里:`durationMs`(整条命令)/
@@ -5588,9 +5702,15 @@ async function commandCreateRequestDirect(args, env) {
5588
5702
  // 计时从**命令入口**开始算(含会话解析、工作流消歧、表单载入)。
5589
5703
  const spans = [];
5590
5704
  const timedEnv = { ...env, host: withApiTiming(env.host, spans) };
5705
+ // 隐藏入参(不进 schema / skill):`false` 时不跑「历史发起流程」那段取数。
5706
+ const getHistory = readHiddenGetHistory(args.getHistory);
5591
5707
  // 取数段本身已经不碰 `chatScene`(`createForm` 自 2026-10-23 起不再接 `userQuestion`),
5592
- // 这里不必再置空任何入参。
5593
- 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
+ });
5594
5714
  const contextId = String(payload.contextId ?? '');
5595
5715
  if (!contextId) {
5596
5716
  // `prepareCreateFormPayload` 正常返回时 contextId 必然存在;这里只用来判断
@@ -5625,8 +5745,10 @@ async function commandCreateRequestDirect(args, env) {
5625
5745
  const overLine = () => finalStdoutChars({ ...data, ...reserve }, 'workflow.createRequestDirect') > CREATE_FORM_STDOUT_SAFE_CHARS;
5626
5746
  // 两级降级:先砍历史(留空 key)→ 再砍记忆(留空 key)。`fields` 不参与裁剪。
5627
5747
  // 小e 档没有 `userMemory` 这个键,第二级跳过(不能借"写空串"把它重新加回来)。
5748
+ // `getHistory:false` 时历史那一档本来就没查(值是 `null`)⇒ 不参与降级,否则会把"没查"说成"查了没数据"。
5628
5749
  if (overLine()) {
5629
- data.historyRequestData = [];
5750
+ if (getHistory)
5751
+ data.historyRequestData = [];
5630
5752
  if ('userMemory' in data && overLine())
5631
5753
  data.userMemory = '';
5632
5754
  }
@@ -5649,10 +5771,30 @@ function formatRemark(value) {
5649
5771
  return text;
5650
5772
  return `_weaverMte_<p>${text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')}</p>`;
5651
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
+ }
5652
5792
  function buildSaveBody(context, prepared) {
5653
5793
  const runtime = context.runtime;
5794
+ // 顶层 `module` 与 `formData.module` 是同一条判据:建模表单的 saveFormData 也走 ebuilder 的服务。
5795
+ const moduleName = formModuleName(context.frame?.relate_type);
5654
5796
  return {
5655
- module: 'workflow',
5797
+ module: moduleName,
5656
5798
  customParam: {
5657
5799
  isCreate: true,
5658
5800
  requestId: runtime.request_id,
@@ -5670,7 +5812,7 @@ function buildSaveBody(context, prepared) {
5670
5812
  },
5671
5813
  employeeId: runtime.employee_id,
5672
5814
  formData: {
5673
- module: 'workflow',
5815
+ module: moduleName,
5674
5816
  presetDataId: runtime.request_id,
5675
5817
  dataDetails: prepared.dataDetails,
5676
5818
  client: 'pc',
@@ -6171,12 +6313,15 @@ async function runCreateNodeFieldVerification(env, context, switches) {
6171
6313
  // ---------------------------------------------------------------------------
6172
6314
  // editLoad / editPrepare / editSave
6173
6315
  // ---------------------------------------------------------------------------
6174
- function buildEditDataLayoutRequest(requestId, workflowId, nodeId, formId, dataId, layoutMultiId, viewFormNodeId, permissionType, runtime) {
6316
+ function buildEditDataLayoutRequest(requestId, workflowId, nodeId, formId, dataId, layoutMultiId, viewFormNodeId, permissionType, runtime, relateType) {
6175
6317
  return {
6176
6318
  terminalType: 'PC',
6177
6319
  dataId,
6178
6320
  formId,
6179
- module: 'workflow',
6321
+ // 建模表单取 `ebuilderform`(2026-10-30 真机请求体实证),**不是** `ebuildercard`:
6322
+ // 同为 `form/core` 下的接口,`getFormLayout` / `saveFormData` 是 `ebuildercard`,
6323
+ // 本接口与 `executeFdLinkage` 是 `ebuilderform` —— 建模表单内部不能按"同族"推定。
6324
+ module: formModuleName(relateType, 'ebuilderform'),
6180
6325
  newLayout: true,
6181
6326
  cacheUid: null,
6182
6327
  layoutMultiId,
@@ -6250,7 +6395,7 @@ async function commandEditLoad(args, env) {
6250
6395
  tenantSetting = {};
6251
6396
  }
6252
6397
  const dataId = requestId;
6253
- 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));
6254
6399
  const dlData = dlResp;
6255
6400
  if (!dlData || typeof dlData !== 'object')
6256
6401
  throw workflowApiError('format_error', 'getFormDataAndLayout 未返回有效 data');
@@ -6558,8 +6703,10 @@ async function commandEditPrepare(args, env) {
6558
6703
  }
6559
6704
  function buildEditSaveBody(context, prepared) {
6560
6705
  const runtime = context.runtime || {};
6706
+ // 同 `buildSaveBody`:改已有表单时也按表单类型取 module,建模表单要 `ebuildercard`。
6707
+ const moduleName = formModuleName(context.frame?.relate_type);
6561
6708
  return {
6562
- module: 'workflow',
6709
+ module: moduleName,
6563
6710
  customParam: {
6564
6711
  isCreate: false,
6565
6712
  requestId: context.requestId ?? context.request_id,
@@ -6579,7 +6726,7 @@ function buildEditSaveBody(context, prepared) {
6579
6726
  formData: {
6580
6727
  id: context.data_id,
6581
6728
  updateTimeStamp: context.update_time_stamp || '',
6582
- module: 'workflow',
6729
+ module: moduleName,
6583
6730
  dataDelRows: [],
6584
6731
  dataDetails: prepared.dataDetails || [],
6585
6732
  client: 'pc',
@@ -59,6 +59,12 @@ function clarificationEnvelope(error, operation) {
59
59
  ? details.clarificationQuestion
60
60
  : error.message;
61
61
  const reason = typeof details.clarificationReason === 'string' ? details.clarificationReason : '';
62
+ // 必填入参缺失(当前只有 `workflow_required` 一档)时,把「缺了哪个键、该按什么形态补」一并下发:
63
+ // 模型原先只能看到「请提供完整名称」,无法区分「用户没说要发起什么」与「我键名写错了」。
64
+ const missingInput = Array.isArray(details.missingInput) ? details.missingInput.map(String) : [];
65
+ const requiredInput = details.requiredInput && typeof details.requiredInput === 'object'
66
+ ? details.requiredInput
67
+ : null;
62
68
  return workflowSuccess(operation, {
63
69
  type: 'workflowClarification',
64
70
  status: 'NEEDS_CLARIFICATION',
@@ -66,6 +72,8 @@ function clarificationEnvelope(error, operation) {
66
72
  clarificationKeyword: details.clarificationKeyword ?? null,
67
73
  clarificationQuestion: question,
68
74
  ...(reason ? { clarificationReason: reason } : {}),
75
+ ...(missingInput.length ? { missingInput } : {}),
76
+ ...(missingInput.length && requiredInput ? { requiredInput } : {}),
69
77
  candidates,
70
78
  candidateCount: candidates.length,
71
79
  note: clarificationNote(reason, candidates.length),
@@ -80,10 +88,24 @@ function clarificationEnvelope(error, operation) {
80
88
  * - `no_create_right` —— 流程**存在**但当前账号没有发起权限,**绝不能**说成"不存在"
81
89
  * (那正是把"没权限"伪装成"没有这条流程",与项目纪律相反)。
82
90
  *
83
- * 无 `reason` 时(名称解析 0 / 多命中)保持原文案不变。
91
+ * 2026-10-30 新增一档:
92
+ * - `workflow_required` —— **必填入参没给**(缺键/空数组/空字符串)。它不是「名称匹配不到」,
93
+ * 而是调用方少传了入参;文案必须让模型先认账、再问用户要流程名,而不是让用户去"核对名称"。
94
+ *
95
+ * 无 `reason` 时(名称解析 0 / 多命中 / 只给了填充词)保持原文案不变。
84
96
  */
85
97
  function clarificationNote(reason, candidateCount) {
86
98
  const base = '这不是失败,也**不代表查询已执行**:本次查询已停止,没有返回任何流程数据。';
99
+ // ★ 2026-10-30:`workflow_required` = **必填入参没给**,与「名称匹配不到」性质完全不同。
100
+ // 这里要模型先认账(少传了入参),而不是去问用户「是不是名字打错了」。
101
+ if (reason === 'workflow_required') {
102
+ return '本次命令**没有拿到必填入参 `workflow`**(没写这个键、空数组、空字符串都算没给)——'
103
+ + '命令停在了查询之前:**没有发起任何流程**,也没有去查可发起列表,'
104
+ + '这既不是执行失败,也不代表「没有匹配的流程」。'
105
+ + '请先向用户确认要发起哪个流程(**必须问,不要自己猜,也不要拿相似的名字代替**),'
106
+ + '再按 `requiredInput.workflow` 给出的形态把入参补上、重发同一条命令。'
107
+ + '注意 `--input` 接收的是**文件路径**(`-` 表示标准输入),内联 JSON 要用 `--input-json`。';
108
+ }
87
109
  if (reason === 'workflow_not_exist') {
88
110
  return base + '请如实告知用户:该工作流不存在(可能已删除或被停用),'
89
111
  + '请用户改用该流程的完整名称(或其它可用于检索的关键词)重新指定——**不要向用户索取 ID**。'
package/docs/ehr.md CHANGED
@@ -56,7 +56,7 @@ weaver-work-cli --json ehr run <operation> --input -
56
56
 
57
57
  CLI 原样透传整个响应对象,不做重命名;取用方按上表判断。
58
58
 
59
- **每页条数**:由服务端按接口独立配置,**`pageSize` 传参无效**(实测):通讯录 100、出勤表格类 20、`worktime`/`leave.report` 10、hr 报表 20、薪酬 `bill.list`/`employee.list` 20、`empchange.list` 100。全量数据一律递增 `current` 翻页。
59
+ **每页条数**:由服务端按接口独立配置,**`pageSize` 传参无效**(实测):通讯录 100、出勤表格类 20、`worktime`/`leave.report` 10、hr 报表 20、薪酬 `bill.list` 20、`empchange.list` 100。全量数据一律递增 `current` 翻页。
60
60
 
61
61
  **成功响应的 `data` 恒存在**:业务数据为 `undefined` 时(如社保福利、调薪记录为空)统一补为 `null`,避免 `JSON.stringify` 省略该键导致调用方需判断键是否存在。
62
62
 
package/docs/fna.md CHANGED
@@ -21,7 +21,7 @@
21
21
  | `fna.expense.reimbursed.sum` | read | POST `expense/center/getSumReimbursedAmountByAi`;body 可空 |
22
22
  | `fna.expense.loan.sum` | read | POST `expense/center/getSumLoanAmountByAi`;只认数字 ID;空 data 自动重试 2 次;已知仅统计首条记录缺陷 |
23
23
  | `fna.expense.prepay.writeoff.sum` | read | POST `expense/center/selectPrepayWriteOffAmountBySkill`;body 可空 |
24
- | `fna.expense.chart` | read | GET `getExpenseChart`(`/api/secondev/fna/`);`userInput` 必填 ≤500 字;`maxRows` 本地截断 1-5000,默认 200;超时 180s;返回 `kind=rows/empty/clarify/blocked/unexpected` |
24
+ | `fna.expense.chart` | read | GET `getExpenseChart`(`/api/secondev/fna/`);`userInput` 必填 ≤500 字;`maxRows` 本地截断 1-5000,默认 200;超时 180s;返回 `kind=rows/empty/clarify/blocked/unexpected`;无权限文案额外返回 `meta.permissionDenied=true` |
25
25
  | `fna.loan.main.page` | read | POST `loanManagementMenu/mainPage` |
26
26
  | `fna.loan.main.list` | read | POST `loanManagementMenu/mainPageList`;`current`/`pageSize`/`menuCode`/`permissionSetCode` 必填 |
27
27
  | `fna.loan.remind.repay.prepare` | write | 校验 displayData 行并预览,不发送 |
@@ -65,6 +65,7 @@ weaver-work-cli --json fna run fna.invoice.writeoff.list --input-json '{"current
65
65
  - `menuCode`/`permissionSetCode` 环境相关,示例值需与环境核对。
66
66
  - 超 2^53 的 requestId 无法用 JS 数字精确表达,保留字符串并提示人工核验(真实环境 ID 一般在安全整数内,已按数字发送)。
67
67
  - `fna.expense.chart`:`code` 恒为 200,必须按 `data` 类型/`kind` 判成败;追问与安全拦截都是字符串 `data`,`meta.messageKindInferred=true` 表示归类为 CLI 推断。实测真实查询 3.3~66.6s,CLI 超时设 180s,禁止自动重试(每次都会消耗模型额度)。不做当前人强制过滤,结果可能是全租户范围;`userInput` 为商品化输入,个人口径必须改用 `fna.expense.reimbursed.sum`。二开包未安装时该 operation 会 404/500,需与其它 `fna.*` 正常但本 operation 失败区分。
68
+ - `fna.expense.chart` 的权限语义:文案含「权限 / 越权」时 CLI 归类为 `clarify` 并置 `meta.permissionDenied=true`(纯权限提示不带「不明确」关键词也照样识别,避免落进 `unexpected` 被误判)。这是**终止信号**,不是换问法信号:Agent 必须直接告知权限边界,禁止改调 `fna.expense.reimbursed.sum`、`fna.budget.*`、借款 / 核销等接口按部门 / 人员 / 金额拼装同一份报表,也禁止自写 SQL 绕过。
68
69
 
69
70
  ## 验证
70
71
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "weaver-work-cli",
3
- "version": "0.1.33",
3
+ "version": "0.1.36",
4
4
  "description": "面向泛微工作工具链的可扩展 TypeScript CLI 基础框架(E10 业票通等能力)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -29,6 +29,24 @@
29
29
  "紧急程度",
30
30
  "参与人"
31
31
  ],
32
+ "weaver-e10-cowork": [
33
+ "协作",
34
+ "协作区",
35
+ "协作事项",
36
+ "工作协作",
37
+ "讨论",
38
+ "回复讨论",
39
+ "协作参与人",
40
+ "共享权限",
41
+ "申请加入",
42
+ "待我审批",
43
+ "我关注的",
44
+ "我收藏的",
45
+ "我的事项",
46
+ "相关我",
47
+ "结束协作",
48
+ "协作版块"
49
+ ],
32
50
  "weaver-e10-meeting": [
33
51
  "会议",
34
52
  "会议室",
@@ -0,0 +1,14 @@
1
+ 本业务域用于 E10 协作区(工作协作)。入口 `SKILL.md` 只做路由与执行纪律:CRITICAL 共享前置、命令面、按场景读 reference、写操作 prepare→确认→apply 协议、输出纪律。具体 operation、字段与失败处理拆到 `references/`:
2
+
3
+ - `cowork-read.md`:13 类列表(scope)、搜索条件元数据、计数、详情、讨论记录、参与人、关联资源、投票日志、版块表单、元数据、共享权限列表。
4
+ - `cowork-write.md`:新建/结束协作、隐藏/投票、发布讨论、讨论置顶/删除/审批、成员邀请/重新加入/申请加入、加入申请审批、事项与交流审批台、共享对象增删。
5
+ - `safety-boundaries.md`:未实现能力(浏览选择器、点赞组件、权限单元高级配置、搜索 UI 元数据)、红线、能力边界与可见性。
6
+
7
+ Agent 调优重点:
8
+
9
+ - `weaver-work-cli cowork schema` 是 operation 合约第一信息源,契约外的命令与参数一律禁止。
10
+ - 业务输入不得包含 Cookie、ETEAMSID、Token、UA;认证与请求头由 `weaver-e10-shared` 与 CLI 托管。
11
+ - 列表筛选用「值字段 + 对应 `*Condition`」;`itemStatus` 取 `1` 进行中 / `2` 已结束(`0` 等于全部)。
12
+ - 动作类写操作(审批、删除、置顶、审批台)的 id 必须先由对应列表查询取得,禁止凭示例或猜测提交。
13
+ - 写操作只接受 CLI 生成的 `continuation`,`confirm=true` 必须在用户明确确认后传入;`partial/write_uncertain` 时先核对现状,禁止自动重试。
14
+ - 查询为空如实说明「没有符合条件的协作或无权查看」,不要断言系统里没有,也不要改用相邻接口拼凑。