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.
- package/README.md +3 -1
- package/dist/publish-build-manifest.json +273 -343
- package/dist/src/agents/command-spec.js +2 -2
- package/dist/src/agents/detect.js +1 -1
- package/dist/src/agents/model-registry/discovery.js +2 -2
- package/dist/src/agents/model-registry/parsers.d.ts +1 -0
- package/dist/src/agents/model-registry/parsers.js +4 -4
- package/dist/src/agents/native-capabilities.d.ts +10 -0
- package/dist/src/agents/native-capabilities.js +1 -0
- package/dist/src/agents/platform-instructions.js +5 -5
- package/dist/src/agents/workbuddy.d.ts +44 -0
- package/dist/src/agents/workbuddy.js +3 -0
- package/dist/src/commands/daemon.d.ts +1 -0
- package/dist/src/commands/daemon.js +9 -9
- package/dist/src/commands/integration.d.ts +2 -0
- package/dist/src/commands/integration.js +1 -0
- package/dist/src/commands/manager.js +1 -2
- package/dist/src/commands/pair-browser.d.ts +43 -0
- package/dist/src/commands/pair-browser.js +1 -0
- package/dist/src/commands/pair.d.ts +2 -0
- package/dist/src/commands/pair.js +11 -8
- package/dist/src/commands/room.d.ts +13 -0
- package/dist/src/commands/room.js +4 -0
- package/dist/src/commands/upgrade.d.ts +3 -0
- package/dist/src/commands/upgrade.js +1 -1
- package/dist/src/config/index.d.ts +3 -1
- package/dist/src/config/index.js +2 -1
- package/dist/src/daemon-ipc/client.d.ts +8 -0
- package/dist/src/daemon-ipc/client.js +3 -0
- package/dist/src/daemon-ipc/paths.d.ts +7 -0
- package/dist/src/daemon-ipc/paths.js +1 -0
- package/dist/src/daemon-ipc/protocol.d.ts +30 -0
- package/dist/src/daemon-ipc/protocol.js +1 -0
- package/dist/src/daemon-ipc/secret.d.ts +3 -0
- package/dist/src/daemon-ipc/secret.js +3 -0
- package/dist/src/daemon-ipc/server.d.ts +13 -0
- package/dist/src/daemon-ipc/server.js +3 -0
- package/dist/src/index.js +2 -2
- package/dist/src/integrations/claude-room-plugin-lifecycle.d.ts +47 -0
- package/dist/src/integrations/claude-room-plugin-lifecycle.js +1 -0
- package/dist/src/integrations/codex-room-plugin-lifecycle.d.ts +49 -0
- package/dist/src/integrations/codex-room-plugin-lifecycle.js +1 -0
- package/dist/src/integrations/room-plugin-bundles.d.ts +23 -0
- package/dist/src/integrations/room-plugin-bundles.js +1 -0
- package/dist/src/integrations/room-plugin-lifecycle-common.d.ts +17 -0
- package/dist/src/integrations/room-plugin-lifecycle-common.js +1 -0
- package/dist/src/integrations/room-plugin-shared.d.ts +23 -0
- package/dist/src/integrations/room-plugin-shared.js +2 -0
- package/dist/src/integrations/room-session-hook.d.ts +30 -0
- package/dist/src/integrations/room-session-hook.js +2 -0
- package/dist/src/integrations/workbuddy-plugin-bundle.d.ts +15 -0
- package/dist/src/integrations/workbuddy-plugin-bundle.js +1 -0
- package/dist/src/integrations/workbuddy-plugin-lifecycle.d.ts +52 -0
- package/dist/src/integrations/workbuddy-plugin-lifecycle.js +2 -0
- package/dist/src/integrations/workbuddy-session-hook.d.ts +22 -0
- package/dist/src/integrations/workbuddy-session-hook.js +1 -0
- package/dist/src/manager/prompt.d.ts +1 -1
- package/dist/src/manager/prompt.js +1 -1
- package/dist/src/manager/retired-external-channel-compat.d.ts +78 -0
- package/dist/src/manager/retired-external-channel-compat.js +1 -0
- package/dist/src/manager/runtime.d.ts +1 -3
- package/dist/src/manager/runtime.js +7 -7
- package/dist/src/relay/client.d.ts +2 -0
- package/dist/src/relay/client.js +1 -1
- package/dist/src/room/activation-audit.d.ts +15 -0
- package/dist/src/room/activation-audit.js +2 -0
- package/dist/src/room/activation-policy.d.ts +8 -0
- package/dist/src/room/activation-policy.js +1 -0
- package/dist/src/room/activation-service.d.ts +25 -0
- package/dist/src/room/activation-service.js +2 -0
- package/dist/src/room/attachment-cache.d.ts +40 -0
- package/dist/src/room/attachment-cache.js +2 -0
- package/dist/src/room/attachment-upload.d.ts +20 -0
- package/dist/src/room/attachment-upload.js +1 -0
- package/dist/src/room/authorized-action-coordinator.d.ts +40 -0
- package/dist/src/room/authorized-action-coordinator.js +1 -0
- package/dist/src/room/authorized-action-ipc.d.ts +11 -0
- package/dist/src/room/authorized-action-ipc.js +1 -0
- package/dist/src/room/device-authorization-client.d.ts +49 -0
- package/dist/src/room/device-authorization-client.js +1 -0
- package/dist/src/room/host-session-observation-ipc.d.ts +9 -0
- package/dist/src/room/host-session-observation-ipc.js +1 -0
- package/dist/src/room/host-session-observations.d.ts +54 -0
- package/dist/src/room/host-session-observations.js +2 -0
- package/dist/src/room/invite-bootstrap.d.ts +35 -0
- package/dist/src/room/invite-bootstrap.js +1 -0
- package/dist/src/room/invocation-token-ipc.d.ts +9 -0
- package/dist/src/room/invocation-token-ipc.js +1 -0
- package/dist/src/room/invocation-token.d.ts +53 -0
- package/dist/src/room/invocation-token.js +1 -0
- package/dist/src/room/jsonl-mirror.d.ts +73 -0
- package/dist/src/room/jsonl-mirror.js +6 -0
- package/dist/src/room/managed-room-session.d.ts +143 -0
- package/dist/src/room/managed-room-session.js +3 -0
- package/dist/src/room/mirror-sync-service.d.ts +33 -0
- package/dist/src/room/mirror-sync-service.js +1 -0
- package/dist/src/room/operator-ipc.d.ts +11 -0
- package/dist/src/room/operator-ipc.js +1 -0
- package/dist/src/room/pending-authorized-actions.d.ts +69 -0
- package/dist/src/room/pending-authorized-actions.js +3 -0
- package/dist/src/room/room-action-client.d.ts +208 -0
- package/dist/src/room/room-action-client.js +1 -0
- package/dist/src/room/room-action-ipc.d.ts +33 -0
- package/dist/src/room/room-action-ipc.js +1 -0
- package/dist/src/room/room-action-schema.d.ts +3 -0
- package/dist/src/room/room-action-schema.js +1 -0
- package/dist/src/room/room-authorized-action-executor.d.ts +23 -0
- package/dist/src/room/room-authorized-action-executor.js +1 -0
- package/dist/src/room/room-binding-client.d.ts +51 -0
- package/dist/src/room/room-binding-client.js +1 -0
- package/dist/src/room/room-binding-ipc.d.ts +29 -0
- package/dist/src/room/room-binding-ipc.js +1 -0
- package/dist/src/room/session-registry-ipc.d.ts +14 -0
- package/dist/src/room/session-registry-ipc.js +1 -0
- package/dist/src/room/session-registry.d.ts +128 -0
- package/dist/src/room/session-registry.js +2 -0
- package/dist/src/room/tool-schema.d.ts +114 -0
- package/dist/src/room/tool-schema.js +1 -0
- package/dist/src/room/tool-server.d.ts +5 -0
- package/dist/src/room/tool-server.js +3 -0
- package/dist/src/session/handlers/agent-capabilities.d.ts +3 -0
- package/dist/src/session/handlers/agent-capabilities.js +1 -0
- package/dist/src/session/handlers/agent-config.js +1 -1
- package/dist/src/session/handlers/chat.js +2 -2
- package/dist/src/session/handlers/control.js +1 -1
- package/dist/src/session/handlers/fs.d.ts +1 -0
- package/dist/src/session/handlers/fs.js +1 -1
- package/dist/src/session/manager.d.ts +16 -6
- package/dist/src/session/manager.js +1 -1
- package/dist/src/session/types.d.ts +5 -0
- package/dist/src/upgrade/engine.d.ts +14 -1
- package/dist/src/upgrade/engine.js +2 -2
- package/dist/src/upgrade/scheduler.d.ts +45 -0
- package/dist/src/upgrade/scheduler.js +1 -0
- package/node_modules/@shennian/wire/dist/agent-capabilities.d.ts +17 -0
- package/node_modules/@shennian/wire/dist/agent-capabilities.d.ts.map +1 -0
- package/node_modules/@shennian/wire/dist/agent-capabilities.js +2 -0
- package/node_modules/@shennian/wire/dist/agent-capabilities.js.map +1 -0
- package/node_modules/@shennian/wire/dist/index.d.ts +2 -1
- package/node_modules/@shennian/wire/dist/index.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/index.js +2 -1
- package/node_modules/@shennian/wire/dist/index.js.map +1 -1
- package/node_modules/@shennian/wire/dist/machine.d.ts +1 -0
- package/node_modules/@shennian/wire/dist/machine.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/methods.d.ts +1 -1
- package/node_modules/@shennian/wire/dist/methods.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/room.d.ts +112 -0
- package/node_modules/@shennian/wire/dist/room.d.ts.map +1 -0
- package/node_modules/@shennian/wire/dist/room.js +4 -0
- package/node_modules/@shennian/wire/dist/room.js.map +1 -0
- package/node_modules/@shennian/wire/dist/session.d.ts +2 -2
- package/node_modules/@shennian/wire/dist/session.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/session.js +1 -1
- package/node_modules/@shennian/wire/dist/session.js.map +1 -1
- package/package.json +3 -5
- package/dist/scripts/wechat-rpa-confirmation.mjs +0 -5
- package/dist/src/agents/pi-context.d.ts +0 -42
- package/dist/src/agents/pi-context.js +0 -12
- package/dist/src/agents/pi.d.ts +0 -70
- package/dist/src/agents/pi.js +0 -17
- package/dist/src/channels/base.d.ts +0 -144
- package/dist/src/channels/base.js +0 -1
- package/dist/src/channels/registry.d.ts +0 -8
- package/dist/src/channels/registry.js +0 -1
- package/dist/src/channels/reply-split.d.ts +0 -1
- package/dist/src/channels/reply-split.js +0 -10
- package/dist/src/channels/runtime.d.ts +0 -138
- package/dist/src/channels/runtime.js +0 -5
- package/dist/src/channels/secret-registry.d.ts +0 -35
- package/dist/src/channels/secret-registry.js +0 -1
- package/dist/src/channels/websocket.d.ts +0 -55
- package/dist/src/channels/websocket.js +0 -8
- package/dist/src/channels/wechat-channel/anchor.d.ts +0 -10
- package/dist/src/channels/wechat-channel/anchor.js +0 -1
- package/dist/src/channels/wechat-channel/automation-lane.d.ts +0 -35
- package/dist/src/channels/wechat-channel/automation-lane.js +0 -2
- package/dist/src/channels/wechat-channel/client.d.ts +0 -283
- package/dist/src/channels/wechat-channel/client.js +0 -1
- package/dist/src/channels/wechat-channel/cooldown.d.ts +0 -21
- package/dist/src/channels/wechat-channel/cooldown.js +0 -1
- package/dist/src/channels/wechat-channel/core/fixture-compare.d.ts +0 -52
- package/dist/src/channels/wechat-channel/core/fixture-compare.js +0 -1
- package/dist/src/channels/wechat-channel/core/media-action-plan.d.ts +0 -3
- package/dist/src/channels/wechat-channel/core/media-action-plan.js +0 -1
- package/dist/src/channels/wechat-channel/core/schema.d.ts +0 -67
- package/dist/src/channels/wechat-channel/core/schema.js +0 -1
- package/dist/src/channels/wechat-channel/core/trace-comparator.d.ts +0 -28
- package/dist/src/channels/wechat-channel/core/trace-comparator.js +0 -1
- package/dist/src/channels/wechat-channel/fingerprint.d.ts +0 -31
- package/dist/src/channels/wechat-channel/fingerprint.js +0 -1
- package/dist/src/channels/wechat-channel/helper-assets.d.ts +0 -103
- package/dist/src/channels/wechat-channel/helper-assets.js +0 -1
- package/dist/src/channels/wechat-channel/helper-client.d.ts +0 -87
- package/dist/src/channels/wechat-channel/helper-client.js +0 -3
- package/dist/src/channels/wechat-channel/helper-protocol.d.ts +0 -122
- package/dist/src/channels/wechat-channel/helper-protocol.js +0 -1
- package/dist/src/channels/wechat-channel/human-coordination.d.ts +0 -25
- package/dist/src/channels/wechat-channel/human-coordination.js +0 -1
- package/dist/src/channels/wechat-channel/index.d.ts +0 -21
- package/dist/src/channels/wechat-channel/index.js +0 -1
- package/dist/src/channels/wechat-channel/ledger.d.ts +0 -48
- package/dist/src/channels/wechat-channel/ledger.js +0 -2
- package/dist/src/channels/wechat-channel/media-cache-resolver.d.ts +0 -42
- package/dist/src/channels/wechat-channel/media-cache-resolver.js +0 -1
- package/dist/src/channels/wechat-channel/media-resolver.d.ts +0 -186
- package/dist/src/channels/wechat-channel/media-resolver.js +0 -1
- package/dist/src/channels/wechat-channel/message-key.d.ts +0 -19
- package/dist/src/channels/wechat-channel/message-key.js +0 -1
- package/dist/src/channels/wechat-channel/observer.d.ts +0 -171
- package/dist/src/channels/wechat-channel/observer.js +0 -7
- package/dist/src/channels/wechat-channel/outbound-ledger.d.ts +0 -96
- package/dist/src/channels/wechat-channel/outbound-ledger.js +0 -2
- package/dist/src/channels/wechat-channel/outbound-sender.d.ts +0 -74
- package/dist/src/channels/wechat-channel/outbound-sender.js +0 -1
- package/dist/src/channels/wechat-channel/pacing.d.ts +0 -3
- package/dist/src/channels/wechat-channel/pacing.js +0 -1
- package/dist/src/channels/wechat-channel/preflight.d.ts +0 -46
- package/dist/src/channels/wechat-channel/preflight.js +0 -1
- package/dist/src/channels/wechat-channel/runner.d.ts +0 -43
- package/dist/src/channels/wechat-channel/runner.js +0 -1
- package/dist/src/channels/wechat-channel/runtime.d.ts +0 -50
- package/dist/src/channels/wechat-channel/runtime.js +0 -1
- package/dist/src/channels/wechat-channel/scheduler.d.ts +0 -74
- package/dist/src/channels/wechat-channel/scheduler.js +0 -1
- package/dist/src/channels/wechat-channel/vector-store.d.ts +0 -44
- package/dist/src/channels/wechat-channel/vector-store.js +0 -1
- package/dist/src/channels/wechat-rpa/macos-flow.d.ts +0 -55
- package/dist/src/channels/wechat-rpa/macos-flow.js +0 -1
- package/dist/src/channels/wechat-rpa/macos.d.ts +0 -11
- package/dist/src/channels/wechat-rpa/macos.js +0 -21
- package/dist/src/channels/wechat-rpa/normalizer.d.ts +0 -49
- package/dist/src/channels/wechat-rpa/normalizer.js +0 -7
- package/dist/src/channels/wechat-rpa/product-channel.d.ts +0 -76
- package/dist/src/channels/wechat-rpa/product-channel.js +0 -16
- package/dist/src/channels/wechat-rpa-session-sync.d.ts +0 -26
- package/dist/src/channels/wechat-rpa-session-sync.js +0 -1
- package/dist/src/channels/wechat-rpa.d.ts +0 -104
- package/dist/src/channels/wechat-rpa.js +0 -6
- package/dist/src/channels/wecom.d.ts +0 -51
- package/dist/src/channels/wecom.js +0 -4
- package/dist/src/commands/external-attachments.d.ts +0 -9
- package/dist/src/commands/external-attachments.js +0 -1
- package/dist/src/commands/external.d.ts +0 -2
- package/dist/src/commands/external.js +0 -1
- package/dist/src/commands/helper-runtime-official-download.d.ts +0 -80
- package/dist/src/commands/helper-runtime-official-download.js +0 -1
- package/dist/src/commands/runtime.d.ts +0 -120
- package/dist/src/commands/runtime.js +0 -1
- package/dist/src/commands/wechat/command.d.ts +0 -3
- package/dist/src/commands/wechat/command.js +0 -1
- package/dist/src/commands/wechat/direct.d.ts +0 -14
- package/dist/src/commands/wechat/direct.js +0 -2
- package/dist/src/commands/wechat/doctor.d.ts +0 -2
- package/dist/src/commands/wechat/doctor.js +0 -1
- package/dist/src/commands/wechat/ipc.d.ts +0 -9
- package/dist/src/commands/wechat/ipc.js +0 -1
- package/dist/src/commands/wechat/operations.d.ts +0 -3
- package/dist/src/commands/wechat/operations.js +0 -4
- package/dist/src/commands/wechat/output.d.ts +0 -7
- package/dist/src/commands/wechat/output.js +0 -4
- package/dist/src/commands/wechat/types.d.ts +0 -142
- package/dist/src/commands/wechat/types.js +0 -1
- package/dist/src/commands/wechat/utils.d.ts +0 -16
- package/dist/src/commands/wechat/utils.js +0 -1
- package/dist/src/commands/wechat.d.ts +0 -6
- package/dist/src/commands/wechat.js +0 -1
- package/dist/src/devtools/wechat-channel-action-smoke.d.ts +0 -105
- package/dist/src/devtools/wechat-channel-action-smoke.js +0 -10
- package/dist/src/devtools/wechat-channel-download-report.d.ts +0 -111
- package/dist/src/devtools/wechat-channel-download-report.js +0 -2
- package/dist/src/devtools/wechat-channel-markdown-report.d.ts +0 -6
- package/dist/src/devtools/wechat-channel-markdown-report.js +0 -5
- package/dist/src/devtools/wechat-channel-product-steps.d.ts +0 -9
- package/dist/src/devtools/wechat-channel-product-steps.js +0 -40
- package/dist/src/session/handlers/skills.d.ts +0 -7
- package/dist/src/session/handlers/skills.js +0 -1
- package/dist/src/session/handlers/wechat-helper-runtime.d.ts +0 -33
- package/dist/src/session/handlers/wechat-helper-runtime.js +0 -1
- package/dist/src/skills/registry.d.ts +0 -16
- package/dist/src/skills/registry.js +0 -15
- package/dist/src/skills/setup.d.ts +0 -11
- 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};
|