weaver-work-cli 0.1.8 → 0.1.21

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 (271) hide show
  1. package/README.md +25 -17
  2. package/dist/cmd/action.js +76 -0
  3. package/dist/cmd/index.js +2 -0
  4. package/dist/cmd/refs/index.js +103 -0
  5. package/dist/cmd/register.js +31 -0
  6. package/dist/cmd/root.js +1 -0
  7. package/dist/cmd/setup/index.js +25 -5
  8. package/dist/cmd/skills/index.js +37 -5
  9. package/dist/core/connector.js +54 -0
  10. package/dist/core/context.js +2 -1
  11. package/dist/core/input.js +48 -0
  12. package/dist/core/output.js +298 -3
  13. package/dist/core/refs.js +435 -0
  14. package/dist/core/state.js +26 -0
  15. package/dist/internal/e10/auth/commands.js +34 -19
  16. package/dist/internal/e10/auth/session.js +74 -2
  17. package/dist/internal/e10/auth/xiaoe.js +359 -94
  18. package/dist/internal/e10/context.js +18 -6
  19. package/dist/internal/e10/request-runtime.js +8 -1
  20. package/dist/internal/skills/install.js +148 -28
  21. package/dist/internal/skills/reader.js +12 -9
  22. package/dist/shortcuts/blog/continuation.js +74 -0
  23. package/dist/shortcuts/blog/errors.js +60 -0
  24. package/dist/shortcuts/blog/host.js +175 -0
  25. package/dist/shortcuts/blog/index.js +324 -0
  26. package/dist/shortcuts/blog/manifest.js +415 -0
  27. package/dist/shortcuts/blog/operations/comment.js +125 -0
  28. package/dist/shortcuts/blog/operations/comments.js +31 -0
  29. package/dist/shortcuts/blog/operations/edit.js +131 -0
  30. package/dist/shortcuts/blog/operations/export.js +46 -0
  31. package/dist/shortcuts/blog/operations/like.js +80 -0
  32. package/dist/shortcuts/blog/operations/publish.js +157 -0
  33. package/dist/shortcuts/blog/operations/query-user.js +58 -0
  34. package/dist/shortcuts/blog/operations/query.js +96 -0
  35. package/dist/shortcuts/blog/operations/registry.js +54 -0
  36. package/dist/shortcuts/blog/operations/remind.js +176 -0
  37. package/dist/shortcuts/blog/operations/shared.js +330 -0
  38. package/dist/shortcuts/blog/operations/types.js +16 -0
  39. package/dist/shortcuts/blog/operations.js +9 -0
  40. package/dist/shortcuts/caizhilian/continuation.js +70 -0
  41. package/dist/shortcuts/caizhilian/errors.js +53 -0
  42. package/dist/shortcuts/caizhilian/host.js +190 -0
  43. package/dist/shortcuts/caizhilian/index.js +186 -0
  44. package/dist/shortcuts/caizhilian/manifest.js +42 -0
  45. package/dist/shortcuts/caizhilian/operations/api.js +801 -0
  46. package/dist/shortcuts/caizhilian/operations/confirm.js +75 -0
  47. package/dist/shortcuts/caizhilian/operations/files.js +306 -0
  48. package/dist/shortcuts/caizhilian/operations/form.js +170 -0
  49. package/dist/shortcuts/caizhilian/operations/handlers/collab.js +611 -0
  50. package/dist/shortcuts/caizhilian/operations/handlers/document.js +890 -0
  51. package/dist/shortcuts/caizhilian/operations/handlers/file-collection.js +1227 -0
  52. package/dist/shortcuts/caizhilian/operations/handlers/file-upload.js +192 -0
  53. package/dist/shortcuts/caizhilian/operations/handlers/fileops.js +570 -0
  54. package/dist/shortcuts/caizhilian/operations/handlers/folder.js +1024 -0
  55. package/dist/shortcuts/caizhilian/operations/handlers/search.js +318 -0
  56. package/dist/shortcuts/caizhilian/operations/handlers/setting-attach.js +294 -0
  57. package/dist/shortcuts/caizhilian/operations/handlers/setting-backup.js +423 -0
  58. package/dist/shortcuts/caizhilian/operations/handlers/setting-encrypt.js +238 -0
  59. package/dist/shortcuts/caizhilian/operations/handlers/setting-storage.js +364 -0
  60. package/dist/shortcuts/caizhilian/operations/handlers/system.js +106 -0
  61. package/dist/shortcuts/caizhilian/operations/registry.js +151 -0
  62. package/dist/shortcuts/caizhilian/operations/shared.js +408 -0
  63. package/dist/shortcuts/caizhilian/operations/specs.js +698 -0
  64. package/dist/shortcuts/caizhilian/operations/types.js +57 -0
  65. package/dist/shortcuts/caizhilian/operations.js +21 -0
  66. package/dist/shortcuts/contract/continuation.js +70 -0
  67. package/dist/shortcuts/contract/errors.js +62 -0
  68. package/dist/shortcuts/contract/host.js +205 -0
  69. package/dist/shortcuts/contract/index.js +318 -0
  70. package/dist/shortcuts/contract/manifest.js +596 -0
  71. package/dist/shortcuts/contract/operations/clause-reference.js +78 -0
  72. package/dist/shortcuts/contract/operations/form-info.js +371 -0
  73. package/dist/shortcuts/contract/operations/read.js +118 -0
  74. package/dist/shortcuts/contract/operations/registry.js +43 -0
  75. package/dist/shortcuts/contract/operations/request.js +300 -0
  76. package/dist/shortcuts/contract/operations/shared.js +133 -0
  77. package/dist/shortcuts/contract/operations/subject.js +157 -0
  78. package/dist/shortcuts/contract/operations/template.js +81 -0
  79. package/dist/shortcuts/contract/operations/types.js +7 -0
  80. package/dist/shortcuts/contract/operations/workflow.js +52 -0
  81. package/dist/shortcuts/contract/operations/write.js +131 -0
  82. package/dist/shortcuts/contract/operations.js +8 -0
  83. package/dist/shortcuts/hrm/index.js +83 -2
  84. package/dist/shortcuts/hrm/manifest.js +16 -9
  85. package/dist/shortcuts/hrm/operations/employee.js +160 -30
  86. package/dist/shortcuts/hrm/operations/org.js +17 -3
  87. package/dist/shortcuts/hrm/operations/position.js +18 -2
  88. package/dist/shortcuts/hrm/operations/registry.js +2 -0
  89. package/dist/shortcuts/hrm/operations/resolve.js +449 -0
  90. package/dist/shortcuts/index.js +5 -1
  91. package/dist/shortcuts/invoice/index.js +74 -36
  92. package/dist/shortcuts/invoice/manifest.js +674 -4
  93. package/dist/shortcuts/invoice/markdown.js +172 -0
  94. package/dist/shortcuts/invoice/operations/add.js +3 -3
  95. package/dist/shortcuts/invoice/operations/delete.js +2 -2
  96. package/dist/shortcuts/invoice/operations/get.js +10 -2
  97. package/dist/shortcuts/invoice/operations/import.js +2 -2
  98. package/dist/shortcuts/invoice/operations/registry.js +8 -1
  99. package/dist/shortcuts/invoice/operations/reim-auto.js +719 -0
  100. package/dist/shortcuts/invoice/operations/reim.js +85 -2
  101. package/dist/shortcuts/invoice/operations/shared.js +75 -8
  102. package/dist/shortcuts/invoice/operations/update.js +2 -2
  103. package/dist/shortcuts/invoice/operations/upload-and-validate.js +93 -0
  104. package/dist/shortcuts/invoice/operations/validate-preview.js +2 -1
  105. package/dist/shortcuts/invoice/projection.js +328 -0
  106. package/dist/shortcuts/meeting/host.js +18 -1
  107. package/dist/shortcuts/meeting/manifest.js +30 -18
  108. package/dist/shortcuts/meeting/operations/eb/catalog.js +390 -0
  109. package/dist/shortcuts/meeting/operations/eb/conflict.js +389 -0
  110. package/dist/shortcuts/meeting/operations/eb/factory.js +389 -0
  111. package/dist/shortcuts/meeting/operations/eb/index.js +22 -0
  112. package/dist/shortcuts/meeting/operations/env.js +8 -1
  113. package/dist/shortcuts/meeting/operations/registry.js +2 -0
  114. package/dist/shortcuts/meeting/operations/signs.js +216 -2
  115. package/dist/shortcuts/workflow/endpoints.js +2 -1
  116. package/dist/shortcuts/workflow/errors.js +8 -2
  117. package/dist/shortcuts/workflow/host.js +11 -4
  118. package/dist/shortcuts/workflow/operations/form.js +1016 -590
  119. package/dist/shortcuts/workflow/operations/read.js +913 -231
  120. package/dist/shortcuts/workflow/operations/shared.js +21 -0
  121. package/dist/shortcuts/workflow/operations/write.js +750 -52
  122. package/dist/shortcuts/workflow/operations.js +36 -10
  123. package/docs/_catalog.md +6 -0
  124. package/docs/agent-invoice.md +5 -1
  125. package/docs/agent-io-channel-design.md +468 -0
  126. package/docs/agent-skill-install.md +9 -4
  127. package/docs/blog.md +123 -0
  128. package/docs/caizhilian.md +304 -0
  129. package/docs/contract.md +91 -0
  130. package/docs/e10-auth.md +4 -2
  131. package/docs/hrm.md +53 -11
  132. package/docs/invoice.md +5 -1
  133. package/docs/meeting.md +1 -1
  134. package/docs/operation-manual.md +15 -3
  135. package/docs/skill-review-2026-09-19.md +2 -2
  136. package/package.json +1 -1
  137. package/scripts/package-skill.mjs +32 -20
  138. package/scripts/xiaoe_env.py +118 -0
  139. package/skill-template/business-info.json +113 -14
  140. package/skill-template/domains/blog.md +24 -0
  141. package/skill-template/domains/caizhilian.md +22 -0
  142. package/skill-template/domains/hrm.md +2 -1
  143. package/skill-template/domains/jinchengda.md +23 -0
  144. package/skill-template/domains/meeting.md +1 -1
  145. package/skill-template/domains/workflow.md +1 -1
  146. package/skill-template/skill-template.md +1 -1
  147. package/skills/weaver-e10-blog/SKILL.md +111 -0
  148. package/skills/weaver-e10-blog/references/blog-comment.md +51 -0
  149. package/skills/weaver-e10-blog/references/blog-comments.md +39 -0
  150. package/skills/weaver-e10-blog/references/blog-default-permission.md +38 -0
  151. package/skills/weaver-e10-blog/references/blog-disabled-capabilities.md +11 -0
  152. package/skills/weaver-e10-blog/references/blog-edit.md +51 -0
  153. package/skills/weaver-e10-blog/references/blog-export.md +42 -0
  154. package/skills/weaver-e10-blog/references/blog-like.md +50 -0
  155. package/skills/weaver-e10-blog/references/blog-publish.md +52 -0
  156. package/skills/weaver-e10-blog/references/blog-query-user.md +45 -0
  157. package/skills/weaver-e10-blog/references/blog-query.md +49 -0
  158. package/skills/weaver-e10-blog/references/blog-remind.md +51 -0
  159. package/skills/weaver-e10-blog/references/blog-resolve-users.md +38 -0
  160. package/skills/weaver-e10-blog/references/source-manifest.json +1540 -0
  161. package/skills/weaver-e10-caizhilian/SKILL.md +217 -0
  162. package/skills/weaver-e10-caizhilian/references/agent-entry.md +106 -0
  163. package/skills/weaver-e10-caizhilian/references/collaboration.md +112 -0
  164. package/skills/weaver-e10-caizhilian/references/document.md +111 -0
  165. package/skills/weaver-e10-caizhilian/references/file-collection.md +173 -0
  166. package/skills/weaver-e10-caizhilian/references/file-upload.md +309 -0
  167. package/skills/weaver-e10-caizhilian/references/files.md +120 -0
  168. package/skills/weaver-e10-caizhilian/references/folder.md +122 -0
  169. package/skills/weaver-e10-caizhilian/references/org-browser.md +104 -0
  170. package/skills/weaver-e10-caizhilian/references/setting-attach.md +440 -0
  171. package/skills/weaver-e10-caizhilian/references/setting-backup.md +372 -0
  172. package/skills/weaver-e10-caizhilian/references/setting-encrypt.md +399 -0
  173. package/skills/weaver-e10-caizhilian/references/setting-storage.md +603 -0
  174. package/skills/weaver-e10-caizhilian/references/source-manifest.json +5694 -0
  175. package/skills/weaver-e10-caizhilian/references/withheld.md +93 -0
  176. package/skills/weaver-e10-caizhilian/references/write-protocol.md +120 -0
  177. package/skills/weaver-e10-calendar/SKILL.md +4 -3
  178. package/skills/weaver-e10-ebuilder-form/SKILL.md +4 -9
  179. package/skills/weaver-e10-ebuilder-form/references/context-routing.md +0 -9
  180. package/skills/weaver-e10-ebuilder-form/references/custom-api.md +1 -5
  181. package/skills/weaver-e10-ebuilder-form/references/fields-browser.md +1 -5
  182. package/skills/weaver-e10-ebuilder-form/references/list-nlist.md +1 -5
  183. package/skills/weaver-e10-ebuilder-form/references/openapi-read.md +1 -5
  184. package/skills/weaver-e10-ebuilder-form/references/openapi-write.md +1 -5
  185. package/skills/weaver-e10-esb/SKILL.md +2 -2
  186. package/skills/weaver-e10-esb/references/source-manifest.json +9 -9
  187. package/skills/weaver-e10-hrm/SKILL.md +104 -9
  188. package/skills/weaver-e10-hrm/references/employee.md +89 -15
  189. package/skills/weaver-e10-hrm/references/org.md +114 -5
  190. package/skills/weaver-e10-hrm/references/position.md +14 -7
  191. package/skills/weaver-e10-hrm/references/source-manifest.json +1 -1
  192. package/skills/weaver-e10-jinchengda/SKILL.md +167 -0
  193. package/skills/weaver-e10-jinchengda/references/contract-agent-entry.md +82 -0
  194. package/skills/weaver-e10-jinchengda/references/contract-clause-recommender.md +69 -0
  195. package/skills/weaver-e10-jinchengda/references/contract-clause-reference-save.md +78 -0
  196. package/skills/weaver-e10-jinchengda/references/contract-disabled-capabilities.md +27 -0
  197. package/skills/weaver-e10-jinchengda/references/contract-request-status.md +71 -0
  198. package/skills/weaver-e10-jinchengda/references/contract-request-write.md +94 -0
  199. package/skills/weaver-e10-jinchengda/references/contract-signing-subjects.md +89 -0
  200. package/skills/weaver-e10-jinchengda/references/contract-subject-create.md +77 -0
  201. package/skills/weaver-e10-jinchengda/references/contract-template-selector.md +66 -0
  202. package/skills/weaver-e10-jinchengda/references/contract-workflow-discovery.md +94 -0
  203. package/skills/weaver-e10-jinchengda/references/source-manifest.json +259 -0
  204. package/skills/weaver-e10-jiuchuanhui/SKILL.md +5 -11
  205. package/skills/weaver-e10-jucailin/SKILL.md +4 -3
  206. package/skills/weaver-e10-mail/SKILL.md +4 -11
  207. package/skills/weaver-e10-meeting/SKILL.md +66 -32
  208. package/skills/weaver-e10-meeting/references/meeting-change.md +5 -2
  209. package/skills/weaver-e10-meeting/references/meeting-create.md +2 -1
  210. package/skills/weaver-e10-meeting/references/meeting-eb.md +114 -0
  211. package/skills/weaver-e10-meeting/references/meeting-lifecycle.md +9 -8
  212. package/skills/weaver-e10-meeting/references/meeting-receipts-signs.md +35 -7
  213. package/skills/weaver-e10-meeting/references/meeting-update.md +1 -1
  214. package/skills/weaver-e10-okr/SKILL.md +6 -11
  215. package/skills/weaver-e10-okr/references/source-manifest.json +3 -3
  216. package/skills/weaver-e10-plan/SKILL.md +3 -3
  217. package/skills/weaver-e10-plan/references/plan-collect-and-compose.md +1 -1
  218. package/skills/weaver-e10-plan/references/plan-overview-and-routing.md +1 -1
  219. package/skills/weaver-e10-plan/references/source-manifest.json +13 -13
  220. package/skills/weaver-e10-qiyecheng/SKILL.md +4 -10
  221. package/skills/weaver-e10-qiyecheng/references/source-manifest.json +9 -9
  222. package/skills/weaver-e10-shared/SKILL.md +42 -34
  223. package/skills/weaver-e10-shared/references/e10-auth-and-session.md +16 -43
  224. package/skills/weaver-e10-shared/references/json-output-contract.md +20 -11
  225. package/skills/weaver-e10-shared/references/non-interactive-environment.md +21 -14
  226. package/skills/weaver-e10-shijingran/SKILL.md +2 -1
  227. package/skills/weaver-e10-shijingran/references/source-manifest.json +9 -9
  228. package/skills/weaver-e10-skill-maker/SKILL.md +4 -10
  229. package/skills/weaver-e10-skill-maker/references/business-skill-generation.md +5 -3
  230. package/skills/weaver-e10-skill-maker/references/module-cli-generation.md +12 -27
  231. package/skills/weaver-e10-skill-maker/references/module-gap-audit-and-repair.md +17 -5
  232. package/skills/weaver-e10-skill-maker/references/source-update-detection.md +4 -27
  233. package/skills/weaver-e10-skill-maker/references/weaver-skill-style.md +1 -1
  234. package/skills/weaver-e10-wenshuding/SKILL.md +5 -16
  235. package/skills/weaver-e10-wenshuding/references/source-manifest.json +7 -7
  236. package/skills/weaver-e10-workflow/SKILL.md +41 -46
  237. package/skills/weaver-e10-workflow/references/source-manifest.json +39 -75
  238. package/skills/weaver-e10-workflow/references/workflow-batch.md +90 -29
  239. package/skills/weaver-e10-workflow/references/workflow-create.md +83 -109
  240. package/skills/weaver-e10-workflow/references/workflow-memory.md +19 -9
  241. package/skills/weaver-e10-workflow/references/workflow-operate.md +2 -2
  242. package/skills/weaver-e10-workflow/references/workflow-query.md +40 -27
  243. package/skills/weaver-e10-workflow/references/workflow-share.md +18 -2
  244. package/skills/weaver-e10-workflow/references/workflow-view.md +3 -4
  245. package/skills/weaver-e10-yepiaotong/SKILL.md +74 -39
  246. package/skills/weaver-e10-yepiaotong/references/invoice-detail.md +22 -1
  247. package/skills/weaver-e10-yepiaotong/references/invoice-enterprise-list.md +3 -1
  248. package/skills/weaver-e10-yepiaotong/references/invoice-output-view.md +135 -0
  249. package/skills/weaver-e10-yepiaotong/references/invoice-personal-list.md +15 -3
  250. package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +1 -1
  251. package/skills/weaver-e10-yepiaotong/references/invoice-summarize.py +217 -0
  252. package/skills/weaver-e10-yepiaotong/references/invoice-upload-and-validate.md +88 -0
  253. package/skills/weaver-e10-yepiaotong/references/invoice-validation-preview.md +7 -2
  254. package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +89 -9
  255. package/skills/weaver-e10-yepiaotong/references/reim-examples.md +1 -0
  256. package/skills/weaver-e10-yepiaotong/references/reim-expense-subject-rules.md +70 -49
  257. package/skills/weaver-e10-yepiaotong/references/reim-fast-path.md +119 -0
  258. package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +55 -36
  259. package/skills/weaver-e10-yepiaotong/references/reim-matching-rules.md +4 -0
  260. package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +149 -0
  261. package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +125 -5
  262. package/skills/weaver-e10-yepiaotong/references/source-manifest.json +430 -63
  263. package/skills/weaver-e10-yimiaoban/SKILL.md +4 -12
  264. package/skills/weaver-e10-yimiaoban/references/source-manifest.json +3 -3
  265. package/skills/weaver-e10-ziguanjia/SKILL.md +2 -1
  266. package/skills/weaver-e10-ziguanjia/references/ziguanjia-agent-entry.md +3 -3
  267. package/tools/weaver-skill-detector-1.0.13/SKILL.md +9 -9
  268. package/tools/weaver-skill-detector-1.0.13/references/checklist.md +3 -3
  269. package/tools/weaver-skill-detector-1.0.13/scripts/__pycache__/validate_skill.cpython-313.pyc +0 -0
  270. package/tools/weaver-skill-detector-1.0.13/scripts/validate_skill.py +98 -91
  271. package/scripts/sync-connector-skills.mjs +0 -172
@@ -100,8 +100,24 @@ const positionDetail = {
100
100
  query: { id, type: 'info' },
101
101
  headers: { Referer: `${baseUrl}/sp/hrm/positionCard/${id}` },
102
102
  });
103
- const data = resp?.data ?? {};
104
- return hrmSuccess('hrm.position.detail', { ...data, link: positionLink(baseUrl, id) });
103
+ // 只提取 data.data 的业务字段,砍掉 groups/layout/items 等前端表单元数据。
104
+ const raw = resp?.data?.data ?? {};
105
+ const parentName = Array.isArray(raw.parent) && raw.parent[0]?.name ? String(raw.parent[0].name) : '';
106
+ const jobsetName = Array.isArray(raw.jobsetid) && raw.jobsetid[0]?.name ? String(raw.jobsetid[0].name) : '';
107
+ const jobsetTypeName = Array.isArray(raw.jobset_type_id) && raw.jobset_type_id[0]?.name ? String(raw.jobset_type_id[0].name) : '';
108
+ const grade = Array.isArray(raw.grade)
109
+ ? raw.grade.map((g) => (g && typeof g === 'object' ? (g.name ?? g) : g))
110
+ : raw.grade;
111
+ return hrmSuccess('hrm.position.detail', {
112
+ id,
113
+ name: raw.name,
114
+ code: raw.code,
115
+ ...(parentName ? { parentName } : {}),
116
+ ...(jobsetName ? { jobsetName } : {}),
117
+ ...(jobsetTypeName ? { jobsetTypeName } : {}),
118
+ ...(grade !== undefined ? { grade } : {}),
119
+ link: positionLink(baseUrl, id),
120
+ });
105
121
  },
106
122
  };
107
123
  const positionList = {
@@ -2,11 +2,13 @@ import { hrmValidationError } from '../errors.js';
2
2
  import { hrmEmployeeOperations } from './employee.js';
3
3
  import { hrmOrgOperations } from './org.js';
4
4
  import { hrmPositionOperations } from './position.js';
5
+ import { hrmResolveOperations } from './resolve.js';
5
6
  function buildRegistry() {
6
7
  const registry = new Map();
7
8
  const definitions = [
8
9
  ...hrmEmployeeOperations,
9
10
  ...hrmOrgOperations,
11
+ ...hrmResolveOperations,
10
12
  ...hrmPositionOperations,
11
13
  ];
12
14
  for (const definition of definitions) {
@@ -0,0 +1,449 @@
1
+ import { hrmValidationError } from '../errors.js';
2
+ import { browserBaseBody, orgLink, } from './shared.js';
3
+ import { READ, SCHEMA_ID, hrmSuccess, schemaOf, } from './types.js';
4
+ const VIRTUAL_PATH = '/api/bs/hrm/companyVirtual/listCompanyVirtual';
5
+ const ORG_DETAIL_PATH = '/api/bs/hrm/organization/getForm';
6
+ const ORG_TYPES = ['department', 'subcompany'];
7
+ const DEFAULT_MAX_CANDIDATES = 20;
8
+ const MAX_CANDIDATES = 200;
9
+ const MAX_SUGGESTIONS = 5;
10
+ function text(value) {
11
+ return value === undefined || value === null ? '' : String(value).trim();
12
+ }
13
+ /** 名称匹配忽略大小写、全半角差异和多余空白。 */
14
+ function normalizedName(value) {
15
+ return text(value).normalize('NFKC').replace(/\s+/gu, '').toLocaleLowerCase();
16
+ }
17
+ function normalizePath(value) {
18
+ return text(value)
19
+ .split(/[|/]+/u)
20
+ .map((part) => part.trim())
21
+ .filter(Boolean)
22
+ .join('/');
23
+ }
24
+ function idValue(value, field) {
25
+ const valueText = text(value);
26
+ if (!/^\d+$/u.test(valueText)) {
27
+ throw hrmValidationError('id_invalid', `${field} 必须是数字 ID`);
28
+ }
29
+ return valueText;
30
+ }
31
+ function maxCandidatesValue(value) {
32
+ if (value === undefined || value === null || value === '')
33
+ return DEFAULT_MAX_CANDIDATES;
34
+ const numeric = Number(value);
35
+ if (!Number.isInteger(numeric) || numeric < 1 || numeric > MAX_CANDIDATES) {
36
+ throw hrmValidationError('number_invalid', `maxCandidates 必须是 1~${MAX_CANDIDATES} 的整数`);
37
+ }
38
+ return numeric;
39
+ }
40
+ function uniqueById(items) {
41
+ const seen = new Set();
42
+ return items.filter((item) => {
43
+ if (!item.id || seen.has(item.id))
44
+ return false;
45
+ seen.add(item.id);
46
+ return true;
47
+ });
48
+ }
49
+ function readVirtuals(response) {
50
+ const root = response?.data;
51
+ const rows = Array.isArray(root) ? root : Array.isArray(root?.data) ? root.data : [];
52
+ return uniqueById(rows
53
+ .map((row) => ({
54
+ id: text(row?.id ?? row?.value),
55
+ name: text(row?.content ?? row?.name ?? row?.label),
56
+ }))
57
+ .filter((item) => item.id && item.name));
58
+ }
59
+ function levenshtein(left, right) {
60
+ const a = [...left];
61
+ const b = [...right];
62
+ let previous = Array.from({ length: b.length + 1 }, (_, index) => index);
63
+ for (let row = 1; row <= a.length; row += 1) {
64
+ const current = [row];
65
+ for (let column = 1; column <= b.length; column += 1) {
66
+ current[column] = Math.min(current[column - 1] + 1, previous[column] + 1, previous[column - 1] + (a[row - 1] === b[column - 1] ? 0 : 1));
67
+ }
68
+ previous = current;
69
+ }
70
+ return previous[b.length];
71
+ }
72
+ function similarity(left, right) {
73
+ const a = normalizedName(left);
74
+ const b = normalizedName(right);
75
+ const longest = Math.max([...a].length, [...b].length);
76
+ return longest === 0 ? 1 : 1 - levenshtein(a, b) / longest;
77
+ }
78
+ function nearVirtuals(keyword, virtuals) {
79
+ return virtuals
80
+ .map((item) => ({ item, score: similarity(keyword, item.name) }))
81
+ .filter(({ score }) => score >= 0.6 && score < 1)
82
+ .sort((left, right) => right.score - left.score)
83
+ .map(({ item }) => item)
84
+ .slice(0, MAX_SUGGESTIONS);
85
+ }
86
+ function orgPath(row, type) {
87
+ const direct = type === 'department' ? row.supDepartment : row.supSubDepartment;
88
+ if (text(direct))
89
+ return normalizePath(direct);
90
+ const title = text(row.title);
91
+ const name = text(row.name);
92
+ if (title && name && title.startsWith(`${name}|`)) {
93
+ return normalizePath(title.slice(name.length + 1));
94
+ }
95
+ return '';
96
+ }
97
+ function fullOrg(row, type, baseUrl, virtual) {
98
+ const id = text(row.id);
99
+ const name = text(row.name);
100
+ const parentPath = orgPath(row, type);
101
+ const rawFullPath = normalizePath(row.fullPath);
102
+ const fullPath = rawFullPath || (parentPath ? `${parentPath}/${name}` : name);
103
+ const virtualName = parentPath.split('/')[0] || virtual.name;
104
+ const parentId = text(row.parent?.id ?? row.parent);
105
+ const subcompanyId = text(row.subcompanyid ?? row.subcompanyId);
106
+ const virtualId = text(row.virtualid ?? row.virtualId) || virtual.id;
107
+ return {
108
+ id,
109
+ name,
110
+ type: text(row.type) || type,
111
+ ...(text(row.code) ? { code: text(row.code) } : {}),
112
+ fullPath,
113
+ ...(parentPath ? { parentPath } : {}),
114
+ ...(parentId ? { parentId } : {}),
115
+ ...(subcompanyId ? { subcompanyId } : {}),
116
+ virtualId,
117
+ virtualName,
118
+ ...(row.status !== undefined ? { status: row.status } : {}),
119
+ link: orgLink(baseUrl, id),
120
+ };
121
+ }
122
+ function orgCandidate(row, type, baseUrl, virtual) {
123
+ const item = fullOrg(row, type, baseUrl, virtual);
124
+ return {
125
+ id: item.id,
126
+ name: item.name,
127
+ type: item.type,
128
+ fullPath: item.fullPath,
129
+ ...(item.code ? { code: item.code } : {}),
130
+ link: item.link,
131
+ };
132
+ }
133
+ function browsePath(type) {
134
+ return type === 'department'
135
+ ? '/api/hrm/common/browser/data/department'
136
+ : '/api/hrm/common/browser/data/subcompany';
137
+ }
138
+ async function browseOrg(host, type, virtualId, keyword, condition, pageSize) {
139
+ const response = await host.request({
140
+ method: 'POST',
141
+ path: browsePath(type),
142
+ body: {
143
+ ...browserBaseBody(),
144
+ virtualType: 'ALL',
145
+ cmd: 'list',
146
+ current: 1,
147
+ pageSize,
148
+ companyId: virtualId,
149
+ formDatas: {
150
+ name: [{
151
+ nameCondition: {
152
+ id: condition,
153
+ content: condition === 'eq' ? '等于' : '包含',
154
+ disabled: false,
155
+ },
156
+ name: keyword,
157
+ }],
158
+ },
159
+ quickSearchDatas: {},
160
+ type: 'and',
161
+ stopDepartment: false,
162
+ },
163
+ });
164
+ const data = response?.data ?? {};
165
+ const rows = Array.isArray(data.data) ? data.data : [];
166
+ const reportedTotal = Number(data.total);
167
+ return {
168
+ type,
169
+ rows,
170
+ total: Number.isFinite(reportedTotal) ? reportedTotal : rows.length,
171
+ };
172
+ }
173
+ async function browseTypes(host, types, virtualId, keyword, condition, pageSize) {
174
+ return Promise.all(types.map((type) => browseOrg(host, type, virtualId, keyword, condition, pageSize)));
175
+ }
176
+ function exactRows(results, keyword) {
177
+ const normalized = normalizedName(keyword);
178
+ return results.map((result) => {
179
+ const rows = result.rows.filter((row) => normalizedName(row.name) === normalized);
180
+ return { ...result, rows, total: rows.length };
181
+ });
182
+ }
183
+ function totalMatches(results) {
184
+ return results.reduce((sum, result) => sum + Math.max(result.total, result.rows.length), 0);
185
+ }
186
+ function allRows(results) {
187
+ return results.flatMap((result) => result.rows.map((row) => ({ type: result.type, row })));
188
+ }
189
+ function resolvedFromMatches(results, explicitType) {
190
+ if (explicitType) {
191
+ const result = results[0];
192
+ const count = Math.max(result.total, result.rows.length);
193
+ return {
194
+ selected: count === 1 && result.rows[0] ? { type: result.type, row: result.rows[0] } : undefined,
195
+ alternatives: [],
196
+ ambiguous: count > 1,
197
+ };
198
+ }
199
+ const department = results.find((result) => result.type === 'department');
200
+ const subcompany = results.find((result) => result.type === 'subcompany');
201
+ const departmentCount = department ? Math.max(department.total, department.rows.length) : 0;
202
+ const subcompanyCount = subcompany ? Math.max(subcompany.total, subcompany.rows.length) : 0;
203
+ if (departmentCount === 1 && department?.rows[0]) {
204
+ return {
205
+ selected: { type: 'department', row: department.rows[0] },
206
+ alternatives: (subcompany?.rows ?? []).map((row) => ({ type: 'subcompany', row })),
207
+ ambiguous: false,
208
+ };
209
+ }
210
+ if (departmentCount > 1)
211
+ return { alternatives: [], ambiguous: true };
212
+ if (subcompanyCount === 1 && subcompany?.rows[0]) {
213
+ return { selected: { type: 'subcompany', row: subcompany.rows[0] }, alternatives: [], ambiguous: false };
214
+ }
215
+ return { alternatives: [], ambiguous: subcompanyCount > 1 };
216
+ }
217
+ function truncatedCandidates(results, maxCandidates, baseUrl, virtual) {
218
+ const candidateTotal = totalMatches(results);
219
+ const candidates = allRows(results)
220
+ .slice(0, maxCandidates)
221
+ .map(({ type, row }) => orgCandidate(row, type, baseUrl, virtual));
222
+ return {
223
+ candidates,
224
+ candidateTotal,
225
+ truncated: candidateTotal > candidates.length,
226
+ };
227
+ }
228
+ async function resolveOrgId(host, orgId, baseUrl, virtual) {
229
+ const response = await host.request({
230
+ method: 'GET',
231
+ path: ORG_DETAIL_PATH,
232
+ query: { id: orgId, readOnly: true, includeSub: true, quote: true, isMobile: false },
233
+ headers: { Referer: `${baseUrl}/sp/hrm/orgCard/${orgId}` },
234
+ });
235
+ const raw = response?.data?.data ?? {};
236
+ const type = raw.type === 'subcompany' ? 'subcompany' : 'department';
237
+ const parentName = Array.isArray(raw.parent) ? text(raw.parent[0]?.name) : '';
238
+ const subcompanyName = Array.isArray(raw.subcompany) ? text(raw.subcompany[0]?.name) : '';
239
+ const fullPath = normalizePath(raw.fullPath);
240
+ const pathParts = fullPath.split('/').filter(Boolean);
241
+ return {
242
+ id: text(raw.id) || orgId,
243
+ name: text(raw.name),
244
+ type,
245
+ ...(text(raw.code) ? { code: text(raw.code) } : {}),
246
+ ...(fullPath ? { fullPath } : {}),
247
+ ...(pathParts.length > 1 ? { parentPath: pathParts.slice(0, -1).join('/') } : {}),
248
+ ...(parentName ? { parentName } : {}),
249
+ ...(subcompanyName ? { subcompanyName } : {}),
250
+ virtualId: virtual.id,
251
+ virtualName: virtual.name,
252
+ ...(raw.status !== undefined ? { status: raw.status } : {}),
253
+ link: orgLink(baseUrl, orgId),
254
+ };
255
+ }
256
+ function relaxedKeywords(name) {
257
+ const characters = [...text(name)];
258
+ if (characters.length <= 2)
259
+ return [characters.join('')].filter(Boolean);
260
+ const suffix = characters.slice(-2).join('');
261
+ const prefix = characters.slice(0, 2).join('');
262
+ return suffix === prefix ? [suffix] : [suffix, prefix];
263
+ }
264
+ async function nearOrgSuggestions(host, type, virtual, name, pageSize, baseUrl) {
265
+ const results = [];
266
+ const seen = new Set();
267
+ for (const keyword of relaxedKeywords(name)) {
268
+ const result = await browseOrg(host, type, virtual.id, keyword, 'in', pageSize);
269
+ for (const row of result.rows) {
270
+ const id = text(row.id);
271
+ if (!id || seen.has(id))
272
+ continue;
273
+ seen.add(id);
274
+ results.push(orgCandidate(row, type, baseUrl, virtual));
275
+ }
276
+ }
277
+ return results;
278
+ }
279
+ const orgResolve = {
280
+ name: 'hrm.org.resolve',
281
+ resource: 'org',
282
+ method: 'org.resolve',
283
+ action: 'hrm.org.resolve',
284
+ summary: '按多维名称与组织名称解析唯一部门/分部;歧义或近似名称只返回候选,不代替用户选择',
285
+ risk: READ,
286
+ inputSchema: schemaOf({
287
+ virtual: { type: 'string', minLength: 1, description: '多维名称;与 virtualId 至少传一个' },
288
+ virtualId: SCHEMA_ID,
289
+ name: { type: 'string', minLength: 1, description: '组织名称;与 orgId 至少传一个' },
290
+ orgId: SCHEMA_ID,
291
+ type: { type: 'string', enum: [...ORG_TYPES] },
292
+ maxCandidates: { type: 'integer', minimum: 1, maximum: MAX_CANDIDATES, default: DEFAULT_MAX_CANDIDATES },
293
+ }),
294
+ handler: async (args, { host }) => {
295
+ const virtualKeyword = text(args.virtual);
296
+ const name = text(args.name);
297
+ const virtualId = args.virtualId === undefined ? '' : idValue(args.virtualId, 'virtualId');
298
+ const orgId = args.orgId === undefined ? '' : idValue(args.orgId, 'orgId');
299
+ if (!virtualKeyword && !virtualId) {
300
+ throw hrmValidationError('virtual_required', 'virtual 或 virtualId 至少传一个');
301
+ }
302
+ if (!name && !orgId) {
303
+ throw hrmValidationError('name_required', 'name 或 orgId 至少传一个');
304
+ }
305
+ const explicitType = args.type !== undefined;
306
+ const requestedType = explicitType ? text(args.type) : '';
307
+ if (explicitType && !ORG_TYPES.includes(requestedType)) {
308
+ throw hrmValidationError('enum_invalid', `type 取值必须是 ${ORG_TYPES.join(' / ')} 之一`);
309
+ }
310
+ const types = explicitType
311
+ ? [requestedType]
312
+ : ['department', 'subcompany'];
313
+ const maxCandidates = maxCandidatesValue(args.maxCandidates);
314
+ const pageSize = Math.max(100, maxCandidates);
315
+ const virtualResponse = await host.request({ method: 'GET', path: VIRTUAL_PATH });
316
+ const virtuals = readVirtuals(virtualResponse);
317
+ let virtual;
318
+ let virtualMatchType = 'exact';
319
+ if (virtualId) {
320
+ virtual = virtuals.find((item) => item.id === virtualId);
321
+ virtualMatchType = 'id';
322
+ }
323
+ else {
324
+ const keyword = normalizedName(virtualKeyword);
325
+ const exact = virtuals.filter((item) => normalizedName(item.name) === keyword);
326
+ const matches = exact.length > 0
327
+ ? exact
328
+ : virtuals.filter((item) => normalizedName(item.name).includes(keyword));
329
+ virtualMatchType = exact.length > 0 ? 'exact' : 'fuzzy';
330
+ if (matches.length > 1) {
331
+ const candidates = matches.slice(0, maxCandidates);
332
+ return hrmSuccess('hrm.org.resolve', {
333
+ status: 'ambiguous',
334
+ stage: 'virtual',
335
+ virtual: null,
336
+ matchType: virtualMatchType,
337
+ candidates,
338
+ candidateTotal: matches.length,
339
+ truncated: matches.length > candidates.length,
340
+ message: `多维「${virtualKeyword}」匹配到 ${matches.length} 个候选,请确认后把候选 id 作为 virtualId 复调。`,
341
+ });
342
+ }
343
+ virtual = matches[0];
344
+ }
345
+ if (!virtual) {
346
+ const suggestions = virtualKeyword ? nearVirtuals(virtualKeyword, virtuals) : [];
347
+ const available = virtuals.map((item) => item.name).join('、');
348
+ const target = virtualId ? `ID ${virtualId}` : `「${virtualKeyword}」`;
349
+ const suggestionText = suggestions.length > 0
350
+ ? `;近似名称:${suggestions.map((item) => item.name).join('、')}。不要自行替换名称,请先让用户确认`
351
+ : '';
352
+ return hrmSuccess('hrm.org.resolve', {
353
+ status: 'not_found',
354
+ stage: 'virtual',
355
+ virtual: null,
356
+ matchType: 'none',
357
+ candidates: [],
358
+ candidateTotal: 0,
359
+ suggestions,
360
+ suggestionTotal: suggestions.length,
361
+ availableVirtuals: virtuals,
362
+ message: `多维${target}不存在${suggestionText}。当前可用多维:${available || '无'}。`,
363
+ });
364
+ }
365
+ const virtualResult = {
366
+ id: virtual.id,
367
+ name: virtual.name,
368
+ keyword: virtualKeyword,
369
+ matchType: virtualMatchType,
370
+ };
371
+ const session = await host.getSession();
372
+ const baseUrl = session.baseUrl.replace(/\/+$/u, '');
373
+ if (orgId) {
374
+ const org = await resolveOrgId(host, orgId, baseUrl, virtual);
375
+ return hrmSuccess('hrm.org.resolve', {
376
+ status: 'resolved',
377
+ stage: 'org',
378
+ matchType: 'id',
379
+ type: org.type,
380
+ virtual: virtualResult,
381
+ org,
382
+ message: `已按 orgId 定位组织「${String(org.name || orgId)}」。`,
383
+ });
384
+ }
385
+ let matchType = 'exact';
386
+ let matches = await browseTypes(host, types, virtual.id, name, 'eq', pageSize);
387
+ let choice = resolvedFromMatches(matches, explicitType);
388
+ if (!choice.selected && !choice.ambiguous) {
389
+ const fuzzyResults = await browseTypes(host, types, virtual.id, name, 'in', pageSize);
390
+ const normalizedExact = exactRows(fuzzyResults, name);
391
+ if (totalMatches(normalizedExact) > 0) {
392
+ matches = normalizedExact;
393
+ matchType = 'exact';
394
+ }
395
+ else {
396
+ matches = fuzzyResults;
397
+ matchType = 'fuzzy';
398
+ }
399
+ choice = resolvedFromMatches(matches, explicitType);
400
+ }
401
+ if (choice.selected) {
402
+ const org = fullOrg(choice.selected.row, choice.selected.type, baseUrl, virtual);
403
+ const alsoMatched = choice.alternatives.map(({ type, row }) => orgCandidate(row, type, baseUrl, virtual));
404
+ const fuzzyMessage = matchType === 'fuzzy' ? '(模糊匹配)' : '';
405
+ const alternativeMessage = alsoMatched.length > 0
406
+ ? `;另有同名节点 ${alsoMatched.length} 个,请一并告知用户`
407
+ : '';
408
+ return hrmSuccess('hrm.org.resolve', {
409
+ status: 'resolved',
410
+ stage: 'org',
411
+ matchType,
412
+ type: choice.selected.type,
413
+ virtual: virtualResult,
414
+ org,
415
+ ...(alsoMatched.length > 0 ? { alsoMatched } : {}),
416
+ message: `已${fuzzyMessage}定位${choice.selected.type === 'department' ? '部门' : '分部'}「${name}」${alternativeMessage}。`,
417
+ });
418
+ }
419
+ if (choice.ambiguous) {
420
+ const candidateData = truncatedCandidates(matches, maxCandidates, baseUrl, virtual);
421
+ const truncatedMessage = candidateData.truncated ? `,仅列出前 ${maxCandidates} 个` : '';
422
+ return hrmSuccess('hrm.org.resolve', {
423
+ status: 'ambiguous',
424
+ stage: 'org',
425
+ matchType,
426
+ virtual: virtualResult,
427
+ ...candidateData,
428
+ message: `组织「${name}」匹配到 ${candidateData.candidateTotal} 个候选${truncatedMessage},请确认后把候选 id 作为 orgId 复调。`,
429
+ });
430
+ }
431
+ // 名称的精确/包含查询均未命中。近似探测只用于提示,绝不自动解析。
432
+ const suggestionType = (requestedType || 'department');
433
+ const allSuggestions = await nearOrgSuggestions(host, suggestionType, virtual, name, pageSize, baseUrl);
434
+ const suggestions = allSuggestions.slice(0, MAX_SUGGESTIONS);
435
+ const suggestionMessage = suggestions.length > 0
436
+ ? `;找到近似名称 ${suggestions.map((item) => item.name).join('、')},不要自行替换名称,请先让用户确认`
437
+ : '';
438
+ return hrmSuccess('hrm.org.resolve', {
439
+ status: 'not_found',
440
+ stage: 'org',
441
+ matchType: 'none',
442
+ virtual: virtualResult,
443
+ suggestions,
444
+ suggestionTotal: allSuggestions.length,
445
+ message: `在多维「${virtual.name}」中未找到组织「${name}」${suggestionMessage}。`,
446
+ });
447
+ },
448
+ };
449
+ export const hrmResolveOperations = [orgResolve];
@@ -1,4 +1,6 @@
1
+ import { caizhilianShortcut } from './caizhilian/index.js';
1
2
  import { projectShortcut } from './project/index.js';
3
+ import { blogShortcut } from './blog/index.js';
2
4
  import { archiveShortcut } from './archive/index.js';
3
5
  import { calendarShortcut } from './calendar/index.js';
4
6
  import { ehrShortcut } from './ehr/index.js';
@@ -32,5 +34,7 @@ export const builtinShortcuts = [
32
34
  assetShortcut,
33
35
  imShortcut,
34
36
  projectShortcut,
35
- workflowShortcut
37
+ workflowShortcut,
38
+ blogShortcut,
39
+ caizhilianShortcut
36
40
  ];