shennian 0.3.1 → 0.3.2

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 (282) hide show
  1. package/README.md +3 -1
  2. package/dist/publish-build-manifest.json +273 -343
  3. package/dist/src/agents/command-spec.js +2 -2
  4. package/dist/src/agents/detect.js +1 -1
  5. package/dist/src/agents/model-registry/discovery.js +2 -2
  6. package/dist/src/agents/model-registry/parsers.d.ts +1 -0
  7. package/dist/src/agents/model-registry/parsers.js +4 -4
  8. package/dist/src/agents/native-capabilities.d.ts +10 -0
  9. package/dist/src/agents/native-capabilities.js +1 -0
  10. package/dist/src/agents/platform-instructions.js +5 -5
  11. package/dist/src/agents/workbuddy.d.ts +44 -0
  12. package/dist/src/agents/workbuddy.js +3 -0
  13. package/dist/src/commands/daemon.d.ts +1 -0
  14. package/dist/src/commands/daemon.js +9 -9
  15. package/dist/src/commands/integration.d.ts +2 -0
  16. package/dist/src/commands/integration.js +1 -0
  17. package/dist/src/commands/manager.js +1 -2
  18. package/dist/src/commands/pair-browser.d.ts +43 -0
  19. package/dist/src/commands/pair-browser.js +1 -0
  20. package/dist/src/commands/pair.d.ts +2 -0
  21. package/dist/src/commands/pair.js +11 -8
  22. package/dist/src/commands/room.d.ts +13 -0
  23. package/dist/src/commands/room.js +4 -0
  24. package/dist/src/commands/upgrade.d.ts +3 -0
  25. package/dist/src/commands/upgrade.js +1 -1
  26. package/dist/src/config/index.d.ts +3 -1
  27. package/dist/src/config/index.js +2 -1
  28. package/dist/src/daemon-ipc/client.d.ts +8 -0
  29. package/dist/src/daemon-ipc/client.js +3 -0
  30. package/dist/src/daemon-ipc/paths.d.ts +7 -0
  31. package/dist/src/daemon-ipc/paths.js +1 -0
  32. package/dist/src/daemon-ipc/protocol.d.ts +30 -0
  33. package/dist/src/daemon-ipc/protocol.js +1 -0
  34. package/dist/src/daemon-ipc/secret.d.ts +3 -0
  35. package/dist/src/daemon-ipc/secret.js +3 -0
  36. package/dist/src/daemon-ipc/server.d.ts +13 -0
  37. package/dist/src/daemon-ipc/server.js +3 -0
  38. package/dist/src/index.js +2 -2
  39. package/dist/src/integrations/claude-room-plugin-lifecycle.d.ts +47 -0
  40. package/dist/src/integrations/claude-room-plugin-lifecycle.js +1 -0
  41. package/dist/src/integrations/codex-room-plugin-lifecycle.d.ts +49 -0
  42. package/dist/src/integrations/codex-room-plugin-lifecycle.js +1 -0
  43. package/dist/src/integrations/room-plugin-bundles.d.ts +23 -0
  44. package/dist/src/integrations/room-plugin-bundles.js +1 -0
  45. package/dist/src/integrations/room-plugin-lifecycle-common.d.ts +17 -0
  46. package/dist/src/integrations/room-plugin-lifecycle-common.js +1 -0
  47. package/dist/src/integrations/room-plugin-shared.d.ts +23 -0
  48. package/dist/src/integrations/room-plugin-shared.js +2 -0
  49. package/dist/src/integrations/room-session-hook.d.ts +30 -0
  50. package/dist/src/integrations/room-session-hook.js +2 -0
  51. package/dist/src/integrations/workbuddy-plugin-bundle.d.ts +15 -0
  52. package/dist/src/integrations/workbuddy-plugin-bundle.js +1 -0
  53. package/dist/src/integrations/workbuddy-plugin-lifecycle.d.ts +52 -0
  54. package/dist/src/integrations/workbuddy-plugin-lifecycle.js +2 -0
  55. package/dist/src/integrations/workbuddy-session-hook.d.ts +22 -0
  56. package/dist/src/integrations/workbuddy-session-hook.js +1 -0
  57. package/dist/src/manager/prompt.d.ts +1 -1
  58. package/dist/src/manager/prompt.js +1 -1
  59. package/dist/src/manager/retired-external-channel-compat.d.ts +78 -0
  60. package/dist/src/manager/retired-external-channel-compat.js +1 -0
  61. package/dist/src/manager/runtime.d.ts +1 -3
  62. package/dist/src/manager/runtime.js +7 -7
  63. package/dist/src/relay/client.d.ts +2 -0
  64. package/dist/src/relay/client.js +1 -1
  65. package/dist/src/room/activation-audit.d.ts +15 -0
  66. package/dist/src/room/activation-audit.js +2 -0
  67. package/dist/src/room/activation-policy.d.ts +8 -0
  68. package/dist/src/room/activation-policy.js +1 -0
  69. package/dist/src/room/activation-service.d.ts +25 -0
  70. package/dist/src/room/activation-service.js +2 -0
  71. package/dist/src/room/attachment-cache.d.ts +40 -0
  72. package/dist/src/room/attachment-cache.js +2 -0
  73. package/dist/src/room/attachment-upload.d.ts +20 -0
  74. package/dist/src/room/attachment-upload.js +1 -0
  75. package/dist/src/room/authorized-action-coordinator.d.ts +40 -0
  76. package/dist/src/room/authorized-action-coordinator.js +1 -0
  77. package/dist/src/room/authorized-action-ipc.d.ts +11 -0
  78. package/dist/src/room/authorized-action-ipc.js +1 -0
  79. package/dist/src/room/device-authorization-client.d.ts +49 -0
  80. package/dist/src/room/device-authorization-client.js +1 -0
  81. package/dist/src/room/host-session-observation-ipc.d.ts +9 -0
  82. package/dist/src/room/host-session-observation-ipc.js +1 -0
  83. package/dist/src/room/host-session-observations.d.ts +54 -0
  84. package/dist/src/room/host-session-observations.js +2 -0
  85. package/dist/src/room/invite-bootstrap.d.ts +35 -0
  86. package/dist/src/room/invite-bootstrap.js +1 -0
  87. package/dist/src/room/invocation-token-ipc.d.ts +9 -0
  88. package/dist/src/room/invocation-token-ipc.js +1 -0
  89. package/dist/src/room/invocation-token.d.ts +53 -0
  90. package/dist/src/room/invocation-token.js +1 -0
  91. package/dist/src/room/jsonl-mirror.d.ts +73 -0
  92. package/dist/src/room/jsonl-mirror.js +6 -0
  93. package/dist/src/room/managed-room-session.d.ts +143 -0
  94. package/dist/src/room/managed-room-session.js +3 -0
  95. package/dist/src/room/mirror-sync-service.d.ts +33 -0
  96. package/dist/src/room/mirror-sync-service.js +1 -0
  97. package/dist/src/room/operator-ipc.d.ts +11 -0
  98. package/dist/src/room/operator-ipc.js +1 -0
  99. package/dist/src/room/pending-authorized-actions.d.ts +69 -0
  100. package/dist/src/room/pending-authorized-actions.js +3 -0
  101. package/dist/src/room/room-action-client.d.ts +208 -0
  102. package/dist/src/room/room-action-client.js +1 -0
  103. package/dist/src/room/room-action-ipc.d.ts +33 -0
  104. package/dist/src/room/room-action-ipc.js +1 -0
  105. package/dist/src/room/room-action-schema.d.ts +3 -0
  106. package/dist/src/room/room-action-schema.js +1 -0
  107. package/dist/src/room/room-authorized-action-executor.d.ts +23 -0
  108. package/dist/src/room/room-authorized-action-executor.js +1 -0
  109. package/dist/src/room/room-binding-client.d.ts +51 -0
  110. package/dist/src/room/room-binding-client.js +1 -0
  111. package/dist/src/room/room-binding-ipc.d.ts +29 -0
  112. package/dist/src/room/room-binding-ipc.js +1 -0
  113. package/dist/src/room/session-registry-ipc.d.ts +14 -0
  114. package/dist/src/room/session-registry-ipc.js +1 -0
  115. package/dist/src/room/session-registry.d.ts +128 -0
  116. package/dist/src/room/session-registry.js +2 -0
  117. package/dist/src/room/tool-schema.d.ts +114 -0
  118. package/dist/src/room/tool-schema.js +1 -0
  119. package/dist/src/room/tool-server.d.ts +5 -0
  120. package/dist/src/room/tool-server.js +3 -0
  121. package/dist/src/session/handlers/agent-capabilities.d.ts +3 -0
  122. package/dist/src/session/handlers/agent-capabilities.js +1 -0
  123. package/dist/src/session/handlers/agent-config.js +1 -1
  124. package/dist/src/session/handlers/chat.js +2 -2
  125. package/dist/src/session/handlers/control.js +1 -1
  126. package/dist/src/session/handlers/fs.d.ts +1 -0
  127. package/dist/src/session/handlers/fs.js +1 -1
  128. package/dist/src/session/manager.d.ts +16 -6
  129. package/dist/src/session/manager.js +1 -1
  130. package/dist/src/session/types.d.ts +5 -0
  131. package/dist/src/upgrade/engine.d.ts +14 -1
  132. package/dist/src/upgrade/engine.js +2 -2
  133. package/dist/src/upgrade/scheduler.d.ts +45 -0
  134. package/dist/src/upgrade/scheduler.js +1 -0
  135. package/node_modules/@shennian/wire/dist/agent-capabilities.d.ts +17 -0
  136. package/node_modules/@shennian/wire/dist/agent-capabilities.d.ts.map +1 -0
  137. package/node_modules/@shennian/wire/dist/agent-capabilities.js +2 -0
  138. package/node_modules/@shennian/wire/dist/agent-capabilities.js.map +1 -0
  139. package/node_modules/@shennian/wire/dist/index.d.ts +2 -1
  140. package/node_modules/@shennian/wire/dist/index.d.ts.map +1 -1
  141. package/node_modules/@shennian/wire/dist/index.js +2 -1
  142. package/node_modules/@shennian/wire/dist/index.js.map +1 -1
  143. package/node_modules/@shennian/wire/dist/machine.d.ts +1 -0
  144. package/node_modules/@shennian/wire/dist/machine.d.ts.map +1 -1
  145. package/node_modules/@shennian/wire/dist/methods.d.ts +1 -1
  146. package/node_modules/@shennian/wire/dist/methods.d.ts.map +1 -1
  147. package/node_modules/@shennian/wire/dist/room.d.ts +112 -0
  148. package/node_modules/@shennian/wire/dist/room.d.ts.map +1 -0
  149. package/node_modules/@shennian/wire/dist/room.js +4 -0
  150. package/node_modules/@shennian/wire/dist/room.js.map +1 -0
  151. package/node_modules/@shennian/wire/dist/session.d.ts +2 -2
  152. package/node_modules/@shennian/wire/dist/session.d.ts.map +1 -1
  153. package/node_modules/@shennian/wire/dist/session.js +1 -1
  154. package/node_modules/@shennian/wire/dist/session.js.map +1 -1
  155. package/package.json +3 -5
  156. package/dist/scripts/wechat-rpa-confirmation.mjs +0 -5
  157. package/dist/src/agents/pi-context.d.ts +0 -42
  158. package/dist/src/agents/pi-context.js +0 -12
  159. package/dist/src/agents/pi.d.ts +0 -70
  160. package/dist/src/agents/pi.js +0 -17
  161. package/dist/src/channels/base.d.ts +0 -144
  162. package/dist/src/channels/base.js +0 -1
  163. package/dist/src/channels/registry.d.ts +0 -8
  164. package/dist/src/channels/registry.js +0 -1
  165. package/dist/src/channels/reply-split.d.ts +0 -1
  166. package/dist/src/channels/reply-split.js +0 -10
  167. package/dist/src/channels/runtime.d.ts +0 -138
  168. package/dist/src/channels/runtime.js +0 -5
  169. package/dist/src/channels/secret-registry.d.ts +0 -35
  170. package/dist/src/channels/secret-registry.js +0 -1
  171. package/dist/src/channels/websocket.d.ts +0 -55
  172. package/dist/src/channels/websocket.js +0 -8
  173. package/dist/src/channels/wechat-channel/anchor.d.ts +0 -10
  174. package/dist/src/channels/wechat-channel/anchor.js +0 -1
  175. package/dist/src/channels/wechat-channel/automation-lane.d.ts +0 -35
  176. package/dist/src/channels/wechat-channel/automation-lane.js +0 -2
  177. package/dist/src/channels/wechat-channel/client.d.ts +0 -283
  178. package/dist/src/channels/wechat-channel/client.js +0 -1
  179. package/dist/src/channels/wechat-channel/cooldown.d.ts +0 -21
  180. package/dist/src/channels/wechat-channel/cooldown.js +0 -1
  181. package/dist/src/channels/wechat-channel/core/fixture-compare.d.ts +0 -52
  182. package/dist/src/channels/wechat-channel/core/fixture-compare.js +0 -1
  183. package/dist/src/channels/wechat-channel/core/media-action-plan.d.ts +0 -3
  184. package/dist/src/channels/wechat-channel/core/media-action-plan.js +0 -1
  185. package/dist/src/channels/wechat-channel/core/schema.d.ts +0 -67
  186. package/dist/src/channels/wechat-channel/core/schema.js +0 -1
  187. package/dist/src/channels/wechat-channel/core/trace-comparator.d.ts +0 -28
  188. package/dist/src/channels/wechat-channel/core/trace-comparator.js +0 -1
  189. package/dist/src/channels/wechat-channel/fingerprint.d.ts +0 -31
  190. package/dist/src/channels/wechat-channel/fingerprint.js +0 -1
  191. package/dist/src/channels/wechat-channel/helper-assets.d.ts +0 -103
  192. package/dist/src/channels/wechat-channel/helper-assets.js +0 -1
  193. package/dist/src/channels/wechat-channel/helper-client.d.ts +0 -87
  194. package/dist/src/channels/wechat-channel/helper-client.js +0 -3
  195. package/dist/src/channels/wechat-channel/helper-protocol.d.ts +0 -122
  196. package/dist/src/channels/wechat-channel/helper-protocol.js +0 -1
  197. package/dist/src/channels/wechat-channel/human-coordination.d.ts +0 -25
  198. package/dist/src/channels/wechat-channel/human-coordination.js +0 -1
  199. package/dist/src/channels/wechat-channel/index.d.ts +0 -21
  200. package/dist/src/channels/wechat-channel/index.js +0 -1
  201. package/dist/src/channels/wechat-channel/ledger.d.ts +0 -48
  202. package/dist/src/channels/wechat-channel/ledger.js +0 -2
  203. package/dist/src/channels/wechat-channel/media-cache-resolver.d.ts +0 -42
  204. package/dist/src/channels/wechat-channel/media-cache-resolver.js +0 -1
  205. package/dist/src/channels/wechat-channel/media-resolver.d.ts +0 -186
  206. package/dist/src/channels/wechat-channel/media-resolver.js +0 -1
  207. package/dist/src/channels/wechat-channel/message-key.d.ts +0 -19
  208. package/dist/src/channels/wechat-channel/message-key.js +0 -1
  209. package/dist/src/channels/wechat-channel/observer.d.ts +0 -171
  210. package/dist/src/channels/wechat-channel/observer.js +0 -7
  211. package/dist/src/channels/wechat-channel/outbound-ledger.d.ts +0 -96
  212. package/dist/src/channels/wechat-channel/outbound-ledger.js +0 -2
  213. package/dist/src/channels/wechat-channel/outbound-sender.d.ts +0 -74
  214. package/dist/src/channels/wechat-channel/outbound-sender.js +0 -1
  215. package/dist/src/channels/wechat-channel/pacing.d.ts +0 -3
  216. package/dist/src/channels/wechat-channel/pacing.js +0 -1
  217. package/dist/src/channels/wechat-channel/preflight.d.ts +0 -46
  218. package/dist/src/channels/wechat-channel/preflight.js +0 -1
  219. package/dist/src/channels/wechat-channel/runner.d.ts +0 -43
  220. package/dist/src/channels/wechat-channel/runner.js +0 -1
  221. package/dist/src/channels/wechat-channel/runtime.d.ts +0 -50
  222. package/dist/src/channels/wechat-channel/runtime.js +0 -1
  223. package/dist/src/channels/wechat-channel/scheduler.d.ts +0 -74
  224. package/dist/src/channels/wechat-channel/scheduler.js +0 -1
  225. package/dist/src/channels/wechat-channel/vector-store.d.ts +0 -44
  226. package/dist/src/channels/wechat-channel/vector-store.js +0 -1
  227. package/dist/src/channels/wechat-rpa/macos-flow.d.ts +0 -55
  228. package/dist/src/channels/wechat-rpa/macos-flow.js +0 -1
  229. package/dist/src/channels/wechat-rpa/macos.d.ts +0 -11
  230. package/dist/src/channels/wechat-rpa/macos.js +0 -21
  231. package/dist/src/channels/wechat-rpa/normalizer.d.ts +0 -49
  232. package/dist/src/channels/wechat-rpa/normalizer.js +0 -7
  233. package/dist/src/channels/wechat-rpa/product-channel.d.ts +0 -76
  234. package/dist/src/channels/wechat-rpa/product-channel.js +0 -16
  235. package/dist/src/channels/wechat-rpa-session-sync.d.ts +0 -26
  236. package/dist/src/channels/wechat-rpa-session-sync.js +0 -1
  237. package/dist/src/channels/wechat-rpa.d.ts +0 -104
  238. package/dist/src/channels/wechat-rpa.js +0 -6
  239. package/dist/src/channels/wecom.d.ts +0 -51
  240. package/dist/src/channels/wecom.js +0 -4
  241. package/dist/src/commands/external-attachments.d.ts +0 -9
  242. package/dist/src/commands/external-attachments.js +0 -1
  243. package/dist/src/commands/external.d.ts +0 -2
  244. package/dist/src/commands/external.js +0 -1
  245. package/dist/src/commands/helper-runtime-official-download.d.ts +0 -80
  246. package/dist/src/commands/helper-runtime-official-download.js +0 -1
  247. package/dist/src/commands/runtime.d.ts +0 -120
  248. package/dist/src/commands/runtime.js +0 -1
  249. package/dist/src/commands/wechat/command.d.ts +0 -3
  250. package/dist/src/commands/wechat/command.js +0 -1
  251. package/dist/src/commands/wechat/direct.d.ts +0 -14
  252. package/dist/src/commands/wechat/direct.js +0 -2
  253. package/dist/src/commands/wechat/doctor.d.ts +0 -2
  254. package/dist/src/commands/wechat/doctor.js +0 -1
  255. package/dist/src/commands/wechat/ipc.d.ts +0 -9
  256. package/dist/src/commands/wechat/ipc.js +0 -1
  257. package/dist/src/commands/wechat/operations.d.ts +0 -3
  258. package/dist/src/commands/wechat/operations.js +0 -4
  259. package/dist/src/commands/wechat/output.d.ts +0 -7
  260. package/dist/src/commands/wechat/output.js +0 -4
  261. package/dist/src/commands/wechat/types.d.ts +0 -142
  262. package/dist/src/commands/wechat/types.js +0 -1
  263. package/dist/src/commands/wechat/utils.d.ts +0 -16
  264. package/dist/src/commands/wechat/utils.js +0 -1
  265. package/dist/src/commands/wechat.d.ts +0 -6
  266. package/dist/src/commands/wechat.js +0 -1
  267. package/dist/src/devtools/wechat-channel-action-smoke.d.ts +0 -105
  268. package/dist/src/devtools/wechat-channel-action-smoke.js +0 -10
  269. package/dist/src/devtools/wechat-channel-download-report.d.ts +0 -111
  270. package/dist/src/devtools/wechat-channel-download-report.js +0 -2
  271. package/dist/src/devtools/wechat-channel-markdown-report.d.ts +0 -6
  272. package/dist/src/devtools/wechat-channel-markdown-report.js +0 -5
  273. package/dist/src/devtools/wechat-channel-product-steps.d.ts +0 -9
  274. package/dist/src/devtools/wechat-channel-product-steps.js +0 -40
  275. package/dist/src/session/handlers/skills.d.ts +0 -7
  276. package/dist/src/session/handlers/skills.js +0 -1
  277. package/dist/src/session/handlers/wechat-helper-runtime.d.ts +0 -33
  278. package/dist/src/session/handlers/wechat-helper-runtime.js +0 -1
  279. package/dist/src/skills/registry.d.ts +0 -16
  280. package/dist/src/skills/registry.js +0 -15
  281. package/dist/src/skills/setup.d.ts +0 -11
  282. package/dist/src/skills/setup.js +0 -1
@@ -1,5 +0,0 @@
1
- import M from"node:crypto";import h from"node:fs";import u from"node:path";import{ChannelConfigRegistry as P}from"./registry.js";import{ChannelSecretRegistry as N}from"./secret-registry.js";import{WeComChannelAdapter as B}from"./wecom.js";import{WeChatRpaChannelAdapter as D}from"./wechat-rpa.js";import{ExternalWebSocketChannelAdapter as x}from"./websocket.js";import{splitExternalReplyText as W}from"./reply-split.js";class J{onExternalMessage;createReplyTarget;configs=new P;secrets=new N;adapters=new Map;completedReplyKeys=new Map;recentMessages=new Map;constructor(e,t,n={}){this.onExternalMessage=e,this.createReplyTarget=t;const o=new B(r=>this.ingest({...r,type:"external.message"}));this.adapters.set(o.type,o);const a=new x(r=>this.ingest({...r,type:"external.message"}));this.adapters.set(a.type,a);const i=new D(r=>this.ingest(r),{createProductRunner:n.createWeChatRpaProductRunner,automationLane:n.weChatAutomationLane});this.adapters.set(i.type,i)}async start(){for(const e of this.configs.list().filter(t=>t.enabled))await this.adapters.get(e.type)?.connect(e).catch(()=>{})}async stop(){for(const e of this.configs.list())await this.adapters.get(e.type)?.disconnect(e).catch(()=>{})}ingest(e){const t=this.findRecentMessageDuplicate(e);if(t)return t;const n=this.configs.get(e.channelId),o=e.managerSessionId??n?.sessionId??n?.managerSessionId;if(!o)throw new Error(`No session bound for channel ${e.channelId}`);const a=e.replyTarget||this.createReplyTarget({managerSessionId:o,channelId:e.channelId,conversationId:e.conversationId,messageId:e.messageId}),i={...e,replyTarget:a};return this.onExternalMessage(o,i),this.recordRecentMessage(i),i}async reply(e){const t=this.configs.get(e.channelId);if(!t)return{ok:!1,error:`Unknown channel: ${e.channelId}`};if((t.sessionId??t.managerSessionId)!==e.managerSessionId)return{ok:!1,error:"Channel is not bound to this session"};const n=this.adapters.get(t.type);if(!n)return{ok:!1,error:`Unsupported channel type: ${t.type}`};try{const o=F(t.type,e);if(!o.length)return{ok:!1,error:"Reply text or attachment is required"};let a=!1;for(const i of o){const r=i.idempotencyKey;if(r&&this.isReplyCompleted(t,e.conversationId,r))continue;const l=await n.send(t,{...e,...i});if(l?.status==="queued"){a=!0;continue}if(l?.status==="manual-review")return{ok:!1,error:l.reason||"Reply requires manual review before retry"};r&&this.markReplyCompleted(t,e.conversationId,r)}return a?{ok:!0,pending:!0}:{ok:!0}}catch(o){return{ok:!1,error:o instanceof Error?o.message:String(o)}}}isReplyCompleted(e,t,n){return this.loadReplyCompletionSet(e).has(A(e.id,t,n))}markReplyCompleted(e,t,n){const o=this.loadReplyCompletionSet(e);o.add(A(e.id,t,n));try{$(e.workDir,o)}catch{}}loadReplyCompletionSet(e){const t=u.resolve(e.workDir),n=this.completedReplyKeys.get(t);if(n)return n;const o=T(e.workDir);return this.completedReplyKeys.set(t,o),o}async getDefaultReplyTarget(e){const t=this.configs.list().find(a=>(a.sessionId??a.managerSessionId)===e&&a.enabled);if(!t)throw new Error("No enabled external channel is bound to this session");const n=this.adapters.get(t.type);if(!n?.defaultConversation)throw new Error(`External channel ${t.type} has no default conversation`);const o=await n.defaultConversation(t);return{channelId:t.id,conversationId:o.conversationId}}getManagerChannel(e,t,n={}){const o=this.configs.list().filter(l=>(l.sessionId??l.managerSessionId)===e&&l.type===t),a=o.find(l=>l.enabled)??o.at(-1);if(!a)return null;const i=this.secrets.get(a.secretRef),r=this.adapters.get(a.type)?.runtimeStatus?.(a)??{};return{id:a.id,type:a.type,name:a.name,sessionId:a.sessionId??a.managerSessionId,managerSessionId:a.managerSessionId,workDir:a.workDir,agentType:a.agentType,agentSessionId:a.agentSessionId,modelId:a.modelId,enabled:a.enabled,wsUrl:i?.wsUrl??"",token:n.includeSecret?i?.token??"":"",tokenConfigured:!!i?.token,canReply:!!i?.canReply,systemPrompt:typeof i?.systemPrompt=="string"?i.systemPrompt:"",...C(i),...r}}getChannelById(e,t={}){const n=this.configs.get(e);if(!n)return null;const o=this.secrets.get(n.secretRef),a=this.adapters.get(n.type)?.runtimeStatus?.(n)??{};return{id:n.id,type:n.type,name:n.name,sessionId:n.sessionId??n.managerSessionId,managerSessionId:n.managerSessionId,workDir:n.workDir,agentType:n.agentType,agentSessionId:n.agentSessionId,modelId:n.modelId,enabled:n.enabled,wsUrl:o?.wsUrl??"",token:t.includeSecret?o?.token??"":"",tokenConfigured:!!o?.token,canReply:!!o?.canReply,systemPrompt:typeof o?.systemPrompt=="string"?o.systemPrompt:"",...C(o),...a,managedBy:n.managedBy}}getChannelStatusById(e){const t=this.configs.get(e);if(!t)return null;const n=this.secrets.get(t.secretRef),o=this.adapters.get(t.type)?.runtimeStatus?.(t)??{};return{configured:!0,connected:y(t,n),type:t.type,channelId:t.id,name:t.name,canReply:!!n?.canReply,systemPrompt:typeof n?.systemPrompt=="string"?n.systemPrompt:"",...w(n),...o}}getManagerChannelStatus(e){const t=this.configs.list().find(a=>(a.sessionId??a.managerSessionId)===e&&a.enabled);if(!t)return null;const n=this.secrets.get(t.secretRef),o=this.adapters.get(t.type)?.runtimeStatus?.(t)??{};return{configured:!0,connected:y(t,n),type:t.type,channelId:t.id,name:t.name,canReply:!!n?.canReply,systemPrompt:typeof n?.systemPrompt=="string"?n.systemPrompt:"",...w(n),...o}}listManagerChannelStatuses(){return this.configs.list().filter(e=>e.enabled).map(e=>({managerSessionId:e.sessionId??e.managerSessionId,status:this.getManagerChannelStatus(e.sessionId??e.managerSessionId)})).filter(e=>!!e.status)}listManagerExternalChannels(e){return this.configs.list().filter(t=>t.enabled&&(t.sessionId??t.managerSessionId)===e).map(t=>{const n=this.secrets.get(t.secretRef),o=this.adapters.get(t.type)?.runtimeStatus?.(t)??{};return{configured:!0,connected:y(t,n),type:t.type,channelId:t.id,name:t.name,canReply:!!n?.canReply,systemPrompt:typeof n?.systemPrompt=="string"?n.systemPrompt:"",...w(n),...o}})}async syncManagerWeChatRpaChannel(e){const t=this.configs.list().find(r=>r.enabled&&r.type==="wechat-rpa"&&(r.sessionId??r.managerSessionId)===e);if(!t)throw new Error("No enabled WeChat RPA channel is bound to this session");const n=this.adapters.get(t.type);if(!n?.syncNow)throw new Error("WeChat RPA channel does not support manual sync");const o=Date.now()-120*1e3,a=await n.syncNow(t)??[],i=K(a,this.getRecentMessages(t.id,o));return{channel:this.getManagerChannel(e,"wechat-rpa",{includeSecret:!0}),messages:a,recentMessages:i}}async cancelManagerWeChatRpaOutbound(e){const t=this.configs.list().find(a=>a.enabled&&a.type==="wechat-rpa"&&(a.sessionId??a.managerSessionId)===e.managerSessionId);if(!t)throw new Error("No enabled WeChat RPA channel is bound to this session");const n=this.adapters.get(t.type);if(!n?.cancelOutbound)throw new Error("WeChat RPA channel does not support outbound cancellation");const o=await n.cancelOutbound(t,{idempotencyKey:e.idempotencyKey,replyId:e.replyId,reason:e.reason});return{cancelled:o.cancelled,status:o.status,channel:this.getManagerChannel(e.managerSessionId,"wechat-rpa",{includeSecret:!0})}}recordRecentMessage(e){const t=this.recentMessages.get(e.channelId)??[];this.findRecentMessageDuplicate(e)||(t.push(e),this.recentMessages.set(e.channelId,t.slice(-50)))}findRecentMessageDuplicate(e){const t=I(e);return t?(this.recentMessages.get(e.channelId)??[]).find(o=>I(o)===t)??null:null}getRecentMessages(e,t){return(this.recentMessages.get(e)??[]).filter(o=>{const a=Date.parse(o.receivedAt);return!Number.isFinite(a)||a>=t})}async upsertManagerChannel(e){const t=this.configs.get(e.id),n=this.configs.list(),o=e.sessionId||e.managerSessionId,a={id:e.id,type:e.type,name:e.name?.trim()||t?.name||"\u5916\u90E8\u6D88\u606F\u901A\u9053",sessionId:o,managerSessionId:o,workDir:e.workDir,agentType:e.agentType||t?.agentType,agentSessionId:e.agentSessionId??t?.agentSessionId??null,modelId:e.modelId??t?.modelId??null,enabled:e.enabled,secretRef:t?.secretRef||`channel:${e.id}`},i=this.secrets.get(a.secretRef),r=e.wsUrl?.trim()||i?.wsUrl||"",l=e.token?.trim()||i?.token||"",p=e.canReply??i?.canReply??!1,m=e.systemPrompt??(typeof i?.systemPrompt=="string"?i.systemPrompt:"");if(a.enabled&&(!r||!l))throw new Error("WebSocket \u5730\u5740\u548C Token \u5FC5\u586B");const f=n.filter(d=>d.id!==a.id).map(d=>(d.sessionId??d.managerSessionId)===o&&d.type===e.type?{...d,enabled:!1}:d);f.push(a),this.configs.replaceAll(f),(r||l)&&this.secrets.upsert(a.secretRef,{type:"websocket",wsUrl:r,token:l,canReply:p,systemPrompt:m});const c=this.adapters.get(a.type);for(const d of n)(d.sessionId??d.managerSessionId)===o&&d.type===e.type&&d.enabled&&await this.adapters.get(d.type)?.disconnect(d).catch(()=>{});return a.enabled&&c?.connect(a).catch(()=>{}),this.getManagerChannel(o,e.type,{includeSecret:!0})}async upsertManagerWeChatRpaChannel(e){const t=this.configs.get(e.id),n=e.sessionId||e.managerSessionId,o=g(e.groups);if(e.enabled&&!o.length)throw new Error("WeChat RPA \u81F3\u5C11\u9700\u8981\u914D\u7F6E\u4E00\u4E2A\u7FA4");if(e.enabled&&o.length>1)throw new Error("WeChat RPA \u6BCF\u4E2A\u5BF9\u8BDD\u53EA\u80FD\u7ED1\u5B9A\u4E00\u4E2A\u7FA4");if(e.enabled){const c=this.findConflictingWeChatRpaBinding({excludeChannelId:e.id,boundSessionId:n,groupNames:o.map(d=>d.name)});if(c){const d=this.configs.get(c.channelId);if(e.managedBy==="session-sync"&&d?.managedBy==="session-sync")await this.deleteManagerWeChatRpaChannel(c.channelId);else throw new Error(`\u5FAE\u4FE1\u5BF9\u8BDD\u300C${c.groupName}\u300D\u5DF2\u88AB\u53E6\u4E00\u4E2A\u667A\u80FD\u4F53\u7ED1\u5B9A(\u901A\u9053 ${c.channelName}),\u540C\u4E00\u4E2A\u5BF9\u8BDD\u53EA\u80FD\u7ED1\u5B9A\u4E00\u6B21\u3002\u8BF7\u5148\u5728\u539F\u667A\u80FD\u4F53\u89E3\u7ED1,\u518D\u91CD\u65B0\u7ED1\u5B9A\u3002`)}}const a=this.configs.list(),i={id:e.id,type:"wechat-rpa",name:e.name?.trim()||t?.name||"\u672C\u673A\u5FAE\u4FE1 RPA",sessionId:n,managerSessionId:n,workDir:e.workDir,agentType:e.agentType||t?.agentType,agentSessionId:e.agentSessionId??t?.agentSessionId??null,modelId:e.modelId??t?.modelId??null,enabled:e.enabled,secretRef:t?.secretRef||`channel:${e.id}`,managedBy:e.managedBy??t?.managedBy},r=this.secrets.get(i.secretRef),l=e.source||(r?.source==="wechat-channel"||r?.source==="macos-probe"||r?.source==="fixture-jsonl"||r?.source==="macos-flow"||r?.source==="windows-visual-flow"||r?.source==="wechat-rpa-lab"?r.source:E());if(e.enabled&&l==="windows-visual-flow")throw new Error("\u65E7 Windows visual flow \u5DF2\u5F52\u6863\uFF1BmacOS \u548C Windows \u6B63\u5F0F\u901A\u9053\u90FD\u4F7F\u7528 wechat-channel");const p=e.privacyConsentAccepted??!!r?.privacyConsentAccepted;if(e.enabled&&!p)throw new Error("\u542F\u7528\u524D\u9700\u8981\u786E\u8BA4\u5FAE\u4FE1\u901A\u9053\u6570\u636E\u4E0E\u9690\u79C1\u6388\u6743");const m=a.filter(c=>c.id!==i.id).map(c=>(c.sessionId??c.managerSessionId)===n&&c.type==="wechat-rpa"?{...c,enabled:!1}:c);m.push(i),this.configs.replaceAll(m),this.secrets.upsert(i.secretRef,{type:"wechat-rpa",source:l,groups:o,pollIntervalMs:R(e.pollIntervalMs,r?.pollIntervalMs),recentLimit:R(e.recentLimit,r?.recentLimit),idleSeconds:R(e.idleSeconds,r?.idleSeconds),forceForeground:e.forceForeground??(r?.forceForeground===void 0?!0:!!r.forceForeground),noRestore:e.noRestore??(r?.noRestore===void 0?!0:!!r.noRestore),downloadAttachments:e.downloadAttachments??(r?.downloadAttachments===void 0?!0:!!r.downloadAttachments),downloadAttachmentsDir:e.downloadAttachmentsDir?.trim()||b(r?.downloadAttachmentsDir),selfNickname:e.selfNickname?.trim()||b(r?.selfNickname),selfTriggerMarker:e.selfTriggerMarker?.trim()||void 0,deferInitialPoll:e.deferInitialPoll===!0?!0:void 0,privacyConsentAccepted:p,flowScriptPath:e.flowScriptPath?.trim()||b(r?.flowScriptPath),canReply:e.canReply??r?.canReply??!1,systemPrompt:e.systemPrompt??(typeof r?.systemPrompt=="string"?r.systemPrompt:"")});const f=this.adapters.get(i.type);for(const c of a)(c.sessionId??c.managerSessionId)===n&&c.type==="wechat-rpa"&&c.enabled&&await this.adapters.get(c.type)?.disconnect(c).catch(()=>{});return i.enabled&&f?.connect(i).catch(c=>{console.error(`[wechat-rpa] connect failed id=${i.id}: ${c instanceof Error?c.message:String(c)}`)}),this.getManagerChannel(n,"wechat-rpa",{includeSecret:!0})}listChannelIdsManagedBy(e){return this.configs.list().filter(t=>t.managedBy===e).map(t=>t.id)}async deleteManagerWeChatRpaChannel(e){const t=this.configs.get(e);if(!t)return{removed:!1};t.enabled&&await this.adapters.get(t.type)?.disconnect(t).catch(()=>{});const n=this.configs.remove(e);return t.secretRef&&this.secrets.remove(t.secretRef),{removed:n}}findConflictingWeChatRpaBinding(e){const t=new Set(e.groupNames);if(!t.size)return null;for(const n of this.configs.list()){if(n.type!=="wechat-rpa"||!n.enabled||n.id===e.excludeChannelId||(n.sessionId??n.managerSessionId)===e.boundSessionId)continue;const o=this.secrets.get(n.secretRef),a=g(Array.isArray(o?.groups)?o.groups:[]);for(const i of a)if(t.has(i.name))return{channelId:n.id,channelName:n.name||n.id,groupName:i.name}}return null}}function y(s,e){return!e||e.type!==s.type?!1:s.type==="wechat-rpa"?!0:s.type==="websocket"?!!(e.wsUrl&&e.token):s.type==="wecom"?!!(e.token||e.botId||e.secret):!!e.token}function C(s){return!s||s.type!=="wechat-rpa"?{}:{wechatRpaSource:typeof s.source=="string"?s.source:"",wechatRpaGroups:g(Array.isArray(s.groups)?s.groups:[]),pollIntervalMs:Number.isFinite(s.pollIntervalMs)?Number(s.pollIntervalMs):void 0,recentLimit:Number.isFinite(s.recentLimit)?Number(s.recentLimit):void 0,idleSeconds:Number.isFinite(s.idleSeconds)?Number(s.idleSeconds):void 0,forceForeground:s.forceForeground===void 0?!0:!!s.forceForeground,noRestore:s.noRestore===void 0?void 0:!!s.noRestore,downloadAttachments:s.downloadAttachments===void 0?!0:!!s.downloadAttachments,downloadAttachmentsDir:typeof s.downloadAttachmentsDir=="string"?s.downloadAttachmentsDir:"",selfNickname:typeof s.selfNickname=="string"?s.selfNickname:"",wechatRpaPrivacyConsentAccepted:!!s.privacyConsentAccepted,wechatRpaServerDecisionAvailable:!0,wechatRpaPreflightChecks:k(s)}}function w(s){return!s||s.type!=="wechat-rpa"?{}:{wechatRpaSource:typeof s.source=="string"?s.source:null,wechatRpaGroups:g(Array.isArray(s.groups)?s.groups:[]),pollIntervalMs:Number.isFinite(s.pollIntervalMs)?Number(s.pollIntervalMs):null,recentLimit:Number.isFinite(s.recentLimit)?Number(s.recentLimit):null,idleSeconds:Number.isFinite(s.idleSeconds)?Number(s.idleSeconds):null,forceForeground:s.forceForeground===void 0?!0:!!s.forceForeground,noRestore:s.noRestore===void 0?null:!!s.noRestore,downloadAttachments:s.downloadAttachments===void 0?!0:!!s.downloadAttachments,downloadAttachmentsDir:typeof s.downloadAttachmentsDir=="string"?s.downloadAttachmentsDir:null,selfNickname:typeof s.selfNickname=="string"?s.selfNickname:null,wechatRpaPrivacyConsentAccepted:!!s.privacyConsentAccepted,wechatRpaServerDecisionAvailable:!0,wechatRpaPreflightChecks:k(s)}}function g(s){const e=new Set,t=[];for(const n of s){const o=String(n?.name||"").replace(/\s+/g," ").trim();!o||e.has(o)||(e.add(o),t.push({name:o}))}return t}function E(){return"wechat-channel"}function k(s){const e=[];if(s.lastHelperPermissions&&typeof s.lastHelperPermissions=="object"){const t=s.lastHelperPermissions;e.push({code:"wechat_window_unavailable",ok:t.wechatWindowAvailable!==!1,severity:"blocking",message:t.wechatWindowAvailable===!1?"\u5FAE\u4FE1\u7A97\u53E3\u4E0D\u53EF\u7528\uFF0C\u8BF7\u6253\u5F00\u5E76\u767B\u5F55\u5FAE\u4FE1\u540E\u518D\u8BD5\u3002":"\u5FAE\u4FE1\u7A97\u53E3\u53EF\u7528\u3002"})}return e.push({code:"platform_unsupported",ok:s.source!=="windows-visual-flow",severity:"blocking",message:s.source==="windows-visual-flow"?"\u65E7 Windows visual flow \u5DF2\u5F52\u6863\uFF0C\u8BF7\u6539\u7528 wechat-channel\u3002":"\u5F53\u524D\u914D\u7F6E\u4F7F\u7528\u8DE8\u5E73\u53F0\u5FAE\u4FE1\u901A\u9053\u3002"}),e.push({code:"privacy_consent_required",ok:!!s.privacyConsentAccepted,severity:"blocking",message:s.privacyConsentAccepted?"\u5DF2\u786E\u8BA4\u5FAE\u4FE1\u901A\u9053\u6570\u636E\u4E0E\u9690\u79C1\u6388\u6743\u3002":"\u542F\u7528\u524D\u9700\u8981\u786E\u8BA4\u5FAE\u4FE1\u901A\u9053\u6570\u636E\u4E0E\u9690\u79C1\u6388\u6743\u3002"}),e.push({code:"server_decision_unavailable",ok:!0,severity:"blocking",message:"\u670D\u52A1\u7AEF\u5224\u65AD\u80FD\u529B\u53EF\u7528\u3002"}),e}function F(s,e){const t=W(e.text);if(!t.length&&!e.attachment)return[];if(s==="wechat-rpa"&&e.attachment&&t.length<=1)return[{text:t[0]??"",attachment:e.attachment,idempotencyKey:e.idempotencyKey}];const n=t.map((o,a)=>({text:o,attachment:void 0,idempotencyKey:t.length>1&&e.idempotencyKey?`${e.idempotencyKey}:${a+1}`:e.idempotencyKey}));return e.attachment&&n.push({text:"",attachment:e.attachment,idempotencyKey:t.length&&e.idempotencyKey?`${e.idempotencyKey}:attachment`:e.idempotencyKey}),n}function K(...s){const e=new Set,t=[];for(const n of s.flat()){const o=I(n);if(!o){t.push(n);continue}e.has(o)||(e.add(o),t.push(n))}return t}function I(s){const e=S(s.channelId),t=S(s.conversationId),n=S(s.messageId);return!e||!t||!n?null:`${e}
2
- ${t}
3
- ${n}`}function S(s){return typeof s=="string"?s.trim():""}function A(s,e,t){return M.createHash("sha256").update(`${s}
4
- ${e}
5
- ${t}`).digest("hex").slice(0,32)}function v(s){return u.join(s,".shennian","external-reply-idempotency.json")}function T(s){try{const e=JSON.parse(h.readFileSync(v(s),"utf8")),t=Array.isArray(e.completed)?e.completed:[];return new Set(t.map(n=>typeof n=="string"?n:n&&typeof n=="object"&&typeof n.key=="string"?n.key:"").filter(Boolean))}catch{return new Set}}function $(s,e){const t=v(s);h.mkdirSync(u.dirname(t),{recursive:!0});const n=Array.from(e).slice(-500);h.writeFileSync(t,JSON.stringify({updatedAt:new Date().toISOString(),completed:n.map(o=>({key:o}))},null,2)),e.clear();for(const o of n)e.add(o)}function R(s,e){const t=Number(s??e);return Number.isFinite(t)&&t>=0?t:void 0}function b(s){return typeof s=="string"&&s.trim()?s.trim():void 0}export{J as ChannelRuntime,F as planExternalReplySends};
@@ -1,35 +0,0 @@
1
- type ChannelSecretRecord = {
2
- type: 'wecom' | 'websocket' | 'wechat-rpa';
3
- botId?: string;
4
- secret?: string;
5
- wsUrl?: string;
6
- token?: string;
7
- canReply?: boolean;
8
- systemPrompt?: string;
9
- source?: 'wechat-channel' | 'macos-probe' | 'macos-flow' | 'windows-visual-flow' | 'wechat-rpa-lab' | 'fixture-jsonl';
10
- fixturePath?: string;
11
- pollIntervalMs?: number;
12
- groups?: Array<{
13
- name: string;
14
- }>;
15
- forceForeground?: boolean;
16
- noRestore?: boolean;
17
- downloadAttachments?: boolean;
18
- downloadAttachmentsDir?: string;
19
- selfNickname?: string;
20
- selfTriggerMarker?: string;
21
- deferInitialPoll?: boolean;
22
- privacyConsentAccepted?: boolean;
23
- idleSeconds?: number;
24
- recentLimit?: number;
25
- flowScriptPath?: string;
26
- updatedAt: string;
27
- };
28
- export declare class ChannelSecretRegistry {
29
- private load;
30
- private save;
31
- get(secretRef: string): ChannelSecretRecord | undefined;
32
- upsert(secretRef: string, value: Omit<ChannelSecretRecord, 'updatedAt'>): ChannelSecretRecord;
33
- remove(secretRef: string): void;
34
- }
35
- export {};
@@ -1 +0,0 @@
1
- import r from"node:fs";import o from"node:path";import{resolveShennianPath as i}from"../config/index.js";function s(){return i("channels.secrets.json")}function a(){return new Date().toISOString()}function u(){return{secrets:{}}}class f{load(){try{return{secrets:JSON.parse(r.readFileSync(s(),"utf-8")).secrets??{}}}catch{return u()}}save(e){r.mkdirSync(o.dirname(s()),{recursive:!0}),r.writeFileSync(s(),JSON.stringify(e,null,2),{mode:384});try{r.chmodSync(s(),384)}catch{}}get(e){return this.load().secrets[e]}upsert(e,t){const n=this.load(),c={...t,updatedAt:a()};return n.secrets[e]=c,this.save(n),c}remove(e){const t=this.load();e in t.secrets&&(delete t.secrets[e],this.save(t))}}export{f as ChannelSecretRegistry};
@@ -1,55 +0,0 @@
1
- import type { ExternalChannelAdapter, ExternalChannelConfig, ExternalReply } from './base.js';
2
- export declare class ExternalWebSocketChannelAdapter implements ExternalChannelAdapter {
3
- private onMessage?;
4
- readonly type: "websocket";
5
- private secrets;
6
- private connections;
7
- constructor(onMessage?: ((event: {
8
- managerSessionId: string;
9
- channelId: string;
10
- channelType: "websocket";
11
- conversationId: string;
12
- messageId: string;
13
- sender: {
14
- id: string;
15
- name?: string | null;
16
- };
17
- text: string;
18
- attachments: Array<{
19
- type: string;
20
- name?: string;
21
- url?: string;
22
- mimeType?: string;
23
- size?: number;
24
- }>;
25
- receivedAt: string;
26
- replyTarget: string;
27
- }) => void) | undefined);
28
- connect(config: ExternalChannelConfig): Promise<void>;
29
- disconnect(config: ExternalChannelConfig): Promise<void>;
30
- send(config: ExternalChannelConfig, reply: ExternalReply): Promise<void>;
31
- health(config: ExternalChannelConfig): Promise<{
32
- ok: boolean;
33
- message?: string;
34
- }>;
35
- defaultConversation(config: ExternalChannelConfig): Promise<{
36
- conversationId: string;
37
- conversationName?: string;
38
- }>;
39
- private ensureConnection;
40
- private readSecret;
41
- private openConnection;
42
- private scheduleReconnect;
43
- private sendJson;
44
- private sendAwaitAck;
45
- private handlePayload;
46
- private buildVisibleText;
47
- private batchMessageKey;
48
- private hasSeenBatchMessage;
49
- private rememberBatchMessage;
50
- private normalizeAttachments;
51
- private formatAttachment;
52
- private formatMessageTime;
53
- private isDuplicate;
54
- private parsePayload;
55
- }
@@ -1,8 +0,0 @@
1
- import{randomUUID as w}from"node:crypto";import u from"ws";import{ChannelSecretRegistry as S}from"./secret-registry.js";const l=[2e3,5e3,1e4,3e4],y=3e4,k=15e3;class M{onMessage;type="websocket";secrets=new S;connections=new Map;constructor(e){this.onMessage=e}async connect(e){if(!e.enabled)return;const t=this.ensureConnection(e);return t.connecting||(t.stopped=!1,t.config=e,t.connecting=this.openConnection(t).finally(()=>{t.connecting=null})),t.connecting}async disconnect(e){const t=this.connections.get(e.id);if(!t)return;t.stopped=!0,t.reconnectTimer&&clearTimeout(t.reconnectTimer),t.pingTimer&&clearInterval(t.pingTimer),t.reconnectTimer=null,t.pingTimer=null;for(const n of t.pendingAcks.values())clearTimeout(n.timer),n.reject(new Error("External websocket adapter disconnected"));t.pendingAcks.clear();const s=t.socket;t.socket=null,s&&await new Promise(n=>{s.once("close",()=>n()),s.close(),setTimeout(n,500)}),this.connections.delete(e.id)}async send(e,t){const s=this.ensureConnection(e);if(this.readSecret(e).canReply===!1)throw new Error("External websocket channel does not allow replies");await this.connect(e);const r=t.idempotencyKey||`send_${w()}`;await this.sendAwaitAck(s,r,{type:"message.send",requestId:r,conversationId:t.conversationId,contentType:"text",text:t.text,replyToMessageId:t.messageId??void 0})}async health(e){const t=this.readSecret(e);return!t.wsUrl||!t.token?{ok:!1,message:"External websocket requires local wsUrl and token"}:this.connections.get(e.id)?.socket?.readyState===u.OPEN?{ok:!0}:{ok:!1,message:"External websocket disconnected"}}async defaultConversation(e){const t=this.readSecret(e),s=new URL(t.wsUrl);s.protocol=s.protocol==="wss:"?"https:":"http:",s.pathname=s.pathname.replace(/\/ws\/?$/,"/subscription/self"),s.search="";const n=await fetch(s,{headers:{Authorization:`Bearer ${t.token}`}}),r=await n.json().catch(()=>null);if(!n.ok||!r?.ok)throw new Error(r?.error||`External websocket metadata failed: ${n.status}`);if(r.subscription?.allowSend===!1)throw new Error("External websocket subscription does not allow send");const o=String(r.subscription?.defaultConversationId||"").trim();if(!o)throw new Error("External websocket subscription has no single default conversation");return{conversationId:o,conversationName:String(r.subscription?.defaultConversationName||"").trim()||void 0}}ensureConnection(e){let t=this.connections.get(e.id);return t||(t={config:e,socket:null,connecting:null,stopped:!1,reconnectAttempt:0,reconnectTimer:null,pingTimer:null,dedup:new Set,dedupQueue:[],seenBatchMessageKeys:new Set,seenBatchMessageQueue:[],pendingAcks:new Map},this.connections.set(e.id,t)),t.config=e,t}readSecret(e){const t=this.secrets.get(e.secretRef);if(!t||t.type!=="websocket"||!t.wsUrl||!t.token)throw new Error("External websocket channel is not configured on this daemon");return t}async openConnection(e){const t=this.readSecret(e.config),s=t.wsUrl,n=new u(s,{headers:{Authorization:`Bearer ${t.token}`}});e.socket=n,await new Promise((r,o)=>{const i=()=>{n.off("open",c),n.off("error",a)},c=()=>{i(),r()},a=d=>{i(),o(d)};n.once("open",c),n.once("error",a)}),n.on("message",r=>{const o=this.parsePayload(r.toString());o&&this.handlePayload(e,o)}),n.on("close",()=>this.scheduleReconnect(e)),n.on("error",()=>this.scheduleReconnect(e)),e.reconnectAttempt=0,e.pingTimer&&clearInterval(e.pingTimer),e.pingTimer=setInterval(()=>{this.sendJson(e,{type:"ping",timestamp:new Date().toISOString()}).catch(()=>{})},y),e.pingTimer.unref()}scheduleReconnect(e){if(e.stopped||e.reconnectTimer||e.connecting)return;const t=l[Math.min(e.reconnectAttempt,l.length-1)];e.reconnectAttempt+=1,e.reconnectTimer=setTimeout(()=>{e.reconnectTimer=null,this.connect(e.config).catch(()=>{})},t),e.reconnectTimer.unref()}async sendJson(e,t){if(!e.socket||e.socket.readyState!==u.OPEN)throw new Error("External websocket is not connected");e.socket.send(JSON.stringify(t))}async sendAwaitAck(e,t,s){await new Promise((n,r)=>{const o=setTimeout(()=>{e.pendingAcks.delete(t),r(new Error("External websocket send timed out"))},k);o.unref(),e.pendingAcks.set(t,{resolve:n,reject:r,timer:o}),this.sendJson(e,s).catch(i=>{clearTimeout(o),e.pendingAcks.delete(t),r(i instanceof Error?i:new Error(String(i)))})})}handlePayload(e,t){const s=String(t.type||"");if(s==="ack"||s==="error"){const c=String(t.requestId||""),a=c?e.pendingAcks.get(c):void 0;if(!a)return;clearTimeout(a.timer),e.pendingAcks.delete(c),s==="ack"&&t.ok!==!1?a.resolve():a.reject(new Error(String(t.error||"External websocket send failed")));return}if(s==="hello"||s==="pong"||s!=="message.inbound"&&s!=="message.inbound.batch")return;const n=String(t.messageId||t.batchId||t.id||"");if(!n||this.isDuplicate(e,n))return;const r=this.normalizeAttachments(t),o=this.buildVisibleText(e,t,r),i=String(t.conversationId||"").trim();Array.isArray(t.messages)&&!o||!o&&r.length===0||!i||this.onMessage?.({managerSessionId:e.config.managerSessionId,channelId:e.config.id,channelType:"websocket",conversationId:i,messageId:n,sender:{id:String(t.senderId||"unknown"),name:typeof t.senderName=="string"?t.senderName:null},text:o,attachments:r,receivedAt:typeof t.endedAt=="string"?t.endedAt:new Date().toISOString(),replyTarget:""})}buildVisibleText(e,t,s){const n=String(t.text||"").trim();return n||(Array.isArray(t.messages)?t.messages.map((r,o)=>{if(!r||typeof r!="object")return"";const i=r,c=this.batchMessageKey(i,t);if(c&&this.hasSeenBatchMessage(e,c))return"";const a=String(i.conversationType||t.conversationType||"")==="group",d=String(i.senderName||(a?"\u7FA4\u53CB":i.senderExternalId||i.senderId||"unknown")),m=this.formatMessageTime(i.timestampIso||i.timestamp),h=String(i.text||"").trim(),g=this.normalizeAttachments(i).map(f=>this.formatAttachment(f)).join(" "),p=[h,g].filter(Boolean).join(" ").trim()||`[${String(i.contentType||"message")}]`;return c&&this.rememberBatchMessage(e,c),`${o+1}. ${m} ${d}: ${p}`}).filter(Boolean).join(`
2
- `).trim():s.map(r=>this.formatAttachment(r)).join(`
3
- `))}batchMessageKey(e,t){const s=String(e.messageId||e.msgid||e.id||e.rawId||"").trim();if(s)return`id:${s}`;const n=String(e.senderExternalId||e.senderId||e.senderName||"").trim(),r=String(e.timestampIso||e.timestamp||e.receivedAt||"").trim(),o=String(e.text||"").trim(),i=String(e.contentType||"").trim(),c=String(e.conversationId||t.conversationId||"").trim(),a=this.normalizeAttachments(e).map(d=>[d.type,d.name||"",d.url||"",d.size??""].join(":")).join("|");return`content:${c}
4
- ${n}
5
- ${r}
6
- ${i}
7
- ${o}
8
- ${a}`}hasSeenBatchMessage(e,t){return e.seenBatchMessageKeys.has(t)}rememberBatchMessage(e,t){if(!e.seenBatchMessageKeys.has(t))for(e.seenBatchMessageKeys.add(t),e.seenBatchMessageQueue.push(t);e.seenBatchMessageQueue.length>2e3;){const s=e.seenBatchMessageQueue.shift();s&&e.seenBatchMessageKeys.delete(s)}}normalizeAttachments(e){const t=Array.isArray(e.attachments)?e.attachments:[],s=Array.isArray(e.messages)?e.messages.flatMap(n=>{if(!n||typeof n!="object")return[];const r=n;return Array.isArray(r.attachments)?r.attachments:[]}):[];return[...t,...s].filter(n=>!!n&&typeof n=="object").map(n=>({type:String(n.type||"file"),name:typeof n.name=="string"?n.name:void 0,url:typeof n.url=="string"?n.url:void 0,mimeType:typeof n.mimeType=="string"?n.mimeType:void 0,size:typeof n.size=="number"?n.size:void 0}))}formatAttachment(e){const t=e.name?`${e.type}: ${e.name}`:e.type;return e.url?`[${t} ${e.url}]`:`[${t}]`}formatMessageTime(e){const t=typeof e=="number"?new Date(e<1e10?e*1e3:e):new Date(String(e||""));return Number.isNaN(t.getTime())?String(e||""):new Intl.DateTimeFormat("zh-CN",{timeZone:"Asia/Shanghai",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1}).format(t).replace(/\//g,"-")}isDuplicate(e,t){if(e.dedup.has(t))return!0;if(e.dedup.add(t),e.dedupQueue.push(t),e.dedupQueue.length>1e3){const s=e.dedupQueue.shift();s&&e.dedup.delete(s)}return!1}parsePayload(e){try{const t=JSON.parse(e);return t&&typeof t=="object"?t:null}catch{return null}}}export{M as ExternalWebSocketChannelAdapter};
@@ -1,10 +0,0 @@
1
- import type { WeChatChannelObservedMessage } from './client.js';
2
- export declare function normalizeWeChatAnchorText(value: unknown): string;
3
- export declare function weChatAnchorText(message: WeChatChannelObservedMessage): string;
4
- export declare function weChatTextSimilarity(left: unknown, right: unknown): number;
5
- export declare function isLikelySameWeChatMessage(previous: WeChatChannelObservedMessage, current: WeChatChannelObservedMessage, threshold?: number): boolean;
6
- export declare function filterNewWeChatMessagesByAnchor(input: {
7
- previous: WeChatChannelObservedMessage[];
8
- current: WeChatChannelObservedMessage[];
9
- threshold?: number;
10
- }): WeChatChannelObservedMessage[];
@@ -1 +0,0 @@
1
- function i(e){return typeof e!="string"?"":e.normalize("NFKC").replace(/\s+/g," ").trim().toLowerCase()}function a(e){return i(e.anchorText||e.normalizedText||e.textExcerpt||"")}function l(e,t){const o=i(e),r=i(t);return!o||!r?0:o===r?1:1-f(o,r)/Math.max(o.length,r.length)}function h(e,t,o=.95){if(e.stableMessageKey&&e.stableMessageKey===t.stableMessageKey)return!0;if(e.senderRole!==t.senderRole||e.kind!==t.kind)return!1;const r=a(e),s=a(t);return!r||!s?!1:l(r,s)>=o}function u(e){const t=new Set,o=[];for(const r of e.current){const s=e.previous.findIndex((n,c)=>!t.has(c)&&h(n,r,e.threshold));if(s>=0){t.add(s);continue}o.push(r)}return o}function f(e,t){const o=Array.from({length:t.length+1},(s,n)=>n),r=Array.from({length:t.length+1},()=>0);for(let s=1;s<=e.length;s+=1){r[0]=s;for(let n=1;n<=t.length;n+=1)r[n]=Math.min(o[n]+1,r[n-1]+1,o[n-1]+(e[s-1]===t[n-1]?0:1));for(let n=0;n<=t.length;n+=1)o[n]=r[n]}return o[t.length]}export{u as filterNewWeChatMessagesByAnchor,h as isLikelySameWeChatMessage,i as normalizeWeChatAnchorText,a as weChatAnchorText,l as weChatTextSimilarity};
@@ -1,35 +0,0 @@
1
- export type WeChatAutomationLaneRunOptions = {
2
- waitMs?: number;
3
- };
4
- export type WeChatAutomationLane = {
5
- run<T>(label: string, operation: () => Promise<T>, options?: WeChatAutomationLaneRunOptions): Promise<T>;
6
- snapshot(): WeChatAutomationLaneSnapshot;
7
- };
8
- export type WeChatAutomationLaneSnapshot = {
9
- active: boolean;
10
- queued: number;
11
- lastLabel: string | null;
12
- lockPath?: string;
13
- };
14
- export type WeChatAutomationLaneOptions = {
15
- lockPath?: string;
16
- staleMs?: number;
17
- owner?: string;
18
- defaultWaitMs?: number;
19
- };
20
- export declare class SerialWeChatAutomationLane implements WeChatAutomationLane {
21
- private tail;
22
- private active;
23
- private queued;
24
- private lastLabel;
25
- private readonly lockPath?;
26
- private readonly staleMs;
27
- private readonly owner;
28
- private readonly defaultWaitMs;
29
- constructor(options?: WeChatAutomationLaneOptions);
30
- run<T>(label: string, operation: () => Promise<T>, options?: WeChatAutomationLaneRunOptions): Promise<T>;
31
- snapshot(): WeChatAutomationLaneSnapshot;
32
- private acquireLockWithWait;
33
- }
34
- export declare function createWeChatAutomationLane(options?: WeChatAutomationLaneOptions): WeChatAutomationLane;
35
- export declare function defaultWeChatAutomationLockPath(): string;
@@ -1,2 +0,0 @@
1
- import{AsyncLocalStorage as L}from"node:async_hooks";import i from"node:fs";import m from"node:os";import u from"node:path";import{resolveShennianPath as P}from"../../config/index.js";const h=new L,w=900*1e3,p=3e4,y=100,A=1e3;class M{tail=Promise.resolve();active=!1;queued=0;lastLabel=null;lockPath;staleMs;owner;defaultWaitMs;constructor(t={}){this.lockPath=t.lockPath,this.staleMs=t.staleMs??w,this.owner=t.owner??`${process.platform}:${process.pid}`,this.defaultWaitMs=t.defaultWaitMs??p}async run(t,a,r={}){if(this.lockPath&&h.getStore()?.has(this.lockPath))return this.lastLabel=t,a();const n=Math.max(0,r.waitMs??this.defaultWaitMs);this.queued+=1;const o=this.tail;let s;this.tail=new Promise(l=>{s=l}),await o.catch(()=>{}),this.queued-=1,this.active=!0,this.lastLabel=t;const c=Date.now()+n;let f=null;try{if(f=await this.acquireLockWithWait(t,c),!this.lockPath)return await a();const l=h.getStore(),d=new Set(l??[]);return d.add(this.lockPath),await h.run(d,a)}finally{f?.release(),this.active=!1,s()}}snapshot(){return{active:this.active,queued:this.queued,lastLabel:this.lastLabel,lockPath:this.lockPath}}async acquireLockWithWait(t,a){if(!this.lockPath)return null;i.mkdirSync(u.dirname(this.lockPath),{recursive:!0});let r=y,n=null;for(;;)try{return i.mkdirSync(this.lockPath),O(this.lockPath,{pid:process.pid,label:t,owner:this.owner,hostname:m.hostname(),startedAt:new Date().toISOString()}),{release:()=>{i.rmSync(this.lockPath,{recursive:!0,force:!0})}}}catch(o){if(!b(o))throw o;const s=W(this.lockPath);if(n=s,v(this.lockPath,s,this.staleMs)){i.rmSync(this.lockPath,{recursive:!0,force:!0});continue}const c=a-Date.now();if(c<=0)throw new Error(T(this.lockPath,n));await _(Math.min(r,c)),r=Math.min(r*2,A)}}}function j(e={}){return new M({lockPath:S(),...e})}function S(){return P("runtime","wechat-automation.lock")}function _(e){return new Promise(t=>setTimeout(t,e))}function O(e,t){i.writeFileSync(u.join(e,"owner.json"),`${JSON.stringify(t,null,2)}
2
- `,"utf8")}function W(e){try{const t=JSON.parse(i.readFileSync(u.join(e,"owner.json"),"utf8"));return t&&typeof t=="object"?t:null}catch{return null}}function v(e,t,a){if(t?.pid&&k(t.pid))return!1;if(t?.pid&&E(t)&&!k(t.pid))return!0;try{return Date.now()-i.statSync(e).mtimeMs>a}catch{return!0}}function E(e){return e?.hostname?e.hostname===m.hostname():!1}function k(e){if(!Number.isInteger(e)||e<=0)return!1;try{return process.kill(e,0),!0}catch{return!1}}function T(e,t){return`wechat_automation_busy: another WeChat automation run is active (${[`lock=${e}`,t?.pid?`pid=${t.pid}`:"",t?.label?`label=${t.label}`:"",t?.startedAt?`startedAt=${t.startedAt}`:"",t?.owner?`owner=${t.owner}`:""].filter(Boolean).join(" ")})`}function b(e){return typeof e=="object"&&e!==null&&"code"in e&&e.code==="EEXIST"}export{M as SerialWeChatAutomationLane,j as createWeChatAutomationLane,S as defaultWeChatAutomationLockPath};
@@ -1,283 +0,0 @@
1
- import type { WeChatChannelRuntime, WeChatChannelBindingConfig } from './runtime.js';
2
- export type WeChatChannelApiClientOptions = {
3
- serverUrl?: string;
4
- machineToken?: string;
5
- fetchImpl?: typeof fetch;
6
- };
7
- export type WeChatChannelObservedMessage = {
8
- stableMessageKey: string;
9
- senderRole: 'self' | 'contact' | 'system' | 'unknown';
10
- senderName?: string | null;
11
- kind: string;
12
- normalizedText?: string | null;
13
- anchorText?: string | null;
14
- anchorMetadata?: unknown;
15
- neighborContext?: unknown;
16
- textExcerpt?: string | null;
17
- bbox?: unknown;
18
- mediaMetadata?: unknown;
19
- isBaseline?: boolean;
20
- deliveryStatus?: string;
21
- observedAt?: string;
22
- visualBlocks?: WeChatChannelVisualBlock[];
23
- };
24
- export type WeChatChannelStructuredMessageCandidate = Omit<WeChatChannelObservedMessage, 'stableMessageKey'> & {
25
- stableMessageKey?: string;
26
- };
27
- export type WeChatChannelVisualBlock = {
28
- stableMessageKey?: string;
29
- blockId: string;
30
- blockKind: string;
31
- bbox?: unknown;
32
- model?: string;
33
- modelVersion?: string | null;
34
- dims?: number;
35
- vectorBase64?: string;
36
- vectorStoreKey?: string;
37
- signature?: string;
38
- };
39
- export type WeChatChannelEmbedVisualInput = {
40
- screenshots?: Array<{
41
- captureIndex?: number;
42
- mimeType: string;
43
- dataBase64: string;
44
- width: number;
45
- height: number;
46
- }>;
47
- visualBlocks: Array<{
48
- stableMessageKey?: string;
49
- blockId?: string;
50
- blockKind?: string;
51
- bbox?: unknown;
52
- mimeType?: string;
53
- dataBase64?: string;
54
- width?: number;
55
- height?: number;
56
- }>;
57
- traceId?: string;
58
- };
59
- export type WeChatChannelEmbedVisualResponse = {
60
- ok: true;
61
- visualBlocks?: WeChatChannelVisualBlock[];
62
- embeddedBlocks?: WeChatChannelVisualBlock[];
63
- reasonCode?: string;
64
- modelVersion?: string | null;
65
- dims?: number | null;
66
- usage?: unknown;
67
- usageRefId?: string;
68
- latencyMs?: number | null;
69
- };
70
- export type WeChatChannelClassifyWindowInput = {
71
- screenshot: {
72
- mimeType: string;
73
- dataBase64: string;
74
- width: number;
75
- height: number;
76
- windowId?: string | null;
77
- };
78
- traceId?: string;
79
- };
80
- export type WeChatChannelClassifyWindowResponse = {
81
- ok: true;
82
- status?: string;
83
- windowKind?: 'chat_main' | 'article' | 'settings' | 'login' | 'other';
84
- conversationTitle?: string | null;
85
- isTargetConversation?: boolean;
86
- confidence?: number;
87
- layout?: {
88
- messageInputRect?: {
89
- x?: number;
90
- y?: number;
91
- width?: number;
92
- height?: number;
93
- coordinateSpace?: string;
94
- } | null;
95
- searchInputRect?: {
96
- x?: number;
97
- y?: number;
98
- width?: number;
99
- height?: number;
100
- coordinateSpace?: string;
101
- } | null;
102
- } | null;
103
- reasonCode?: string;
104
- warnings?: string[];
105
- usageRefId?: string;
106
- latencyMs?: number | null;
107
- modelVersion?: string | null;
108
- };
109
- export type WeChatChannelApiClient = ReturnType<typeof createWeChatChannelApiClient>;
110
- export declare class WeChatChannelApiError extends Error {
111
- readonly reasonCode: string;
112
- readonly statusCode: number;
113
- readonly details?: unknown | undefined;
114
- constructor(message: string, reasonCode: string, statusCode: number, details?: unknown | undefined);
115
- }
116
- export type WeChatChannelObserveInput = {
117
- screenshots: Array<{
118
- captureIndex?: number;
119
- mimeType: string;
120
- dataBase64: string;
121
- width: number;
122
- height: number;
123
- }>;
124
- edgeOcrBlocks?: unknown[];
125
- visibleConversationFingerprints?: unknown[];
126
- localLedgerTailAnchors?: unknown[];
127
- traceId?: string;
128
- };
129
- export type WeChatChannelObserveResponse = {
130
- ok: true;
131
- observedMessages?: WeChatChannelObservedMessage[];
132
- diff?: unknown;
133
- reasonCode?: string;
134
- usageRefId?: string;
135
- };
136
- export type WeChatChannelStructureWindowInput = WeChatChannelObserveInput;
137
- export type WeChatChannelStructureWindowResponse = {
138
- ok: true;
139
- structuredMessages?: WeChatChannelStructuredMessageCandidate[];
140
- observedMessages?: WeChatChannelStructuredMessageCandidate[];
141
- mediaCandidates?: unknown[];
142
- reasonCode?: string;
143
- usageRefId?: string;
144
- schemaVersion?: number;
145
- };
146
- export type WeChatChannelRuntimePolicyResponse = {
147
- ok: true;
148
- feature?: {
149
- enabled?: boolean;
150
- reasonCode?: string | null;
151
- edgeRuntime?: {
152
- enabled?: boolean;
153
- reasonCode?: string | null;
154
- minClientRuntimeVersion?: number;
155
- };
156
- };
157
- serverDecision?: {
158
- required?: boolean;
159
- available?: boolean;
160
- edgeRuntimeAvailable?: boolean;
161
- };
162
- runtime?: {
163
- defaultPollIntervalSeconds?: number;
164
- minPollIntervalSeconds?: number;
165
- maxPollIntervalSeconds?: number;
166
- current?: {
167
- id?: string;
168
- status?: string | null;
169
- pollIntervalSeconds?: number | null;
170
- foregroundPolicy?: string | null;
171
- } | null;
172
- scanPolicy?: {
173
- plan?: 'free' | 'pro' | 'team';
174
- defaultPollIntervalSeconds?: number;
175
- minPollIntervalSeconds?: number;
176
- maxPollIntervalSeconds?: number;
177
- highFrequencyAvailable?: boolean;
178
- reasonCode?: string | null;
179
- };
180
- };
181
- usagePolicy?: {
182
- scanPolicy?: {
183
- plan?: 'free' | 'pro' | 'team';
184
- defaultPollIntervalSeconds?: number;
185
- minPollIntervalSeconds?: number;
186
- maxPollIntervalSeconds?: number;
187
- highFrequencyAvailable?: boolean;
188
- reasonCode?: string | null;
189
- };
190
- };
191
- };
192
- export type WeChatChannelBindingResponse = {
193
- ok: true;
194
- binding: {
195
- id: string;
196
- runtimeId?: string | null;
197
- machineId: string;
198
- sessionId: string;
199
- conversationName: string;
200
- enabled: boolean;
201
- allowReply?: boolean;
202
- downloadMedia?: boolean;
203
- updatedAt?: string | null;
204
- } | null;
205
- };
206
- export type WeChatChannelBindingsResponse = {
207
- ok: true;
208
- machineId: string;
209
- bindings: Array<{
210
- id: string;
211
- runtimeId?: string | null;
212
- machineId: string;
213
- sessionId: string;
214
- conversationName: string;
215
- enabled: boolean;
216
- allowReply?: boolean;
217
- downloadMedia?: boolean;
218
- updatedAt?: string | null;
219
- sessionTitle?: string | null;
220
- sessionWorkDir?: string | null;
221
- sessionAgentType?: string | null;
222
- sessionAgentSessionId?: string | null;
223
- sessionModelId?: string | null;
224
- }>;
225
- };
226
- export type WeChatChannelOutboundStatusInput = {
227
- replyId: string;
228
- idempotencyKey: string;
229
- status: string;
230
- replyBaseRevision?: number;
231
- sentAt?: string;
232
- confirmedAt?: string;
233
- failureCode?: string;
234
- lastErrorSummary?: string;
235
- nextAttemptAt?: string;
236
- attemptCount?: number;
237
- commitStage?: string;
238
- copyableContentRef?: string;
239
- copyableText?: string;
240
- agentVisible?: boolean;
241
- };
242
- export type WeChatChannelRunStatusInput = {
243
- status: string;
244
- reasonCode?: string;
245
- traceId?: string;
246
- lastErrorSummary?: string;
247
- preflight?: {
248
- checkedAt?: string;
249
- screenRecording?: boolean | 'granted' | 'denied' | 'restricted' | 'unknown' | 'not_determined';
250
- accessibility?: boolean | 'granted' | 'denied' | 'restricted' | 'unknown' | 'not_determined';
251
- inputMonitoring?: boolean | 'granted' | 'denied' | 'restricted' | 'unknown' | 'not_determined';
252
- automation?: boolean | 'granted' | 'denied' | 'restricted' | 'unknown' | 'not_determined';
253
- wechatRunning?: boolean;
254
- wechatAppDetected?: boolean;
255
- helperReady?: boolean;
256
- };
257
- };
258
- export type WeChatChannelRuntimePreflightInput = WeChatChannelRunStatusInput['preflight'];
259
- export declare function createWeChatChannelApiClient(options?: WeChatChannelApiClientOptions): {
260
- getRuntimePolicy: () => Promise<WeChatChannelRuntimePolicyResponse>;
261
- getBinding: (input: {
262
- machineId?: string | null;
263
- sessionId: string;
264
- }) => Promise<WeChatChannelBindingResponse>;
265
- listBindings: (input?: {
266
- machineId?: string | null;
267
- }) => Promise<WeChatChannelBindingsResponse>;
268
- upsertRuntime: (runtime: WeChatChannelRuntime, binding?: WeChatChannelBindingConfig, input?: {
269
- preflight?: WeChatChannelRuntimePreflightInput;
270
- helperVersion?: string;
271
- clientRuntimeVersion?: string;
272
- }) => Promise<unknown>;
273
- observe: (runtime: WeChatChannelRuntime, binding: WeChatChannelBindingConfig, input: WeChatChannelObserveInput) => Promise<WeChatChannelObserveResponse>;
274
- structureWindow: (runtime: WeChatChannelRuntime, binding: WeChatChannelBindingConfig, input: WeChatChannelStructureWindowInput) => Promise<WeChatChannelStructureWindowResponse>;
275
- embedVisual: (runtime: WeChatChannelRuntime, binding: WeChatChannelBindingConfig, input: WeChatChannelEmbedVisualInput) => Promise<WeChatChannelEmbedVisualResponse>;
276
- classifyWindow: (runtime: WeChatChannelRuntime, binding: WeChatChannelBindingConfig, input: WeChatChannelClassifyWindowInput) => Promise<WeChatChannelClassifyWindowResponse>;
277
- ingest: (runtime: WeChatChannelRuntime, binding: WeChatChannelBindingConfig, input: {
278
- idempotencyKey: string;
279
- messages: WeChatChannelObservedMessage[];
280
- }) => Promise<unknown>;
281
- reportOutboundStatus: (runtime: WeChatChannelRuntime, binding: WeChatChannelBindingConfig, input: WeChatChannelOutboundStatusInput) => Promise<unknown>;
282
- reportRunStatus: (runtime: WeChatChannelRuntime, binding: WeChatChannelBindingConfig, input: WeChatChannelRunStatusInput) => Promise<unknown>;
283
- };
@@ -1 +0,0 @@
1
- import{SERVERS as f}from"../../region.js";import{loadConfig as y}from"../../config/index.js";class h extends Error{reasonCode;statusCode;details;constructor(o,d,c,I){super(o),this.reasonCode=d,this.statusCode=c,this.details=I,this.name="WeChatChannelApiError"}}function A(r={}){const o=y(),d=v(r.serverUrl||o.serverUrl||f.cn.url),c=r.machineToken||o.machineToken,I=r.fetchImpl||fetch;if(!c)throw new Error("WeChat channel requires a paired machine token");async function t(s,n){const e=C(n);let a;try{a=await I(`${d}/api/channels/wechat${s}`,{method:n===void 0?"GET":"POST",headers:{authorization:`Bearer ${c}`,...n===void 0?{}:{"content-type":"application/json"},...e?{"x-trace-id":e}:{}},body:n===void 0?void 0:JSON.stringify(n)})}catch(i){const u=i instanceof Error?i.message:String(i||"network request failed");throw new h(`WeChat channel API ${s} network failed: ${u}`,"wechat_channel_network_failed",0,{path:s,traceId:e||null,cause:u})}const m=await a.text();let l=null;try{l=m?JSON.parse(m):null}catch{throw new h(`WeChat channel API ${s} returned invalid JSON`,"wechat_channel_invalid_response",a.status,{path:s,traceId:e||null,text:m.slice(0,200)})}if(!a.ok||l?.ok===!1){const i=w(l?.reasonCode)||a.statusText||"request_failed";throw new h(`WeChat channel API ${s} failed: ${i}`,i,a.status,{path:s,traceId:e||null,statusCode:a.status})}return l}return{getRuntimePolicy:()=>t("/runtime-policy"),getBinding:s=>{const n=new URLSearchParams;return s.machineId&&n.set("machineId",s.machineId),n.set("sessionId",s.sessionId),t(`/binding?${n}`)},listBindings:(s={})=>{const n=new URLSearchParams;s.machineId&&n.set("machineId",s.machineId);const e=n.toString()?`?${n}`:"";return t(`/bindings${e}`)},upsertRuntime:(s,n,e)=>t("/runtime",{runtimeId:s.runtimeId,machineId:s.machineId,pollIntervalSeconds:Math.round(s.policy.pollIntervalMs/1e3),foregroundPolicy:s.foregroundPolicy,clientRuntimeVersion:e?.clientRuntimeVersion??String(s.policy.runtimeVersion),helperVersion:e?.helperVersion,preflight:e?.preflight,...n?g(n):{}}),observe:(s,n,e)=>t("/observe",{runtimeId:s.runtimeId,bindingId:n.bindingId,sessionId:n.sessionId,machineId:s.machineId,conversationName:n.conversationDisplayName,schemaVersion:s.policy.runtimeVersion,screenshots:e.screenshots,edgeOcrBlocks:e.edgeOcrBlocks??[],visibleConversationFingerprints:e.visibleConversationFingerprints??[],localLedgerTailAnchors:e.localLedgerTailAnchors??[],traceId:e.traceId}),structureWindow:(s,n,e)=>t("/structure-window",{runtimeId:s.runtimeId,bindingId:n.bindingId,sessionId:n.sessionId,machineId:s.machineId,conversationName:n.conversationDisplayName,schemaVersion:s.policy.runtimeVersion,screenshots:e.screenshots,edgeOcrBlocks:e.edgeOcrBlocks??[],visibleConversationFingerprints:e.visibleConversationFingerprints??[],localLedgerTailAnchors:e.localLedgerTailAnchors??[],traceId:e.traceId}),embedVisual:(s,n,e)=>t("/embed-visual",{runtimeId:s.runtimeId,bindingId:n.bindingId,sessionId:n.sessionId,machineId:s.machineId,conversationName:n.conversationDisplayName,schemaVersion:s.policy.runtimeVersion,screenshots:e.screenshots??[],visualBlocks:e.visualBlocks,traceId:e.traceId}),classifyWindow:(s,n,e)=>t("/classify-window",{runtimeId:s.runtimeId,bindingId:n.bindingId,sessionId:n.sessionId,machineId:s.machineId,conversationName:n.conversationDisplayName,screenshot:e.screenshot,traceId:e.traceId}),ingest:(s,n,e)=>t("/ingest",{runtimeId:s.runtimeId,idempotencyKey:e.idempotencyKey,bindingId:n.bindingId,sessionId:n.sessionId,machineId:s.machineId,messages:e.messages}),reportOutboundStatus:(s,n,e)=>t("/outbound-status",{runtimeId:s.runtimeId,replyId:e.replyId,idempotencyKey:e.idempotencyKey,bindingId:n.bindingId,sessionId:n.sessionId,machineId:s.machineId,status:e.status,replyBaseRevision:e.replyBaseRevision,sentAt:e.sentAt,confirmedAt:e.confirmedAt,failureCode:e.failureCode,lastErrorSummary:e.lastErrorSummary,nextAttemptAt:e.nextAttemptAt,attemptCount:e.attemptCount,commitStage:e.commitStage,copyableContentRef:e.copyableContentRef,copyableText:e.copyableText,agentVisible:e.agentVisible}),reportRunStatus:(s,n,e)=>t("/run-status",{runtimeId:s.runtimeId,bindingId:n.bindingId,sessionId:n.sessionId,machineId:s.machineId,status:e.status,reasonCode:e.reasonCode,traceId:e.traceId,lastErrorSummary:e.lastErrorSummary,preflight:e.preflight})}}function g(r){return{bindingId:r.bindingId,sessionId:r.sessionId,conversationName:r.conversationDisplayName,enabled:r.enabled,allowReply:r.allowReply,downloadMedia:r.downloadMedia}}function v(r){return r.replace(/\/+$/,"")}function C(r){if(!r||typeof r!="object")return;const o=r.traceId;return(typeof o=="string"?o.trim():"")||void 0}function w(r){return typeof r=="string"?r.trim():""}export{h as WeChatChannelApiError,A as createWeChatChannelApiClient};
@@ -1,21 +0,0 @@
1
- export type WeChatChannelCooldownState = {
2
- consecutiveInterruptions: number;
3
- cooldownUntil?: string | null;
4
- manualReviewReason?: string | null;
5
- };
6
- export declare const WECHAT_CHANNEL_INTERRUPTION_COOLDOWN_THRESHOLD = 3;
7
- export declare const WECHAT_CHANNEL_INTERRUPTION_COOLDOWN_MS: number;
8
- export declare const WECHAT_CHANNEL_BILLING_PAUSE_MS: number;
9
- export declare function isWeChatChannelCooldownActive(state: WeChatChannelCooldownState | undefined, now?: Date): boolean;
10
- export declare function noteWeChatChannelInterruption(input: {
11
- state?: WeChatChannelCooldownState;
12
- reason?: string;
13
- now?: Date;
14
- }): WeChatChannelCooldownState;
15
- export declare function noteWeChatChannelStableRun(state?: WeChatChannelCooldownState): WeChatChannelCooldownState;
16
- export declare function clearExpiredWeChatChannelCooldown(state: WeChatChannelCooldownState, now?: Date): WeChatChannelCooldownState;
17
- export declare function noteWeChatChannelBillingPause(input: {
18
- state?: WeChatChannelCooldownState;
19
- reason?: string;
20
- now?: Date;
21
- }): WeChatChannelCooldownState;
@@ -1 +0,0 @@
1
- const r=3,u=3e5,a=18e5;function l(n,e=new Date){if(!n?.cooldownUntil)return!1;const o=new Date(n.cooldownUntil).getTime();return Number.isFinite(o)&&o>e.getTime()}function c(n){const e=n.now??new Date,o=n.state??{consecutiveInterruptions:0},i=o.consecutiveInterruptions+1,t={consecutiveInterruptions:i,cooldownUntil:o.cooldownUntil??null,manualReviewReason:o.manualReviewReason??null};return i>=3&&(t.cooldownUntil=new Date(e.getTime()+3e5).toISOString(),t.manualReviewReason=n.reason||"user_interruption_cooldown"),t}function s(n){return{consecutiveInterruptions:0,cooldownUntil:n?.cooldownUntil??null,manualReviewReason:n?.manualReviewReason??null}}function w(n,e=new Date){return l(n,e)?n:{...n,cooldownUntil:null}}function C(n){const e=n.now??new Date;return{consecutiveInterruptions:0,cooldownUntil:new Date(e.getTime()+18e5).toISOString(),manualReviewReason:n.reason||"insufficient_credits"}}export{a as WECHAT_CHANNEL_BILLING_PAUSE_MS,u as WECHAT_CHANNEL_INTERRUPTION_COOLDOWN_MS,r as WECHAT_CHANNEL_INTERRUPTION_COOLDOWN_THRESHOLD,w as clearExpiredWeChatChannelCooldown,l as isWeChatChannelCooldownActive,C as noteWeChatChannelBillingPause,c as noteWeChatChannelInterruption,s as noteWeChatChannelStableRun};
@@ -1,52 +0,0 @@
1
- import { type WeChatChannelMediaAction, type WeChatChannelMediaActionPlan, type WeChatChannelMediaCandidate, type WeChatChannelMessageKind, type WeChatChannelRect } from './schema.js';
2
- export type WeChatChannelFixtureNormalizedMessage = {
3
- index: number;
4
- senderRole: string;
5
- senderName: string | null;
6
- kind: WeChatChannelMessageKind;
7
- text: string;
8
- bbox?: WeChatChannelRect;
9
- mediaStatus: string;
10
- downloadActionBbox?: WeChatChannelRect | null;
11
- };
12
- export type WeChatChannelFixtureActionPlanProjection = {
13
- messageKey: string;
14
- kind: WeChatChannelMessageKind;
15
- reasonCode: string;
16
- actions: Array<Pick<WeChatChannelMediaAction, 'type' | 'target' | 'label' | 'reasonCode'>>;
17
- };
18
- export type WeChatChannelFixtureProjection = {
19
- normalizedMessages: WeChatChannelFixtureNormalizedMessage[];
20
- mediaCandidates: Array<WeChatChannelMediaCandidate & {
21
- index: number;
22
- }>;
23
- actionPlans: WeChatChannelFixtureActionPlanProjection[];
24
- };
25
- export type WeChatChannelFixtureProjectionDiff = {
26
- section: keyof WeChatChannelFixtureProjection;
27
- index: number;
28
- reasonCode: 'missing_left_item' | 'missing_right_item' | 'fixture_projection_mismatch';
29
- left?: unknown;
30
- right?: unknown;
31
- };
32
- export type WeChatChannelFixtureProjectionComparison = {
33
- ok: boolean;
34
- firstDiff?: WeChatChannelFixtureProjectionDiff;
35
- diffs: WeChatChannelFixtureProjectionDiff[];
36
- };
37
- export type WeChatChannelPlatformFixtureProjectionDiff = WeChatChannelFixtureProjectionDiff & {
38
- leftPlatform: string;
39
- rightPlatform: string;
40
- };
41
- export type WeChatChannelPlatformFixtureProjectionComparison = {
42
- ok: boolean;
43
- firstDiff?: WeChatChannelPlatformFixtureProjectionDiff;
44
- diffs: WeChatChannelPlatformFixtureProjectionDiff[];
45
- };
46
- export declare function projectWeChatChannelFixtureMessages(input: {
47
- messages: unknown[];
48
- messageKeyPrefix?: string;
49
- }): WeChatChannelFixtureProjection;
50
- export declare function compareWeChatChannelFixtureProjections(left: WeChatChannelFixtureProjection, right: WeChatChannelFixtureProjection): WeChatChannelFixtureProjectionComparison;
51
- export declare function compareWeChatChannelPlatformFixtureProjections(projections: Record<string, WeChatChannelFixtureProjection>): WeChatChannelPlatformFixtureProjectionComparison;
52
- export declare function projectActionPlan(plan: WeChatChannelMediaActionPlan): WeChatChannelFixtureActionPlanProjection;
@@ -1 +0,0 @@
1
- import{buildWeChatChannelMediaActionPlan as g}from"./media-action-plan.js";import{normalizeWeChatChannelMessageKind as p}from"./schema.js";const x=new Set(["image","file","video-file"]);function M(n){const t=n.messages.map((o,r)=>C(o,r)),e=t.filter(o=>x.has(o.kind)&&!!o.bbox).map(o=>y(o,n.messageKeyPrefix)).filter(o=>o!=null),i=e.map(o=>_(g(o))).filter(o=>o.actions.length>0);return{normalizedMessages:t,mediaCandidates:e,actionPlans:i}}function w(n,t){const e=[];for(const i of["normalizedMessages","mediaCandidates","actionPlans"]){const o=n[i],r=t[i],f=Math.max(o.length,r.length);for(let d=0;d<f;d+=1){const a=o[d],l=r[d];if(a==null||l==null){e.push({section:i,index:d,reasonCode:a==null?"missing_left_item":"missing_right_item",...a!=null?{left:a}:{},...l!=null?{right:l}:{}});continue}h(a)!==h(l)&&e.push({section:i,index:d,reasonCode:"fixture_projection_mismatch",left:a,right:l})}}return{ok:e.length===0,firstDiff:e[0],diffs:e}}function j(n){const t=Object.entries(n);if(t.length<=1)return{ok:!0,firstDiff:void 0,diffs:[]};const[e,i]=t[0],o=[];for(const[r,f]of t.slice(1)){const d=w(i,f);o.push(...d.diffs.map(a=>({...a,leftPlatform:e,rightPlatform:r})))}return{ok:o.length===0,firstDiff:o[0],diffs:o}}function _(n){return{messageKey:n.messageKey,kind:n.kind,reasonCode:n.reasonCode,actions:n.actions.map(t=>({type:t.type,...t.target?{target:t.target}:{},...t.label?{label:t.label}:{},...t.reasonCode?{reasonCode:t.reasonCode}:{}}))}}function C(n,t){const e=m(n)?n:{},i=p(e.kind??e.messageType??e.message_type??e.type),o=b(e.bbox??e.rect),r=b(e.downloadActionBbox??e.downloadActionBbox_2d??e.download_action_bbox??e.download_action_bbox_2d);return{index:c(e.index)??t,senderRole:s(e.senderRole)||"incoming",senderName:s(e.senderName)||null,kind:i,text:i==="text"?s(e.text).trim():s(e.text),...o?{bbox:o}:{},mediaStatus:A(e.mediaStatus??e.media_status??e.downloadStatus??e.download_status,i),...r?{downloadActionBbox:r}:{}}}function y(n,t){return n.bbox?{index:n.index,messageKey:t?`${t}:${n.index}`:String(n.index),kind:n.kind,bbox:n.bbox,downloadActionBbox:n.downloadActionBbox??null,mediaStatus:n.mediaStatus}:null}function A(n,t){if(!x.has(t))return"unknown";const e=s(n).toLowerCase().replace(/-/g,"_");return["downloaded","ready","available","loaded","\u5DF2\u4E0B\u8F7D"].includes(e)?"downloaded":["not_downloaded","undownloaded","needs_download","need_download","download_required","\u672A\u4E0B\u8F7D","\u5F85\u4E0B\u8F7D"].includes(e)?"not_downloaded":["loading","downloading","in_progress","\u4E0B\u8F7D\u4E2D"].includes(e)?"loading":"unknown"}function b(n){if(!m(n))return;const t=c(n.x),e=c(n.y),i=c(n.width),o=c(n.height);if(!(t==null||e==null||i==null||o==null))return{x:t,y:e,width:i,height:o,...s(n.coordinateSpace)?{coordinateSpace:s(n.coordinateSpace)}:{}}}function h(n){return JSON.stringify(u(n))}function u(n){return Array.isArray(n)?n.map(u):m(n)?Object.fromEntries(Object.keys(n).sort().map(t=>[t,u(n[t])])):n}function m(n){return!!n&&typeof n=="object"&&!Array.isArray(n)}function s(n){return typeof n=="string"?n.trim():""}function c(n){const t=Number(n);return Number.isFinite(t)?t:null}export{w as compareWeChatChannelFixtureProjections,j as compareWeChatChannelPlatformFixtureProjections,_ as projectActionPlan,M as projectWeChatChannelFixtureMessages};
@@ -1,3 +0,0 @@
1
- import { type WeChatChannelMediaActionPlan, type WeChatChannelMediaCandidate } from './schema.js';
2
- export declare function buildWeChatChannelMediaActionPlan(candidate: WeChatChannelMediaCandidate): WeChatChannelMediaActionPlan;
3
- export declare function shouldClickDownloadAffordance(candidate: WeChatChannelMediaCandidate): boolean;
@@ -1 +0,0 @@
1
- import{normalizeWeChatChannelMessageKind as a,normalizeWeChatChannelAttachmentAvailability as n}from"./schema.js";const r=new Set(["image","file","video-file"]),i=new Set(["video-card","link-card","official-account-card","mini-program-card"]);function m(e){const o=a(e.kind);if(!r.has(o))return{messageKey:e.messageKey,kind:o,actions:[],reasonCode:i.has(o)?"unsupported_share_card":"unsupported_media_kind"};if(!e.bbox)return{messageKey:e.messageKey,kind:o,actions:[],reasonCode:"media_bbox_missing"};const t=[...c(o,e.bbox),{type:"postprocess-file",reasonCode:"verify-local-attachment"}];return{messageKey:e.messageKey,kind:o,actions:t,reasonCode:"copy_clipboard_plan"}}function u(e){return e.downloadActionBbox?n(e.mediaStatus)==="pending-download"?!0:String(e.mediaStatus??"").trim().toLowerCase().replace(/-/g,"_")==="loading":!1}function s(e){return e==="image"?"\u590D\u5236\u56FE\u7247":e==="video-file"?"\u590D\u5236\u89C6\u9891":"\u590D\u5236\u6587\u4EF6"}function c(e,o,t=!1){return[{type:"right-click-media",target:o,reasonCode:t?`retry-open-${e}-context-menu-after-download`:`open-${e}-context-menu`},{type:"ocr-click-menu-item",label:s(e),reasonCode:t?`retry-copy-${e}-from-context-menu`:`copy-${e}-from-context-menu`},{type:"materialize-clipboard",reasonCode:t?"retry-materialize-system-clipboard-attachment":"materialize-system-clipboard-attachment"}]}export{m as buildWeChatChannelMediaActionPlan,u as shouldClickDownloadAffordance};