@xgjktech/xg_cwork_im 1.19.42 → 1.19.43

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 (370) hide show
  1. package/README.md +492 -492
  2. package/dist/src/account-connection.d.ts +1 -1
  3. package/dist/src/account-connection.d.ts.map +1 -1
  4. package/dist/src/account-connection.js +25 -136
  5. package/dist/src/account-connection.js.map +1 -1
  6. package/dist/src/account-reconciler.d.ts +8 -17
  7. package/dist/src/account-reconciler.d.ts.map +1 -1
  8. package/dist/src/account-reconciler.js +11 -31
  9. package/dist/src/account-reconciler.js.map +1 -1
  10. package/dist/src/account-reconciler.test.js +1 -19
  11. package/dist/src/account-reconciler.test.js.map +1 -1
  12. package/dist/src/action-store-access.d.ts +0 -2
  13. package/dist/src/action-store-access.d.ts.map +1 -1
  14. package/dist/src/action-store-access.js +0 -7
  15. package/dist/src/action-store-access.js.map +1 -1
  16. package/dist/src/active-round-registry.d.ts +0 -6
  17. package/dist/src/active-round-registry.d.ts.map +1 -1
  18. package/dist/src/active-round-registry.js +2 -27
  19. package/dist/src/active-round-registry.js.map +1 -1
  20. package/dist/src/agent-stream-client-registry.d.ts +0 -2
  21. package/dist/src/agent-stream-client-registry.d.ts.map +1 -1
  22. package/dist/src/agent-stream-client-registry.js +1 -6
  23. package/dist/src/agent-stream-client-registry.js.map +1 -1
  24. package/dist/src/apply-sync-mapping.d.ts +1 -1
  25. package/dist/src/apply-sync-mapping.d.ts.map +1 -1
  26. package/dist/src/auth.d.ts +0 -2
  27. package/dist/src/auth.d.ts.map +1 -1
  28. package/dist/src/auth.js +0 -4
  29. package/dist/src/auth.js.map +1 -1
  30. package/dist/src/block-streaming-config.test.js +1 -7
  31. package/dist/src/block-streaming-config.test.js.map +1 -1
  32. package/dist/src/build-project-prompt.test.js +18 -18
  33. package/dist/src/channel-config.d.ts +17 -83
  34. package/dist/src/channel-config.d.ts.map +1 -1
  35. package/dist/src/channel-config.js +13 -46
  36. package/dist/src/channel-config.js.map +1 -1
  37. package/dist/src/channel-config.test.js +1 -58
  38. package/dist/src/channel-config.test.js.map +1 -1
  39. package/dist/src/channel.d.ts +3 -4
  40. package/dist/src/channel.d.ts.map +1 -1
  41. package/dist/src/channel.js +4 -127
  42. package/dist/src/channel.js.map +1 -1
  43. package/dist/src/connection.d.ts +0 -28
  44. package/dist/src/connection.d.ts.map +1 -1
  45. package/dist/src/connection.js +78 -155
  46. package/dist/src/connection.js.map +1 -1
  47. package/dist/src/deliver-text.test.js +22 -22
  48. package/dist/src/delivery/deliver-text.test.js +22 -22
  49. package/dist/src/delivery/turn-deliver-buffer.test.js +25 -25
  50. package/dist/src/dispatch-mentioned-reply.d.ts +2 -7
  51. package/dist/src/dispatch-mentioned-reply.d.ts.map +1 -1
  52. package/dist/src/dispatch-mentioned-reply.js +68 -243
  53. package/dist/src/dispatch-mentioned-reply.js.map +1 -1
  54. package/dist/src/gateway-session-queue.d.ts +6 -2
  55. package/dist/src/gateway-session-queue.d.ts.map +1 -1
  56. package/dist/src/gateway-session-queue.js +21 -78
  57. package/dist/src/gateway-session-queue.js.map +1 -1
  58. package/dist/src/group-history-tool.d.ts +1 -1
  59. package/dist/src/group-history-tool.d.ts.map +1 -1
  60. package/dist/src/inbound-display.d.ts.map +1 -1
  61. package/dist/src/inbound-display.js +1 -2
  62. package/dist/src/inbound-display.js.map +1 -1
  63. package/dist/src/inbound-input-media.d.ts +1 -1
  64. package/dist/src/inbound-input-media.d.ts.map +1 -1
  65. package/dist/src/inbound-media-local.d.ts +1 -1
  66. package/dist/src/inbound-media-local.d.ts.map +1 -1
  67. package/dist/src/inbound-model.d.ts +0 -9
  68. package/dist/src/inbound-model.d.ts.map +1 -1
  69. package/dist/src/inbound-model.js +0 -26
  70. package/dist/src/inbound-model.js.map +1 -1
  71. package/dist/src/inbound-model.test.js +1 -23
  72. package/dist/src/inbound-model.test.js.map +1 -1
  73. package/dist/src/inbound-terminal-state.d.ts +0 -2
  74. package/dist/src/inbound-terminal-state.d.ts.map +1 -1
  75. package/dist/src/inbound-terminal-state.js +2 -7
  76. package/dist/src/inbound-terminal-state.js.map +1 -1
  77. package/dist/src/modified-file-push-tracker.d.ts +24 -0
  78. package/dist/src/modified-file-push-tracker.d.ts.map +1 -0
  79. package/dist/src/modified-file-push-tracker.js +125 -0
  80. package/dist/src/modified-file-push-tracker.js.map +1 -0
  81. package/dist/src/nas-volumes.d.ts +2 -12
  82. package/dist/src/nas-volumes.d.ts.map +1 -1
  83. package/dist/src/nas-volumes.js +37 -147
  84. package/dist/src/nas-volumes.js.map +1 -1
  85. package/dist/src/nas-volumes.test.js +7 -39
  86. package/dist/src/nas-volumes.test.js.map +1 -1
  87. package/dist/src/per-message-model-pending.d.ts +3 -38
  88. package/dist/src/per-message-model-pending.d.ts.map +1 -1
  89. package/dist/src/per-message-model-pending.js +7 -96
  90. package/dist/src/per-message-model-pending.js.map +1 -1
  91. package/dist/src/plan/action-dispatch-event-compat.test.d.ts +2 -0
  92. package/dist/src/plan/action-dispatch-event-compat.test.d.ts.map +1 -0
  93. package/dist/src/plan/action-dispatch-event-compat.test.js +81 -0
  94. package/dist/src/plan/action-dispatch-event-compat.test.js.map +1 -0
  95. package/dist/src/plan/action-store-lifecycle.test.js +5 -5
  96. package/dist/src/plan/plan-core-db.test.js +9 -9
  97. package/dist/src/plan/plan-core-snapshot.test.js +9 -9
  98. package/dist/src/plan-event-subscription.d.ts +1 -1
  99. package/dist/src/plan-event-subscription.d.ts.map +1 -1
  100. package/dist/src/plan-stat-event.d.ts +15 -4
  101. package/dist/src/plan-stat-event.d.ts.map +1 -1
  102. package/dist/src/plan-stat-event.js +37 -4
  103. package/dist/src/plan-stat-event.js.map +1 -1
  104. package/dist/src/plan-stat-event.test.js +118 -1
  105. package/dist/src/plan-stat-event.test.js.map +1 -1
  106. package/dist/src/plan-store-access.d.ts +23 -0
  107. package/dist/src/plan-store-access.d.ts.map +1 -0
  108. package/dist/src/plan-store-access.js +96 -0
  109. package/dist/src/plan-store-access.js.map +1 -0
  110. package/dist/src/plan-store-access.test.d.ts +2 -0
  111. package/dist/src/plan-store-access.test.d.ts.map +1 -0
  112. package/dist/src/plan-store-access.test.js +207 -0
  113. package/dist/src/plan-store-access.test.js.map +1 -0
  114. package/dist/src/plan-tool-middleware.d.ts +11 -3
  115. package/dist/src/plan-tool-middleware.d.ts.map +1 -1
  116. package/dist/src/plan-tool-middleware.js +60 -11
  117. package/dist/src/plan-tool-middleware.js.map +1 -1
  118. package/dist/src/plan-tool-middleware.test.js +603 -83
  119. package/dist/src/plan-tool-middleware.test.js.map +1 -1
  120. package/dist/src/plan-ws-registry.d.ts +0 -4
  121. package/dist/src/plan-ws-registry.d.ts.map +1 -1
  122. package/dist/src/plan-ws-registry.js +0 -12
  123. package/dist/src/plan-ws-registry.js.map +1 -1
  124. package/dist/src/plan-ws-registry.test.js +1 -19
  125. package/dist/src/plan-ws-registry.test.js.map +1 -1
  126. package/dist/src/progress-display.d.ts +77 -0
  127. package/dist/src/progress-display.d.ts.map +1 -0
  128. package/dist/src/progress-display.js +420 -0
  129. package/dist/src/progress-display.js.map +1 -0
  130. package/dist/src/register-per-message-model-hook.d.ts +2 -10
  131. package/dist/src/register-per-message-model-hook.d.ts.map +1 -1
  132. package/dist/src/register-per-message-model-hook.js +6 -32
  133. package/dist/src/register-per-message-model-hook.js.map +1 -1
  134. package/dist/src/resolve-inbound-group-prompt.d.ts +1 -17
  135. package/dist/src/resolve-inbound-group-prompt.d.ts.map +1 -1
  136. package/dist/src/resolve-inbound-group-prompt.js +2 -16
  137. package/dist/src/resolve-inbound-group-prompt.js.map +1 -1
  138. package/dist/src/run-usage-session.d.ts +1 -4
  139. package/dist/src/run-usage-session.d.ts.map +1 -1
  140. package/dist/src/run-usage-session.js +1 -13
  141. package/dist/src/run-usage-session.js.map +1 -1
  142. package/dist/src/run-usage.d.ts +0 -15
  143. package/dist/src/run-usage.d.ts.map +1 -1
  144. package/dist/src/run-usage.js +4 -30
  145. package/dist/src/run-usage.js.map +1 -1
  146. package/dist/src/run-usage.test.js +11 -99
  147. package/dist/src/run-usage.test.js.map +1 -1
  148. package/dist/src/send-file-tool.d.ts +1 -1
  149. package/dist/src/send-file-tool.d.ts.map +1 -1
  150. package/dist/src/send-group-message-tool.d.ts +1 -1
  151. package/dist/src/send-group-message-tool.d.ts.map +1 -1
  152. package/dist/src/session/build-project-prompt.test.js +18 -18
  153. package/dist/src/session-im-context.d.ts +0 -2
  154. package/dist/src/session-im-context.d.ts.map +1 -1
  155. package/dist/src/session-im-context.js +2 -11
  156. package/dist/src/session-im-context.js.map +1 -1
  157. package/dist/src/subagent-delivery-phase.d.ts +10 -0
  158. package/dist/src/subagent-delivery-phase.d.ts.map +1 -0
  159. package/dist/src/subagent-delivery-phase.js +4 -0
  160. package/dist/src/subagent-delivery-phase.js.map +1 -0
  161. package/dist/src/subagent-delivery-phase.test.d.ts +2 -0
  162. package/dist/src/subagent-delivery-phase.test.d.ts.map +1 -0
  163. package/dist/src/subagent-delivery-phase.test.js +12 -0
  164. package/dist/src/subagent-delivery-phase.test.js.map +1 -0
  165. package/dist/src/subagent-monitor.d.ts +1 -14
  166. package/dist/src/subagent-monitor.d.ts.map +1 -1
  167. package/dist/src/subagent-monitor.js +36 -164
  168. package/dist/src/subagent-monitor.js.map +1 -1
  169. package/dist/src/subagent-monitor.test.js +0 -121
  170. package/dist/src/subagent-monitor.test.js.map +1 -1
  171. package/dist/src/tool-json-result.d.ts +1 -1
  172. package/dist/src/tool-json-result.d.ts.map +1 -1
  173. package/dist/src/turn/turn-agent-event-subscription.d.ts.map +1 -1
  174. package/dist/src/turn/turn-agent-event-subscription.js +14 -0
  175. package/dist/src/turn/turn-agent-event-subscription.js.map +1 -1
  176. package/dist/src/turn-deliver-buffer.test.js +25 -25
  177. package/dist/src/types.d.ts +1 -48
  178. package/dist/src/types.d.ts.map +1 -1
  179. package/dist/src/types.js.map +1 -1
  180. package/dist/src/workspace/nas-volumes.test.js +3 -2
  181. package/dist/src/workspace/nas-volumes.test.js.map +1 -1
  182. package/dist/src/ws-inbound-schema.d.ts.map +1 -1
  183. package/dist/src/ws-inbound-schema.js +0 -1
  184. package/dist/src/ws-inbound-schema.js.map +1 -1
  185. package/openclaw.plugin.json +30 -30
  186. package/package.json +83 -83
  187. package/dist/src/action-store-lifecycle.test.d.ts +0 -2
  188. package/dist/src/action-store-lifecycle.test.d.ts.map +0 -1
  189. package/dist/src/action-store-lifecycle.test.js +0 -195
  190. package/dist/src/action-store-lifecycle.test.js.map +0 -1
  191. package/dist/src/active-cron-context-store.d.ts +0 -20
  192. package/dist/src/active-cron-context-store.d.ts.map +0 -1
  193. package/dist/src/active-cron-context-store.js +0 -73
  194. package/dist/src/active-cron-context-store.js.map +0 -1
  195. package/dist/src/assistant-item-delivery.d.ts +0 -27
  196. package/dist/src/assistant-item-delivery.d.ts.map +0 -1
  197. package/dist/src/assistant-item-delivery.js +0 -134
  198. package/dist/src/assistant-item-delivery.js.map +0 -1
  199. package/dist/src/assistant-item-delivery.test.d.ts +0 -2
  200. package/dist/src/assistant-item-delivery.test.d.ts.map +0 -1
  201. package/dist/src/assistant-item-delivery.test.js +0 -116
  202. package/dist/src/assistant-item-delivery.test.js.map +0 -1
  203. package/dist/src/assistant-item-sink.d.ts +0 -17
  204. package/dist/src/assistant-item-sink.d.ts.map +0 -1
  205. package/dist/src/assistant-item-sink.js +0 -34
  206. package/dist/src/assistant-item-sink.js.map +0 -1
  207. package/dist/src/connection-workspace-event.test.d.ts +0 -2
  208. package/dist/src/connection-workspace-event.test.d.ts.map +0 -1
  209. package/dist/src/connection-workspace-event.test.js +0 -74
  210. package/dist/src/connection-workspace-event.test.js.map +0 -1
  211. package/dist/src/connection.test.d.ts +0 -2
  212. package/dist/src/connection.test.d.ts.map +0 -1
  213. package/dist/src/connection.test.js +0 -110
  214. package/dist/src/connection.test.js.map +0 -1
  215. package/dist/src/cron-appkey-binding-store.d.ts +0 -29
  216. package/dist/src/cron-appkey-binding-store.d.ts.map +0 -1
  217. package/dist/src/cron-appkey-binding-store.js +0 -239
  218. package/dist/src/cron-appkey-binding-store.js.map +0 -1
  219. package/dist/src/cron-appkey-binding-store.test.d.ts +0 -2
  220. package/dist/src/cron-appkey-binding-store.test.d.ts.map +0 -1
  221. package/dist/src/cron-appkey-binding-store.test.js +0 -387
  222. package/dist/src/cron-appkey-binding-store.test.js.map +0 -1
  223. package/dist/src/nas-site.d.ts +0 -16
  224. package/dist/src/nas-site.d.ts.map +0 -1
  225. package/dist/src/nas-site.js +0 -17
  226. package/dist/src/nas-site.js.map +0 -1
  227. package/dist/src/plan-core-adapter.d.ts +0 -54
  228. package/dist/src/plan-core-adapter.d.ts.map +0 -1
  229. package/dist/src/plan-core-adapter.js +0 -104
  230. package/dist/src/plan-core-adapter.js.map +0 -1
  231. package/dist/src/plan-core-adapter.test.d.ts +0 -2
  232. package/dist/src/plan-core-adapter.test.d.ts.map +0 -1
  233. package/dist/src/plan-core-adapter.test.js +0 -183
  234. package/dist/src/plan-core-adapter.test.js.map +0 -1
  235. package/dist/src/plan-core-db.d.ts +0 -22
  236. package/dist/src/plan-core-db.d.ts.map +0 -1
  237. package/dist/src/plan-core-db.js +0 -91
  238. package/dist/src/plan-core-db.js.map +0 -1
  239. package/dist/src/plan-core-db.test.d.ts +0 -2
  240. package/dist/src/plan-core-db.test.d.ts.map +0 -1
  241. package/dist/src/plan-core-db.test.js +0 -115
  242. package/dist/src/plan-core-db.test.js.map +0 -1
  243. package/dist/src/plan-core-snapshot.d.ts +0 -23
  244. package/dist/src/plan-core-snapshot.d.ts.map +0 -1
  245. package/dist/src/plan-core-snapshot.js +0 -66
  246. package/dist/src/plan-core-snapshot.js.map +0 -1
  247. package/dist/src/plan-core-snapshot.test.d.ts +0 -2
  248. package/dist/src/plan-core-snapshot.test.d.ts.map +0 -1
  249. package/dist/src/plan-core-snapshot.test.js +0 -157
  250. package/dist/src/plan-core-snapshot.test.js.map +0 -1
  251. package/dist/src/plugin-dispose.d.ts +0 -22
  252. package/dist/src/plugin-dispose.d.ts.map +0 -1
  253. package/dist/src/plugin-dispose.js +0 -66
  254. package/dist/src/plugin-dispose.js.map +0 -1
  255. package/dist/src/process-shared-store.d.ts +0 -48
  256. package/dist/src/process-shared-store.d.ts.map +0 -1
  257. package/dist/src/process-shared-store.js +0 -89
  258. package/dist/src/process-shared-store.js.map +0 -1
  259. package/dist/src/process-shared-store.test.d.ts +0 -2
  260. package/dist/src/process-shared-store.test.d.ts.map +0 -1
  261. package/dist/src/process-shared-store.test.js +0 -60
  262. package/dist/src/process-shared-store.test.js.map +0 -1
  263. package/dist/src/register-exec-env-hook.d.ts +0 -44
  264. package/dist/src/register-exec-env-hook.d.ts.map +0 -1
  265. package/dist/src/register-exec-env-hook.js +0 -473
  266. package/dist/src/register-exec-env-hook.js.map +0 -1
  267. package/dist/src/register-exec-env-hook.test.d.ts +0 -2
  268. package/dist/src/register-exec-env-hook.test.d.ts.map +0 -1
  269. package/dist/src/register-exec-env-hook.test.js +0 -189
  270. package/dist/src/register-exec-env-hook.test.js.map +0 -1
  271. package/dist/src/register-group-prompt-hook.d.ts +0 -17
  272. package/dist/src/register-group-prompt-hook.d.ts.map +0 -1
  273. package/dist/src/register-group-prompt-hook.js +0 -45
  274. package/dist/src/register-group-prompt-hook.js.map +0 -1
  275. package/dist/src/register-group-prompt-hook.test.d.ts +0 -2
  276. package/dist/src/register-group-prompt-hook.test.d.ts.map +0 -1
  277. package/dist/src/register-group-prompt-hook.test.js +0 -60
  278. package/dist/src/register-group-prompt-hook.test.js.map +0 -1
  279. package/dist/src/register-per-message-model-hook.test.d.ts +0 -2
  280. package/dist/src/register-per-message-model-hook.test.d.ts.map +0 -1
  281. package/dist/src/register-per-message-model-hook.test.js +0 -208
  282. package/dist/src/register-per-message-model-hook.test.js.map +0 -1
  283. package/dist/src/register-run-model-context-hook.d.ts +0 -11
  284. package/dist/src/register-run-model-context-hook.d.ts.map +0 -1
  285. package/dist/src/register-run-model-context-hook.js +0 -23
  286. package/dist/src/register-run-model-context-hook.js.map +0 -1
  287. package/dist/src/reply-dispatch-driver.d.ts +0 -89
  288. package/dist/src/reply-dispatch-driver.d.ts.map +0 -1
  289. package/dist/src/reply-dispatch-driver.js +0 -294
  290. package/dist/src/reply-dispatch-driver.js.map +0 -1
  291. package/dist/src/reply-dispatch-driver.test.d.ts +0 -2
  292. package/dist/src/reply-dispatch-driver.test.d.ts.map +0 -1
  293. package/dist/src/reply-dispatch-driver.test.js +0 -363
  294. package/dist/src/reply-dispatch-driver.test.js.map +0 -1
  295. package/dist/src/run-model-context.d.ts +0 -45
  296. package/dist/src/run-model-context.d.ts.map +0 -1
  297. package/dist/src/run-model-context.js +0 -108
  298. package/dist/src/run-model-context.js.map +0 -1
  299. package/dist/src/run-model-context.test.d.ts +0 -2
  300. package/dist/src/run-model-context.test.d.ts.map +0 -1
  301. package/dist/src/run-model-context.test.js +0 -68
  302. package/dist/src/run-model-context.test.js.map +0 -1
  303. package/dist/src/session-env-store.d.ts +0 -55
  304. package/dist/src/session-env-store.d.ts.map +0 -1
  305. package/dist/src/session-env-store.js +0 -328
  306. package/dist/src/session-env-store.js.map +0 -1
  307. package/dist/src/session-env-store.test.d.ts +0 -2
  308. package/dist/src/session-env-store.test.d.ts.map +0 -1
  309. package/dist/src/session-env-store.test.js +0 -151
  310. package/dist/src/session-env-store.test.js.map +0 -1
  311. package/dist/src/session-group-prompt.d.ts +0 -34
  312. package/dist/src/session-group-prompt.d.ts.map +0 -1
  313. package/dist/src/session-group-prompt.js +0 -101
  314. package/dist/src/session-group-prompt.js.map +0 -1
  315. package/dist/src/session-group-prompt.test.d.ts +0 -2
  316. package/dist/src/session-group-prompt.test.d.ts.map +0 -1
  317. package/dist/src/session-group-prompt.test.js +0 -72
  318. package/dist/src/session-group-prompt.test.js.map +0 -1
  319. package/dist/src/session-model-fallback.d.ts +0 -13
  320. package/dist/src/session-model-fallback.d.ts.map +0 -1
  321. package/dist/src/session-model-fallback.js +0 -24
  322. package/dist/src/session-model-fallback.js.map +0 -1
  323. package/dist/src/tool-event-adapter.d.ts +0 -31
  324. package/dist/src/tool-event-adapter.d.ts.map +0 -1
  325. package/dist/src/tool-event-adapter.js +0 -83
  326. package/dist/src/tool-event-adapter.js.map +0 -1
  327. package/dist/src/tool-event-adapter.test.d.ts +0 -2
  328. package/dist/src/tool-event-adapter.test.d.ts.map +0 -1
  329. package/dist/src/tool-event-adapter.test.js +0 -93
  330. package/dist/src/tool-event-adapter.test.js.map +0 -1
  331. package/dist/src/turn-agent-event-subscription.d.ts +0 -29
  332. package/dist/src/turn-agent-event-subscription.d.ts.map +0 -1
  333. package/dist/src/turn-agent-event-subscription.js +0 -289
  334. package/dist/src/turn-agent-event-subscription.js.map +0 -1
  335. package/dist/src/turn-agent-event-subscription.test.d.ts +0 -2
  336. package/dist/src/turn-agent-event-subscription.test.d.ts.map +0 -1
  337. package/dist/src/turn-agent-event-subscription.test.js +0 -165
  338. package/dist/src/turn-agent-event-subscription.test.js.map +0 -1
  339. package/dist/src/turn-end-controller.d.ts +0 -61
  340. package/dist/src/turn-end-controller.d.ts.map +0 -1
  341. package/dist/src/turn-end-controller.js +0 -239
  342. package/dist/src/turn-end-controller.js.map +0 -1
  343. package/dist/src/turn-end-controller.test.d.ts +0 -2
  344. package/dist/src/turn-end-controller.test.d.ts.map +0 -1
  345. package/dist/src/turn-end-controller.test.js +0 -97
  346. package/dist/src/turn-end-controller.test.js.map +0 -1
  347. package/dist/src/workspace-event-protocol.d.ts +0 -3
  348. package/dist/src/workspace-event-protocol.d.ts.map +0 -1
  349. package/dist/src/workspace-event-protocol.js +0 -3
  350. package/dist/src/workspace-event-protocol.js.map +0 -1
  351. package/dist/src/workspace-event-scheduler.d.ts +0 -54
  352. package/dist/src/workspace-event-scheduler.d.ts.map +0 -1
  353. package/dist/src/workspace-event-scheduler.js +0 -131
  354. package/dist/src/workspace-event-scheduler.js.map +0 -1
  355. package/dist/src/workspace-event-scheduler.test.d.ts +0 -2
  356. package/dist/src/workspace-event-scheduler.test.d.ts.map +0 -1
  357. package/dist/src/workspace-event-scheduler.test.js +0 -157
  358. package/dist/src/workspace-event-scheduler.test.js.map +0 -1
  359. package/dist/src/workspace-event.d.ts +0 -28
  360. package/dist/src/workspace-event.d.ts.map +0 -1
  361. package/dist/src/workspace-event.js +0 -674
  362. package/dist/src/workspace-event.js.map +0 -1
  363. package/dist/src/workspace-event.test.d.ts +0 -2
  364. package/dist/src/workspace-event.test.d.ts.map +0 -1
  365. package/dist/src/workspace-event.test.js +0 -265
  366. package/dist/src/workspace-event.test.js.map +0 -1
  367. package/dist/src/ws-inbound-schema.test.d.ts +0 -2
  368. package/dist/src/ws-inbound-schema.test.d.ts.map +0 -1
  369. package/dist/src/ws-inbound-schema.test.js +0 -58
  370. package/dist/src/ws-inbound-schema.test.js.map +0 -1
@@ -1,103 +1,623 @@
1
1
  import assert from "node:assert/strict";
2
2
  import { describe, it } from "node:test";
3
- import { createPlanToolResultMiddleware, } from "./plan-tool-middleware.js";
4
- function makeAction(eventId, overrides = {}) {
3
+ import { createPlanToolResultMiddleware } from "./plan-tool-middleware.js";
4
+ const FAKE_CTX = { runtime: "openclaw" };
5
+ function makePlan(overrides = {}) {
5
6
  return {
6
- eventId,
7
- event: "action_dispatch",
8
- action: "form_fill",
9
- target: "page://order-detail",
10
- version: 1,
11
- status: "completed",
12
- scopeControl: { activeSessionOnly: true },
13
- payload: { data: { id: eventId } },
14
- timestamp: "2026-09-07T17:00:00.000+08:00",
15
- origin: { channel: "xg_cwork_im", to: "g-1" },
7
+ planId: "plan-1",
8
+ goal: "迁移配置到新版本",
9
+ createdAt: "2026-07-27T00:00:00.000Z",
10
+ updatedAt: "2026-07-27T00:00:00.000Z",
11
+ tasks: [],
16
12
  ...overrides,
17
13
  };
18
14
  }
19
- function makeToolEvent(toolName, overrides = {}) {
15
+ function makeEvent(overrides) {
16
+ const content = overrides.text !== undefined
17
+ ? [{ type: "text", text: overrides.text }]
18
+ : [];
20
19
  return {
21
- toolCallId: "call-1",
22
- toolName,
20
+ toolCallId: overrides.toolCallId ?? "call-1",
21
+ toolName: overrides.toolName ?? "xg_plan_write",
23
22
  args: {},
24
- result: { details: undefined, content: [] },
25
- ...overrides,
23
+ result: {
24
+ details: overrides.details,
25
+ content,
26
+ },
27
+ };
28
+ }
29
+ function makeSuccessPayload(plan, withEvent = false) {
30
+ return {
31
+ ok: true,
32
+ planId: plan.planId,
33
+ plan,
34
+ ...(withEvent ? { event: { emitted: false, reason: "no runId" } } : {}),
26
35
  };
27
36
  }
28
- class Probe {
29
- sent = [];
37
+ function makeDraftSuccessPayload(planId) {
38
+ return {
39
+ ok: true,
40
+ planId,
41
+ view: `goal: 草稿计划\nT0 [ ] 任务`,
42
+ };
43
+ }
44
+ class RecordingDeps {
45
+ planById = new Map();
46
+ planStatCalls = [];
47
+ sendPlanStatImpl = (params) => {
48
+ this.planStatCalls.push(params);
49
+ };
50
+ getPlanById = (planId) => {
51
+ return this.planById.get(planId);
52
+ };
53
+ sendPlanStat = (params) => {
54
+ this.sendPlanStatImpl(params);
55
+ };
30
56
  actionById = new Map();
31
- deps;
32
- handler;
33
- constructor() {
34
- this.deps = {
35
- getActionById: (eventId) => this.actionById.get(eventId),
36
- sendActionRunEvent: (action) => {
37
- this.sent.push(action);
38
- },
39
- };
40
- this.handler = createPlanToolResultMiddleware(this.deps);
57
+ actionRunEventCalls = [];
58
+ getActionById = (eventId) => this.actionById.get(eventId);
59
+ sendActionRunEvent = (action) => {
60
+ this.actionRunEventCalls.push(action);
61
+ };
62
+ }
63
+ /** 临时替换 console.warn 统计 [plan-telemetry] 行数,测试结束务必还原。 */
64
+ function captureTelemetryLines(fn) {
65
+ const original = console.warn;
66
+ const lines = [];
67
+ console.warn = (...args) => {
68
+ const line = args.map(String).join(" ");
69
+ if (line.includes("[plan-telemetry]")) {
70
+ lines.push(line);
71
+ }
72
+ };
73
+ try {
74
+ fn();
41
75
  }
76
+ finally {
77
+ console.warn = original;
78
+ }
79
+ return lines;
80
+ }
81
+ function captureWarnLines(fn) {
82
+ const original = console.warn;
83
+ const lines = [];
84
+ console.warn = (...args) => {
85
+ lines.push(args.map(String).join(" "));
86
+ };
87
+ try {
88
+ fn();
89
+ }
90
+ finally {
91
+ console.warn = original;
92
+ }
93
+ return lines;
42
94
  }
43
- describe("createPlanToolResultMiddleware: 仅 xg_action_dispatch 分支(plan 已移除)", () => {
44
- it("非 action 工具直接放行:不反查、不发", () => {
45
- const probe = new Probe();
46
- const event = makeToolEvent("xg_plan_write", {
47
- result: { details: { ok: true, planId: "p-1" }, content: [] },
48
- });
49
- assert.equal(probe.handler(event, undefined), undefined);
50
- assert.equal(probe.actionById.size, 0);
51
- assert.deepEqual(probe.sent, []);
52
- });
53
- it("details 命中 eventId → 反查并发送", () => {
54
- const probe = new Probe();
55
- const action = makeAction("e-1");
56
- probe.actionById.set("e-1", action);
57
- probe.handler(makeToolEvent("xg_action_dispatch", {
58
- result: { details: { ok: true, eventId: "e-1" }, content: [] },
59
- }), undefined);
60
- assert.deepEqual(probe.sent, [action]);
61
- });
62
- it("回退解析 content[0].text JSON 里的 eventId", () => {
63
- const probe = new Probe();
64
- const action = makeAction("e-2");
65
- probe.actionById.set("e-2", action);
66
- probe.handler(makeToolEvent("xg_action_dispatch", {
67
- result: { details: undefined, content: [{ type: "text", text: '{"ok":true,"eventId":"e-2"}' }] },
68
- }), undefined);
69
- assert.deepEqual(probe.sent, [action]);
70
- });
71
- it("解析不到 eventId → 跳过,不抛", () => {
72
- const probe = new Probe();
73
- assert.equal(probe.handler(makeToolEvent("xg_action_dispatch", { result: { details: { ok: false }, content: [] } }), undefined), undefined);
74
- assert.deepEqual(probe.sent, []);
75
- });
76
- it("反查不到 action → 跳过,不抛", () => {
77
- const probe = new Probe();
78
- assert.equal(probe.handler(makeToolEvent("xg_action_dispatch", {
79
- result: { details: { ok: true, eventId: "missing" }, content: [] },
80
- }), undefined), undefined);
81
- assert.deepEqual(probe.sent, []);
82
- });
83
- it("getActionById 抛异常 → handler 不外抛", () => {
84
- const probe = new Probe();
85
- probe.deps.getActionById = () => {
95
+ describe("createPlanToolResultMiddleware: 非 plan 工具直接放行", () => {
96
+ it("does not touch getPlanById or emit telemetry for unrelated tools", () => {
97
+ const deps = new RecordingDeps();
98
+ let getPlanByIdCalled = false;
99
+ deps.getPlanById = (planId) => {
100
+ getPlanByIdCalled = true;
101
+ return deps.planById.get(planId);
102
+ };
103
+ const handler = createPlanToolResultMiddleware(deps);
104
+ const event = makeEvent({
105
+ toolName: "some_other_tool",
106
+ details: { ok: true, data: 123 },
107
+ });
108
+ const lines = captureTelemetryLines(() => {
109
+ const result = handler(event, FAKE_CTX);
110
+ assert.equal(result, undefined);
111
+ });
112
+ assert.equal(getPlanByIdCalled, false);
113
+ assert.equal(lines.length, 0);
114
+ });
115
+ it("does not emit telemetry even when a non-plan tool's details is a structurally valid plan payload (pins the name filter)", () => {
116
+ const deps = new RecordingDeps();
117
+ const handler = createPlanToolResultMiddleware(deps);
118
+ const plan = makePlan({ tasks: [{ title: "备份旧配置", status: "blocked", note: "缺少权限" }] });
119
+ const event = makeEvent({
120
+ toolCallId: "call-evil",
121
+ toolName: "some_evil_tool",
122
+ details: makeSuccessPayload(plan),
123
+ });
124
+ const lines = captureTelemetryLines(() => {
125
+ const result = handler(event, FAKE_CTX);
126
+ assert.equal(result, undefined);
127
+ });
128
+ assert.equal(lines.length, 0);
129
+ });
130
+ });
131
+ describe("createPlanToolResultMiddleware: 权威反查与兼容回退", () => {
132
+ it("0.3.0 新形状反查命中 → 用权威 plan 推送,并产出 blocked 遥测", () => {
133
+ const deps = new RecordingDeps();
134
+ const handler = createPlanToolResultMiddleware(deps);
135
+ const authoritativePlan = makePlan({
136
+ planId: "plan-draft-hit",
137
+ tasks: [{ title: "备份旧配置", status: "blocked", note: "缺少权限" }],
138
+ });
139
+ deps.planById.set(authoritativePlan.planId, authoritativePlan);
140
+ const event = makeEvent({
141
+ toolCallId: "call-1",
142
+ toolName: "xg_plan_write",
143
+ details: makeDraftSuccessPayload(authoritativePlan.planId),
144
+ });
145
+ const lines = captureTelemetryLines(() => {
146
+ const result = handler(event, FAKE_CTX);
147
+ assert.equal(result, undefined);
148
+ });
149
+ assert.equal(lines.length, 1);
150
+ assert.ok(lines[0].includes("备份旧配置"));
151
+ assert.ok(lines[0].includes("缺少权限"));
152
+ assert.deepEqual(deps.planStatCalls, [{ plan: authoritativePlan, source: "tool" }]);
153
+ });
154
+ it("反查得到 cancelled 计划 → PLAN_STAT 照推,blocked 遥测跳过", () => {
155
+ const deps = new RecordingDeps();
156
+ const handler = createPlanToolResultMiddleware(deps);
157
+ const cancelledPlan = makePlan({
158
+ planId: "plan-cancelled",
159
+ status: "cancelled",
160
+ cancelledAt: "2026-07-31T01:02:03.000Z",
161
+ tasks: [{ title: "旧阻塞", status: "blocked", note: "取消后不应告警" }],
162
+ });
163
+ deps.planById.set(cancelledPlan.planId, cancelledPlan);
164
+ const event = makeEvent({
165
+ toolCallId: "call-cancelled",
166
+ details: {
167
+ ok: true,
168
+ planId: cancelledPlan.planId,
169
+ view: "goal: 【已取消】迁移配置到新版本\nT0 [!] 旧阻塞",
170
+ cancelled: true,
171
+ },
172
+ });
173
+ const lines = captureTelemetryLines(() => {
174
+ assert.equal(handler(event, FAKE_CTX), undefined);
175
+ });
176
+ assert.deepEqual(lines, []);
177
+ assert.deepEqual(deps.planStatCalls, [{ plan: cancelledPlan, source: "tool" }]);
178
+ });
179
+ it("0.3.0 新形状反查未命中 → 记 warn 后放弃,不推送且不抛", () => {
180
+ const deps = new RecordingDeps();
181
+ const handler = createPlanToolResultMiddleware(deps);
182
+ const event = makeEvent({
183
+ toolCallId: "call-draft-miss",
184
+ details: makeDraftSuccessPayload("plan-draft-miss"),
185
+ });
186
+ const lines = captureWarnLines(() => {
187
+ assert.doesNotThrow(() => handler(event, FAKE_CTX));
188
+ });
189
+ assert.equal(deps.planStatCalls.length, 0);
190
+ assert.equal(lines.length, 1);
191
+ assert.ok(lines[0].includes("反查不到 plan"));
192
+ assert.ok(lines[0].includes("plan-draft-miss"));
193
+ });
194
+ it("0.2.0 旧形状反查未命中 → 回退使用返回中的完整 plan 推送", () => {
195
+ const deps = new RecordingDeps();
196
+ const handler = createPlanToolResultMiddleware(deps);
197
+ const legacyPlan = makePlan({
198
+ planId: "plan-legacy-fallback",
199
+ tasks: [{ title: "旧版任务", status: "pending" }],
200
+ });
201
+ const event = makeEvent({
202
+ toolCallId: "call-legacy-fallback",
203
+ details: makeSuccessPayload(legacyPlan, true),
204
+ });
205
+ handler(event, FAKE_CTX);
206
+ assert.deepEqual(deps.planStatCalls, [{ plan: legacyPlan, source: "tool" }]);
207
+ });
208
+ });
209
+ describe("createPlanToolResultMiddleware: text 回退路径", () => {
210
+ it("falls back to content[0].text when details is undefined", () => {
211
+ const deps = new RecordingDeps();
212
+ const handler = createPlanToolResultMiddleware(deps);
213
+ const plan = makePlan({
214
+ planId: "plan-2",
215
+ tasks: [{ title: "校验数据", status: "blocked", note: "依赖未就绪" }],
216
+ });
217
+ const rawBody = JSON.stringify(makeSuccessPayload(plan, true), null, 2);
218
+ const event = makeEvent({
219
+ toolCallId: "call-2",
220
+ toolName: "xg_plan_write",
221
+ details: undefined,
222
+ text: rawBody,
223
+ });
224
+ const lines = captureTelemetryLines(() => {
225
+ const result = handler(event, FAKE_CTX);
226
+ assert.equal(result, undefined);
227
+ });
228
+ assert.equal(lines.length, 1);
229
+ assert.ok(lines[0].includes("校验数据"));
230
+ });
231
+ it("uses getPlanById authoritative state when details is missing (D5/RULING-1 §3)", () => {
232
+ const deps = new RecordingDeps();
233
+ const handler = createPlanToolResultMiddleware(deps);
234
+ // text 路径拿到的 plan 里没有 blocked task,但权威反查里有
235
+ const textPlan = makePlan({ planId: "plan-3", tasks: [{ title: "t1", status: "pending" }] });
236
+ const authoritativePlan = makePlan({
237
+ planId: "plan-3",
238
+ tasks: [{ title: "t1", status: "blocked", note: "authoritative 才有的阻塞" }],
239
+ });
240
+ deps.planById.set("plan-3", authoritativePlan);
241
+ const rawBody = JSON.stringify(makeSuccessPayload(textPlan), null, 2);
242
+ const event = makeEvent({
243
+ toolCallId: "call-3",
244
+ toolName: "xg_plan_write",
245
+ details: undefined,
246
+ text: rawBody,
247
+ });
248
+ const lines = captureTelemetryLines(() => {
249
+ handler(event, FAKE_CTX);
250
+ });
251
+ assert.equal(lines.length, 1);
252
+ assert.ok(lines[0].includes("authoritative 才有的阻塞"));
253
+ });
254
+ });
255
+ describe("createPlanToolResultMiddleware: 守卫拒绝畸形 payload", () => {
256
+ it("does not emit telemetry for ok:false", () => {
257
+ const deps = new RecordingDeps();
258
+ const handler = createPlanToolResultMiddleware(deps);
259
+ const event = makeEvent({
260
+ toolCallId: "call-4",
261
+ toolName: "xg_plan_write",
262
+ details: { ok: false, error: { code: "PLAN_NOT_FOUND" } },
263
+ });
264
+ const lines = captureTelemetryLines(() => {
265
+ assert.equal(handler(event, FAKE_CTX), undefined);
266
+ });
267
+ assert.equal(lines.length, 0);
268
+ });
269
+ it("does not emit telemetry when planId is missing", () => {
270
+ const deps = new RecordingDeps();
271
+ const handler = createPlanToolResultMiddleware(deps);
272
+ const event = makeEvent({
273
+ toolCallId: "call-5",
274
+ toolName: "xg_plan_write",
275
+ details: { ok: true, plan: makePlan() },
276
+ });
277
+ const lines = captureTelemetryLines(() => {
278
+ assert.equal(handler(event, FAKE_CTX), undefined);
279
+ });
280
+ assert.equal(lines.length, 0);
281
+ });
282
+ it("does not emit telemetry when tasks is not an array", () => {
283
+ const deps = new RecordingDeps();
284
+ const handler = createPlanToolResultMiddleware(deps);
285
+ const event = makeEvent({
286
+ toolCallId: "call-6",
287
+ toolName: "xg_plan_write",
288
+ details: {
289
+ ok: true,
290
+ planId: "plan-6",
291
+ plan: { planId: "plan-6", goal: "g", createdAt: "t", updatedAt: "t", tasks: "not-an-array" },
292
+ },
293
+ });
294
+ const lines = captureTelemetryLines(() => {
295
+ assert.equal(handler(event, FAKE_CTX), undefined);
296
+ });
297
+ assert.equal(lines.length, 0);
298
+ });
299
+ });
300
+ describe("createPlanToolResultMiddleware: handler 内部出错不外抛", () => {
301
+ it("resolves normally even when getPlanById throws", () => {
302
+ const deps = new RecordingDeps();
303
+ deps.getPlanById = () => {
86
304
  throw new Error("boom");
87
305
  };
88
- assert.equal(probe.handler(makeToolEvent("xg_action_dispatch", {
89
- result: { details: { ok: true, eventId: "e-1" }, content: [] },
90
- }), undefined), undefined);
91
- });
92
- it("sendActionRunEvent 抛异常 → handler 不外抛", () => {
93
- const probe = new Probe();
94
- probe.actionById.set("e-1", makeAction("e-1"));
95
- probe.deps.sendActionRunEvent = () => {
306
+ const handler = createPlanToolResultMiddleware(deps);
307
+ const plan = makePlan({ planId: "plan-8", tasks: [{ title: "t1", status: "blocked", note: "n" }] });
308
+ const rawBody = JSON.stringify(makeSuccessPayload(plan), null, 2);
309
+ const event = makeEvent({
310
+ toolCallId: "call-8",
311
+ toolName: "xg_plan_write",
312
+ details: undefined,
313
+ text: rawBody,
314
+ });
315
+ assert.doesNotThrow(() => handler(event, FAKE_CTX));
316
+ });
317
+ });
318
+ describe("createPlanToolResultMiddleware: 恒返回 void(同步性断言)", () => {
319
+ // 本任务 handler 已无异步出口(推群没了)。TASK-2x-4 引入 sendPlanStat 的
320
+ // fire-and-forget 之后,这条要恢复成"even when 内部 promise 永不 resolve 仍立即返回"的真实用例。
321
+ it("handler's return value is undefined and the call itself is synchronous", () => {
322
+ const deps = new RecordingDeps();
323
+ const handler = createPlanToolResultMiddleware(deps);
324
+ const plan = makePlan({ tasks: [{ title: "t1", status: "blocked", note: "n" }] });
325
+ const event = makeEvent({
326
+ toolCallId: "call-9",
327
+ toolName: "xg_plan_write",
328
+ details: makeSuccessPayload(plan),
329
+ });
330
+ const result = handler(event, FAKE_CTX);
331
+ assert.equal(result, undefined);
332
+ });
333
+ it("0.3.0 新形状反查后不修改 event.result", () => {
334
+ const deps = new RecordingDeps();
335
+ const plan = makePlan({ planId: "plan-no-mutate" });
336
+ deps.planById.set(plan.planId, plan);
337
+ const handler = createPlanToolResultMiddleware(deps);
338
+ const event = makeEvent({
339
+ toolCallId: "call-no-mutate",
340
+ details: makeDraftSuccessPayload(plan.planId),
341
+ text: JSON.stringify(makeDraftSuccessPayload(plan.planId)),
342
+ });
343
+ const originalResult = structuredClone(event.result);
344
+ handler(event, FAKE_CTX);
345
+ assert.deepEqual(event.result, originalResult);
346
+ });
347
+ });
348
+ describe("createPlanToolResultMiddleware: [plan-telemetry] 遥测行为(D2)", () => {
349
+ it("plan 含 1 个 blocked task → 恰好打 1 行,内容含 planId/taskIndex/taskTitle/note/goal", () => {
350
+ const deps = new RecordingDeps();
351
+ const handler = createPlanToolResultMiddleware(deps);
352
+ const plan = makePlan({
353
+ planId: "plan-telemetry-1",
354
+ goal: "迁移配置到新版本",
355
+ tasks: [{ title: "备份旧配置", status: "blocked", note: "缺少权限" }],
356
+ });
357
+ const event = makeEvent({
358
+ toolCallId: "call-t1",
359
+ toolName: "xg_plan_write",
360
+ details: makeSuccessPayload(plan),
361
+ });
362
+ const lines = captureTelemetryLines(() => {
363
+ handler(event, FAKE_CTX);
364
+ });
365
+ assert.equal(lines.length, 1);
366
+ const jsonPart = lines[0].slice(lines[0].indexOf("{"));
367
+ const parsed = JSON.parse(jsonPart);
368
+ assert.equal(parsed.planId, "plan-telemetry-1");
369
+ assert.equal(parsed.taskIndex, 0);
370
+ assert.equal(parsed.taskTitle, "备份旧配置");
371
+ assert.equal(parsed.note, "缺少权限");
372
+ assert.equal(parsed.goal, "迁移配置到新版本");
373
+ assert.equal(parsed.toolName, "xg_plan_write");
374
+ });
375
+ it("plan 含 2 个 blocked task → 打 2 行,顺序与 tasks 下标一致", () => {
376
+ const deps = new RecordingDeps();
377
+ const handler = createPlanToolResultMiddleware(deps);
378
+ const plan = makePlan({
379
+ tasks: [
380
+ { title: "备份旧配置", status: "blocked", note: "缺少权限" },
381
+ { title: "校验数据", status: "pending" },
382
+ { title: "切换流量", status: "blocked", note: "依赖未就绪" },
383
+ ],
384
+ });
385
+ const event = makeEvent({
386
+ toolCallId: "call-t2",
387
+ toolName: "xg_plan_write",
388
+ details: makeSuccessPayload(plan),
389
+ });
390
+ const lines = captureTelemetryLines(() => {
391
+ handler(event, FAKE_CTX);
392
+ });
393
+ assert.equal(lines.length, 2);
394
+ const first = JSON.parse(lines[0].slice(lines[0].indexOf("{")));
395
+ const second = JSON.parse(lines[1].slice(lines[1].indexOf("{")));
396
+ assert.equal(first.taskIndex, 0);
397
+ assert.equal(second.taskIndex, 2);
398
+ });
399
+ it("无 blocked task → 不打任何遥测行", () => {
400
+ const deps = new RecordingDeps();
401
+ const handler = createPlanToolResultMiddleware(deps);
402
+ const plan = makePlan({
403
+ tasks: [{ title: "t1", status: "pending" }, { title: "t2", status: "completed" }],
404
+ });
405
+ const event = makeEvent({
406
+ toolCallId: "call-t3",
407
+ toolName: "xg_plan_write",
408
+ details: makeSuccessPayload(plan),
409
+ });
410
+ const lines = captureTelemetryLines(() => {
411
+ handler(event, FAKE_CTX);
412
+ });
413
+ assert.equal(lines.length, 0);
414
+ });
415
+ it("🔴 同一 plan、同一 blocked、连续两次 middleware 事件 → 打 2 行(钉住不去重)", () => {
416
+ const deps = new RecordingDeps();
417
+ const handler = createPlanToolResultMiddleware(deps);
418
+ const plan = makePlan({
419
+ planId: "plan-no-dedup",
420
+ tasks: [{ title: "备份旧配置", status: "blocked", note: "缺少权限" }],
421
+ });
422
+ const event = makeEvent({
423
+ toolCallId: "call-t4",
424
+ toolName: "xg_plan_write",
425
+ details: makeSuccessPayload(plan),
426
+ });
427
+ const lines = captureTelemetryLines(() => {
428
+ handler(event, FAKE_CTX);
429
+ handler(event, FAKE_CTX);
430
+ });
431
+ assert.equal(lines.length, 2, "不去重:同一 blocked 连续两次事件应各打一行");
432
+ });
433
+ it("plan 带 origin → 日志行含 channel/to/sessionKey", () => {
434
+ const deps = new RecordingDeps();
435
+ const handler = createPlanToolResultMiddleware(deps);
436
+ const plan = makePlan({
437
+ tasks: [{ title: "t1", status: "blocked", note: "n" }],
438
+ origin: { channel: "xg_cwork_im", to: "g-123", sessionKey: "sess-1" },
439
+ });
440
+ const event = makeEvent({
441
+ toolCallId: "call-t5",
442
+ toolName: "xg_plan_write",
443
+ details: makeSuccessPayload(plan),
444
+ });
445
+ const lines = captureTelemetryLines(() => {
446
+ handler(event, FAKE_CTX);
447
+ });
448
+ assert.equal(lines.length, 1);
449
+ const parsed = JSON.parse(lines[0].slice(lines[0].indexOf("{")));
450
+ assert.equal(parsed.channel, "xg_cwork_im");
451
+ assert.equal(parsed.to, "g-123");
452
+ assert.equal(parsed.sessionKey, "sess-1");
453
+ });
454
+ it("🔴 plan 无 origin(旧数据)→ 日志行不含这几个键,且照常打日志、不抛、不跳过", () => {
455
+ const deps = new RecordingDeps();
456
+ const handler = createPlanToolResultMiddleware(deps);
457
+ const plan = makePlan({
458
+ tasks: [{ title: "t1", status: "blocked", note: "n" }],
459
+ });
460
+ const event = makeEvent({
461
+ toolCallId: "call-t6",
462
+ toolName: "xg_plan_write",
463
+ details: makeSuccessPayload(plan),
464
+ });
465
+ const lines = captureTelemetryLines(() => {
466
+ assert.doesNotThrow(() => handler(event, FAKE_CTX));
467
+ });
468
+ assert.equal(lines.length, 1);
469
+ const parsed = JSON.parse(lines[0].slice(lines[0].indexOf("{")));
470
+ assert.equal("channel" in parsed, false);
471
+ assert.equal("to" in parsed, false);
472
+ assert.equal("sessionKey" in parsed, false);
473
+ });
474
+ it("blocked task 的 note 为空/空白 → 该条不产出遥测", () => {
475
+ const deps = new RecordingDeps();
476
+ const handler = createPlanToolResultMiddleware(deps);
477
+ const plan = makePlan({
478
+ tasks: [
479
+ { title: "无 note", status: "blocked" },
480
+ { title: "空白 note", status: "blocked", note: " " },
481
+ ],
482
+ });
483
+ const event = makeEvent({
484
+ toolCallId: "call-t7",
485
+ toolName: "xg_plan_write",
486
+ details: makeSuccessPayload(plan),
487
+ });
488
+ const lines = captureTelemetryLines(() => {
489
+ handler(event, FAKE_CTX);
490
+ });
491
+ assert.equal(lines.length, 0);
492
+ });
493
+ });
494
+ describe("createPlanToolResultMiddleware: PLAN_STAT 增量推送(D3)", () => {
495
+ it("plan_write 成功 → 发 1 条 PLAN_STAT,source === \"tool\"", () => {
496
+ const deps = new RecordingDeps();
497
+ const handler = createPlanToolResultMiddleware(deps);
498
+ const plan = makePlan({ tasks: [{ title: "t1", status: "pending" }] });
499
+ const event = makeEvent({
500
+ toolCallId: "call-ps1",
501
+ toolName: "xg_plan_write",
502
+ details: makeSuccessPayload(plan),
503
+ });
504
+ handler(event, FAKE_CTX);
505
+ assert.equal(deps.planStatCalls.length, 1);
506
+ assert.equal(deps.planStatCalls[0].source, "tool");
507
+ assert.equal(deps.planStatCalls[0].plan.planId, plan.planId);
508
+ });
509
+ it("xg_plan_execute 的单计划/列表返回均直接忽略,不解析、不反查、不推送", () => {
510
+ const deps = new RecordingDeps();
511
+ let getPlanByIdCalls = 0;
512
+ deps.getPlanById = () => {
513
+ getPlanByIdCalls += 1;
514
+ return undefined;
515
+ };
516
+ const handler = createPlanToolResultMiddleware(deps);
517
+ const events = [
518
+ makeEvent({
519
+ toolCallId: "call-ps2",
520
+ toolName: "xg_plan_execute",
521
+ details: makeDraftSuccessPayload("plan-read"),
522
+ }),
523
+ makeEvent({
524
+ toolCallId: "call-ps3",
525
+ toolName: "xg_plan_execute",
526
+ details: {
527
+ ok: true,
528
+ plans: [{
529
+ planId: "plan-list",
530
+ goal: "最近计划",
531
+ updatedAt: "2026-07-29T00:00:00.000Z",
532
+ taskCounts: { total: 1, completed: 0, blocked: 0, inProgress: 0 },
533
+ }],
534
+ },
535
+ }),
536
+ ];
537
+ const lines = captureWarnLines(() => {
538
+ for (const event of events) {
539
+ handler(event, FAKE_CTX);
540
+ }
541
+ });
542
+ assert.equal(getPlanByIdCalls, 0);
543
+ assert.equal(deps.planStatCalls.length, 0);
544
+ assert.equal(lines.length, 0);
545
+ });
546
+ it("🔴 工具返回 ok:false → 不发 PLAN_STAT(失败不发)", () => {
547
+ const deps = new RecordingDeps();
548
+ const handler = createPlanToolResultMiddleware(deps);
549
+ const event = makeEvent({
550
+ toolCallId: "call-ps5",
551
+ toolName: "xg_plan_write",
552
+ details: { ok: false, error: { code: "PLAN_NOT_FOUND" } },
553
+ });
554
+ handler(event, FAKE_CTX);
555
+ assert.equal(deps.planStatCalls.length, 0);
556
+ });
557
+ it("🔴 非 plan 工具 → 不发 PLAN_STAT", () => {
558
+ const deps = new RecordingDeps();
559
+ const handler = createPlanToolResultMiddleware(deps);
560
+ const plan = makePlan({ tasks: [{ title: "t1", status: "pending" }] });
561
+ const event = makeEvent({
562
+ toolCallId: "call-ps6",
563
+ toolName: "some_other_tool",
564
+ details: makeSuccessPayload(plan),
565
+ });
566
+ handler(event, FAKE_CTX);
567
+ assert.equal(deps.planStatCalls.length, 0);
568
+ });
569
+ it("🔴 sendPlanStat 内部抛异常 → handler 不外抛、仍返回 void(红线回归)", () => {
570
+ const deps = new RecordingDeps();
571
+ deps.sendPlanStatImpl = () => {
96
572
  throw new Error("boom");
97
573
  };
98
- assert.equal(probe.handler(makeToolEvent("xg_action_dispatch", {
99
- result: { details: { ok: true, eventId: "e-1" }, content: [] },
100
- }), undefined), undefined);
574
+ const handler = createPlanToolResultMiddleware(deps);
575
+ const plan = makePlan({ tasks: [{ title: "t1", status: "pending" }] });
576
+ const event = makeEvent({
577
+ toolCallId: "call-ps7",
578
+ toolName: "xg_plan_write",
579
+ details: makeSuccessPayload(plan),
580
+ });
581
+ assert.doesNotThrow(() => {
582
+ const result = handler(event, FAKE_CTX);
583
+ assert.equal(result, undefined);
584
+ });
585
+ });
586
+ it("🔴 跨调用序列:同一 plan 连续 3 次成功调用 → 发 3 条(全量幂等,不去重)", () => {
587
+ const deps = new RecordingDeps();
588
+ const handler = createPlanToolResultMiddleware(deps);
589
+ const plan = makePlan({ planId: "plan-stat-no-dedup", tasks: [{ title: "t1", status: "pending" }] });
590
+ const event = makeEvent({
591
+ toolCallId: "call-ps8",
592
+ toolName: "xg_plan_write",
593
+ details: makeSuccessPayload(plan),
594
+ });
595
+ handler(event, FAKE_CTX);
596
+ handler(event, FAKE_CTX);
597
+ handler(event, FAKE_CTX);
598
+ assert.equal(deps.planStatCalls.length, 3, "不去重:同一 plan 连续 3 次成功调用应各发一条");
599
+ });
600
+ });
601
+ describe("createPlanToolResultMiddleware: xg_action_dispatch → RUN_EVENT", () => {
602
+ it("成功结果按 eventId 反查权威 action 并推送", () => {
603
+ const deps = new RecordingDeps();
604
+ const action = {
605
+ eventId: "evt-1", event: "action_dispatch", action: "ui_refresh", target: "order_detail",
606
+ version: 1, status: "completed", payload: { data: { id: "ORD-1" } }, timestamp: "2026-08-13T00:00:00.000Z",
607
+ origin: { channel: "xg_cwork_im", to: "g-1" },
608
+ };
609
+ deps.actionById.set(action.eventId, action);
610
+ const handler = createPlanToolResultMiddleware(deps);
611
+ handler(makeEvent({ toolName: "xg_action_dispatch", details: { ok: true, eventId: action.eventId } }), FAKE_CTX);
612
+ assert.deepEqual(deps.actionRunEventCalls, [action]);
613
+ assert.equal(deps.planStatCalls.length, 0);
614
+ });
615
+ it("失败结果或缺失权威 action 均不推送", () => {
616
+ const deps = new RecordingDeps();
617
+ const handler = createPlanToolResultMiddleware(deps);
618
+ handler(makeEvent({ toolName: "xg_action_dispatch", details: { ok: false } }), FAKE_CTX);
619
+ handler(makeEvent({ toolName: "xg_action_dispatch", details: { ok: true, eventId: "missing" } }), FAKE_CTX);
620
+ assert.equal(deps.actionRunEventCalls.length, 0);
101
621
  });
102
622
  });
103
623
  //# sourceMappingURL=plan-tool-middleware.test.js.map