weaver-work-cli 0.1.29 → 0.1.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/dist/chunks/archive-U766FTFH.js +2537 -0
  2. package/dist/chunks/archive-oa-DMWEKX3L.js +1317 -0
  3. package/dist/chunks/asset-TCR7VDEV.js +2109 -0
  4. package/dist/chunks/attachment-content-AQNX5N3S.js +23 -0
  5. package/dist/chunks/blog-EVZWGDVM.js +2157 -0
  6. package/dist/chunks/caizhilian-JOWS6SL5.js +10087 -0
  7. package/dist/chunks/calendar-5WNCV66Q.js +1195 -0
  8. package/dist/chunks/chunk-2DUV44UX.js +15606 -0
  9. package/dist/chunks/chunk-324YPTC2.js +1607 -0
  10. package/dist/chunks/chunk-65QMVWHS.js +231 -0
  11. package/dist/chunks/chunk-6V7ZLF34.js +387 -0
  12. package/dist/chunks/chunk-AC7KJWC5.js +358 -0
  13. package/dist/chunks/chunk-AJ62BGAW.js +29 -0
  14. package/dist/chunks/chunk-BUSC6UAE.js +43 -0
  15. package/dist/chunks/chunk-CVZ2JOSW.js +62 -0
  16. package/dist/chunks/chunk-D4LTJSJD.js +477 -0
  17. package/dist/chunks/chunk-EG6ZU444.js +654 -0
  18. package/dist/chunks/chunk-EZALDOQH.js +383 -0
  19. package/dist/chunks/chunk-FMPJJYYI.js +106 -0
  20. package/dist/chunks/chunk-G2JSIUWF.js +769 -0
  21. package/dist/chunks/chunk-GCG2NMWR.js +703 -0
  22. package/dist/chunks/chunk-GPMFD4RD.js +75 -0
  23. package/dist/chunks/chunk-H3WDBYJW.js +508 -0
  24. package/dist/chunks/chunk-H6XSTSLM.js +2357 -0
  25. package/dist/chunks/chunk-J7RJTZSV.js +5556 -0
  26. package/dist/chunks/chunk-LUSPKZKY.js +53 -0
  27. package/dist/chunks/chunk-NIAJ5ZCG.js +73 -0
  28. package/dist/chunks/chunk-NOODWMCL.js +584 -0
  29. package/dist/chunks/chunk-OOUTBLZ4.js +51 -0
  30. package/dist/chunks/chunk-P26ZWSKU.js +73 -0
  31. package/dist/chunks/chunk-QWY6PGL6.js +3472 -0
  32. package/dist/chunks/chunk-R2IJAK7T.js +464 -0
  33. package/dist/chunks/chunk-R7O5PUWO.js +205 -0
  34. package/dist/chunks/chunk-RCGYCOMG.js +6962 -0
  35. package/dist/chunks/chunk-VZTXRG6X.js +403 -0
  36. package/dist/chunks/chunk-WHD4XMRP.js +161 -0
  37. package/dist/chunks/chunk-YLCYX7LE.js +371 -0
  38. package/dist/chunks/chunk-ZEDWSH32.js +68 -0
  39. package/dist/chunks/continuation-2CKSBLA6.js +11 -0
  40. package/dist/chunks/continuation-HZIZRZBX.js +13 -0
  41. package/dist/chunks/continuation-NLECEJPX.js +11 -0
  42. package/dist/chunks/ebuilder-form-NJ4YK6CC.js +2276 -0
  43. package/dist/chunks/ehr-MMYN36VA.js +5241 -0
  44. package/dist/chunks/employee-SAK2QYXX.js +11 -0
  45. package/dist/chunks/esb-HIWHOU7Q.js +141 -0
  46. package/dist/chunks/fna-KBACQTA5.js +1444 -0
  47. package/dist/chunks/host-3OHS5QUX.js +21 -0
  48. package/dist/chunks/host-IG6KEH5Q.js +19 -0
  49. package/dist/chunks/host-KQL5N4HO.js +23 -0
  50. package/dist/chunks/host-LLSZQCWR.js +17 -0
  51. package/dist/chunks/hrm-LYEC67ZQ.js +244 -0
  52. package/dist/chunks/im-RN2UKAEU.js +252 -0
  53. package/dist/chunks/invoice-EEPHLAF6.js +5179 -0
  54. package/dist/chunks/jiuchuanhui-WVVZYSJE.js +1940 -0
  55. package/dist/chunks/lazy-dispatch-MDOFFL2S.js +28 -0
  56. package/dist/chunks/mail-LNQLTF6L.js +2695 -0
  57. package/dist/chunks/meeting-XSD3BDVQ.js +504 -0
  58. package/dist/chunks/msg-parse-4GSQ2WTO.js +41 -0
  59. package/dist/chunks/okr-TMWTIU2K.js +2482 -0
  60. package/dist/chunks/plan-A2FSFA7T.js +2025 -0
  61. package/dist/chunks/project-T26QLBQF.js +1361 -0
  62. package/dist/chunks/registry-2VLUAESA.js +14 -0
  63. package/dist/chunks/registry-JCFEYXOE.js +18 -0
  64. package/dist/chunks/registry-NYPYMZXG.js +16 -0
  65. package/dist/chunks/registry-Q7OQJ3SU.js +19 -0
  66. package/dist/chunks/registry-ZJMJVWFA.js +19 -0
  67. package/dist/chunks/room-recommend-UR4ZDZS6.js +20 -0
  68. package/dist/chunks/schedule-5L2PM4M6.js +24 -0
  69. package/dist/chunks/state-Y2XBP6YE.js +15 -0
  70. package/dist/chunks/workflow-TR6PG2SL.js +245 -0
  71. package/dist/cmd/argv.js +45 -0
  72. package/dist/cmd/docs/index.js +3 -3
  73. package/dist/cmd/lazy-dispatch.js +20 -0
  74. package/dist/cmd/root.js +2 -4
  75. package/dist/cmd/setup/index.js +2 -2
  76. package/dist/cmd/skills/index.js +2 -2
  77. package/dist/core/package-paths.js +47 -0
  78. package/dist/index.js +163 -7
  79. package/dist/internal/e10/auth/xiaoe.js +3 -3
  80. package/dist/internal/e10/request-runtime.js +18 -62
  81. package/dist/internal/skills/detector.js +2 -2
  82. package/dist/shortcuts/contract/data/performance-catalog.js +1306 -0
  83. package/dist/shortcuts/contract/host.js +91 -35
  84. package/dist/shortcuts/contract/index.js +213 -0
  85. package/dist/shortcuts/contract/manifest.js +928 -0
  86. package/dist/shortcuts/contract/ooxml/docx.js +295 -0
  87. package/dist/shortcuts/contract/ooxml/xlsx.js +221 -0
  88. package/dist/shortcuts/contract/ooxml/zip.js +158 -0
  89. package/dist/shortcuts/contract/operations/assistant.js +1156 -0
  90. package/dist/shortcuts/contract/operations/clause-library.js +522 -0
  91. package/dist/shortcuts/contract/operations/compare.js +193 -0
  92. package/dist/shortcuts/contract/operations/credit-page.js +34 -0
  93. package/dist/shortcuts/contract/operations/flow.js +98 -0
  94. package/dist/shortcuts/contract/operations/page.js +66 -0
  95. package/dist/shortcuts/contract/operations/performance.js +733 -0
  96. package/dist/shortcuts/contract/operations/quote.js +557 -0
  97. package/dist/shortcuts/contract/operations/recommend.js +78 -0
  98. package/dist/shortcuts/contract/operations/registry.js +18 -0
  99. package/dist/shortcuts/contract/operations/review.js +83 -0
  100. package/dist/shortcuts/contract/operations/shared.js +37 -0
  101. package/dist/shortcuts/contract/operations/upload.js +108 -0
  102. package/dist/shortcuts/contract/operations/write.js +3 -2
  103. package/dist/shortcuts/index.js +140 -40
  104. package/dist/shortcuts/invoice/manifest.js +34 -11
  105. package/dist/shortcuts/invoice/operations/reim-auto.js +9 -0
  106. package/dist/shortcuts/invoice/operations/reim.js +81 -5
  107. package/dist/shortcuts/invoice/operations/shared.js +12 -5
  108. package/dist/shortcuts/meeting/host.js +45 -3
  109. package/dist/shortcuts/meeting/invitation/docx.js +442 -0
  110. package/dist/shortcuts/meeting/operations/attachment-content.js +418 -0
  111. package/dist/shortcuts/meeting/operations/attachment.js +442 -0
  112. package/dist/shortcuts/meeting/operations/eb/cache.js +57 -0
  113. package/dist/shortcuts/meeting/operations/eb/catalog.js +343 -28
  114. package/dist/shortcuts/meeting/operations/eb/conflict.js +372 -11
  115. package/dist/shortcuts/meeting/operations/eb/create-flow.js +710 -0
  116. package/dist/shortcuts/meeting/operations/eb/decision.js +47 -1
  117. package/dist/shortcuts/meeting/operations/eb/factory.js +129 -11
  118. package/dist/shortcuts/meeting/operations/eb/index.js +122 -2
  119. package/dist/shortcuts/meeting/operations/eb/room-recommend.js +378 -0
  120. package/dist/shortcuts/meeting/operations/eb/room-summary.js +84 -0
  121. package/dist/shortcuts/meeting/operations/eb/schedule.js +450 -0
  122. package/dist/shortcuts/meeting/operations/from-group-chat.js +576 -0
  123. package/dist/shortcuts/meeting/operations/invitation.js +458 -0
  124. package/dist/shortcuts/meeting/operations/minute-content.js +266 -0
  125. package/dist/shortcuts/meeting/operations/pipeline.js +489 -0
  126. package/dist/shortcuts/meeting/operations/qrcode.js +131 -0
  127. package/dist/shortcuts/meeting/operations/receipts.js +1 -1
  128. package/dist/shortcuts/meeting/operations/registry.js +18 -0
  129. package/dist/shortcuts/meeting/operations/summary.js +276 -0
  130. package/dist/shortcuts/meeting/operations/task-notify.js +325 -0
  131. package/dist/shortcuts/meeting/operations.js +42 -1
  132. package/dist/shortcuts/meeting/qr/encoder.js +427 -0
  133. package/dist/shortcuts/meeting/qr/render.js +103 -0
  134. package/dist/shortcuts/workflow/operations/form.js +17 -5
  135. package/docs/contract.md +39 -4
  136. package/docs/invoice.md +5 -5
  137. package/package.json +3 -2
  138. package/scripts/bundle.mjs +63 -0
  139. package/skill-template/business-info.json +25 -4
  140. package/skill-template/domains/jinchengda.md +16 -3
  141. package/skill-template/domains/yepiaotong.md +1 -1
  142. package/skills/weaver-e10-jinchengda/SKILL.md +111 -31
  143. package/skills/weaver-e10-jinchengda/references/contract-agent-entry.md +7 -13
  144. package/skills/weaver-e10-jinchengda/references/contract-ai-assistant.md +150 -0
  145. package/skills/weaver-e10-jinchengda/references/contract-ai-review.md +87 -0
  146. package/skills/weaver-e10-jinchengda/references/contract-clause-library-crud.md +111 -0
  147. package/skills/weaver-e10-jinchengda/references/contract-clause-recommender.md +0 -15
  148. package/skills/weaver-e10-jinchengda/references/contract-clause-reference-save.md +0 -13
  149. package/skills/weaver-e10-jinchengda/references/contract-credit-page.md +50 -0
  150. package/skills/weaver-e10-jinchengda/references/contract-disabled-capabilities.md +4 -2
  151. package/skills/weaver-e10-jinchengda/references/contract-doc-compare.md +74 -0
  152. package/skills/weaver-e10-jinchengda/references/contract-flow-launch.md +84 -0
  153. package/skills/weaver-e10-jinchengda/references/contract-performance-query.md +29 -0
  154. package/skills/weaver-e10-jinchengda/references/contract-quote-to-contract.md +28 -0
  155. package/skills/weaver-e10-jinchengda/references/contract-request-status.md +2 -21
  156. package/skills/weaver-e10-jinchengda/references/contract-request-write.md +0 -24
  157. package/skills/weaver-e10-jinchengda/references/contract-signing-subjects.md +0 -15
  158. package/skills/weaver-e10-jinchengda/references/contract-subject-create.md +0 -17
  159. package/skills/weaver-e10-jinchengda/references/contract-template-recommend.md +70 -0
  160. package/skills/weaver-e10-jinchengda/references/contract-template-selector.md +0 -15
  161. package/skills/weaver-e10-jinchengda/references/contract-workflow-discovery.md +0 -15
  162. package/skills/weaver-e10-jinchengda/references/source-manifest.json +1168 -152
  163. package/skills/weaver-e10-meeting/SKILL.md +493 -17
  164. package/skills/weaver-e10-meeting/references/meeting-change.md +4 -4
  165. package/skills/weaver-e10-meeting/references/meeting-create.md +6 -6
  166. package/skills/weaver-e10-meeting/references/meeting-eb.md +503 -27
  167. package/skills/weaver-e10-meeting/references/meeting-invitation.md +113 -0
  168. package/skills/weaver-e10-meeting/references/meeting-lifecycle.md +6 -6
  169. package/skills/weaver-e10-meeting/references/meeting-minute-file.md +425 -0
  170. package/skills/weaver-e10-meeting/references/meeting-queries.md +4 -4
  171. package/skills/weaver-e10-meeting/references/meeting-receipts-signs.md +15 -15
  172. package/skills/weaver-e10-meeting/references/meeting-verification.md +19 -11
  173. package/skills/weaver-e10-meeting.zip +0 -0
  174. package/skills/weaver-e10-yepiaotong/SKILL.md +9 -5
  175. package/skills/weaver-e10-yepiaotong/references/invoice-enterprise-list.md +1 -1
  176. package/skills/weaver-e10-yepiaotong/references/invoice-personal-list.md +6 -5
  177. package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +14 -11
  178. package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +97 -56
  179. package/skills/weaver-e10-yepiaotong/references/reim-examples.md +84 -60
  180. package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +142 -105
  181. package/skills/weaver-e10-yepiaotong/references/reim-matching-rules.md +53 -194
  182. package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +7 -7
  183. package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +164 -72
  184. package/skills/weaver-e10-yepiaotong/references/source-manifest.json +6 -0
  185. package/templates/meeting/invitation.docx +0 -0
@@ -0,0 +1,83 @@
1
+ import { contractValidationError } from '../errors.js';
2
+ import { reviewPageUrl } from './page.js';
3
+ import { requireNonEmptyString } from './shared.js';
4
+ import { assertContractDocument, uploadFile } from './upload.js';
5
+ /** 固定 AI 审查助手 ID,只用于导出审查记录接口,不要拼到审查页地址上。 */
6
+ export const AI_REVIEW_ASSISTANT_ID = '1326842382967570463';
7
+ const MAX_FILES = 10;
8
+ const SCLX_PATTERN = /^[1-3](?:,[1-3]){0,2}$/u;
9
+ function normalizeSclx(value) {
10
+ if (value === undefined || value === null || value === '')
11
+ return '1,2,3';
12
+ if (typeof value !== 'string' || !SCLX_PATTERN.test(value)) {
13
+ throw contractValidationError('sclx_invalid', 'sclx 只能是 "1"、"2"、"3" 或它们的逗号组合(如 "1,2,3")');
14
+ }
15
+ return value;
16
+ }
17
+ function collectRecords(value) {
18
+ const data = value?.data;
19
+ if (Array.isArray(data))
20
+ return data;
21
+ if (data && typeof data === 'object') {
22
+ const arrays = Object.values(data).filter(Array.isArray);
23
+ if (arrays.length)
24
+ return arrays.flat();
25
+ return Object.keys(data).length ? [data] : [];
26
+ }
27
+ return [];
28
+ }
29
+ export const contractReviewOperations = [
30
+ {
31
+ name: 'contract.review.upload',
32
+ async execute(input, { host }) {
33
+ const paths = input.paths;
34
+ if (!Array.isArray(paths) || paths.length === 0) {
35
+ throw contractValidationError('paths_required', 'paths 必须是非空的本地合同文件路径数组');
36
+ }
37
+ if (paths.length > MAX_FILES) {
38
+ throw contractValidationError('paths_too_many', `一次最多上传 ${MAX_FILES} 份合同`);
39
+ }
40
+ const files = [];
41
+ for (const rawPath of paths) {
42
+ const path = requireNonEmptyString(rawPath, 'paths[]', 1000);
43
+ assertContractDocument(path);
44
+ files.push(await uploadFile(host, { path, module: 'ebContract' }));
45
+ }
46
+ const session = await host.getSession();
47
+ return {
48
+ status: 'COMPLETE',
49
+ data: {
50
+ files,
51
+ url: reviewPageUrl(session.baseUrl, files),
52
+ page: { width: 1000 },
53
+ note: '把 url 原样放进 browsertool 的 arguments.url,并带 width: 1000;不要做整体编码',
54
+ },
55
+ };
56
+ },
57
+ },
58
+ {
59
+ name: 'contract.review.export',
60
+ async execute(input, { host }) {
61
+ const fileId = requireNonEmptyString(input.fileId, 'fileId', 64);
62
+ const sclx = normalizeSclx(input.sclx);
63
+ const value = await host.contractRequest({
64
+ method: 'POST',
65
+ path: '/api/ebd/contract/ai/getAiReviewRecord',
66
+ body: { sclx, fileId, ai_id: AI_REVIEW_ASSISTANT_ID },
67
+ timeoutMs: 120_000,
68
+ });
69
+ const records = collectRecords(value);
70
+ return {
71
+ status: records.length ? 'COMPLETE' : 'EMPTY',
72
+ data: {
73
+ fileId,
74
+ sclx,
75
+ aiId: AI_REVIEW_ASSISTANT_ID,
76
+ hasContent: records.length > 0,
77
+ records,
78
+ raw: value,
79
+ },
80
+ };
81
+ },
82
+ },
83
+ ];
@@ -70,6 +70,43 @@ function canonicalJson(value) {
70
70
  export function objectFingerprint(value) {
71
71
  return createHash('sha256').update(canonicalJson(value)).digest('hex');
72
72
  }
73
+ /**
74
+ * 写入指纹只覆盖业务字段。
75
+ * 默认指纹会把 continuation / confirm 一起算进去,导致 apply 必然 target_changed。
76
+ */
77
+ export function fingerprintFields(fields) {
78
+ return (input) => objectFingerprint(Object.fromEntries(fields.map((field) => [field, input[field] ?? null])));
79
+ }
80
+ /** 服务端要求 JSON 字符串的字段(pzxx / element_mxb / contract_rule_source / config 等):对象转字符串,字符串校验可解析。 */
81
+ export function toJsonString(value, name) {
82
+ if (typeof value === 'string') {
83
+ const trimmed = value.trim();
84
+ if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
85
+ throw contractValidationError('json_invalid', `${name} 必须是 JSON 对象/数组的字符串`);
86
+ }
87
+ try {
88
+ JSON.parse(trimmed);
89
+ }
90
+ catch {
91
+ throw contractValidationError('json_invalid', `${name} 必须是可解析的 JSON 字符串`);
92
+ }
93
+ return trimmed;
94
+ }
95
+ if (value === undefined || value === null || typeof value !== 'object') {
96
+ throw contractValidationError('input_invalid', `${name} 必须是对象/数组或其 JSON 字符串`);
97
+ }
98
+ return JSON.stringify(value);
99
+ }
100
+ /** 逗号分隔字符串或字符串数组,统一成正整数 id 列表。 */
101
+ export function idList(value, name) {
102
+ const raw = Array.isArray(value)
103
+ ? value
104
+ : typeof value === 'string' ? value.split(',') : undefined;
105
+ if (!raw || raw.length === 0) {
106
+ throw contractValidationError('input_invalid', `${name} 至少包含一个 id`);
107
+ }
108
+ return raw.map((item) => requireId(String(item).trim(), name));
109
+ }
73
110
  export function sessionMatches(lease, session) {
74
111
  return lease.baseUrl === session.baseUrl && lease.profile === session.profile && lease.userId === session.userId;
75
112
  }
@@ -0,0 +1,108 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readFile, stat } from 'node:fs/promises';
3
+ import { basename, resolve } from 'node:path';
4
+ import { contractPolicyError, contractValidationError } from '../errors.js';
5
+ const MAX_FILE_BYTES = 200 * 1024 * 1024;
6
+ const DEFAULT_UPLOAD_TIMEOUT_MS = 120_000;
7
+ const DOC_EXTENSIONS = new Set(['.doc', '.docx']);
8
+ function text(value) {
9
+ if (typeof value === 'string' && value.trim())
10
+ return value;
11
+ if (typeof value === 'number' && Number.isFinite(value))
12
+ return String(value);
13
+ return undefined;
14
+ }
15
+ function pickFileId(payload) {
16
+ return text(payload.fileid)
17
+ ?? text(payload.fileId)
18
+ ?? text(payload.uploadModuleDto?.fileid)
19
+ ?? text(payload.uploadModuleDto?.fileId);
20
+ }
21
+ /**
22
+ * 两段式文件上传:preUploadCheck 预检(命中秒传直接返回 fileId)→ module/upload 实传。
23
+ * 成功判据是拿到非空 fileId,HTTP 200 不算成功。
24
+ */
25
+ export async function uploadFile(host, options) {
26
+ const absolutePath = resolve(options.path);
27
+ const info = await stat(absolutePath).catch(() => null);
28
+ if (!info || !info.isFile()) {
29
+ throw contractValidationError('file_not_found', `文件不存在或不是普通文件:${options.path}`);
30
+ }
31
+ if (info.size === 0) {
32
+ throw contractValidationError('file_empty', `文件内容为空:${options.path}`);
33
+ }
34
+ if (info.size > MAX_FILE_BYTES) {
35
+ throw contractValidationError('file_too_large', `文件超过 ${MAX_FILE_BYTES / 1024 / 1024}MB 上限:${options.path}`);
36
+ }
37
+ const name = basename(absolutePath);
38
+ const buffer = await readFile(absolutePath);
39
+ const md5 = createHash('md5').update(buffer).digest('hex');
40
+ const modified = String(Math.trunc(info.mtimeMs));
41
+ const form = {
42
+ compressImg: 'false',
43
+ module: options.module,
44
+ ...(options.module === 'ebContract' ? { createDoc: 'true' } : {}),
45
+ ...(options.extraFields ?? {}),
46
+ size: String(buffer.length),
47
+ name,
48
+ MD5: md5,
49
+ lastModified: modified,
50
+ lastModifiedDate: modified,
51
+ };
52
+ const query = options.query ?? (options.module === 'ebContract' ? {} : { sf_request_type: 'ajax' });
53
+ const timeoutMs = options.timeoutMs ?? DEFAULT_UPLOAD_TIMEOUT_MS;
54
+ const precheck = await host.contractRequest({
55
+ method: 'POST',
56
+ path: '/api/file/preUploadCheck',
57
+ query,
58
+ form,
59
+ timeoutMs,
60
+ });
61
+ const precheckData = (precheck?.data ?? {});
62
+ const secondUploadId = pickFileId(precheckData);
63
+ if (secondUploadId) {
64
+ return {
65
+ fileId: secondUploadId,
66
+ docId: text(precheckData.docId) ?? text(precheckData.uploadModuleDto?.docId),
67
+ name: text(precheckData.name) ?? text(precheckData.uploadModuleDto?.name) ?? name,
68
+ size: buffer.length,
69
+ md5,
70
+ };
71
+ }
72
+ const preUploadId = text(precheckData.preUploadId);
73
+ const uploadType = text(precheckData.uploadType) ?? 'common';
74
+ if (!preUploadId) {
75
+ throw contractPolicyError('upload_precheck_failed', '上传预检未返回 preUploadId,也没有秒传 fileId;请核对 module、fieldId 与登录态', { path: '/api/file/preUploadCheck', module: options.module });
76
+ }
77
+ if (uploadType === 'chunk') {
78
+ throw contractPolicyError('upload_chunk_unsupported', '服务端要求分片上传(uploadType=chunk),当前 CLI 尚未实现分片链路,请改用较小文件或补充分片接口契约', { module: options.module, chunkSize: precheckData.chunkDto?.chunkSize });
79
+ }
80
+ const uploaded = await host.contractRequest({
81
+ method: 'POST',
82
+ path: '/api/file/module/upload',
83
+ query,
84
+ form: { ...form, preUploadId, uploadType },
85
+ file: { path: absolutePath, filename: name },
86
+ timeoutMs,
87
+ });
88
+ const uploadData = (uploaded?.data ?? {});
89
+ const fileId = pickFileId(uploadData);
90
+ if (!fileId) {
91
+ throw contractPolicyError('upload_no_fileid', '上传接口未返回 fileId,上传未完成;请核对登录态、module 与文件本体是否随请求发送', { module: options.module });
92
+ }
93
+ return {
94
+ fileId,
95
+ docId: text(uploadData.docId) ?? text(uploadData.uploadModuleDto?.docId),
96
+ name: text(uploadData.name) ?? name,
97
+ size: buffer.length,
98
+ md5,
99
+ };
100
+ }
101
+ export function assertContractDocument(path) {
102
+ const lower = path.toLowerCase();
103
+ const dot = lower.lastIndexOf('.');
104
+ const ext = dot >= 0 ? lower.slice(dot) : '';
105
+ if (!DOC_EXTENSIONS.has(ext)) {
106
+ throw contractValidationError('file_type_unsupported', `合同智能审查与流程发起仅支持 .doc/.docx:${path}`);
107
+ }
108
+ }
@@ -22,9 +22,10 @@ export class ContractWritePrepareOperation {
22
22
  const session = await host.getSession();
23
23
  const preview = this.spec.preview(input);
24
24
  const baseName = baseNameOf(this.name);
25
+ const resolvedPath = this.spec.pathOf ? this.spec.pathOf(input) : this.spec.path;
25
26
  const continuationToken = await continuation.issue({
26
27
  operation: this.applyName,
27
- path: this.spec.path,
28
+ path: resolvedPath,
28
29
  baseUrl: session.baseUrl,
29
30
  profile: session.profile,
30
31
  userId: session.userId,
@@ -75,7 +76,7 @@ export class ContractWriteApplyOperation {
75
76
  try {
76
77
  result = await host.contractRequest({
77
78
  method: this.spec.method,
78
- path: this.spec.path,
79
+ path: this.spec.pathOf ? this.spec.pathOf(input) : this.spec.path,
79
80
  body,
80
81
  ...(this.spec.userIdField ? { userIdField: this.spec.userIdField } : {}),
81
82
  });
@@ -1,42 +1,142 @@
1
- import { caizhilianShortcut } from './caizhilian/index.js';
2
- import { projectShortcut } from './project/index.js';
3
- import { blogShortcut } from './blog/index.js';
4
- import { archiveShortcut } from './archive/index.js';
5
- import { archiveOaShortcut } from './archive-oa/index.js';
6
- import { calendarShortcut } from './calendar/index.js';
7
- import { ehrShortcut } from './ehr/index.js';
8
- import { esbShortcut } from './esb/index.js';
9
- import { fnaShortcut } from './fna/index.js';
10
- import { hrmShortcut } from './hrm/index.js';
11
- import { invoiceShortcut } from './invoice/index.js';
12
- import { mailShortcut } from './mail/index.js';
13
- import { meetingShortcut } from './meeting/index.js';
14
- import { okrShortcut } from './okr/index.js';
15
- import { planShortcut } from './plan/index.js';
16
- import { jiuchuanhuiShortcut } from './jiuchuanhui/index.js';
17
- import { assetShortcut } from './asset/index.js';
18
- import { ebuilderFormShortcut } from './ebuilder-form/index.js';
19
- import { imShortcut } from './im/index.js';
20
- import { workflowShortcut } from './workflow/index.js';
1
+ function lazyShortcut(definition) {
2
+ return {
3
+ name: definition.name,
4
+ description: definition.description,
5
+ category: 'shortcut',
6
+ load: definition.load,
7
+ register({ program }) {
8
+ const placeholder = program.command(definition.name).description(definition.description);
9
+ // 占位的唯一职责是"接住 argv":子命令、未知选项、多余参数一律放行,不做任何校验。
10
+ placeholder.allowUnknownOption(true);
11
+ placeholder.allowExcessArguments(true);
12
+ // `-h` 也要放行到重放那一步,否则这里会打出"占位命令"的空帮助(只有 5 个 IO 选项),
13
+ // 而不是真实命令树的帮助。
14
+ placeholder.helpOption(false);
15
+ placeholder.action(async () => {
16
+ const { dispatchLazyShortcut } = await import('../cmd/lazy-dispatch.js');
17
+ await dispatchLazyShortcut(definition, shortcutMetadata());
18
+ });
19
+ },
20
+ };
21
+ }
22
+ /**
23
+ * 全部 shortcut 的**元数据清单**(不含实现)。
24
+ *
25
+ * 顺序即 `commands list` / 顶层 `--help` 的展示顺序,与改造前**完全一致**,不要随手调换。
26
+ */
21
27
  export const builtinShortcuts = [
22
- invoiceShortcut,
23
- ehrShortcut,
24
- archiveShortcut,
25
- archiveOaShortcut,
26
- calendarShortcut,
27
- fnaShortcut,
28
- hrmShortcut,
29
- mailShortcut,
30
- meetingShortcut,
31
- okrShortcut,
32
- planShortcut,
33
- esbShortcut,
34
- ebuilderFormShortcut,
35
- jiuchuanhuiShortcut,
36
- assetShortcut,
37
- imShortcut,
38
- projectShortcut,
39
- workflowShortcut,
40
- blogShortcut,
41
- caizhilianShortcut
28
+ lazyShortcut({
29
+ name: 'invoice',
30
+ description: 'E10 业票通发票管理 CLI',
31
+ load: async () => (await import('./invoice/index.js')).invoiceShortcut,
32
+ }),
33
+ lazyShortcut({
34
+ name: 'ehr',
35
+ description: '泛微E10聚才林(人事/出勤/薪酬)CLI',
36
+ load: async () => (await import('./ehr/index.js')).ehrShortcut,
37
+ }),
38
+ lazyShortcut({
39
+ name: 'archive',
40
+ description: 'E10 文书定档案管理 CLI',
41
+ load: async () => (await import('./archive/index.js')).archiveShortcut,
42
+ }),
43
+ lazyShortcut({
44
+ name: 'archive-oa',
45
+ description: 'E10 档案定位与 OA 商务合同借阅 CLI',
46
+ load: async () => (await import('./archive-oa/index.js')).archiveOaShortcut,
47
+ }),
48
+ lazyShortcut({
49
+ name: 'calendar',
50
+ description: '泛微E10日程管理 CLI(创建/查询/更新/删除/字典)',
51
+ load: async () => (await import('./calendar/index.js')).calendarShortcut,
52
+ }),
53
+ lazyShortcut({
54
+ name: 'fna',
55
+ description: '泛微E10齐业成费控中心(预算/费用中心/借款管理/发票核销)CLI',
56
+ load: async () => (await import('./fna/index.js')).fnaShortcut,
57
+ }),
58
+ lazyShortcut({
59
+ name: 'hrm',
60
+ description: '泛微E10组织管理(员工/组织/岗位查询)CLI',
61
+ load: async () => (await import('./hrm/index.js')).hrmShortcut,
62
+ }),
63
+ lazyShortcut({
64
+ name: 'mail',
65
+ description: '泛微E10邮件管理 CLI',
66
+ load: async () => (await import('./mail/index.js')).mailShortcut,
67
+ }),
68
+ lazyShortcut({
69
+ name: 'meeting',
70
+ description: '泛微E10会议管理 CLI(标准版:查询/冲突/预约/回执/签到)',
71
+ load: async () => (await import('./meeting/index.js')).meetingShortcut,
72
+ }),
73
+ lazyShortcut({
74
+ name: 'okr',
75
+ description: '泛微E10 OKR 目标管理 CLI(目标查询/新建/编辑、关键成果、目标对齐、评论)',
76
+ load: async () => (await import('./okr/index.js')).okrShortcut,
77
+ }),
78
+ lazyShortcut({
79
+ name: 'plan',
80
+ description: '泛微E10计划报告 CLI(查询/新建/修改/发布/撤回/提交提醒/评论)',
81
+ load: async () => (await import('./plan/index.js')).planShortcut,
82
+ }),
83
+ lazyShortcut({
84
+ name: 'esb',
85
+ description: '泛微E10 ESB 中心自定义触发动作流 CLI',
86
+ load: async () => (await import('./esb/index.js')).esbShortcut,
87
+ }),
88
+ lazyShortcut({
89
+ name: 'ebuilder-form',
90
+ description: '泛微E10 eBuilder 表单菜单、列表和表单数据 CLI',
91
+ load: async () => (await import('./ebuilder-form/index.js')).ebuilderFormShortcut,
92
+ }),
93
+ lazyShortcut({
94
+ name: 'jiuchuanhui',
95
+ description: '泛微E10九氚汇营销管理 CLI(客户/联系人/商机/线索/联系计划/公海)',
96
+ load: async () => (await import('./jiuchuanhui/index.js')).jiuchuanhuiShortcut,
97
+ }),
98
+ lazyShortcut({
99
+ name: 'asset',
100
+ description: 'E10 资产管理(资管家)CLI',
101
+ load: async () => (await import('./asset/index.js')).assetShortcut,
102
+ }),
103
+ lazyShortcut({
104
+ name: 'im',
105
+ description: '泛微E10易秒办(即时通讯)CLI',
106
+ load: async () => (await import('./im/index.js')).imShortcut,
107
+ }),
108
+ lazyShortcut({
109
+ name: 'project',
110
+ description: '泛微E10事井然项目管理 CLI(项目/任务查询与确认写入)',
111
+ load: async () => (await import('./project/index.js')).projectShortcut,
112
+ }),
113
+ lazyShortcut({
114
+ name: 'workflow',
115
+ description: '泛微E10流程智能助手 CLI(查询/查看/操作/批量/发起/修改)',
116
+ load: async () => (await import('./workflow/index.js')).workflowShortcut,
117
+ }),
118
+ lazyShortcut({
119
+ name: 'blog',
120
+ description: '泛微E10工作日报 CLI(查询/发布/编辑/评论/点赞/提醒/导出)',
121
+ load: async () => (await import('./blog/index.js')).blogShortcut,
122
+ }),
123
+ lazyShortcut({
124
+ name: 'caizhilian',
125
+ description: '泛微E10采知连(文档中心)CLI',
126
+ load: async () => (await import('./caizhilian/index.js')).caizhilianShortcut,
127
+ }),
42
128
  ];
129
+ /** 全部 shortcut 的 CLI 元数据(不触发任何实现模块加载)。 */
130
+ export function shortcutMetadata() {
131
+ return builtinShortcuts;
132
+ }
133
+ /** 按需加载:只 import 名字命中的那几个。 */
134
+ export async function loadShortcuts(names) {
135
+ const wanted = new Set(names);
136
+ const hits = builtinShortcuts.filter((shortcut) => wanted.has(shortcut.name));
137
+ return Promise.all(hits.map((shortcut) => shortcut.load()));
138
+ }
139
+ /** 全量加载(只在"argv 里那个名字既不是内建命令、也不是已知 shortcut"时兜底用)。 */
140
+ export async function loadAllShortcuts() {
141
+ return Promise.all(builtinShortcuts.map((shortcut) => shortcut.load()));
142
+ }
@@ -24,6 +24,15 @@ function epochDateProperty(label) {
24
24
  description: `${label}。可传 YYYY-MM-DD(按东八区零点换算)或秒级时间戳。`,
25
25
  };
26
26
  }
27
+ function epochEndDateProperty(label) {
28
+ return {
29
+ oneOf: [
30
+ { type: 'integer', minimum: 0 },
31
+ { type: 'string', pattern: '^\\d{4}-\\d{2}-\\d{2}$' },
32
+ ],
33
+ description: `${label}。可传 YYYY-MM-DD(按东八区当天 23:59:59 换算)或秒级时间戳。`,
34
+ };
35
+ }
27
36
  const listProperties = {
28
37
  page_size: { type: 'integer', minimum: 1, maximum: 200 },
29
38
  start_pos: { type: 'integer', minimum: 0 },
@@ -36,6 +45,8 @@ const listProperties = {
36
45
  date_end: epochDateProperty('开票日期止(含)'),
37
46
  create_tm_begin: epochDateProperty('创建时间起(含)'),
38
47
  create_tm_end: epochDateProperty('创建时间止(含)'),
48
+ consumption_tm_begin: epochDateProperty('消费日期起(含)'),
49
+ consumption_tm_end: epochEndDateProperty('消费日期止(含)'),
39
50
  payer_company: { type: 'string' },
40
51
  buyer_company: { type: 'string' },
41
52
  payer_taxno: { type: 'string' },
@@ -478,14 +489,11 @@ const requestListDataSchema = arrayOf(objectSchema({
478
489
  requestid: { type: 'string' },
479
490
  workflowid: { type: 'string' },
480
491
  requestname: { type: 'string' },
481
- requestnametitle: { type: 'string' },
482
492
  flowStatus: { type: 'integer' },
483
493
  creatorId: { type: 'string' },
484
494
  creatorName: { type: 'string' },
485
- creatorDepartmentId: { type: 'string' },
486
- nodeid: { type: 'string' },
487
495
  createTime: { type: 'string' },
488
- }, ['requestid', 'workflowid', 'requestname'], true));
496
+ }, ['requestid', 'workflowid', 'requestname']));
489
497
  const workflowResolveDataSchema = objectSchema({
490
498
  requestWorkflowMap: objectSchema({}, [], objectSchema({
491
499
  workFlowId: { type: 'string' },
@@ -532,11 +540,12 @@ const employeeSuperiorsDataSchema = objectSchema({
532
540
  currentEmployee: employeeSchema,
533
541
  allSuperiors: arrayOf(employeeSchema),
534
542
  }, ['currentEmployee', 'allSuperiors'], true);
535
- const fieldSearchDataSchema = arrayOf(objectSchema({
543
+ const fieldSearchItemSchema = objectSchema({
536
544
  id: { type: 'string' },
537
545
  name: { type: 'string' },
538
546
  value: { type: 'string' },
539
- }, ['id', 'name'], true));
547
+ }, ['id', 'name'], true);
548
+ const fieldSearchItemsSchema = arrayOf(fieldSearchItemSchema);
540
549
  const flowPreviewOutputSchema = objectSchema({
541
550
  requestName: { type: 'string' },
542
551
  workflowId: { type: 'string' },
@@ -987,16 +996,20 @@ export const invoiceOperations = [
987
996
  {
988
997
  name: 'invoice.reim.requests.list',
989
998
  risk: 'read',
990
- fixed: { path: '/api/inc/book/getRequestListByTabId', defaultPageNo: 1, defaultPageSize: 20 },
999
+ fixed: { path: '/api/inc/book/getRequestListByTabId', defaultPageNo: 1, defaultPageSize: 100, defaultCusCreateDateEnd: 'passedOrShanghaiToday+1' },
991
1000
  inputSchema: {
992
1001
  type: 'object',
993
1002
  additionalProperties: false,
994
1003
  properties: {
995
1004
  pageNo: { type: 'integer', minimum: 1, maximum: 10000, default: 1 },
996
- pageSize: { type: 'integer', minimum: 1, maximum: 200, default: 20 },
1005
+ pageSize: { type: 'integer', minimum: 1, maximum: 200, default: 100, description: '每页条数。不传时默认 100。' },
997
1006
  requestname: { type: 'string', minLength: 1 },
998
1007
  cusCreateDateStart: { type: 'string', pattern: '^\\d{4}-\\d{2}-\\d{2}$' },
999
- cusCreateDateEnd: { type: 'string', pattern: '^\\d{4}-\\d{2}-\\d{2}$' },
1008
+ cusCreateDateEnd: {
1009
+ type: 'string',
1010
+ pattern: '^\\d{4}-\\d{2}-\\d{2}$',
1011
+ description: '发起日期结束(YYYY-MM-DD)。不传时按东八区当天 + 1 天填入;传入时按该日期再 + 1 天后发给接口。调用方传业务结束日本身,不要自己再加 1 天。',
1012
+ },
1000
1013
  },
1001
1014
  },
1002
1015
  outputSchema: resultEnvelopeOutput(requestListDataSchema),
@@ -1086,7 +1099,7 @@ export const invoiceOperations = [
1086
1099
  {
1087
1100
  name: 'invoice.reim.field.search',
1088
1101
  risk: 'read',
1089
- fixed: { path: '/api/government/formStructure/fieldRelateSearch', formModeType: 'wf', defaultNodeId: '100004140000000271' },
1102
+ fixed: { path: '/api/government/formStructure/fieldRelateSearch', method: 'GET', formModeType: 'wf', defaultNodeId: '100004140000000271' },
1090
1103
  inputSchema: {
1091
1104
  type: 'object',
1092
1105
  additionalProperties: false,
@@ -1098,7 +1111,15 @@ export const invoiceOperations = [
1098
1111
  },
1099
1112
  required: ['keywords', 'fieldId', 'workflowId'],
1100
1113
  },
1101
- outputSchema: resultEnvelopeOutput(fieldSearchDataSchema),
1114
+ outputSchema: objectSchema({
1115
+ result: rawObject,
1116
+ data: fieldSearchItemsSchema,
1117
+ keywords: { type: 'string' },
1118
+ match: { type: 'string', enum: ['unique', 'multiple', 'none'] },
1119
+ items: fieldSearchItemsSchema,
1120
+ selected: { anyOf: [fieldSearchItemSchema, { type: 'null' }] },
1121
+ workflow: workflowSchema,
1122
+ }, ['result', 'data', 'keywords', 'match', 'items', 'workflow']),
1102
1123
  },
1103
1124
  {
1104
1125
  name: 'invoice.reim.flow.create.prepare',
@@ -1166,6 +1187,8 @@ export const invoiceOperations = [
1166
1187
  properties: {
1167
1188
  date_begin: { type: 'string', pattern: '^\\d{4}-\\d{2}-\\d{2}$', description: '开票日期起(YYYY-MM-DD,含)。' },
1168
1189
  date_end: { type: 'string', pattern: '^\\d{4}-\\d{2}-\\d{2}$', description: '开票日期止(YYYY-MM-DD,含)。' },
1190
+ consumption_tm_begin: epochDateProperty('消费日期起(含)'),
1191
+ consumption_tm_end: epochEndDateProperty('消费日期止(含)'),
1169
1192
  page_size: { type: 'integer', minimum: 10, maximum: 200, default: 50, description: '单页条数。' },
1170
1193
  max_items: { type: 'integer', minimum: 1, maximum: 500, default: 200, description: '最多拉取条数(不含被过滤的红冲票),超出截断并产生 warning。' },
1171
1194
  include_red_reversed: { type: 'boolean', default: false, description: '是否在结果中保留全额红冲(status=8)发票。默认 false —— 报销场景直接过滤掉,过滤张数由 summary.filteredRedReversedCount 告知,不会静默丢失。' },
@@ -592,9 +592,14 @@ export class InvoiceReimCandidatesListOperation {
592
592
  const includeRedReversed = input.include_red_reversed === true;
593
593
  const dateBegin = optionalEpochSeconds(input.date_begin, 'date_begin');
594
594
  const dateEnd = optionalEpochSeconds(input.date_end, 'date_end');
595
+ const consumptionBegin = optionalEpochSeconds(input.consumption_tm_begin, 'consumption_tm_begin');
596
+ const consumptionEnd = optionalEpochSeconds(input.consumption_tm_end, 'consumption_tm_end', { endOfDay: true });
595
597
  if (dateBegin !== undefined && dateEnd !== undefined && dateBegin > dateEnd) {
596
598
  throw invoiceValidationError('input_invalid', 'date_begin 不能晚于 date_end');
597
599
  }
600
+ if (consumptionBegin !== undefined && consumptionEnd !== undefined && consumptionBegin > consumptionEnd) {
601
+ throw invoiceValidationError('input_invalid', 'consumption_tm_begin 不能晚于 consumption_tm_end');
602
+ }
598
603
  const warnings = [];
599
604
  const kept = [];
600
605
  let total = 0;
@@ -616,6 +621,10 @@ export class InvoiceReimCandidatesListOperation {
616
621
  body.date_begin = dateBegin;
617
622
  if (dateEnd !== undefined)
618
623
  body.date_end = dateEnd;
624
+ if (consumptionBegin !== undefined)
625
+ body.consumption_tm_begin = consumptionBegin;
626
+ if (consumptionEnd !== undefined)
627
+ body.consumption_tm_end = consumptionEnd;
619
628
  const result = await host.invoiceRequest({ path: '/api/inc/sync', method: 'POST', body, operation: this.name });
620
629
  total = Number(result?.total ?? 0);
621
630
  const infos = Array.isArray(result?.infos) ? result.infos : [];