weaver-work-cli 0.1.42 → 0.1.44

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 (318) hide show
  1. package/README.md +17 -0
  2. package/dist/chunks/{archive-J4I6MCKF.js → archive-P6TBQGKL.js} +13 -5
  3. package/dist/chunks/{archive-oa-BRZKKTO4.js → archive-oa-7TQ2NXOH.js} +12 -5
  4. package/dist/chunks/{asset-L7D4FAOZ.js → asset-3ELRG37G.js} +11 -4
  5. package/dist/chunks/{asset-idle-DADLLV75.js → asset-idle-WIGMUFMD.js} +7 -3
  6. package/dist/chunks/{attachment-content-K4C7VLWQ.js → attachment-content-E3276UOV.js} +5 -4
  7. package/dist/chunks/{blog-BVGQ7NZL.js → blog-C5NMZAAC.js} +11 -4
  8. package/dist/chunks/{caizhilian-SAADNFD6.js → caizhilian-5XSM2DFP.js} +13 -6
  9. package/dist/chunks/{calendar-Q7NQY5Z2.js → calendar-FI2WNSBO.js} +12 -5
  10. package/dist/chunks/{chunk-YRSZQUD2.js → chunk-3YBDYOC4.js} +3 -3
  11. package/dist/chunks/{chunk-OOUTBLZ4.js → chunk-56EZERK4.js} +1 -1
  12. package/dist/chunks/chunk-6N4JPNFL.js +76 -0
  13. package/dist/chunks/{chunk-ZUX3P6BQ.js → chunk-727FH2NI.js} +1 -1
  14. package/dist/chunks/chunk-7BDPM5ST.js +11 -0
  15. package/dist/chunks/{chunk-EKWAQSLU.js → chunk-BCVYBYYT.js} +432 -2248
  16. package/dist/chunks/{chunk-W7BEHOSR.js → chunk-CWYGFU5B.js} +2 -2
  17. package/dist/chunks/{chunk-NOODWMCL.js → chunk-D4ADSZ7H.js} +1 -1
  18. package/dist/chunks/{chunk-SA6VBIHY.js → chunk-ETNJSKMM.js} +214 -16
  19. package/dist/chunks/{chunk-BBKDXQEC.js → chunk-F4E4EM35.js} +3 -3
  20. package/dist/chunks/{chunk-IZ7S7QUS.js → chunk-FAZTGX7S.js} +6 -6
  21. package/dist/chunks/{chunk-NKZRQXST.js → chunk-FRZKBMSW.js} +52 -36
  22. package/dist/chunks/{chunk-BYBSCN4X.js → chunk-G7PQWD4L.js} +6 -3
  23. package/dist/chunks/{chunk-GEWYMQME.js → chunk-GAMZLAG2.js} +1 -1
  24. package/dist/chunks/{chunk-R4CHUSKC.js → chunk-GM6J7Q4B.js} +4 -4
  25. package/dist/chunks/{chunk-APVFJUQH.js → chunk-GRDRG6HP.js} +3 -3
  26. package/dist/chunks/{chunk-LDZQPUIA.js → chunk-HIT4Y6OI.js} +1 -1
  27. package/dist/chunks/{chunk-EZALDOQH.js → chunk-HP7JIYMT.js} +5 -2
  28. package/dist/chunks/{chunk-LADPYOWC.js → chunk-IAZ3UPY6.js} +3 -3
  29. package/dist/chunks/{chunk-ZEDWSH32.js → chunk-IC62NFM5.js} +1 -1
  30. package/dist/chunks/{chunk-P26ZWSKU.js → chunk-KIHNAS25.js} +5 -2
  31. package/dist/chunks/{chunk-BIPYLLVS.js → chunk-N4M2DDFE.js} +15 -15
  32. package/dist/chunks/{chunk-QKNKR4RH.js → chunk-OF4S23UB.js} +4 -4
  33. package/dist/chunks/{chunk-JPRO6ER2.js → chunk-PC7VKEB5.js} +57 -60
  34. package/dist/chunks/{chunk-4PD5NWAX.js → chunk-PUQS5MWL.js} +2 -2
  35. package/dist/chunks/{chunk-2LV74IWP.js → chunk-Q4OYAQYH.js} +1 -1
  36. package/dist/chunks/{chunk-72CKAUAG.js → chunk-QVSWRLLU.js} +7 -5
  37. package/dist/chunks/{chunk-4RAE6JXP.js → chunk-TA7FXXJD.js} +6 -3
  38. package/dist/chunks/{chunk-GPMFD4RD.js → chunk-TXUG266F.js} +1 -1
  39. package/dist/chunks/{chunk-FOAA27U5.js → chunk-UFIT2UU3.js} +16 -4
  40. package/dist/chunks/{chunk-LUSPKZKY.js → chunk-UG5G54VL.js} +1 -0
  41. package/dist/chunks/{chunk-NIAJ5ZCG.js → chunk-UL5XUQ25.js} +5 -2
  42. package/dist/chunks/{chunk-FMPJJYYI.js → chunk-WRXSAVKO.js} +1 -1
  43. package/dist/chunks/{chunk-G4UR6NXN.js → chunk-WSF4NNMR.js} +3 -3
  44. package/dist/chunks/chunk-XHK4MDR5.js +2497 -0
  45. package/dist/chunks/{chunk-3KTFS4IA.js → chunk-XNIK66I4.js} +19 -9
  46. package/dist/chunks/{chunk-3SO6QL6U.js → chunk-YWX377BY.js} +5 -2
  47. package/dist/chunks/{chunk-BYATLLEF.js → chunk-Z3GDFVJR.js} +1 -1
  48. package/dist/chunks/{chunk-GHXCDPTM.js → chunk-Z7VYWPZV.js} +1 -1
  49. package/dist/chunks/{conflict-F2OMZRTO.js → conflict-ARLSZJ6V.js} +4 -3
  50. package/dist/chunks/{continuation-2CKSBLA6.js → continuation-3S37AUSH.js} +4 -3
  51. package/dist/chunks/{continuation-RN6PZN2M.js → continuation-3XLYYTKV.js} +4 -3
  52. package/dist/chunks/{continuation-HZIZRZBX.js → continuation-HFW2YT5S.js} +4 -3
  53. package/dist/chunks/{continuation-NLECEJPX.js → continuation-KI7DRRZN.js} +4 -3
  54. package/dist/chunks/{contract-5BETHRSG.js → contract-DNIIW5VJ.js} +13 -5
  55. package/dist/chunks/{cowork-3MN6EQQO.js → cowork-GMLRGVIW.js} +11 -4
  56. package/dist/chunks/{create-flow-5FQNNMVO.js → create-flow-J22BO65E.js} +8 -7
  57. package/dist/chunks/{ebuilder-form-SBHOYBUD.js → ebuilder-form-ANV2FHYV.js} +12 -7
  58. package/dist/chunks/{ehr-KMOJULKG.js → ehr-GSTGAIY3.js} +266 -24
  59. package/dist/chunks/{employee-SAK2QYXX.js → employee-22BGJ3QS.js} +3 -3
  60. package/dist/chunks/{env-LB7NBL2O.js → env-BX3VRFS7.js} +4 -3
  61. package/dist/chunks/{esb-W2PJCFCX.js → esb-ATAIASX2.js} +12 -7
  62. package/dist/chunks/{factory-6ZFQXQ46.js → factory-PETTFME6.js} +3 -2
  63. package/dist/chunks/{fna-ZQPCUV4R.js → fna-YEKBSFSX.js} +14 -8
  64. package/dist/chunks/{group-chat-2HHAJN46.js → group-chat-BFVXAYFX.js} +5 -4
  65. package/dist/chunks/{host-ATKVNZAT.js → host-HRBXEPDQ.js} +5 -5
  66. package/dist/chunks/{host-BQH22NTQ.js → host-LR55CTHP.js} +5 -5
  67. package/dist/chunks/{host-X2CSLFM6.js → host-SUOY6VYQ.js} +5 -5
  68. package/dist/chunks/{host-4CBHGOHT.js → host-SZGV4UNT.js} +5 -5
  69. package/dist/chunks/{host-YTODKMSL.js → host-WIKN2EJ5.js} +5 -5
  70. package/dist/chunks/{hrm-FFM4UJFS.js → hrm-NRDO4W5G.js} +11 -7
  71. package/dist/chunks/{im-VEHKDQPB.js → im-IQ2HN23S.js} +8 -7
  72. package/dist/chunks/{invoice-LVIKSIIF.js → invoice-MNRW76PP.js} +636 -1768
  73. package/dist/chunks/{jiuchuanhui-X6DINO5P.js → jiuchuanhui-DTRBAX4N.js} +14 -6
  74. package/dist/chunks/{lazy-dispatch-KSWTN5L6.js → lazy-dispatch-ZVWAI25B.js} +7 -6
  75. package/dist/chunks/{mail-VDKRGUD3.js → mail-ZVAUXOJA.js} +16 -14
  76. package/dist/chunks/{meeting-CLC6HP3Z.js → meeting-FEVPZ67S.js} +21 -14
  77. package/dist/chunks/{okr-CHG4OO3U.js → okr-SDH3E5RA.js} +12 -5
  78. package/dist/chunks/{operations-5QL3AECO.js → operations-62N6EP3C.js} +4 -3
  79. package/dist/chunks/{plan-XWR75667.js → plan-E35JFDI7.js} +12 -5
  80. package/dist/chunks/{project-5BXOOKMG.js → project-73QXBAB2.js} +11 -4
  81. package/dist/chunks/reception-UWZVACBN.js +1899 -0
  82. package/dist/chunks/{recruit-stage-DGMFNNDE.js → recruit-stage-4MAOCKFY.js} +320 -57
  83. package/dist/chunks/registry-IM5G23LS.js +24 -0
  84. package/dist/chunks/{registry-RHMW6ANW.js → registry-JDUS4E7D.js} +7 -6
  85. package/dist/chunks/{registry-7FFOXIAW.js → registry-KNKSCJNT.js} +7 -6
  86. package/dist/chunks/{registry-Z43434VG.js → registry-PO7SI256.js} +4 -4
  87. package/dist/chunks/{registry-OZSMDVPP.js → registry-PVUZQDDQ.js} +3 -3
  88. package/dist/chunks/{room-recommend-62H7ZQQ6.js → room-recommend-H7KLXA5R.js} +6 -5
  89. package/dist/chunks/{schedule-FNXKH3DQ.js → schedule-ESZIBAUO.js} +6 -5
  90. package/dist/chunks/{workflow-ADHKCAJK.js → workflow-CWJFJLQU.js} +13 -8
  91. package/dist/cmd/action.js +6 -0
  92. package/dist/cmd/identity/index.js +45 -0
  93. package/dist/cmd/index.js +2 -0
  94. package/dist/core/continuation-ttl.js +18 -0
  95. package/dist/core/error-codes.js +85 -0
  96. package/dist/core/logger.js +11 -0
  97. package/dist/index.js +37 -31
  98. package/dist/internal/e10/auth/commands.js +163 -8
  99. package/dist/internal/e10/auth/error-log.js +182 -0
  100. package/dist/internal/e10/auth/session.js +17 -3
  101. package/dist/internal/e10/auth-recovery.js +39 -12
  102. package/dist/internal/e10/context.js +17 -2
  103. package/dist/internal/skills/install.js +9 -1
  104. package/dist/shortcuts/archive/continuation.js +2 -1
  105. package/dist/shortcuts/archive/index.js +3 -0
  106. package/dist/shortcuts/archive/operations/confirm.js +2 -1
  107. package/dist/shortcuts/archive-oa/continuation.js +2 -1
  108. package/dist/shortcuts/archive-oa/index.js +2 -0
  109. package/dist/shortcuts/archive-oa/operations/confirm.js +2 -1
  110. package/dist/shortcuts/asset/continuation.js +2 -1
  111. package/dist/shortcuts/asset/index.js +2 -0
  112. package/dist/shortcuts/asset-idle/index.js +2 -0
  113. package/dist/shortcuts/blog/continuation.js +2 -1
  114. package/dist/shortcuts/blog/index.js +2 -0
  115. package/dist/shortcuts/caizhilian/continuation.js +2 -1
  116. package/dist/shortcuts/caizhilian/index.js +2 -0
  117. package/dist/shortcuts/caizhilian/operations/confirm.js +3 -2
  118. package/dist/shortcuts/calendar/continuation.js +2 -1
  119. package/dist/shortcuts/calendar/index.js +2 -0
  120. package/dist/shortcuts/calendar/operations/write.js +1 -1
  121. package/dist/shortcuts/contract/continuation.js +2 -1
  122. package/dist/shortcuts/contract/index.js +2 -0
  123. package/dist/shortcuts/contract/operations/write.js +2 -1
  124. package/dist/shortcuts/cowork/continuation.js +2 -1
  125. package/dist/shortcuts/cowork/index.js +2 -0
  126. package/dist/shortcuts/ebuilder-form/continuation.js +2 -1
  127. package/dist/shortcuts/ebuilder-form/index.js +2 -0
  128. package/dist/shortcuts/ebuilder-form/operations/write.js +3 -2
  129. package/dist/shortcuts/ehr/continuation.js +2 -1
  130. package/dist/shortcuts/ehr/index.js +2 -0
  131. package/dist/shortcuts/ehr/operations/attend-write.js +1 -1
  132. package/dist/shortcuts/ehr/operations/recruit-candidate-import.js +182 -3
  133. package/dist/shortcuts/ehr/operations/recruit-position.js +134 -2
  134. package/dist/shortcuts/ehr/operations/recruit-write.js +1 -1
  135. package/dist/shortcuts/esb/continuation.js +2 -1
  136. package/dist/shortcuts/esb/index.js +2 -0
  137. package/dist/shortcuts/esb/operations/trigger.js +2 -1
  138. package/dist/shortcuts/fna/continuation.js +2 -1
  139. package/dist/shortcuts/fna/index.js +2 -0
  140. package/dist/shortcuts/fna/operations/invoice-writeoff.js +1 -1
  141. package/dist/shortcuts/fna/operations/loan.js +1 -1
  142. package/dist/shortcuts/hrm/index.js +2 -0
  143. package/dist/shortcuts/im/continuation.js +2 -1
  144. package/dist/shortcuts/index.js +5 -0
  145. package/dist/shortcuts/invoice/continuation.js +2 -1
  146. package/dist/shortcuts/invoice/index.js +14 -15
  147. package/dist/shortcuts/invoice/invoice-record.js +93 -0
  148. package/dist/shortcuts/invoice/manifest.js +190 -393
  149. package/dist/shortcuts/invoice/operations/add.js +2 -1
  150. package/dist/shortcuts/invoice/operations/delete.js +2 -1
  151. package/dist/shortcuts/invoice/operations/import.js +2 -1
  152. package/dist/shortcuts/invoice/operations/issuing-contract-detail.js +86 -0
  153. package/dist/shortcuts/invoice/operations/issuing-contracts.js +210 -0
  154. package/dist/shortcuts/invoice/operations/registry.js +17 -17
  155. package/dist/shortcuts/invoice/operations/reim-auto.js +4 -569
  156. package/dist/shortcuts/invoice/operations/reim.js +52 -341
  157. package/dist/shortcuts/invoice/operations/shared.js +21 -4
  158. package/dist/shortcuts/invoice/operations/update.js +2 -1
  159. package/dist/shortcuts/invoice/projection.js +10 -62
  160. package/dist/shortcuts/jiuchuanhui/continuation.js +2 -1
  161. package/dist/shortcuts/jiuchuanhui/index.js +2 -0
  162. package/dist/shortcuts/jiuchuanhui/operations/datajson.js +2 -1
  163. package/dist/shortcuts/jiuchuanhui/operations/esb.js +2 -1
  164. package/dist/shortcuts/mail/continuation.js +2 -1
  165. package/dist/shortcuts/mail/index.js +2 -0
  166. package/dist/shortcuts/mail/operations/mail-blacklist.js +1 -1
  167. package/dist/shortcuts/mail/operations/mail-contacts.js +1 -1
  168. package/dist/shortcuts/mail/operations/mail-send.js +1 -1
  169. package/dist/shortcuts/mail/operations/mail-sign.js +1 -1
  170. package/dist/shortcuts/mail/operations/mail-template.js +1 -1
  171. package/dist/shortcuts/meeting/continuation.js +2 -1
  172. package/dist/shortcuts/meeting/index.js +2 -0
  173. package/dist/shortcuts/meeting/operations/change.js +1 -1
  174. package/dist/shortcuts/meeting/operations/create.js +1 -1
  175. package/dist/shortcuts/meeting/operations/eb/create-flow.js +16 -7
  176. package/dist/shortcuts/meeting/operations/eb/decision.js +1 -1
  177. package/dist/shortcuts/meeting/operations/eb/factory.js +1 -1
  178. package/dist/shortcuts/meeting/operations/lifecycle.js +1 -1
  179. package/dist/shortcuts/meeting/operations/receipts.js +1 -1
  180. package/dist/shortcuts/meeting/operations/signs.js +1 -1
  181. package/dist/shortcuts/okr/continuation.js +2 -1
  182. package/dist/shortcuts/okr/index.js +2 -0
  183. package/dist/shortcuts/okr/operations/write.js +1 -1
  184. package/dist/shortcuts/plan/continuation.js +2 -1
  185. package/dist/shortcuts/plan/index.js +2 -0
  186. package/dist/shortcuts/plan/operations/write.js +1 -1
  187. package/dist/shortcuts/project/continuation.js +2 -1
  188. package/dist/shortcuts/project/index.js +2 -0
  189. package/dist/shortcuts/reception/constants.js +53 -0
  190. package/dist/shortcuts/reception/errors.js +54 -0
  191. package/dist/shortcuts/reception/host.js +125 -0
  192. package/dist/shortcuts/reception/index.js +198 -0
  193. package/dist/shortcuts/reception/manifest.js +177 -0
  194. package/dist/shortcuts/reception/operations/ask.js +71 -0
  195. package/dist/shortcuts/reception/operations/browsertool.js +58 -0
  196. package/dist/shortcuts/reception/operations/compose.js +129 -0
  197. package/dist/shortcuts/reception/operations/customparams.js +74 -0
  198. package/dist/shortcuts/reception/operations/doc.js +238 -0
  199. package/dist/shortcuts/reception/operations/docrender.js +36 -0
  200. package/dist/shortcuts/reception/operations/panels.js +179 -0
  201. package/dist/shortcuts/reception/operations/registry.js +26 -0
  202. package/dist/shortcuts/reception/operations/render-assets.js +184 -0
  203. package/dist/shortcuts/reception/operations/render.js +123 -0
  204. package/dist/shortcuts/reception/operations/runs.js +38 -0
  205. package/dist/shortcuts/reception/operations/schedule.js +127 -0
  206. package/dist/shortcuts/reception/operations/shared.js +196 -0
  207. package/dist/shortcuts/reception/operations/snapshot.js +68 -0
  208. package/dist/shortcuts/reception/operations/types.js +1 -0
  209. package/dist/shortcuts/reception/operations.js +33 -0
  210. package/dist/shortcuts/reception/upload.js +218 -0
  211. package/dist/shortcuts/recruit-stage/context.js +145 -33
  212. package/dist/shortcuts/recruit-stage/continuation.js +2 -1
  213. package/dist/shortcuts/recruit-stage/operations/jd-create.js +106 -17
  214. package/dist/shortcuts/recruit-stage/operations/resume-import.js +166 -10
  215. package/dist/shortcuts/workflow/continuation.js +2 -1
  216. package/dist/shortcuts/workflow/index.js +2 -0
  217. package/dist/shortcuts/workflow/operations/form.js +32 -8
  218. package/dist/shortcuts/workflow/operations/write.js +1 -1
  219. package/docs/_catalog.md +3 -0
  220. package/docs/agent-invoice.md +1 -1
  221. package/docs/archive-oa.md +1 -1
  222. package/docs/caizhilian.md +1 -1
  223. package/docs/calendar.md +1 -1
  224. package/docs/contract.md +1 -1
  225. package/docs/e10-auth.md +16 -0
  226. package/docs/ehr.md +2 -2
  227. package/docs/esb.md +1 -1
  228. package/docs/im.md +1 -1
  229. package/docs/invoice.md +8 -12
  230. package/docs/okr.md +1 -1
  231. package/docs/reception.md +119 -0
  232. package/package.json +1 -1
  233. package/scripts/clean.mjs +43 -2
  234. package/skill-template/business-info.json +18 -2
  235. package/skill-template/domains/caizhilian.md +1 -1
  236. package/skill-template/domains/reception-flow.md +18 -0
  237. package/skill-template/domains/yepiaotong.md +4 -7
  238. package/skills/weaver-e10-archive-oa/references/source-manifest.json +14 -14
  239. package/skills/weaver-e10-blog/references/blog-publish.md +1 -1
  240. package/skills/weaver-e10-blog/references/source-manifest.json +7 -7
  241. package/skills/weaver-e10-caizhilian/references/source-manifest.json +21 -21
  242. package/skills/weaver-e10-caizhilian/references/write-protocol.md +2 -2
  243. package/skills/weaver-e10-calendar/references/calendar-write.md +1 -1
  244. package/skills/weaver-e10-cowork/SKILL.md +1 -1
  245. package/skills/weaver-e10-ebuilder-form/SKILL.md +1 -1
  246. package/skills/weaver-e10-ebuilder-form/references/custom-api.md +1 -1
  247. package/skills/weaver-e10-ebuilder-form/references/openapi-write.md +1 -1
  248. package/skills/weaver-e10-esb/SKILL.md +2 -2
  249. package/skills/weaver-e10-esb/references/source-manifest.json +22 -22
  250. package/skills/weaver-e10-esb/references/trigger.md +2 -2
  251. package/skills/weaver-e10-jinchengda/references/contract-clause-library-crud.md +1 -1
  252. package/skills/weaver-e10-jinchengda/references/contract-clause-reference-save.md +1 -1
  253. package/skills/weaver-e10-jinchengda/references/contract-request-write.md +1 -1
  254. package/skills/weaver-e10-jinchengda/references/source-manifest.json +29 -29
  255. package/skills/weaver-e10-jucailin/SKILL.md +1 -1
  256. package/skills/weaver-e10-jucailin/references/attend-write.md +2 -2
  257. package/skills/weaver-e10-jucailin/references/recruit-create.md +12 -3
  258. package/skills/weaver-e10-jucailin/references/recruit-write.md +1 -1
  259. package/skills/weaver-e10-meeting/SKILL.md +8 -6
  260. package/skills/weaver-e10-meeting/references/meeting-change.md +1 -1
  261. package/skills/weaver-e10-meeting/references/meeting-create.md +1 -1
  262. package/skills/weaver-e10-meeting/references/meeting-lifecycle.md +1 -1
  263. package/skills/weaver-e10-meeting/references/meeting-verification.md +1 -1
  264. package/skills/weaver-e10-okr/references/okr-align.md +1 -1
  265. package/skills/weaver-e10-okr/references/okr-keyresult.md +1 -1
  266. package/skills/weaver-e10-okr/references/okr-write.md +1 -1
  267. package/skills/weaver-e10-okr/references/source-manifest.json +8 -8
  268. package/skills/weaver-e10-plan/references/plan-report-write.md +1 -1
  269. package/skills/weaver-e10-plan/references/source-manifest.json +20 -20
  270. package/skills/weaver-e10-qiyecheng/references/loan-management.md +1 -1
  271. package/skills/weaver-e10-qiyecheng/references/source-manifest.json +18 -18
  272. package/skills/weaver-e10-reception-flow/SKILL.md +173 -0
  273. package/skills/weaver-e10-reception-flow/assets//350/241/214/347/250/213/345/215/225/346/250/241/346/235/277-/346/263/233/345/276/256.docx +0 -0
  274. package/skills/weaver-e10-reception-flow/data/fields-snapshot.json +213 -0
  275. package/skills/weaver-e10-reception-flow/references/browsertool.md +68 -0
  276. package/skills/weaver-e10-reception-flow/references/env-pitfalls.md +51 -0
  277. package/skills/weaver-e10-reception-flow/references/fields-snapshot.md +227 -0
  278. package/skills/weaver-e10-reception-flow/references/guide.md +179 -0
  279. package/skills/weaver-e10-reception-flow/scripts/locate.sh +14 -0
  280. package/skills/weaver-e10-reception-flow/scripts/render.py +724 -0
  281. package/skills/weaver-e10-recruit-stage/SKILL.md +9 -5
  282. package/skills/weaver-e10-recruit-stage/lib/recruit-xiaoe-file.mjs +1 -1
  283. package/skills/weaver-e10-recruit-stage/lib/xiaoe-session.mjs +66 -0
  284. package/skills/weaver-e10-recruit-stage/references/position-templates.md +202 -0
  285. package/skills/weaver-e10-recruit-stage/references/recruit-jd-create.md +22 -0
  286. package/skills/weaver-e10-recruit-stage/references/recruit-resume-import.md +14 -1
  287. package/skills/weaver-e10-shared/references/e10-auth-and-session.md +6 -0
  288. package/skills/weaver-e10-shijingran/SKILL.md +5 -5
  289. package/skills/weaver-e10-shijingran/references/source-manifest.json +37 -36
  290. package/skills/weaver-e10-skill-maker/references/module-cli-generation.md +2 -0
  291. package/skills/weaver-e10-wenshuding/references/source-manifest.json +3 -3
  292. package/skills/weaver-e10-workflow/references/source-manifest.json +32 -32
  293. package/skills/weaver-e10-yepiaotong/SKILL.md +19 -26
  294. package/skills/weaver-e10-yepiaotong/references/invoice-detail.md +13 -10
  295. package/skills/weaver-e10-yepiaotong/references/invoice-enterprise-list.md +2 -0
  296. package/skills/weaver-e10-yepiaotong/references/invoice-issuing-workflow.md +194 -155
  297. package/skills/weaver-e10-yepiaotong/references/invoice-output-view.md +28 -32
  298. package/skills/weaver-e10-yepiaotong/references/invoice-personal-list.md +5 -1
  299. package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +8 -10
  300. package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +211 -616
  301. package/skills/weaver-e10-yepiaotong/references/reim-examples.md +149 -117
  302. package/skills/weaver-e10-yepiaotong/references/reim-expense-subject-rules.md +17 -20
  303. package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +20 -39
  304. package/skills/weaver-e10-yepiaotong/references/reim-matching-rules.md +55 -22
  305. package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +7 -17
  306. package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +88 -92
  307. package/skills/weaver-e10-yepiaotong/references/source-manifest.json +144 -354
  308. package/skills/weaver-e10-yimiaoban/SKILL.md +1 -1
  309. package/skills/weaver-e10-yimiaoban/references/msg-write.md +1 -1
  310. package/skills/weaver-e10-yimiaoban/references/safety-boundaries.md +1 -1
  311. package/skills/weaver-e10-yimiaoban/references/source-manifest.json +7 -7
  312. package/dist/chunks/chunk-TTPJJJC4.js +0 -465
  313. package/dist/chunks/registry-BKBZPBAJ.js +0 -23
  314. package/dist/shortcuts/invoice/markdown.js +0 -172
  315. package/dist/shortcuts/invoice/operations/issuing-qys.js +0 -424
  316. package/skills/weaver-e10-meeting.zip +0 -0
  317. package/skills/weaver-e10-yepiaotong/references/invoice-issuing-examples.md +0 -131
  318. package/skills/weaver-e10-yepiaotong/references/invoice-issuing-form-fill-rules.md +0 -179
@@ -5,6 +5,24 @@ import { homedir } from 'node:os';
5
5
  import { createRecruitContextLoader, } from '../ehr/operations/recruit.js';
6
6
  import { rsFail } from './errors.js';
7
7
  const flowMemo = new Map();
8
+ /**
9
+ * 自用系统(selfUse=1)默认招聘流程兜底常量 —— 2026-11-05 用户明确指定写死。
10
+ *
11
+ * 背景:www.e-cology.com.cn 是自用系统,招聘流程**只有一条**「初筛+面试+offer阶段」。
12
+ * 该环境的运行时解析通道全部取不到值(实测):
13
+ * · 环境缓存无 defaultRecruitFlow 键、无 menus 字段
14
+ * · 原接口 /api/recruit/position/recruitFlow/list 不存在(静默失败)
15
+ * · 招聘流程菜单列表经 listInit + getListDatas 仍未返回可用行
16
+ *
17
+ * ⚠️ 与技能「环境 id 绝不入包、跨环境自适应」原则冲突,故**加双重守卫**:
18
+ * 仅当 selfUse=1 且域名等于 selfUseHost 时才使用本常量;其他环境继续走运行时解析,不受影响。
19
+ * 换环境或该流程数据变更时必须同步修改此处。
20
+ */
21
+ const SELFUSE_DEFAULT_FLOW = {
22
+ selfUseHost: 'www.e-cology.com.cn',
23
+ id: '874896524979806209',
24
+ name: '初筛+面试+offer阶段',
25
+ };
8
26
  const digitalMenuMemo = new Map();
9
27
  function cacheDirFor(baseUrl) {
10
28
  const url = new URL(baseUrl);
@@ -24,29 +42,63 @@ async function readLegacyCacheExtra(baseUrl) {
24
42
  const dir = cacheDirFor(baseUrl);
25
43
  if (!existsSync(dir))
26
44
  return { defaultRecruitFlow: null, digitalHumanMenu: null };
27
- const files = (await import('node:fs/promises')).readdir(dir);
28
- const jsonFiles = (await files).filter((f) => f.endsWith('.json'));
29
- if (jsonFiles.length !== 1)
30
- return { defaultRecruitFlow: null, digitalHumanMenu: null };
31
- const raw = JSON.parse(await readFile(join(dir, jsonFiles[0]), 'utf8'));
32
- const flow = raw?.defaultRecruitFlow && raw.defaultRecruitFlow.id
33
- ? { id: String(raw.defaultRecruitFlow.id), name: String(raw.defaultRecruitFlow.name || '') }
34
- : null;
35
- const dh = raw?.lists?.digital_human?.listId
36
- ? {
37
- menuName: String(raw.lists.digital_human.menuName || '面试数字人配置'),
38
- listId: String(raw.lists.digital_human.listId),
39
- cusMenuId: String(raw.lists.digital_human.cusMenuId || ''),
45
+ const files = await (await import('node:fs/promises')).readdir(dir);
46
+ const jsonFiles = files.filter((f) => f.endsWith('.json'));
47
+ // 原实现要求「目录内恰好 1 个 json 才读」,多环境/多应用共存时必然读不到 →
48
+ // 改为遍历全部 json,取第一个带所需键的(2026-11-05 修)。
49
+ let flow = null;
50
+ let dh = null;
51
+ for (const f of jsonFiles) {
52
+ let raw;
53
+ try {
54
+ raw = JSON.parse(await readFile(join(dir, f), 'utf8'));
55
+ }
56
+ catch {
57
+ continue;
58
+ }
59
+ if (!flow && raw?.defaultRecruitFlow && raw.defaultRecruitFlow.id) {
60
+ flow = { id: String(raw.defaultRecruitFlow.id), name: String(raw.defaultRecruitFlow.name || '') };
61
+ }
62
+ if (!dh && raw?.lists?.digital_human?.listId) {
63
+ dh = {
64
+ menuName: String(raw.lists.digital_human.menuName || '面试数字人配置'),
65
+ listId: String(raw.lists.digital_human.listId),
66
+ cusMenuId: String(raw.lists.digital_human.cusMenuId || ''),
67
+ };
40
68
  }
41
- : null;
69
+ if (flow && dh)
70
+ break;
71
+ }
42
72
  return { defaultRecruitFlow: flow, digitalHumanMenu: dh };
43
73
  }
44
74
  catch {
45
75
  return { defaultRecruitFlow: null, digitalHumanMenu: null };
46
76
  }
47
77
  }
48
- /** 默认招聘流程解析:招聘设置/流程列表中「默认启用」的那条(运行时解析,跨环境不写死)。 */
49
- async function resolveDefaultRecruitFlow(host, baseUrl, appId) {
78
+ /** 从菜单树/list 里找「招聘流程」列表参数(本环境实测存在于 lists.all_search) */
79
+ function findFlowMenu(cache) {
80
+ const all = ((cache.lists || {}).all_search || []);
81
+ const hit = all.find((m) => m && m.listId && /招聘流程/.test(String(m.menuName || '')));
82
+ if (hit) {
83
+ return { listId: String(hit.listId), cusMenuId: String(hit.cusMenuId || ''), menuName: String(hit.menuName || '招聘流程') };
84
+ }
85
+ return null;
86
+ }
87
+ /** 判断某行是否为「默认启用」流程:兼容多种字段命名 */
88
+ function isDefaultFlowRow(x) {
89
+ if (!x)
90
+ return false;
91
+ const cands = [x.is_default, x.isDefault, x.default_flow, x.defaultFlow, x.is_enable, x.enabled, x.status];
92
+ for (const v of cands) {
93
+ if (v === true || v === 1 || v === '1')
94
+ return true;
95
+ if (String(v) === '是' || String(v) === '启用' || String(v) === '默认')
96
+ return true;
97
+ }
98
+ return false;
99
+ }
100
+ /** 默认招聘流程解析:优先 legacy 缓存 → 招聘流程菜单列表 → 旧接口兜底。失败**不缓存**(允许多次重试)。 */
101
+ async function resolveDefaultRecruitFlow(host, baseUrl, appId, cache) {
50
102
  const memoKey = baseUrl;
51
103
  if (flowMemo.has(memoKey))
52
104
  return flowMemo.get(memoKey) ?? null;
@@ -56,24 +108,84 @@ async function resolveDefaultRecruitFlow(host, baseUrl, appId) {
56
108
  return legacy.defaultRecruitFlow;
57
109
  }
58
110
  let result = null;
59
- try {
60
- // 招聘流程配置( hire structures ):优先业务配置通道;接口不可用或为空时保持 null(由摘要标注"未解析到默认流程")
61
- const r = await host.request({
62
- path: '/api/recruit/position/recruitFlow/list',
63
- method: 'POST',
64
- body: { appId, current: 1, pageSize: 50 },
65
- operation: 'context.defaultRecruitFlow',
66
- });
67
- const rows = r?.data?.list || r?.data?.rows || r?.data || [];
68
- const list = Array.isArray(rows) ? rows : [];
69
- const enabled = list.find((x) => x && (x.isDefault === true || Number(x.isDefault) === 1 || x.default_flow === '1'))
70
- || list.find((x) => x && x.id);
71
- if (enabled?.id) {
72
- result = { id: String(enabled.id), name: String(enabled.name || enabled.flow_name || '') };
111
+ // ① 招聘流程菜单列表(本环境实测入口,原实现只调接口必然失败)
112
+ const menu = findFlowMenu(cache);
113
+ if (menu) {
114
+ try {
115
+ // getListDatas 的 passid/cid 必须是**表单 objId**,不是 listId;
116
+ // 先用 listInit 用 listId 反查 objId(口径同 interview-arrange 的数字人菜单解析)
117
+ let flowObjId = '';
118
+ try {
119
+ const liBody = {
120
+ cusMenuId: menu.cusMenuId,
121
+ listId: menu.listId,
122
+ urlPageTitle: menu.menuName,
123
+ };
124
+ liBody['appId_' + menu.listId] = appId;
125
+ const li = await host.request({ path: '/api/ebuilder/form/list/listInit', body: liBody });
126
+ flowObjId = String(li?.data?.objid || '');
127
+ }
128
+ catch { /* listInit 不可用 → 走接口兜底 */ }
129
+ if (flowObjId) {
130
+ const body = {
131
+ current: 1, pageSize: 50, tableuid: Math.random().toString(16).slice(2, 34),
132
+ listId: menu.listId, searchParamData: { searchType: '3', type: 'and' },
133
+ terminal: 'PC', browser: 'Chrome', requiredMatch: 1, mapResult: 1,
134
+ recheckQuery: 1, isFollow: 0, isShareToMe: 0, filterCondition: {},
135
+ cusMenuId: menu.cusMenuId, urlPageTitle: menu.menuName, menuName: menu.menuName,
136
+ };
137
+ const r = await host.request({
138
+ path: `/api/ebuilder/form/list/getListDatas?passid=${flowObjId}&cid=${flowObjId}`,
139
+ body,
140
+ headers: { ebBusinessId: menu.listId },
141
+ });
142
+ const rows = (r?.data?.data || r?.data?.displayData || []);
143
+ const pick = rows.find(isDefaultFlowRow) || (rows.length === 1 ? rows[0] : null);
144
+ if (pick) {
145
+ const id = String(pick.form_data_id || pick.id || '');
146
+ const name = String(pick.name || pick.flow_name || pick.content || '');
147
+ if (id && name)
148
+ result = { id, name };
149
+ }
150
+ }
151
+ }
152
+ catch { /* 菜单通道不可用 → 走接口兜底 */ }
153
+ }
154
+ // ② 旧接口兜底(原实现唯一通道,部分环境保留)
155
+ if (!result) {
156
+ try {
157
+ const r = await host.request({
158
+ path: '/api/recruit/position/recruitFlow/list',
159
+ method: 'POST',
160
+ body: { appId, current: 1, pageSize: 50 },
161
+ operation: 'context.defaultRecruitFlow',
162
+ });
163
+ const rows = r?.data?.list || r?.data?.rows || r?.data || [];
164
+ const list = Array.isArray(rows) ? rows : [];
165
+ const enabled = list.find(isDefaultFlowRow) || null;
166
+ if (enabled?.id) {
167
+ result = { id: String(enabled.id), name: String(enabled.name || enabled.flow_name || '') };
168
+ }
169
+ }
170
+ catch { /* 接口形态不符/未开放 */ }
171
+ }
172
+ // ③ 自用系统兜底(用户指定写死):仅 selfUse=1 且域名匹配时生效,不影响其他环境
173
+ if (!result) {
174
+ const isSelfUse = String(cache?.selfUse || '') === '1';
175
+ let host = '';
176
+ try {
177
+ host = new URL(baseUrl).hostname;
178
+ }
179
+ catch {
180
+ host = '';
181
+ }
182
+ if (isSelfUse && host === SELFUSE_DEFAULT_FLOW.selfUseHost) {
183
+ result = { id: SELFUSE_DEFAULT_FLOW.id, name: SELFUSE_DEFAULT_FLOW.name };
73
184
  }
74
185
  }
75
- catch { /* 接口形态不符/未开放:保持 null,不阻塞建职位 */ }
76
- flowMemo.set(memoKey, result);
186
+ // 只有解析成功才写入 memo:失败若也缓存 null,进程内后续所有请求都拿不到(原实现缺陷)
187
+ if (result)
188
+ flowMemo.set(memoKey, result);
77
189
  return result;
78
190
  }
79
191
  async function resolveDigitalHumanMenu(host, baseUrl, cache) {
@@ -102,7 +214,7 @@ export function createRecruitStageContext() {
102
214
  const cache = await loaders.get(loaderKey).load(host);
103
215
  const baseUrl = (await host.getSession()).baseUrl.replace(/\/+$/, '');
104
216
  const [defaultRecruitFlow, digitalHumanMenu] = await Promise.all([
105
- resolveDefaultRecruitFlow(host, baseUrl, cache.appId),
217
+ resolveDefaultRecruitFlow(host, baseUrl, cache.appId, cache),
106
218
  resolveDigitalHumanMenu(host, baseUrl, cache),
107
219
  ]);
108
220
  return { ...cache, defaultRecruitFlow, digitalHumanMenu };
@@ -1,3 +1,4 @@
1
+ import { CONTINUATION_TTL_MS } from '../../core/continuation-ttl.js';
1
2
  import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
2
3
  import { existsSync } from 'node:fs';
3
4
  import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises';
@@ -35,7 +36,7 @@ function signature(payload, key) {
35
36
  }
36
37
  export function createRecruitStageContinuationSigner(ctx) {
37
38
  return {
38
- async issue(payload, ttlMs = 10 * 60_000) {
39
+ async issue(payload, ttlMs = CONTINUATION_TTL_MS) {
39
40
  const issuedAt = Date.now();
40
41
  const body = encode({ ...payload, issuedAt, expiresAt: issuedAt + ttlMs });
41
42
  const sig = signature(body, await loadKey(ctx));
@@ -35,9 +35,10 @@ const DATAKEYS_MTEXT = ['position_duty', 'work_request'];
35
35
  const DEF_TEXT = { recruit_count: '1', number_of_pay_months: '12' };
36
36
  const DEF_OPTION = { salary_type: '月薪', recruit_type: '社会招聘' };
37
37
  const DEF_CURRENT_USER = ['recr_principal', 'employ_manager'];
38
+ // 🔴 薪资不继承:历史职位薪资可能是脏数据(实测抓到 300 元月薪),
39
+ // 改为按 references/position-templates.md §1.1 的推荐表由 Agent 填入 sets,未指定就留空。
38
40
  const DEF_FROM_REF = [
39
41
  'position_nature', 'job_category', 'education', 'work_years', 'work_location',
40
- 'salary_min', 'salary_max',
41
42
  ];
42
43
  const DEF_STATUS = '招聘中';
43
44
  // sets 覆盖解析:字段取值类别
@@ -115,14 +116,63 @@ function refToSubmit(d) {
115
116
  return null;
116
117
  return o;
117
118
  }
118
- // 工作地点:按名称/详细地址/城市解析「办公地点」记录 id(tag uf_rcrt_work_place → 表单 → 列表匹配)
119
+ // 工作地点的「办公地点」菜单定位:三级来源,不依赖 cache.menus
120
+ // 实测(2026-11-05):本环境环境缓存**没有 menus 字段**(只有 forms/lists/fields/dict 等),
121
+ // 原实现直接读 cache.menus → 拿到 undefined → findMenuNode 返回 null → resolveWorkLocation 恒为 null
122
+ // → work_location 每次进 setSkipped(连完整地址都写不进去)。改为:
123
+ // ① cache.lists.all_search(与面试数字人菜单解析同一模式,已在用)
124
+ // ② cache.menus(若某环境确实有)
125
+ // ③ allMenus 接口兜底(resolvePositionNewUrl 已在用,同一写法)
126
+ const WORK_PLACE_NAMES = ['办公地点', '工作地点'];
127
+ async function findWorkPlaceMenu(ctx) {
128
+ const { host, appId, cache } = ctx;
129
+ const ok = (m) => m && m.listId;
130
+ // ① all_search
131
+ const allSearch = ((cache.lists || {}).all_search || []);
132
+ const hit1 = allSearch.find((m) => ok(m) && WORK_PLACE_NAMES.some((n) => String(m.menuName || '').includes(n)));
133
+ if (hit1)
134
+ return { listId: String(hit1.listId), cusMenuId: String(hit1.cusMenuId || ''), menuName: String(hit1.menuName || '') };
135
+ // ② cache.menus(可能不存在)
136
+ const hit2 = findMenuNode(cache.menus || [], WORK_PLACE_NAMES, (m) => ok(m));
137
+ if (hit2)
138
+ return { listId: String(hit2.listId), cusMenuId: String(hit2.cusMenuId || ''), menuName: String(hit2.menuName || '') };
139
+ // ③ allMenus 接口
140
+ try {
141
+ const r = await host.request({ path: `/api/cusapp/app/allMenus?isFront=1&appId=${appId}&terminalType=PC`, method: 'GET' });
142
+ const flat = [];
143
+ (function walk(ns) { for (const n of (ns || []))
144
+ if (n && typeof n === 'object') {
145
+ flat.push(n);
146
+ walk(n.children || n.childs);
147
+ } })(r?.data?.cusAppMenus || r?.data);
148
+ const hit3 = findMenuNode(flat, WORK_PLACE_NAMES, (m) => ok(m));
149
+ if (hit3)
150
+ return { listId: String(hit3.listId), cusMenuId: String(hit3.cusMenuId || ''), menuName: String(hit3.menuName || '') };
151
+ }
152
+ catch { /* 接口不可用则放弃 */ }
153
+ return null;
154
+ }
155
+ // 工作地点:按名称/详细地址/城市解析「办公地点」记录 id
119
156
  async function resolveWorkLocation(ctx, value) {
120
157
  const { host, appId, cache } = ctx;
121
- const t = await host.request({ path: `/api/ebuilder/form/obj/getObjsByTag?appId=${appId}&tag=uf_rcrt_work_place`, method: 'GET' });
122
- const d = t?.data;
123
- const pObj = (Array.isArray(d) && d[0]) ? String(d[0].id || '') : '';
124
- const menu = findMenuNode(cache.menus || [], ['办公地点', '工作地点'], (m) => m.listId && m.cusMenuId);
125
- if (!pObj || !menu)
158
+ const v = String(value).trim();
159
+ if (!v)
160
+ return null;
161
+ // objId:优先按 tag 取;取不到时用菜单节点自带的(部分环境 tag 未注册)
162
+ let pObj = '';
163
+ try {
164
+ const t = await host.request({ path: `/api/ebuilder/form/obj/getObjsByTag?appId=${appId}&tag=uf_rcrt_work_place`, method: 'GET' });
165
+ const d = t?.data;
166
+ if (Array.isArray(d) && d[0])
167
+ pObj = String(d[0].id || '');
168
+ }
169
+ catch { /* tag 未注册:继续用菜单兜底 */ }
170
+ const menu = await findWorkPlaceMenu(ctx);
171
+ if (!menu)
172
+ return null;
173
+ if (!pObj)
174
+ pObj = String(menu.objId || '');
175
+ if (!pObj)
126
176
  return null;
127
177
  const body = {
128
178
  current: 1, pageSize: 200, tableuid: randHex32(),
@@ -132,10 +182,12 @@ async function resolveWorkLocation(ctx, value) {
132
182
  cusMenuId: menu.cusMenuId, urlPageTitle: menu.menuName, menuName: menu.menuName,
133
183
  };
134
184
  const r = await host.request({ path: `/api/ebuilder/form/list/getListDatas?passid=${pObj}&cid=${pObj}`, body, headers: { ebBusinessId: menu.listId } });
135
- const rows = r?.data?.data || [];
136
- const v = String(value).trim();
185
+ // displayData 是服务端翻译后的可读文本;data 为原始行 —— 两者都兜
186
+ const rows = r?.data?.data || r?.data?.displayData || [];
137
187
  const hit = rows.find((x) => {
138
- const name = String(x.name || ''), detail = String(x.detail_location || ''), area = String(x.area_text || '');
188
+ const name = String(x.name || x.detail_location || '');
189
+ const detail = String(x.detail_location || '');
190
+ const area = String(x.area_text || '');
139
191
  return name.includes(v) || detail.includes(v) || area.includes(v) || (detail && v.includes(detail));
140
192
  });
141
193
  return hit ? { id: String(hit.form_data_id || hit.id), name: String(hit.detail_location || hit.name || v) } : null;
@@ -391,6 +443,10 @@ async function buildJd(opts) {
391
443
  }
392
444
  }
393
445
  }
446
+ // 其余必填字段默认值:从「环境内最近一条职位记录」继承
447
+ // ⚠️ 继承来源可能是脏数据(实测本环境 836 条职位中「蓝堡舟山普陀区蓝堡」占 35 条),
448
+ // 因此逐个字段记录 inheritedFromRef,在确认摘要里明示,避免用户以为是自己指定的值。
449
+ const inheritedFromRef = [];
394
450
  for (const k of DEF_FROM_REF) {
395
451
  const id = fid(k);
396
452
  if (id && !map.has(String(id)) && refByFid[String(id)]) {
@@ -398,6 +454,7 @@ async function buildJd(opts) {
398
454
  if (d) {
399
455
  put(d);
400
456
  filled.push(k);
457
+ inheritedFromRef.push({ field: k, value: detailValueId(refByFid[String(id)]) });
401
458
  }
402
459
  }
403
460
  }
@@ -414,10 +471,17 @@ async function buildJd(opts) {
414
471
  requestLen: (requestText || '').length,
415
472
  demand: demandId ? (demandName || demandId) : '(未关联需求)',
416
473
  status: DEF_STATUS,
417
- recruitFlow: (defFlow && defFlow.id) ? defFlow.name : '(未解析到默认流程)',
474
+ // 解析不到环境默认流程时不写该字段,表单自身默认值生效;文案按实际行为表述,避免误导。
475
+ recruitFlow: (defFlow && defFlow.id) ? defFlow.name : '(沿用表单默认值)',
418
476
  currentUser: currentUser ? currentUser.name : null,
419
477
  setApplied: appliedSets,
420
478
  setSkipped: skippedSets,
479
+ // 明示哪些字段值继承自「环境内最近一条职位记录」——这些不是用户指定的,可能来自脏数据,
480
+ // 必须在确认摘要里人工核对(尤其 work_location)
481
+ inheritedFromRef: inheritedFromRef.length ? inheritedFromRef : undefined,
482
+ inheritedNote: inheritedFromRef.length
483
+ ? '以上字段未指定,值继承自环境内最近一条职位记录,可能含历史脏数据(如重复地点),请核对后再提交'
484
+ : undefined,
421
485
  requiredDefaultsFilled,
422
486
  },
423
487
  };
@@ -456,19 +520,44 @@ async function prepare(args, env) {
456
520
  demandName: args.demandName ? String(args.demandName) : undefined,
457
521
  sets: setsOf(args),
458
522
  });
459
- const refs = await fetchRecentReferences(ctx, jd, String(args.referenceKeyword || positionName))
460
- .catch((e) => ({ available: false, reason: e.message, items: [] }));
523
+ // 参考检索默认关闭:环境职位数据重复严重(实测 836 条中「舟山民宿管家」30 条)且列表层
524
+ // 无薪资/学历字段,参考价值低于请求成本。需要时显式传 referenceKeyword 才执行;
525
+ // 岗位范式改由 references/position-templates.md 提供(零请求)。
526
+ const refs = args.referenceKeyword
527
+ ? await fetchRecentReferences(ctx, jd, String(args.referenceKeyword))
528
+ .catch((e) => ({ available: false, reason: e.message, items: [] }))
529
+ : {
530
+ available: false,
531
+ skipped: true,
532
+ reason: '未显式指定 referenceKeyword,已跳过同类职位参考检索(改用 references/position-templates.md 的岗位模板)',
533
+ items: [],
534
+ };
535
+ // fingerprint 必须基于完整 dataDetails(apply 阶段比对同一口径),回执里才做瘦身。
461
536
  const willSubmit = { formId: jd.formId, objId: jd.objId, dataDetails: jd.dataDetails };
462
537
  const fp = fingerprint(willSubmit);
463
538
  const continuation = await env.continuation.issue({ operation: 'recruit-stage.jd.create.apply', fingerprint: fp });
539
+ // 回执瘦身:willSubmit 只输出字段名清单(不含内部 fieldId),continuation 提到首部——
540
+ // 避免大输出被截断导致 Agent 取不到 continuation 而重复调用 prepare(实测多花 10.7s)。
541
+ const invFieldKeys = {};
542
+ for (const [k, v] of Object.entries(ctx.cache.fields[jd.objId] || {}))
543
+ invFieldKeys[String(v)] = k;
464
544
  return rsSuccess('recruit-stage.jd.create.prepare', {
465
545
  mode: 'prepare',
546
+ continuation,
547
+ fingerprint: fp,
466
548
  ...jd.summary,
467
549
  recentReferences: refs.items,
468
- recentReferencesNote: refs.available
469
- ? `已按「${refs.keyword}」在当前环境职位列表中检索(扫描 ${refs.scanned} 条,命中 ${refs.items.length} 条)——请对标这些同类职位的薪酬/人数/要求给出推荐值,一并放进确认摘要,不要逐字段询问用户`
470
- : ('参考检索不可用:' + (refs.reason || '')),
471
- willSubmit,
550
+ recentReferencesNote: refs.skipped
551
+ ? refs.reason
552
+ : refs.available
553
+ ? `已按「${refs.keyword}」在当前环境职位列表中检索(扫描 ${refs.scanned} 条,命中 ${refs.items.length} 条)——请对标这些同类职位的薪酬/人数/要求给出推荐值,一并放进确认摘要,不要逐字段询问用户`
554
+ : ('参考检索不可用:' + (refs.reason || '')),
555
+ willSubmit: {
556
+ formId: willSubmit.formId,
557
+ objId: willSubmit.objId,
558
+ fieldCount: willSubmit.dataDetails.length,
559
+ fields: willSubmit.dataDetails.map((d) => invFieldKeys[String(d.formField && d.formField.id)] || String(d.formField && d.formField.id)),
560
+ },
472
561
  }, {
473
562
  continuation,
474
563
  fingerprint: fp,
@@ -223,10 +223,14 @@ function buildSubDetails(structured, subs, cache) {
223
223
  const parts = Array.isArray(v) ? v : String(v).split(/[,~]/);
224
224
  const s = String(parts[0] || '').trim();
225
225
  const e = String(parts[1] || '').trim();
226
- if (!s || !e)
226
+ // 「至今」的岗位/项目只有开始日期(实测 2026-11-05:原逻辑一旦缺 end 就整行跳过,
227
+ // 导致在职经历的起始日期丢失)。有哪个写哪个,两者都空才跳过。
228
+ if (s)
229
+ row[col.startKey] = s;
230
+ if (e)
231
+ row[col.endKey] = e;
232
+ if (!s && !e)
227
233
  continue;
228
- row[col.startKey] = s;
229
- row[col.endKey] = e;
230
234
  continue;
231
235
  }
232
236
  const scalar = typeof v === 'object' ? String(v.optionId ?? v.content ?? '') : String(v);
@@ -632,6 +636,140 @@ function normalizeTextStructured(cache, s, warnings) {
632
636
  fixRows(s.languageAbilities, ['mastery', 'ls_ability', 'literacy']);
633
637
  return s;
634
638
  }
639
+ // ── 日期格式预检与归一(prepare 阶段前置,避免格式引发连锁失败)──
640
+ // 实测(2026-11-05):人才表单接口只接受 yyyy-MM-dd。模型常给「2020.11」「2008-08」「2004.09-2008.07」,
641
+ // 会让 dataset 新增整批校验失败 → 回退 form/core 建主表 → 回退补明细又被同一格式拦下 → 明细全丢却报 success,
642
+ // 且实测多花 3.4s(5523ms vs 2105ms)。此处统一归一:
643
+ // · 只有年月 → 开始补 -01、结束补当月最后一天(语义约定,写入 warnings 明示)
644
+ // · 「至今/现在」→ 空(表示至今,不伪造结束日)
645
+ // · 区间统一成 "start,end"(comma 分隔,供 DateRange 拆两键)
646
+ // · 无法识别 → 跳过该字段并告警(宁缺勿整批失败),绝不静默改写
647
+ const DATE_ONLY_RE = /^\d{4}-\d{2}-\d{2}$/;
648
+ const ONGOING_RE = /至今|现在|今|now|present/i;
649
+ const RE_RANGE_FULL = /^\s*(\d{4}[.\-/年]\d{1,2}[.\-/月]\d{1,2}\s*日?)\s*[-–—~至,,]\s*(\d{4}[.\-/年]\d{1,2}[.\-/月]\d{1,2}\s*日?|至今|现在|今)\s*$/;
650
+ const RE_RANGE_YM = /^\s*(\d{4}[.\-/年]\d{1,2})\s*[-–—~至,,]\s*(\d{4}[.\-/年]\d{1,2}|至今|现在|今)\s*$/;
651
+ /** 单日期片段 → yyyy-MM-dd;isEnd=true 且缺日时补该月最后一天。无法解析返回 ''。 */
652
+ function normDatePart(raw, isEnd) {
653
+ const s = String(raw ?? '').trim();
654
+ if (!s)
655
+ return '';
656
+ if (ONGOING_RE.test(s))
657
+ return '';
658
+ if (DATE_ONLY_RE.test(s))
659
+ return s;
660
+ const m = s.match(/^(\d{4})\s*[.\-/年]?\s*(\d{1,2})?\s*[.\-/月]?\s*(\d{1,2})?\s*日?$/);
661
+ if (!m)
662
+ return '';
663
+ const y = Number(m[1]);
664
+ const mo = m[2] ? Number(m[2]) : 1;
665
+ if (!y || mo < 1 || mo > 12)
666
+ return '';
667
+ const lastDay = new Date(y, mo, 0).getDate();
668
+ let d;
669
+ if (m[3]) {
670
+ d = Number(m[3]);
671
+ if (d < 1 || d > lastDay)
672
+ return '';
673
+ }
674
+ else {
675
+ d = isEnd ? lastDay : 1;
676
+ }
677
+ return y + '-' + String(mo).padStart(2, '0') + '-' + String(d).padStart(2, '0');
678
+ }
679
+ /** 日期区间 → "start,end";只有单值时返回单值。 */
680
+ function normDateRange(raw) {
681
+ const s = Array.isArray(raw)
682
+ ? raw.map((x) => String(x ?? '').trim()).filter(Boolean).join(',')
683
+ : String(raw ?? '').trim();
684
+ if (!s)
685
+ return '';
686
+ const m = s.match(RE_RANGE_FULL) || s.match(RE_RANGE_YM);
687
+ if (m) {
688
+ const a = normDatePart(m[1], false);
689
+ if (!a)
690
+ return '';
691
+ const b = normDatePart(m[2], true);
692
+ return b ? a + ',' + b : a;
693
+ }
694
+ return normDatePart(s, false);
695
+ }
696
+ /** 就地归一结构化简历里的全部日期字段,把每处改动写进 warnings(不静默改写)。 */
697
+ function normalizeDates(s, warnings) {
698
+ if (!s || typeof s !== 'object')
699
+ return;
700
+ const one = (label, val, isEnd = false) => {
701
+ const before = String(val ?? '').trim();
702
+ if (!before)
703
+ return '';
704
+ if (ONGOING_RE.test(before))
705
+ return '';
706
+ const after = normDatePart(before, isEnd);
707
+ if (!after) {
708
+ warnings.push('日期无法识别,已跳过该字段(避免接口整批校验失败):' + label + ' = 「' + before + '」');
709
+ return '';
710
+ }
711
+ if (after !== before)
712
+ warnings.push('日期已规范化:' + label + ' 「' + before + '」→「' + after + '」');
713
+ return after;
714
+ };
715
+ // 主表单值日期
716
+ for (const k of ['joinworkdate', 'graduate_date', 'birthday']) {
717
+ if (s[k] === undefined || s[k] === null)
718
+ continue;
719
+ s[k] = one(k, s[k], false);
720
+ }
721
+ // 教育经历:区间(一个组件 = 起止两个物理字段,必须 comma 分隔)
722
+ if (Array.isArray(s.academicInformations)) {
723
+ for (let i = 0; i < s.academicInformations.length; i++) {
724
+ const r = s.academicInformations[i];
725
+ if (!r || typeof r !== 'object' || r.study_date === undefined)
726
+ continue;
727
+ const before = String(r.study_date ?? '').trim();
728
+ if (!before)
729
+ continue;
730
+ const after = normDateRange(before);
731
+ if (!after) {
732
+ warnings.push('日期区间无法识别,已跳过(避免接口整批校验失败):academicInformations[' + i + '].study_date = 「' + before + '」');
733
+ r.study_date = '';
734
+ }
735
+ else {
736
+ if (after !== before)
737
+ warnings.push('日期已规范化:academicInformations[' + i + '].study_date 「' + before + '」→「' + after + '」');
738
+ r.study_date = after;
739
+ }
740
+ }
741
+ }
742
+ // 工作/项目经历:起止为两个独立字段,需分别归一后由 buildSubDetails 拼成区间
743
+ for (const key of ['jobInformations', 'workExperiences', 'projectExperiences']) {
744
+ const arr = s[key];
745
+ if (!Array.isArray(arr))
746
+ continue;
747
+ for (let i = 0; i < arr.length; i++) {
748
+ const r = arr[i];
749
+ if (!r || typeof r !== 'object')
750
+ continue;
751
+ if (r.start_date !== undefined && r.start_date !== null) {
752
+ r.start_date = one(key + '[' + i + '].start_date', r.start_date, false);
753
+ }
754
+ if (r.end_date !== undefined && r.end_date !== null) {
755
+ r.end_date = one(key + '[' + i + '].end_date', r.end_date, true);
756
+ }
757
+ }
758
+ }
759
+ // 实习入职时间 / 获奖日期:单值日期
760
+ for (const [key, field] of [['internshipExperiences', 'entry_time'], ['awardExperiences', 'award_date']]) {
761
+ const arr = s[key];
762
+ if (!Array.isArray(arr))
763
+ continue;
764
+ for (let i = 0; i < arr.length; i++) {
765
+ const r = arr[i];
766
+ if (!r || typeof r !== 'object')
767
+ continue;
768
+ if (r[field] !== undefined && r[field] !== null)
769
+ r[field] = one(key + '[' + i + '].' + field, r[field], false);
770
+ }
771
+ }
772
+ }
635
773
  // 读回校验:统计各子表实际落库行数(不能只看写入接口返回,必须回读)
636
774
  async function verifySubRows(ctx, formId, objId, dataId) {
637
775
  const L = await getFormLayoutMeta(ctx.host, formId);
@@ -670,7 +808,9 @@ async function loadStructured(ctx, args) {
670
808
  if (!String(s.telephone || '').trim() && !String(s.candidateName || '').trim()) {
671
809
  throw rsValidationError('structured_invalid', '结构化简历缺少 telephone 与 candidateName(至少要有手机号或姓名,否则无法查重建档)');
672
810
  }
673
- return { structured: normalizeTextStructured(ctx.cache, s, warnings), textMode: true, warnings };
811
+ const normalizedInline = normalizeTextStructured(ctx.cache, s, warnings);
812
+ normalizeDates(normalizedInline, warnings);
813
+ return { structured: normalizedInline, textMode: true, warnings };
674
814
  }
675
815
  if (args.structuredFile) {
676
816
  const p = path.resolve(String(args.structuredFile));
@@ -680,7 +820,9 @@ async function loadStructured(ctx, args) {
680
820
  if (!String(s.telephone || '').trim() && !String(s.candidateName || '').trim()) {
681
821
  throw rsValidationError('structured_invalid', '结构化简历缺少 telephone 与 candidateName');
682
822
  }
683
- return { structured: normalizeTextStructured(ctx.cache, s, warnings), textMode: true, warnings };
823
+ const normalizedFile = normalizeTextStructured(ctx.cache, s, warnings);
824
+ normalizeDates(normalizedFile, warnings);
825
+ return { structured: normalizedFile, textMode: true, warnings };
684
826
  }
685
827
  return { structured: null, textMode: false, warnings };
686
828
  }
@@ -1053,9 +1195,10 @@ async function apply(args, env) {
1053
1195
  verifyWarnings = checkAfter(after);
1054
1196
  }
1055
1197
  return rsSuccess('recruit-stage.resume.import.apply', {
1056
- mode: 'update', result: 'success',
1198
+ // 更新模式同理:明细行/格数对不上时只能报 partial,不能因主表写入成功就报 success
1199
+ mode: 'update', result: verifyWarnings.length ? 'partial' : 'success',
1200
+ detailsState: verifyWarnings.length ? 'missing' : 'complete',
1057
1201
  talentId: updateTalentId,
1058
- applied: verifyWarnings, // placeholder replaced below
1059
1202
  afterSummary: { mainFieldCount: Object.keys(after.main).length, subRows: after.subRows, subCells: after.subCells },
1060
1203
  verifyWarnings: verifyWarnings.length ? verifyWarnings : undefined,
1061
1204
  talentCardUrl: resolveTalentCardUrl(ctx, updateTalentId),
@@ -1129,8 +1272,20 @@ async function apply(args, env) {
1129
1272
  addEntityTags(host, talentId, built.tagNames).then((v) => ({ ok: true, v }), (e) => ({ ok: false, e })),
1130
1273
  ]);
1131
1274
  const subTableVerify = verifyRes.ok ? verifyRes.v : { error: verifyRes.e?.message };
1132
- if (subTableVerify && subTableVerify.rowTotal === 0 && built.subRowTotal > 0) {
1133
- writeWarnings.push('明细行未落库(期望 ' + built.subRowTotal + ' 行,读回 0 行)');
1275
+ // 明细完整性判定:主表建成 ≠ 建档成功。实测(2026-11-05)出现过主表 19 字段写入成功、
1276
+ // 18 行明细 0 行落库,而返回仍是 result=success —— 只看 writeWarnings 才会发现问题。
1277
+ // 规则:期望行数 > 0 时读回行数必须 >= 期望,否则 result 只能报 partial;回读失败则标 unverified。
1278
+ let detailsState = 'complete';
1279
+ if (!verifyRes.ok) {
1280
+ detailsState = 'unverified';
1281
+ writeWarnings.push('明细读回校验失败(无法确认明细是否落库):' + (verifyRes.e?.message || ''));
1282
+ }
1283
+ else if (built.subRowTotal > 0) {
1284
+ const gotRows = Number(subTableVerify?.rowTotal || 0);
1285
+ if (gotRows < built.subRowTotal) {
1286
+ detailsState = 'missing';
1287
+ writeWarnings.push('明细行未完整落库(期望 ' + built.subRowTotal + ' 行,读回 ' + gotRows + ' 行):主表已写入,请按 writeWarnings 修正后走 updateTalentId 补明细');
1288
+ }
1134
1289
  }
1135
1290
  const saveEsbActions = esbRes.ok ? esbRes.v : { error: esbRes.e?.message };
1136
1291
  const labelMatch = labelRes.ok ? labelRes.v : 'ERR:' + (labelRes.e?.message || '');
@@ -1142,7 +1297,8 @@ async function apply(args, env) {
1142
1297
  const talentCardUrl = resolveTalentCardUrl(ctx, talentId);
1143
1298
  const talentListLocateUrl = resolveTalentListLocateUrl(ctx, talentId);
1144
1299
  return rsSuccess('recruit-stage.resume.import.apply', {
1145
- mode: 'apply', result: 'success',
1300
+ mode: 'apply', result: detailsState === 'complete' ? 'success' : 'partial',
1301
+ detailsState,
1146
1302
  newCandidateFormDataId: newId,
1147
1303
  talentId,
1148
1304
  writeChannel,
@@ -1,10 +1,11 @@
1
+ import { CONTINUATION_TTL_MS } from '../../core/continuation-ttl.js';
1
2
  import { createHash, createHmac, randomBytes, randomUUID, timingSafeEqual } from 'node:crypto';
2
3
  import { existsSync } from 'node:fs';
3
4
  import { chmod, mkdir, readFile, readdir, unlink, writeFile } from 'node:fs/promises';
4
5
  import { homedir, hostname } from 'node:os';
5
6
  import { resolve } from 'node:path';
6
7
  import { workflowAlreadyAppliedError, workflowPartialError, workflowValidationError, } from './errors.js';
7
- const DEFAULT_TTL_MS = 10 * 60_000;
8
+ const DEFAULT_TTL_MS = CONTINUATION_TTL_MS;
8
9
  /**
9
10
  * 「上一次只抢到句柄、还没发出写入」的**安全重占宽限期**。
10
11
  *