shennian 0.2.108 → 0.2.110
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/dist/publish-build-manifest.json +63 -58
- package/dist/src/agents/model-registry/discovery.js +2 -2
- package/dist/src/agents/pi-context.d.ts +1 -1
- package/dist/src/agents/pi-context.js +3 -3
- package/dist/src/channels/runtime.d.ts +2 -0
- package/dist/src/channels/runtime.js +1 -1
- package/dist/src/channels/secret-registry.d.ts +2 -0
- package/dist/src/channels/wechat-channel/automation-lane.d.ts +12 -0
- package/dist/src/channels/wechat-channel/automation-lane.js +2 -1
- package/dist/src/channels/wechat-channel/client.d.ts +25 -2
- package/dist/src/channels/wechat-channel/client.js +1 -1
- package/dist/src/channels/wechat-channel/helper-assets.d.ts +1 -1
- package/dist/src/channels/wechat-channel/helper-assets.js +1 -1
- package/dist/src/channels/wechat-channel/helper-client.d.ts +2 -0
- package/dist/src/channels/wechat-channel/helper-client.js +3 -3
- package/dist/src/channels/wechat-channel/helper-protocol.d.ts +1 -1
- package/dist/src/channels/wechat-channel/observer.d.ts +9 -1
- package/dist/src/channels/wechat-channel/observer.js +7 -6
- package/dist/src/channels/wechat-channel/outbound-sender.d.ts +8 -0
- package/dist/src/channels/wechat-channel/outbound-sender.js +1 -1
- package/dist/src/channels/wechat-channel/runner.js +1 -1
- package/dist/src/channels/wechat-channel/runtime.d.ts +1 -0
- package/dist/src/channels/wechat-channel/runtime.js +1 -1
- package/dist/src/channels/wechat-channel/scheduler.d.ts +1 -1
- package/dist/src/channels/wechat-channel/scheduler.js +1 -1
- package/dist/src/channels/wechat-rpa/product-channel.d.ts +1 -0
- package/dist/src/channels/wechat-rpa/product-channel.js +4 -4
- package/dist/src/channels/wechat-rpa.d.ts +2 -0
- package/dist/src/channels/wechat-rpa.js +2 -2
- package/dist/src/commands/helper-runtime-official-download.d.ts +80 -0
- package/dist/src/commands/helper-runtime-official-download.js +1 -0
- package/dist/src/commands/runtime.d.ts +24 -0
- package/dist/src/commands/runtime.js +1 -1
- package/dist/src/commands/wechat/command.d.ts +1 -0
- package/dist/src/commands/wechat/command.js +1 -1
- package/dist/src/commands/wechat/ipc.js +1 -1
- package/dist/src/commands/wechat/output.js +3 -3
- package/dist/src/commands/wechat.d.ts +1 -1
- package/dist/src/commands/wechat.js +1 -1
- package/dist/src/devtools/wechat-channel-action-smoke.d.ts +3 -1
- package/dist/src/devtools/wechat-channel-action-smoke.js +9 -9
- package/dist/src/index.js +2 -2
- package/dist/src/manager/runtime.js +10 -10
- package/dist/src/native-fusion/service.d.ts +0 -10
- package/dist/src/native-fusion/service.js +2 -2
- package/dist/src/session/handlers/chat.js +2 -2
- package/dist/src/session/handlers/session-refresh.js +1 -1
- package/dist/src/session/handlers/wechat-helper-runtime.d.ts +31 -0
- package/dist/src/session/handlers/wechat-helper-runtime.js +1 -0
- package/dist/src/session/manager.d.ts +4 -1
- package/dist/src/session/manager.js +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/package.json +1 -1
- package/dist/src/agents/codex-control.d.ts +0 -35
- package/dist/src/agents/codex-control.js +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import v from"node:fs";import S from"node:http";import P from"node:https";import k from"node:path";import{resolveShennianPath as g}from"../../config/index.js";import{weChatChannelConversationId as x}from"../../channels/wechat-rpa/product-channel.js";import{WeChatToolOperationError as w}from"./types.js";import{clampPositiveInteger as I,isAbortError as y,processExists as M,safePathSegment as T,stableId as E,stringValue as u}from"./utils.js";function p(){const r=g("runtime","manager-ipc.json");let e;try{e=JSON.parse(v.readFileSync(r,"utf-8"))}catch{throw new Error("Manager IPC is not available. Open Shennian Desktop or run `shennian start` first.")}const t=Number(e.pid);if(Number.isInteger(t)&&t>0&&!M(t))throw new Error(`Manager IPC runtime file is stale for PID ${t}. Restart Shennian Desktop or run \`shennian restart\`.`);const a=typeof e.url=="string"?e.url.replace(/\/+$/,""):"",s=typeof e.token=="string"?e.token:"";if(!a||!s)throw new Error(`Manager IPC runtime file is incomplete: ${r}`);return{url:a,token:s}}function $(){try{return p()}catch{return null}}function W(r){if(r.directRuntime)return null;const e=r.transport??"auto";if(e==="direct")return null;if(r.ipc)return{ctx:r.ipc,mode:"session"};if(r.sessionId?.trim())return{ctx:p(),mode:"session"};if(e==="daemon")return{ctx:p(),mode:"tool"};if(e==="auto"){const t=$();if(t)return{ctx:t,mode:"tool"}}return null}function _(r,e){if((r.transport??"auto")!=="auto"||r.sessionId?.trim()||r.ipc)return!1;const a=e instanceof Error?e.message:String(e||"");return/Unknown manager IPC path:\s*\/wechat-rpa\/tool\//i.test(a)||/Manager IPC is not available/i.test(a)||/Manager IPC runtime file is stale/i.test(a)||/Manager IPC runtime file is incomplete/i.test(a)}async function A(r,e,t){return C(r,"/wechat-rpa/channel/upsert",{managerSessionId:e.sessionId,id:e.channelId,name:`WeChat ${e.conversationName}`,workDir:e.workDir,enabled:!0,groups:[{name:e.conversationName}],canReply:!0,source:t.source||"wechat-channel",recentLimit:I(t.recentLimit,20),pollIntervalMs:I(t.pollIntervalMs,3e4),forceForeground:!0,downloadAttachments:t.download!=="never",privacyConsentAccepted:!0},t.fetchImpl,t.timeoutMs)}async function C(r,e,t,a=fetch,s){const m=String(t.managerSessionId||"");if(!m)throw new Error("managerSessionId is required");let o,c=0,f="";try{if(a===fetch){const n=await D(r,e,t,s);o=n.data,c=n.status,f=n.statusText}else{const n=s?new AbortController:null,i=n?setTimeout(()=>n.abort(),s):null;try{const l=await a(`${r.url}${e}`,{method:"POST",headers:{authorization:`Bearer ${r.token}`,"content-type":"application/json","x-shennian-manager-session-id":m},body:JSON.stringify(t),signal:n?.signal});c=l.status,f=l.statusText,o=await l.json().catch(()=>({ok:!1,error:l.statusText}))}finally{i&&clearTimeout(i)}}}catch(n){throw new w({reasonCode:y(n)?"manager_ipc_timeout":"manager_ipc_network_failed",message:n instanceof Error?n.message:String(n||"manager ipc request failed"),traceId:u(t.traceId)||void 0})}if(c<200||c>=300||!o.ok){const n=u(o.reasonCode);throw n?new w({reasonCode:n,message:u(o.error)||n,outDir:u(o.outDir)||void 0,helperTracePath:u(o.helperTracePath)||null,activityGuardPath:u(o.activityGuardPath)||null,traceId:u(o.traceId)||void 0}):new Error(o.error||`Manager IPC failed: ${c||f}`)}return o}function D(r,e,t,a){const s=JSON.stringify(t),m=new URL(e,`${r.url}/`),o=m.protocol==="https:"?P:S;return new Promise((c,f)=>{const n=o.request(m,{method:"POST",headers:{authorization:`Bearer ${r.token}`,"content-type":"application/json","content-length":Buffer.byteLength(s),"x-shennian-manager-session-id":String(t.managerSessionId||"")},timeout:a},i=>{const l=[];i.on("data",h=>l.push(Buffer.from(h))),i.on("end",()=>{const h=Buffer.concat(l).toString("utf8");let d;try{d=h?JSON.parse(h):{ok:!1,error:i.statusMessage||"empty response"}}catch{d={ok:!1,error:i.statusMessage||"invalid json response"}}c({status:i.statusCode||0,statusText:i.statusMessage||"",data:d})})});n.on("timeout",()=>{n.destroy(Object.assign(new Error("Manager IPC request timed out"),{name:"AbortError"}))}),n.on("error",f),n.end(s)})}function L(r){const e=r.conversation.trim();if(!e)throw new Error("--conversation is required");const t=E("wechat-cli-conversation",e),a=r.sessionId?.trim()||`wechat-cli-${t.slice(-24)}`,s=`wechat-rpa:${a}`;return{sessionId:a,channelId:s,conversationId:x(e),conversationName:e,workDir:k.resolve(r.workDir||g("wechat-cli",T(e)))}}async function J(r,e,t){try{return await C(r,"/wechat-rpa/channel/sync",{managerSessionId:e.sessionId},t.fetchImpl,t.timeoutMs)}catch(a){if(y(a))return null;throw a}}export{L as buildWeChatToolBinding,A as ensureWeChatToolChannel,C as ipc,p as loadManagerIpcFromRuntimeFile,W as resolveWeChatManagerIpc,_ as shouldFallbackManagerToolToDirect,$ as tryLoadManagerIpcFromRuntimeFile,J as trySyncWeChatToolChannel};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import y from"node:path";import{cleanInline as a,stringValue as o}from"./utils.js";const b=["SHENNIAN_WECHAT_CHANNEL_HELPER_DIR","SHENNIAN_HELPER_RUNTIME_DIR","packages/helper-runtime/wechat-channel","packages\\helper-runtime\\wechat-channel","packages/helper-runtime/dist","packages\\helper-runtime\\dist","wechat-rpa-windows-product-send-runner","PowerShell one-shot runner","activity.snapshot","automation.lease."],w=new Set(["wechat_not_running","wechat_window_not_found","permission_screen_recording_missing","permission_accessibility_missing","permission_input_monitoring_missing"]);function
|
|
2
|
-
`;for(const n of e.messages)i.push(`${
|
|
1
|
+
import y from"node:path";import{cleanInline as a,stringValue as o}from"./utils.js";const b=["SHENNIAN_WECHAT_CHANNEL_HELPER_DIR","SHENNIAN_HELPER_RUNTIME_DIR","packages/helper-runtime/wechat-channel","packages\\helper-runtime\\wechat-channel","packages/helper-runtime/dist","packages\\helper-runtime\\dist","wechat-rpa-windows-product-send-runner","PowerShell one-shot runner","activity.snapshot","automation.lease."],w=new Set(["wechat_not_running","wechat_window_not_found","permission_screen_recording_missing","permission_accessibility_missing","permission_input_monitoring_missing"]);function x(e,i){if(i){console.log(JSON.stringify(e,null,2));return}console.log(e.sendStatus)}function T(e,i){if(i==="json"){console.log(JSON.stringify(e,null,2));return}console.log(k(e).trimEnd())}function C(e,i,n,t){const r=S(e,i,n);t?console.log(JSON.stringify(r,null,2)):console.error(`${r.reasonCode}: ${r.message}`),process.exitCode=1}function S(e,i,n){const t=n instanceof Error?n.message:String(n||"wechat_tool_failed"),r=a(t)||"wechat_tool_failed",l=/^([a-z][a-z0-9_]*)(?::\s*(.*))?$/i.exec(r),s=o(n?.reasonCode)||l?.[1]||"wechat_tool_failed",c=W(s,r),_=a(l?.[2]||r),v=E(c,_,s),p=o(n?.outDir),d=o(n?.helperTracePath),h=o(n?.activityGuardPath),m=o(n?.traceId),f=q(c,s);return{ok:!1,operation:e,...i?.trim()?{conversation:i.trim()}:{},reasonCode:c,...$(s,c,_)?{rawReasonCode:s}:{},message:v,...m?{traceId:m}:{},...p?{outDir:p}:{},...d?{helperTracePath:d}:{},...h?{activityGuardPath:h}:{},...f?{userAction:f}:{}}}function k(e){const i=[];if(e.messages.length===0)return`\uFF08\u6CA1\u6709\u8BFB\u5230\uFF09
|
|
2
|
+
`;for(const n of e.messages)i.push(`${A(n)}: ${I(n)}`);return`${i.join(`
|
|
3
3
|
`)}
|
|
4
|
-
`}function W(e,i=""){const n=e.trim().toLowerCase(),t=`${n} ${i}`.toLowerCase();return n?n==="insufficient_credits"?"insufficient_credits":n==="entitlement_required"||n==="enterprise_required"||n.includes("entitlement")?"entitlement_required":n==="manual_review_required"||n.includes("manual_review")?"manual_review_required":n==="attachment_pending"||/attachment.*pending|media_original_pending/.test(t)?"attachment_pending":/helper_runtime_required|helper_runtime_source_missing|helper_runtime_package_manifest_missing|manifest_missing|helper_missing|helper_not_executable/.test(n)?"helper_missing":/helper_runtime_cli_too_old|helper_runtime_version_mismatch|helper_runtime_protocol_mismatch|helper_runtime_platform_mismatch|helper_runtime_package_manifest_invalid|integrity_mismatch/.test(n)?"helper_version_incompatible":/^user_active|recent_(keyboard|mouse|scroll)|frontmost_app_changed|user_takeover|activity/.test(n)?"user_active_retry_later":/helper_command_timeout/.test(n)?"wechat_window_unavailable":u(t)?"wechat_tool_failed":/permission|accessibility|screen_recording|automation|mac_input|input-monitoring/.test(t)?"permission_required":/wechat_login_required|login_required|安全验证|扫码登录|重新登录/.test(t)?"wechat_login_required":/wechat_single_main_window_required|wechat_duplicate_instance|duplicate_main_window/.test(n)?"wechat_window_unavailable":/visible_desktop|desktop_session|screen_locked|session_locked|rdp_disconnected|rdp.*visible|rdp.*desktop/.test(t)?"windows_visible_desktop_unavailable":/dpi_mapping_failed|display_topology|monitor_topology|multi_?monitor|multi_?screen/.test(t)?"dpi_mapping_failed":/conversation_not|conversation_title_not_confirmed|conversation_not_visible|open_read_required|search_result_not_visible/.test(n)?"conversation_not_found":/wechat_window|wechat_not_running|window_not|window_unavailable|window_unresponsive/.test(n)?"wechat_window_unavailable":n:"wechat_tool_failed"}function
|
|
4
|
+
`}function W(e,i=""){const n=e.trim().toLowerCase(),t=`${n} ${i}`.toLowerCase();return n?n==="insufficient_credits"?"insufficient_credits":n==="entitlement_required"||n==="enterprise_required"||n.includes("entitlement")?"entitlement_required":n==="manual_review_required"||n.includes("manual_review")?"manual_review_required":n==="attachment_pending"||/attachment.*pending|media_original_pending/.test(t)?"attachment_pending":/helper_runtime_required|helper_runtime_source_missing|helper_runtime_package_manifest_missing|manifest_missing|helper_missing|helper_not_executable/.test(n)?"helper_missing":/helper_runtime_cli_too_old|helper_runtime_version_mismatch|helper_runtime_protocol_mismatch|helper_runtime_platform_mismatch|helper_runtime_package_manifest_invalid|integrity_mismatch/.test(n)?"helper_version_incompatible":/^user_active|recent_(keyboard|mouse|scroll)|frontmost_app_changed|user_takeover|activity/.test(n)?"user_active_retry_later":/^manager_ipc_(timeout|network_failed)$/.test(n)?n:/helper_command_timeout/.test(n)?"wechat_window_unavailable":u(t)?"wechat_tool_failed":/permission|accessibility|screen_recording|automation|mac_input|input-monitoring/.test(t)?"permission_required":/wechat_login_required|login_required|安全验证|扫码登录|重新登录/.test(t)?"wechat_login_required":/wechat_single_main_window_required|wechat_duplicate_instance|duplicate_main_window/.test(n)?"wechat_window_unavailable":/visible_desktop|desktop_session|screen_locked|session_locked|rdp_disconnected|rdp.*visible|rdp.*desktop/.test(t)?"windows_visible_desktop_unavailable":/dpi_mapping_failed|display_topology|monitor_topology|multi_?monitor|multi_?screen/.test(t)?"dpi_mapping_failed":/conversation_not|conversation_title_not_confirmed|conversation_not_visible|open_read_required|search_result_not_visible/.test(n)?"conversation_not_found":/wechat_window|wechat_not_running|window_not|window_unavailable|window_unresponsive/.test(n)?"wechat_window_unavailable":n:"wechat_tool_failed"}function q(e,i=""){if(e==="wechat_login_required")return"Open WeChat on this machine, complete login or security verification, then retry.";if(e==="wechat_window_unavailable")return"Open Shennian Desktop and the main WeChat window on the active desktop, then retry. If running this command over SSH on Windows, retry with the local daemon available.";if(e==="wechat_single_main_window_required")return"Keep WeChat open and visible. If the window state is unclear, let Shennian re-check it with visual classification.";if(e==="windows_visible_desktop_unavailable")return"Unlock or reconnect the Windows visible desktop session, keep WeChat visible, then retry.";if(e==="dpi_mapping_failed")return"Move WeChat fully onto one visible display or use a supported display scaling setup, then retry.";if(e==="conversation_not_found")return"Check the WeChat conversation name and make sure the conversation can be searched.";if(e==="helper_missing")return"Open the \u4F7F\u7528\u5FAE\u4FE1 page in Shennian and click Install Helper, or open Shennian Desktop, then retry.";if(e==="helper_version_incompatible")return"Use Repair Helper on the \u4F7F\u7528\u5FAE\u4FE1 page, or upgrade Shennian CLI, then retry.";if(e==="permission_required")return H(i);if(e==="entitlement_required")return"Enable the WeChat capability for this account in Shennian.";if(e==="insufficient_credits")return"Add credits or adjust the account plan in Shennian.";if(e==="user_active_retry_later")return"Wait until the user is idle, then retry.";if(e==="attachment_pending")return"Open WeChat and let the attachment finish downloading, then retry.";if(e==="manual_review_required")return"Review the current WeChat window before retrying.";if(e==="manager_ipc_timeout"||e==="manager_ipc_network_failed")return"Restart Shennian Desktop or run this command with --transport direct, then retry."}function E(e,i,n){const t=n.trim().toLowerCase();return e==="permission_required"?R(t):!i||i===e||u(i)||w.has(t)?P(e):i}function R(e){return e.includes("screen_recording")?"Shennian Helper.app needs Screen Recording permission.":e.includes("accessibility")?"Shennian Helper.app needs Accessibility permission.":e.includes("input_monitoring")||e.includes("input-monitoring")?"Shennian Helper.app needs Input Monitoring permission.":"Shennian Helper.app needs macOS privacy permissions."}function H(e){const i=e.trim().toLowerCase();return i.includes("screen_recording")?"Grant Shennian Helper.app Screen Recording in Privacy & Security, then retry.":i.includes("accessibility")?"Grant Shennian Helper.app Accessibility in Privacy & Security, then retry.":i.includes("input_monitoring")||i.includes("input-monitoring")?"Grant Shennian Helper.app Input Monitoring in Privacy & Security, then retry.":"Grant Shennian Helper.app the required macOS permissions in Privacy & Security, then retry."}function $(e,i,n){const t=e.trim().toLowerCase();return!(e===i||w.has(t)||u(`${e} ${n}`))}function u(e){const i=e.replace(/\\/g,"/").toLowerCase();return b.some(n=>{const t=n.replace(/\\/g,"/").toLowerCase();return i.includes(t)})}function P(e){return e==="wechat_login_required"?"WeChat needs login or security verification on this machine.":e==="wechat_window_unavailable"?"WeChat window is not available on the active desktop.":e==="wechat_single_main_window_required"?"WeChat window state needs visual confirmation.":e==="windows_visible_desktop_unavailable"?"Windows visible desktop session is unavailable.":e==="dpi_mapping_failed"?"Windows display scaling or monitor geometry cannot be mapped safely.":e==="conversation_not_found"?"WeChat conversation was not found.":e==="helper_missing"?"Shennian Helper runtime is not installed or cannot be found.":e==="helper_version_incompatible"?"Shennian Helper runtime is incompatible with this CLI.":e==="permission_required"?"Shennian Helper.app needs macOS privacy permissions.":e==="entitlement_required"?"WeChat capability is not enabled for this account.":e==="insufficient_credits"?"Insufficient credits.":e==="user_active_retry_later"?"User activity is in progress; retry later.":e==="attachment_pending"?"WeChat attachment is still pending.":e==="manual_review_required"?"Manual review is required before retrying.":e==="manager_ipc_timeout"?"Local Shennian daemon did not respond before the request timed out.":e==="manager_ipc_network_failed"?"Local Shennian daemon connection failed during the request.":e}function I(e){const i=e.attachments||[],n=a(e.text);return n&&i.length===0?n:n&&i.length>0?`${n} ${i.map(g).join("\u3001")}`:i.length>0?i.map(g).join("\u3001"):"\uFF08\u6D88\u606F\uFF09"}function A(e){return a(e.sender.name||e.sender.id||"\u5BF9\u65B9")}function g(e){const i=a(e.name||y.basename(e.localPath||"")||e.type||"\u9644\u4EF6"),n=e.localPath||e.url||"",t=e.availability&&e.availability!=="edge-local"?` (${e.availability})`:"";return n?`[${M(i)}](${L(n)})${t}`:`${i}${t}`}function L(e){const i=e.replace(/\\/g,"/");return/[\s()<>]/.test(i)?`<${i.replace(/[<>]/g,"")}>`:i}function M(e){return a(e).replace(/([\\\]])/g,"\\$1")}export{k as buildWeChatReadMarkdown,S as buildWeChatToolErrorResult,T as printReadLatestResult,C as printToolError,x as printToolResult};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{registerWeChatCommand as e}from"./wechat/command.js";export*from"./wechat/direct.js";export*from"./wechat/doctor.js";export*from"./wechat/operations.js";export*from"./wechat/output.js";export*from"./wechat/types.js";export{e as registerWeChatCommand};
|
|
1
|
+
import{registerWeChatCommand as e,resolveWeChatCommandTimeout as m}from"./wechat/command.js";export*from"./wechat/direct.js";export*from"./wechat/doctor.js";export*from"./wechat/operations.js";export*from"./wechat/output.js";export*from"./wechat/types.js";export{e as registerWeChatCommand,m as resolveWeChatCommandTimeout};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { buildBottomPageReport, buildDownloadVisibleMediaReport } from './wechat-channel-download-report.js';
|
|
2
|
-
import { type WeChatChannelObserveActivityGuardOptions } from '../channels/wechat-channel/observer.js';
|
|
2
|
+
import { type WeChatChannelObserveActivityGuardOptions, type WeChatChannelOcrBlock } from '../channels/wechat-channel/observer.js';
|
|
3
3
|
import { type WeChatChannelRuntimePlatform } from '../channels/wechat-channel/runtime.js';
|
|
4
4
|
export type WeChatChannelActionSmokeStep = 'open-read' | 'send-text' | 'send-file' | 'send-image' | 'send-video' | 'structure-window' | 'server-observe' | 'read-bottom-page' | 'download-visible-media' | 'send-and-confirm' | 'human-send-preflight-busy' | 'human-send-preflight-busy-then-idle' | 'human-send-user-active-timeout' | 'human-send-takeover-during-run' | 'human-send-takeover-then-idle' | 'human-send-normal' | 'human-observe-deferred';
|
|
5
5
|
export type WeChatChannelActionSmokeOptions = {
|
|
@@ -57,6 +57,7 @@ export declare function runWeChatChannelActionSmoke(options: WeChatChannelAction
|
|
|
57
57
|
export declare function buildSendStepAcceptance(input: {
|
|
58
58
|
sendAccepted: boolean;
|
|
59
59
|
text?: string | null;
|
|
60
|
+
attachmentPath?: string | null;
|
|
60
61
|
beforeTextCount?: number | null;
|
|
61
62
|
afterTextCount?: number | null;
|
|
62
63
|
}): {
|
|
@@ -100,3 +101,4 @@ export declare function buildSendAndConfirmEvidence(input: WeChatChannelSendAndC
|
|
|
100
101
|
export declare function countMarkerOccurrencesInOcrBlocks(blocks: Array<{
|
|
101
102
|
text?: string | null;
|
|
102
103
|
}>, marker: string): number;
|
|
104
|
+
export declare function countMarkerOccurrencesInChatContentBlocks(blocks: Array<WeChatChannelOcrBlock>, marker: string): number;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import _ from"node:crypto";import{spawnSync as ae}from"node:child_process";import w from"node:fs";import i from"node:path";import{fileURLToPath as ie}from"node:url";import{buildBottomPageReport as D,buildDownloadVisibleMediaReport as q}from"./wechat-channel-download-report.js";import{buildWeChatMessagesMarkdown as y}from"./wechat-channel-markdown-report.js";import{loadConfig as de}from"../config/index.js";import{createWeChatChannelApiClient as ce}from"../channels/wechat-channel/client.js";import{resolveWeChatChannelHelperAsset as ue,WECHAT_CHANNEL_HELPER_VERSION as le}from"../channels/wechat-channel/helper-assets.js";import{WeChatChannelHelperClient as me}from"../channels/wechat-channel/helper-client.js";import{requiredWindowsWeChatChannelHelperCapabilitiesForProfile as T}from"../channels/wechat-channel/helper-protocol.js";import{classifyWeChatOutboundEchoes as he,enqueueWeChatOutboundReply as K}from"../channels/wechat-channel/outbound-ledger.js";import{loadWeChatChannelLedger as fe,saveWeChatChannelLedger as ge,updateWeChatChannelBindingLedger as pe}from"../channels/wechat-channel/ledger.js";import{waitForWeChatChannelPacing as U}from"../channels/wechat-channel/pacing.js";import{WeChatChannelOutboundSender as G,sendQueuedWeChatOutboundRecords as S}from"../channels/wechat-channel/outbound-sender.js";import{captureWeChatWindow as j,ensureWeChatWindowReady as C,fallbackWeChatMessageInputPointForWindow as we,focusKnownWeChatWindow as k,observeWeChatChannelBindingViaHelper as be,openConversationBySearch as I,recognizeWeChatScreenshot as E}from"../channels/wechat-channel/observer.js";import{createWeChatChannelRuntime as ve}from"../channels/wechat-channel/runtime.js";function ye(e){const t=!e.sessionId&&e.observePipeline==="edge-structure";if(!e.sessionId&&!t)throw new Error("session_id_required: pass --session-id <existing Shennian session id> for server observe steps");return t?"direct-edge-structure":"session-bound"}const Se="ABC",Ce="wechat-channel-action-smoke";function ke(e){const t=e.filter(u=>u!=="--"),n=ct(t),o=lt(t,"--step").map(ut).filter(u=>u!=null),r=de(),s=g(t,"--trace-id")||`wechat-action-smoke-${Date.now().toString(36)}`,a=i.resolve(g(t,"--out")||g(t,"--output")||i.join(process.cwd(),".dev-runtime","wechat-channel","action-smoke",s)),d=o.length?mt(o):Ie(n);return{conversation:g(t,"--conversation")||g(t,"--group")||Se,mode:o.length?"custom":n,steps:d,outDir:a,workDir:i.resolve(g(t,"--work-dir")||process.cwd()),traceId:s,runtimeId:g(t,"--runtime-id")||Ce,machineId:g(t,"--machine-id")||process.env.SHENNIAN_MACHINE_ID||r.machineId||"local",sessionId:g(t,"--session-id")||process.env.SHENNIAN_EXTERNAL_SESSION_ID||process.env.SHENNIAN_MANAGER_SESSION_ID,serverUrl:g(t,"--server-url")||r.serverUrl,platform:at(g(t,"--platform")),text:g(t,"--text"),filePath:B(g(t,"--file")),imagePath:B(g(t,"--image")),videoPath:B(g(t,"--video")),downloadAnchorText:g(t,"--download-anchor-text")||g(t,"--media-anchor-text"),allowEmptyMedia:t.includes("--allow-empty-media"),requireServer:t.includes("--require-server")}}function Ie(e){return e==="send"?["open-read","send-text","send-file","send-image","send-video"]:e==="observe"?["structure-window"]:e==="all"?["open-read","send-text","send-file","send-image","send-video","structure-window"]:["open-read"]}async function xe(e){const t=Date.now(),n=new Date(t).toISOString();w.mkdirSync(e.outDir,{recursive:!0});const o=i.join(e.outDir,"helper-trace.jsonl");w.writeFileSync(o,"");const r=et(e),s=r.bindings[0],a=tt(e,o);await a.start();const d={ok:!1,conversation:e.conversation,outDir:e.outDir,helperTracePath:o,traceId:e.traceId,runtimeId:e.runtimeId,machineId:e.machineId,startedAt:n,finishedAt:n,durationMs:0,steps:[]};try{for(const u of e.steps){if(Ae(u)&&d.steps.some(c=>c.step==="open-read"&&!c.ok&&!c.skipped)){d.steps.push({step:u,ok:!1,reasonCode:"open_read_required",errorSummary:"open-read failed; refusing to run send step against the current WeChat window"});continue}d.steps.push(await _e({step:u,options:e,runtime:r,binding:s,helper:a}))}}finally{await a.stop().catch(()=>{}),d.finishedAt=new Date().toISOString(),d.durationMs=Date.now()-t,d.ok=d.steps.every(u=>u.ok||u.skipped),m(i.join(e.outDir,"summary.json"),d)}return d}function Ae(e){return e==="send-text"||e==="send-file"||e==="send-image"||e==="send-video"||e==="send-and-confirm"}async function _e(e){try{return e.step==="open-read"?await Te(e):e.step==="structure-window"?await Ke(e):e.step==="server-observe"?await qe(e):e.step==="read-bottom-page"?await Le(e):e.step==="download-visible-media"?await He(e):e.step==="send-and-confirm"?await Fe(e):e.step.startsWith("human-")?await Me(e):await z(e)}catch(t){const n=bt(t),o=await De(e,n,t);return{step:e.step,ok:!1,reasonCode:n,errorSummary:t instanceof Error?t.message:String(t),userAction:vt(n),...o?{details:o}:{}}}}async function De(e,t,n){if(!Re(t))return;const o=i.join(e.options.outDir,`${e.step}-failure-diagnostics.json`),r={step:e.step,reasonCode:t,errorSummary:n instanceof Error?n.message:String(n),capturedAt:new Date().toISOString()};try{r.permissions=await e.helper.request("permissions.check",{},e.options.traceId)}catch(s){r.permissionsError=s instanceof Error?s.message:String(s)}try{r.windows=await e.helper.request("windows.list",{},e.options.traceId)}catch(s){r.windowsError=s instanceof Error?s.message:String(s)}return m(o,r),{failureDiagnosticsPath:o}}function Re(e){return e.startsWith("wechat_")||e.startsWith("permission_")||e.startsWith("user_active")}async function Me(e){if(e.step==="human-observe-deferred")return await Pe(e);const t=e.step,n=`human-${A(`${e.options.traceId}:${t}:${Date.now()}`)}`,o={version:1,runtimeId:e.runtime.runtimeId,records:[]},r=K({ledger:o,replyId:`human:${t}:${n}`,idempotencyKey:`human:${n}`,bindingId:e.binding.bindingId,runtimeId:e.runtime.runtimeId,sessionId:e.binding.sessionId,conversationName:e.binding.conversationDisplayName,replyBaseRevision:0,text:`${n} ${e.options.text||"Shennian WeChat human coordination smoke"}`}),s=Q(e.helper,Z(t)),a=s.actionLog,d=async H=>{a.push(`openConversation:${H}`);const re=await C(s,e.options.traceId),se=await k(s,re,e.options.traceId);return I({helper:s,window:se,settleToBottom:!1,binding:{...e.binding,conversationDisplayName:H},traceId:e.options.traceId})},u=new G({helper:s,platform:e.runtime.policy.platform,openConversation:d,traceId:e.options.traceId,activityGatePolicy:e.step==="human-send-user-active-timeout"?{keyDownThresholdMs:3e4,mouseMovedThresholdMs:3e4,mouseClickThresholdMs:3e4,scrollWheelThresholdMs:3e4}:void 0});let f=await S({ledger:o,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:u,now:new Date("2026-06-15T00:00:00.000Z"),maxUserActivityWaitMs:e.step==="human-send-user-active-timeout"?1e3:void 0});e.step==="human-send-user-active-timeout"&&(f=await S({ledger:o,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:u,now:new Date("2026-06-15T00:00:02.000Z"),maxUserActivityWaitMs:1e3})),(e.step==="human-send-preflight-busy-then-idle"||e.step==="human-send-takeover-then-idle")&&(s.setScenario(Ve()),f=await S({ledger:o,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:u,now:new Date("2026-06-15T00:00:06.000Z")}));const h=Je(e.step,r)?await O({helper:s,binding:e.binding,marker:n,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:e.step}):0,p=h>0?he({ledger:o,bindingId:e.binding.bindingId,messages:[{stableMessageKey:`human-echo:${n}`,senderRole:"self",kind:"text",anchorText:r.text,normalizedText:r.text,textExcerpt:r.text,observedAt:new Date().toISOString()}]}):{confirmedRecords:[],manualReviewRecords:[],remainingMessages:[]},l=o.records[0],b=Xe(l,f,p.confirmedRecords),v={case:e.step,marker:n,runStatus:b,reasonCode:l.deferReason||l.failureCode||null,outboundStatus:l.sendStatus,attemptCount:l.attemptCount??0,nextAttemptAt:l.nextAttemptAt??null,observedMarkerCount:h,actionLog:a,clipboardRestore:a.includes("clipboard.restore")?"attempted":"not_needed",commitStage:l.commitStage??null};return m(i.join(e.options.outDir,`${e.step}-summary.json`),v),{step:e.step,ok:Ye(e.step,v),reasonCode:v.reasonCode||void 0,details:v}}async function Pe(e){const t=Q(e.helper,Z("human-observe-deferred")),n=await t.request("activity.snapshot",{},e.options.traceId),o=!!(n.ok&&n.result&&typeof n.result=="object"&&Number(n.result.keyDownSecondsAgo)<5),r={case:e.step,marker:null,runStatus:o?"observe_deferred_user_active":"baseline_or_no_change",reasonCode:o?"recent_keyboard_activity":null,outboundStatus:null,attemptCount:0,nextAttemptAt:null,observedMarkerCount:0,actionLog:t.actionLog,clipboardRestore:"not_needed"};return m(i.join(e.options.outDir,`${e.step}-summary.json`),r),{step:e.step,ok:o&&!t.actionLog.some(s=>s.startsWith("windows.")||s.startsWith("wechat.")||s.startsWith("clipboard.")),reasonCode:r.reasonCode||void 0,details:r}}async function Te(e){const t=await C(e.helper,e.options.traceId),n=await k(e.helper,t,e.options.traceId),o=await I({helper:e.helper,window:n,binding:e.binding,traceId:e.options.traceId});if(!o.opened)throw await je({helper:e.helper,window:n,outDir:e.options.outDir,traceId:e.options.traceId,reason:o.reason||"conversation_not_opened"}),new Error(o.reason||"conversation_not_opened");const r=await j(e.helper,n.windowId,e.options.traceId),s=P(e.options.outDir,"open-read-full-window",r),a=await E(e.helper,r,e.options.traceId);return m(i.join(e.options.outDir,"open-read-ocr.json"),a),{step:"open-read",ok:!0,details:{openedReason:o.reason,windowId:n.windowId,screenshotPath:s,screenshot:{width:r.width,height:r.height,mimeType:r.mimeType},ocrBlockCount:a.blocks?.length??0,visibleConversationFingerprintCount:a.visibleConversationFingerprints?.length??0}}}async function je(e){try{const t=await j(e.helper,e.window.windowId,e.traceId,e.window.bounds),n=P(e.outDir,"open-read-failure-window",t),o=await E(e.helper,t,e.traceId);m(i.join(e.outDir,"open-read-failure-ocr.json"),o),m(i.join(e.outDir,"open-read-failure-summary.json"),{reason:e.reason,windowId:e.window.windowId,screenshotPath:n,screenshot:{width:t.width,height:t.height,mimeType:t.mimeType},ocrBlockCount:o.blocks?.length??0,visibleConversationFingerprintCount:o.visibleConversationFingerprints?.length??0,topTexts:(o.blocks??[]).slice(0,30).map(r=>({text:r.text,bbox:r.bbox}))})}catch(t){m(i.join(e.outDir,"open-read-failure-summary.json"),{reason:e.reason,captureError:t instanceof Error?t.message:String(t)})}}async function z(e){return await Ee(e,it(e.step,e.options))}async function Ee(e,t){if(t.skipped)return{step:e.step,ok:!0,skipped:!0,reasonCode:t.reasonCode};const n={version:1,runtimeId:e.runtime.runtimeId,records:[]},o=`${e.options.traceId}:${e.step}:${t.text}:${t.attachmentPath||""}`,r=t.text?await O({helper:e.helper,binding:e.binding,marker:t.text,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:`${e.step}-before-send`,settleToBottom:!1}).catch(()=>null):null;K({ledger:n,replyId:`action-smoke:${e.step}:${A(o)}`,idempotencyKey:`action-smoke:${A(o)}`,bindingId:e.binding.bindingId,runtimeId:e.runtime.runtimeId,sessionId:e.binding.sessionId,conversationName:e.binding.conversationDisplayName,replyBaseRevision:0,text:t.text,attachmentLocalRefs:t.attachmentPath?[t.attachmentPath]:[]});const s=new G({helper:e.helper,platform:e.runtime.policy.platform,traceId:e.options.traceId,openConversation:async p=>{const l=await C(e.helper,e.options.traceId),b=await k(e.helper,l,e.options.traceId);return{...await I({helper:e.helper,window:b,settleToBottom:!1,binding:{...e.binding,conversationDisplayName:p},traceId:e.options.traceId}),inputPoint:we(b)}}}),a=await $e({ledger:n,bindingId:e.binding.bindingId,sender:s});await U("send-after-submit",`${e.options.traceId}:${e.step}:after-submit`);const d=n.records[0],u=a.failedRecords[0]?.failureCode||a.manualReviewRecords[0]?.failureCode||a.waitingRecords[0]?.deferReason||a.staleRecords[0]?.failureCode,c=a.sentRecords.length===1&&a.failedRecords.length===0&&a.waitingRecords.length===0&&a.manualReviewRecords.length===0&&a.staleRecords.length===0,f=c&&t.text?await Ze({helper:e.helper,binding:e.binding,marker:t.text,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:`${e.step}-after-send`,settleToBottom:!1,attempts:3,targetGreaterThan:r}):null,h=We({sendAccepted:c,text:t.text,beforeTextCount:r,afterTextCount:f});return{step:e.step,ok:h.ok,reasonCode:u||h.reasonCode,errorSummary:a.failedRecords[0]?.lastErrorSummary||a.manualReviewRecords[0]?.lastErrorSummary,details:{text:t.text,attachmentPath:t.attachmentPath??null,helperTracePath:i.join(e.options.outDir,"helper-trace.jsonl"),confirmationRequired:h.confirmationRequired,sendAccepted:h.sendAccepted,beforeTextCount:r,afterTextCount:f,sentRecords:a.sentRecords.length,failedRecords:a.failedRecords.length,waitingRecords:a.waitingRecords.length,manualReviewRecords:a.manualReviewRecords.length,staleRecords:a.staleRecords.length,sendStatus:d?.sendStatus,failureCode:d?.failureCode??null,lastErrorSummary:d?.lastErrorSummary??null,deferReason:d?.deferReason,commitStage:d?.commitStage??null,attemptCount:d?.attemptCount??0,nextAttemptAt:d?.nextAttemptAt??null}}}function We(e){const t=!!(e.text&&e.text.trim());if(!e.sendAccepted)return{ok:!1,reasonCode:void 0,sendAccepted:!1,confirmationRequired:t};if(!t)return{ok:!0,sendAccepted:!0,confirmationRequired:t};const n=typeof e.beforeTextCount=="number"&&Number.isFinite(e.beforeTextCount)?e.beforeTextCount:null,o=typeof e.afterTextCount=="number"&&Number.isFinite(e.afterTextCount)?e.afterTextCount:0,r=n==null?o>0:o>n;return{ok:r,reasonCode:r?void 0:"sent_text_not_observed",sendAccepted:!0,confirmationRequired:t}}async function $e(e){const t=e.maxAttempts??24,n=e.maxWaitMs??9e4,o=Date.now();let r=await S({ledger:e.ledger,bindingId:e.bindingId,currentLastInboundRevision:0,sender:e.sender,maxUserActivityWaitMs:n});for(let s=2;r.waitingRecords.length>0&&s<=t&&!(Date.now()-o>=n);s+=1){const a=Oe(r.waitingRecords[0]?.nextAttemptAt,o,n);await L(a),r=await S({ledger:e.ledger,bindingId:e.bindingId,currentLastInboundRevision:0,sender:e.sender,maxUserActivityWaitMs:n})}return r}function Oe(e,t,n){const o=Math.max(0,n-(Date.now()-t));if(o<=0)return 0;const r=e?new Date(e).getTime():Number.NaN,s=Number.isFinite(r)?r-Date.now():1e3;return Math.max(500,Math.min(Math.max(500,s),Math.min(5e3,o)))}function Be(e){const t=e.sendResults.filter(l=>!V(l)),n=e.sendResults.filter(l=>!l.skipped).map(l=>l.details?.text&&typeof l.details.text=="string"?l.details.text:"").filter(Boolean),o=e.observedMessages.map(l=>[l.normalizedText||"",l.anchorText||"",l.textExcerpt||""].join(`
|
|
1
|
+
import M from"node:crypto";import{spawnSync as de}from"node:child_process";import p from"node:fs";import i from"node:path";import{fileURLToPath as ce}from"node:url";import{buildBottomPageReport as T,buildDownloadVisibleMediaReport as K}from"./wechat-channel-download-report.js";import{buildWeChatMessagesMarkdown as S}from"./wechat-channel-markdown-report.js";import{loadConfig as le}from"../config/index.js";import{createWeChatChannelApiClient as k}from"../channels/wechat-channel/client.js";import{resolveWeChatChannelHelperAsset as ue,WECHAT_CHANNEL_HELPER_VERSION as me}from"../channels/wechat-channel/helper-assets.js";import{WeChatChannelHelperClient as he}from"../channels/wechat-channel/helper-client.js";import{requiredWindowsWeChatChannelHelperCapabilitiesForProfile as B}from"../channels/wechat-channel/helper-protocol.js";import{classifyWeChatOutboundEchoes as fe,enqueueWeChatOutboundReply as G}from"../channels/wechat-channel/outbound-ledger.js";import{loadWeChatChannelLedger as ge,saveWeChatChannelLedger as we,updateWeChatChannelBindingLedger as pe}from"../channels/wechat-channel/ledger.js";import{waitForWeChatChannelPacing as V}from"../channels/wechat-channel/pacing.js";import{WeChatChannelOutboundSender as z,sendQueuedWeChatOutboundRecords as C}from"../channels/wechat-channel/outbound-sender.js";import{captureWeChatWindow as j,detectWeChatMessageInputPointByServerVision as be,ensureWeChatWindowReady as y,focusKnownWeChatWindow as I,observeWeChatChannelBindingViaHelper as ve,openConversationBySearch as x,recognizeWeChatScreenshot as E}from"../channels/wechat-channel/observer.js";import{createWeChatChannelRuntime as ye}from"../channels/wechat-channel/runtime.js";function Se(e){const t=!e.sessionId&&e.observePipeline==="edge-structure";if(!e.sessionId&&!t)throw new Error("session_id_required: pass --session-id <existing Shennian session id> for server observe steps");return t?"direct-edge-structure":"session-bound"}const ke="ABC",Ce="wechat-channel-action-smoke";function Ie(e){const t=e.filter(l=>l!=="--"),n=ht(t),r=gt(t,"--step").map(ft).filter(l=>l!=null),o=le(),s=f(t,"--trace-id")||`wechat-action-smoke-${Date.now().toString(36)}`,d=i.resolve(f(t,"--out")||f(t,"--output")||i.join(process.cwd(),".dev-runtime","wechat-channel","action-smoke",s)),a=r.length?wt(r):xe(n);return{conversation:f(t,"--conversation")||f(t,"--group")||ke,mode:r.length?"custom":n,steps:a,outDir:d,workDir:i.resolve(f(t,"--work-dir")||process.cwd()),traceId:s,runtimeId:f(t,"--runtime-id")||Ce,machineId:f(t,"--machine-id")||process.env.SHENNIAN_MACHINE_ID||o.machineId||"local",sessionId:f(t,"--session-id")||process.env.SHENNIAN_EXTERNAL_SESSION_ID||process.env.SHENNIAN_MANAGER_SESSION_ID,serverUrl:f(t,"--server-url")||o.serverUrl,platform:lt(f(t,"--platform")),text:f(t,"--text"),filePath:L(f(t,"--file")),imagePath:L(f(t,"--image")),videoPath:L(f(t,"--video")),downloadAnchorText:f(t,"--download-anchor-text")||f(t,"--media-anchor-text"),allowEmptyMedia:t.includes("--allow-empty-media"),requireServer:t.includes("--require-server")}}function xe(e){return e==="send"?["open-read","send-text","send-file","send-image","send-video"]:e==="observe"?["structure-window"]:e==="all"?["open-read","send-text","send-file","send-image","send-video","structure-window"]:["open-read"]}async function De(e){const t=Date.now(),n=new Date(t).toISOString();p.mkdirSync(e.outDir,{recursive:!0});const r=i.join(e.outDir,"helper-trace.jsonl");p.writeFileSync(r,"");const o=ot(e),s=o.bindings[0],d=st(e,r);await d.start();const a={ok:!1,conversation:e.conversation,outDir:e.outDir,helperTracePath:r,traceId:e.traceId,runtimeId:e.runtimeId,machineId:e.machineId,startedAt:n,finishedAt:n,durationMs:0,steps:[]};try{for(const l of e.steps){if(Ae(l)&&a.steps.some(c=>c.step==="open-read"&&!c.ok&&!c.skipped)){a.steps.push({step:l,ok:!1,reasonCode:"open_read_required",errorSummary:"open-read failed; refusing to run send step against the current WeChat window"});continue}a.steps.push(await _e({step:l,options:e,runtime:o,binding:s,helper:d}))}}finally{await d.stop().catch(()=>{}),a.finishedAt=new Date().toISOString(),a.durationMs=Date.now()-t,a.ok=a.steps.every(l=>l.ok||l.skipped),m(i.join(e.outDir,"summary.json"),a)}return a}function Ae(e){return e==="send-text"||e==="send-file"||e==="send-image"||e==="send-video"||e==="send-and-confirm"}async function _e(e){try{return e.step==="open-read"?await je(e):e.step==="structure-window"?await Ke(e):e.step==="server-observe"?await qe(e):e.step==="read-bottom-page"?await He(e):e.step==="download-visible-media"?await Ue(e):e.step==="send-and-confirm"?await Fe(e):e.step.startsWith("human-")?await Me(e):await J(e)}catch(t){const n=kt(t),r=await Re(e,n,t);return{step:e.step,ok:!1,reasonCode:n,errorSummary:t instanceof Error?t.message:String(t),userAction:Ct(n),...r?{details:r}:{}}}}async function Re(e,t,n){if(!Pe(t))return;const r=i.join(e.options.outDir,`${e.step}-failure-diagnostics.json`),o={step:e.step,reasonCode:t,errorSummary:n instanceof Error?n.message:String(n),capturedAt:new Date().toISOString()};try{o.permissions=await e.helper.request("permissions.check",{},e.options.traceId)}catch(s){o.permissionsError=s instanceof Error?s.message:String(s)}try{o.windows=await e.helper.request("windows.list",{},e.options.traceId)}catch(s){o.windowsError=s instanceof Error?s.message:String(s)}return m(r,o),{failureDiagnosticsPath:r}}function Pe(e){return e.startsWith("wechat_")||e.startsWith("permission_")||e.startsWith("user_active")}async function Me(e){if(e.step==="human-observe-deferred")return await Te(e);const t=e.step,n=`human-${_(`${e.options.traceId}:${t}:${Date.now()}`)}`,r={version:1,runtimeId:e.runtime.runtimeId,records:[]},o=G({ledger:r,replyId:`human:${t}:${n}`,idempotencyKey:`human:${n}`,bindingId:e.binding.bindingId,runtimeId:e.runtime.runtimeId,sessionId:e.binding.sessionId,conversationName:e.binding.conversationDisplayName,replyBaseRevision:0,text:`${n} ${e.options.text||"Shennian WeChat human coordination smoke"}`}),s=Z(e.helper,Y(t)),d=s.actionLog,a=k({serverUrl:e.options.serverUrl}),l=async P=>{d.push(`openConversation:${P}`);const ae=await y(s,e.options.traceId),ie=await I(s,ae,e.options.traceId);return x({helper:s,window:ie,settleToBottom:!1,binding:{...e.binding,conversationDisplayName:P},runtime:e.runtime,api:a,workDir:e.options.workDir,traceId:e.options.traceId})},c=new z({helper:s,platform:e.runtime.policy.platform,openConversation:l,traceId:e.options.traceId,activityGatePolicy:e.step==="human-send-user-active-timeout"?{keyDownThresholdMs:3e4,mouseMovedThresholdMs:3e4,mouseClickThresholdMs:3e4,scrollWheelThresholdMs:3e4}:void 0});let h=await C({ledger:r,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:c,now:new Date("2026-06-15T00:00:00.000Z"),maxUserActivityWaitMs:e.step==="human-send-user-active-timeout"?1e3:void 0});e.step==="human-send-user-active-timeout"&&(h=await C({ledger:r,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:c,now:new Date("2026-06-15T00:00:02.000Z"),maxUserActivityWaitMs:1e3})),(e.step==="human-send-preflight-busy-then-idle"||e.step==="human-send-takeover-then-idle")&&(s.setScenario(Je()),h=await C({ledger:r,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:c,now:new Date("2026-06-15T00:00:06.000Z")}));const g=Qe(e.step,o)?await F({helper:s,runtime:e.runtime,binding:e.binding,api:a,workDir:e.options.workDir,marker:n,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:e.step}):0,u=g>0?fe({ledger:r,bindingId:e.binding.bindingId,messages:[{stableMessageKey:`human-echo:${n}`,senderRole:"self",kind:"text",anchorText:o.text,normalizedText:o.text,textExcerpt:o.text,observedAt:new Date().toISOString()}]}):{confirmedRecords:[],manualReviewRecords:[],remainingMessages:[]},b=r.records[0],R=nt(b,h,u.confirmedRecords),v={case:e.step,marker:n,runStatus:R,reasonCode:b.deferReason||b.failureCode||null,outboundStatus:b.sendStatus,attemptCount:b.attemptCount??0,nextAttemptAt:b.nextAttemptAt??null,observedMarkerCount:g,actionLog:d,clipboardRestore:d.includes("clipboard.restore")?"attempted":"not_needed",commitStage:b.commitStage??null};return m(i.join(e.options.outDir,`${e.step}-summary.json`),v),{step:e.step,ok:rt(e.step,v),reasonCode:v.reasonCode||void 0,details:v}}async function Te(e){const t=Z(e.helper,Y("human-observe-deferred")),n=await t.request("activity.snapshot",{},e.options.traceId),r=!!(n.ok&&n.result&&typeof n.result=="object"&&Number(n.result.keyDownSecondsAgo)<5),o={case:e.step,marker:null,runStatus:r?"observe_deferred_user_active":"baseline_or_no_change",reasonCode:r?"recent_keyboard_activity":null,outboundStatus:null,attemptCount:0,nextAttemptAt:null,observedMarkerCount:0,actionLog:t.actionLog,clipboardRestore:"not_needed"};return m(i.join(e.options.outDir,`${e.step}-summary.json`),o),{step:e.step,ok:r&&!t.actionLog.some(s=>s.startsWith("windows.")||s.startsWith("wechat.")||s.startsWith("clipboard.")),reasonCode:o.reasonCode||void 0,details:o}}async function je(e){const t=await y(e.helper,e.options.traceId),n=await I(e.helper,t,e.options.traceId),r=k({serverUrl:e.options.serverUrl}),o=await x({helper:e.helper,window:n,binding:e.binding,runtime:e.runtime,api:r,workDir:e.options.workDir,traceId:e.options.traceId});if(!o.opened)throw await Ee({helper:e.helper,window:n,outDir:e.options.outDir,traceId:e.options.traceId,reason:o.reason||"conversation_not_opened"}),new Error(o.reason||"conversation_not_opened");const s=await j(e.helper,n.windowId,e.options.traceId),d=D(e.options.outDir,"open-read-full-window",s),a=await E(e.helper,s,e.options.traceId);return m(i.join(e.options.outDir,"open-read-ocr.json"),a),{step:"open-read",ok:!0,details:{openedReason:o.reason,windowId:n.windowId,screenshotPath:d,screenshot:{width:s.width,height:s.height,mimeType:s.mimeType},ocrBlockCount:a.blocks?.length??0,visibleConversationFingerprintCount:a.visibleConversationFingerprints?.length??0}}}async function Ee(e){try{const t=await j(e.helper,e.window.windowId,e.traceId,e.window.bounds),n=D(e.outDir,"open-read-failure-window",t),r=await E(e.helper,t,e.traceId);m(i.join(e.outDir,"open-read-failure-ocr.json"),r),m(i.join(e.outDir,"open-read-failure-summary.json"),{reason:e.reason,windowId:e.window.windowId,screenshotPath:n,screenshot:{width:t.width,height:t.height,mimeType:t.mimeType},ocrBlockCount:r.blocks?.length??0,visibleConversationFingerprintCount:r.visibleConversationFingerprints?.length??0,topTexts:(r.blocks??[]).slice(0,30).map(o=>({text:o.text,bbox:o.bbox}))})}catch(t){m(i.join(e.outDir,"open-read-failure-summary.json"),{reason:e.reason,captureError:t instanceof Error?t.message:String(t)})}}async function J(e){return await We(e,ut(e.step,e.options))}async function We(e,t){if(t.skipped)return{step:e.step,ok:!0,skipped:!0,reasonCode:t.reasonCode};const n=k({serverUrl:e.options.serverUrl}),r={version:1,runtimeId:e.runtime.runtimeId,records:[]},o=`${e.options.traceId}:${e.step}:${t.text}:${t.attachmentPath||""}`,s=t.text?await F({helper:e.helper,runtime:e.runtime,binding:e.binding,api:n,workDir:e.options.workDir,marker:t.text,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:`${e.step}-before-send`,settleToBottom:!1}).catch(()=>null):null;G({ledger:r,replyId:`action-smoke:${e.step}:${_(o)}`,idempotencyKey:`action-smoke:${_(o)}`,bindingId:e.binding.bindingId,runtimeId:e.runtime.runtimeId,sessionId:e.binding.sessionId,conversationName:e.binding.conversationDisplayName,replyBaseRevision:0,text:t.text,attachmentLocalRefs:t.attachmentPath?[t.attachmentPath]:[]});const d=new z({helper:e.helper,platform:e.runtime.policy.platform,traceId:e.options.traceId,activityGatePolicy:e.runtime.foregroundPolicy==="work"?{mouseMovedThresholdMs:0,mouseClickThresholdMs:0,scrollWheelThresholdMs:0,keyDownThresholdMs:0}:void 0,takeoverCheck:e.runtime.foregroundPolicy!=="work",onAfterPaste:async({kind:u})=>{await Xe({helper:e.helper,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:`${e.step}-after-paste-${u}`})},openConversation:async u=>{const b=await y(e.helper,e.options.traceId),R=await I(e.helper,b,e.options.traceId),v=await x({helper:e.helper,window:R,settleToBottom:!1,binding:{...e.binding,conversationDisplayName:u},runtime:e.runtime,api:n,workDir:e.options.workDir,traceId:e.options.traceId});if(!v.opened)return{...v,inputPoint:null};const P=await be({runtime:e.runtime,binding:{...e.binding,conversationDisplayName:u},helper:e.helper,api:n,workDir:e.options.workDir,traceId:e.options.traceId,window:R});return{...v,inputPoint:P}}}),a=await Be({ledger:r,bindingId:e.binding.bindingId,sender:d});await V("send-after-submit",`${e.options.traceId}:${e.step}:after-submit`);const l=r.records[0],c=a.failedRecords[0]?.failureCode||a.manualReviewRecords[0]?.failureCode||a.waitingRecords[0]?.deferReason||a.staleRecords[0]?.failureCode,w=a.sentRecords.length===1&&a.failedRecords.length===0&&a.waitingRecords.length===0&&a.manualReviewRecords.length===0&&a.staleRecords.length===0,h=w&&t.text?await tt({helper:e.helper,runtime:e.runtime,binding:e.binding,api:n,workDir:e.options.workDir,marker:t.text,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:`${e.step}-after-send`,settleToBottom:!1,attempts:3,targetGreaterThan:s}):null,g=$e({sendAccepted:w,text:t.text,attachmentPath:t.attachmentPath,beforeTextCount:s,afterTextCount:h});return{step:e.step,ok:g.ok,reasonCode:c||g.reasonCode,errorSummary:a.failedRecords[0]?.lastErrorSummary||a.manualReviewRecords[0]?.lastErrorSummary,details:{text:t.text,attachmentPath:t.attachmentPath??null,helperTracePath:i.join(e.options.outDir,"helper-trace.jsonl"),confirmationRequired:g.confirmationRequired,sendAccepted:g.sendAccepted,beforeTextCount:s,afterTextCount:h,sentRecords:a.sentRecords.length,failedRecords:a.failedRecords.length,waitingRecords:a.waitingRecords.length,manualReviewRecords:a.manualReviewRecords.length,staleRecords:a.staleRecords.length,sendStatus:l?.sendStatus,failureCode:l?.failureCode??null,lastErrorSummary:l?.lastErrorSummary??null,deferReason:l?.deferReason,commitStage:l?.commitStage??null,attemptCount:l?.attemptCount??0,nextAttemptAt:l?.nextAttemptAt??null}}}function $e(e){const t=!!(e.text&&e.text.trim()&&!e.attachmentPath);if(!e.sendAccepted)return{ok:!1,reasonCode:void 0,sendAccepted:!1,confirmationRequired:t};if(!t)return{ok:!0,sendAccepted:!0,confirmationRequired:t};const n=typeof e.beforeTextCount=="number"&&Number.isFinite(e.beforeTextCount)?e.beforeTextCount:null,r=typeof e.afterTextCount=="number"&&Number.isFinite(e.afterTextCount)?e.afterTextCount:0,o=n==null?r>0:r>n;return{ok:o,reasonCode:o?void 0:"sent_text_not_observed",sendAccepted:!0,confirmationRequired:t}}async function Be(e){const t=e.maxAttempts??24,n=e.maxWaitMs??9e4,r=Date.now();let o=await C({ledger:e.ledger,bindingId:e.bindingId,currentLastInboundRevision:0,sender:e.sender,maxUserActivityWaitMs:n});for(let s=2;o.waitingRecords.length>0&&s<=t&&!(Date.now()-r>=n);s+=1){const d=Ne(o.waitingRecords[0]?.nextAttemptAt,r,n);await q(d),o=await C({ledger:e.ledger,bindingId:e.bindingId,currentLastInboundRevision:0,sender:e.sender,maxUserActivityWaitMs:n})}return o}function Ne(e,t,n){const r=Math.max(0,n-(Date.now()-t));if(r<=0)return 0;const o=e?new Date(e).getTime():Number.NaN,s=Number.isFinite(o)?o-Date.now():1e3;return Math.max(500,Math.min(Math.max(500,s),Math.min(5e3,r)))}function Oe(e){const t=e.sendResults.filter(u=>!Q(u)),n=e.sendResults.filter(u=>!u.skipped).map(u=>u.details?.text&&typeof u.details.text=="string"?u.details.text:"").filter(Boolean),r=e.observedMessages.map(u=>[u.normalizedText||"",u.anchorText||"",u.textExcerpt||""].join(`
|
|
2
2
|
`)).join(`
|
|
3
|
-
`),r=n.filter(l=>o.includes(l)),s=e.sendResults.map(l=>typeof l.details?.sendStatus=="string"?l.details.sendStatus:"").filter(Boolean),a=e.sendResults.filter(V).length,d=W(t,"waitingRecords"),u=W(t,"failedRecords"),c=W(t,"manualReviewRecords"),f=t.find(l=>!l.ok||l.skipped),h=s.length===n.length&&s.every(l=>l==="sent_unconfirmed"||l==="confirmed_echo"),p=!f&&n.length>0&&r.length>0&&h&&d===0&&u===0&&c===0;return{ok:p,reasonCode:p?void 0:f?.reasonCode||(d>0?"outbound_send_waiting":void 0)||(u>0?"outbound_send_failed":void 0)||(c>0?"outbound_manual_review":void 0)||(h?void 0:"outbound_status_not_accepted")||(r.length?"partial_sent_messages_observed":"sent_messages_not_observed"),sentTexts:n,confirmedTexts:r,outboundStatuses:s,skippedFixtureCount:a,pendingOutboundCount:d,failedOutboundCount:u,manualReviewCount:c}}function V(e){return e.skipped===!0&&e.reasonCode==="ffmpeg_unavailable_for_video_fixture"}function W(e,t){return e.reduce((n,o)=>{const r=o.details?.[t];return n+(typeof r=="number"&&Number.isFinite(r)?r:0)},0)}async function Fe(e){const t=["send-text"],n=[];for(const c of t)n.push(await z({...e,step:c}));await L(1200);const o=await R(e,3,{observePipeline:"edge-structure"}),r=D(o.messages),s=i.join(e.options.outDir,"bottom-page.md"),a=y(o.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(o.attachmentsDir)});m(i.join(e.options.outDir,"bottom-page-summary.json"),r),m(i.join(e.options.outDir,"server-observe-messages.json"),o.messages),x(s,a);const d=Be({sendResults:n,observedMessages:o.messages}),u=d.ok&&o.messages.length>0;return{step:"send-and-confirm",ok:u,reasonCode:u?void 0:d.reasonCode,errorSummary:n.find(c=>!c.ok||c.skipped)?.errorSummary,details:{sent:n.map(c=>({step:c.step,ok:c.ok,skipped:c.skipped,reasonCode:c.reasonCode,errorSummary:c.errorSummary,text:c.details?.text,attachmentPath:c.details?.attachmentPath,sendStatus:c.details?.sendStatus,deferReason:c.details?.deferReason,failureCode:c.details?.failureCode,commitStage:c.details?.commitStage,attemptCount:c.details?.attemptCount,nextAttemptAt:c.details?.nextAttemptAt,waitingRecords:c.details?.waitingRecords,failedRecords:c.details?.failedRecords,manualReviewRecords:c.details?.manualReviewRecords})),sentTexts:d.sentTexts,confirmedTexts:d.confirmedTexts,outboundStatuses:d.outboundStatuses,skippedFixtureCount:d.skippedFixtureCount,pendingOutboundCount:d.pendingOutboundCount,failedOutboundCount:d.failedOutboundCount,manualReviewCount:d.manualReviewCount,observedCount:o.messages.length,byKind:r.byKind,attachmentSummary:r.attachmentSummary,attachmentsDir:o.attachmentsDir,reportPath:i.join(e.options.outDir,"bottom-page-summary.json"),markdownPath:s,markdown:a}}}async function R(e,t,n={}){let o;const r=[];for(let s=1;s<=t;s+=1)try{const a=await J(e,n);return r.length&&(r.push({phase:"observe",attempt:s,ok:!0,observedCount:a.messages.length,at:new Date().toISOString()}),m(i.join(e.options.outDir,"observe-retry-events.json"),r)),a}catch(a){if(o=a,r.push({phase:"observe",attempt:s,ok:!1,errorSummary:a instanceof Error?a.message:String(a||""),at:new Date().toISOString()}),s>=t||!Ne(a))break;try{const d=await C(e.helper,e.options.traceId),u=await k(e.helper,d,e.options.traceId),c=await I({helper:e.helper,window:u,binding:e.binding,traceId:e.options.traceId});r.push({phase:"recover",attempt:s,ok:c.opened,reason:c.reason,windowId:u.windowId,at:new Date().toISOString()})}catch(d){r.push({phase:"recover",attempt:s,ok:!1,errorSummary:d instanceof Error?d.message:String(d||""),at:new Date().toISOString()})}m(i.join(e.options.outDir,"observe-retry-events.json"),r),await U("observe-retry",`${e.options.traceId}:observe-retry:${s}`,1500*s)}throw r.length&&m(i.join(e.options.outDir,"observe-retry-events.json"),r),o}function Ne(e){const t=e instanceof Error?e.message:String(e||"");return/conversation_not_visible|wechat_window_unavailable|wechat_window_not_found|title_not_confirmed|server_observe_failed|timeout/i.test(t)}async function Le(e){const t=await R(e,3),n=D(t.messages),o=i.join(e.options.outDir,"bottom-page.md"),r=y(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});return m(i.join(e.options.outDir,"bottom-page-summary.json"),n),m(i.join(e.options.outDir,"server-observe-messages.json"),t.messages),x(o,r),{step:"read-bottom-page",ok:n.messageCount>0,reasonCode:n.messageCount>0?void 0:"no_observed_messages",details:{messageCount:n.messageCount,byKind:n.byKind,attachmentSummary:n.attachmentSummary,attachmentsDir:t.attachmentsDir,reportPath:i.join(e.options.outDir,"bottom-page-summary.json"),markdownPath:o,markdown:r}}}async function He(e){const t=await R(e,3,{observePipeline:"edge-structure",persistLocalLedger:!0});$(e.options.outDir,"download-visible",t.observationEvidence);const n=D(t.messages),o=i.join(e.options.outDir,"download-visible.md"),r=y(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)}),s=q(t.messages,t.attachmentsDir,{observePipeline:t.observePipeline,downloadAnchorText:e.options.downloadAnchorText,ledgerPath:t.ledgerPath,ledgerBinding:t.ledgerBinding,traceHashes:t.traceHashes});m(i.join(e.options.outDir,"bottom-page-summary.json"),n),m(i.join(e.options.outDir,"download-visible-summary.json"),s),m(i.join(e.options.outDir,"download-visible-messages.json"),t.messages),x(o,r);const a=!!(e.options.allowEmptyMedia&&s.reasonCode==="no_visible_media_candidates"&&t.messages.length>0),d=s.ok||a;return{step:"download-visible-media",ok:d,reasonCode:d?void 0:s.reasonCode,details:{mediaCandidateCount:s.mediaCandidateCount,localAttachmentCount:s.localAttachmentCount,originalLocalAttachmentCount:s.originalLocalAttachmentCount,previewAttachmentCount:s.previewAttachmentCount,missingLocalPathCount:s.missingLocalPathCount,pendingAttachmentCount:s.pendingAttachmentCount,byKind:s.byKind,byAvailability:s.byAvailability,reasonCodes:s.reasonCodes,mediaReasonCode:s.reasonCode,allowEmptyMediaRead:a,attachmentsDir:t.attachmentsDir,reportPath:i.join(e.options.outDir,"download-visible-summary.json"),markdownPath:o,markdown:r,phases:s.phases,observePipeline:s.observePipeline,ledgerPath:s.ledgerPath,ledgerRevision:s.ledger?.revision,traceHashes:s.traceHashes,traceEvents:s.traceEvents}}}async function qe(e){const t=await R(e,3,{observePipeline:"server-observe"});$(e.options.outDir,"server-observe",t.observationEvidence),m(i.join(e.options.outDir,"server-observe-messages.json"),t.messages);const n=i.join(e.options.outDir,"server-observe.md"),o=y(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});x(n,o);const r=ee(t.messages);return{step:"server-observe",ok:t.messages.length>0,reasonCode:t.messages.length>0?void 0:"no_observed_messages",details:{observedCount:t.messages.length,byKind:F(t.messages.map(s=>s.kind||"unknown")),attachmentSummary:r,attachmentsDir:t.attachmentsDir,markdownPath:n,markdown:o}}}async function Ke(e){const t=await J(e,{observePipeline:"edge-structure",downloadMedia:!1});$(e.options.outDir,"structure-window",t.observationEvidence),m(i.join(e.options.outDir,"structure-window-messages.json"),t.messages);const n=i.join(e.options.outDir,"structure-window.md"),o=y(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});x(n,o);const r=ee(t.messages);return{step:"structure-window",ok:t.messages.length>0,reasonCode:t.messages.length>0?void 0:"no_observed_messages",details:{observedCount:t.messages.length,byKind:F(t.messages.map(s=>s.kind||"unknown")),attachmentSummary:r,attachmentsDir:t.attachmentsDir,markdownPath:n,markdown:o}}}async function J(e,t={}){const n=ye({sessionId:e.options.sessionId,observePipeline:t.observePipeline}),o=ce({serverUrl:e.options.serverUrl});e.options.skipRuntimeUpsert||(n==="direct-edge-structure"?await o.upsertRuntime(e.runtime):await o.upsertRuntime(e.runtime,{...e.binding,enabled:!1,allowReply:!1}));const r=i.join(e.options.outDir,"inbound-attachments");w.mkdirSync(r,{recursive:!0});const s=t.persistLocalLedger?ht(e.options):void 0,a=s?fe(s,e.runtime.runtimeId):void 0;let d,u,c;const f=await be({runtime:e.runtime,binding:{...e.binding,downloadMedia:t.downloadMedia??e.binding.downloadMedia},helper:e.helper,api:o,workDir:e.options.workDir,attachmentsDir:r,traceId:e.options.traceId,mediaAnchorText:e.options.downloadAnchorText,activityGuard:e.options.activityGuard,observePipeline:t.observePipeline,localLedgerTailAnchors:a?ft(a.bindings[e.binding.bindingId]):void 0,onObservationEvidence:({capture:l,ocr:b})=>{d=Ge(l),u=ze(b),c=Ue(l,b,{captureHash:d,ocrHash:u})}});let h,p;if(a&&s){const l=pe({ledger:a,bindingId:e.binding.bindingId,observedMessages:f});h=l.binding,p=oe({bindingId:e.binding.bindingId,revision:h.revision,messages:l.newMessages}),ge(s,a)}return{messages:f,attachmentsDir:r,observePipeline:t.observePipeline,...s?{ledgerPath:s}:{},...h?{ledgerBinding:h}:{},traceHashes:{...d?{captureHash:d}:{},...u?{ocrHash:u}:{},...p?{ingestPayloadHash:p}:{}},...c?{observationEvidence:c}:{}}}function Ue(e,t,n){return{capture:e,report:{screenshot:{width:e.width,height:e.height,mimeType:e.mimeType,...e.windowId?{windowId:e.windowId}:{}},hashes:n,ocrBlockCount:t.blocks?.length??0,visibleConversationFingerprintCount:t.visibleConversationFingerprints?.length??0,topTexts:(t.blocks??[]).slice(0,40).map(o=>({text:o.text,...o.bbox?{bbox:o.bbox}:{},...typeof o.confidence=="number"?{confidence:o.confidence}:{}}))}}}function $(e,t,n){if(!n)return;const o=n.capture.dataBase64?P(e,`${t}-observation-window`,n.capture):void 0;m(i.join(e,`${t}-observation-evidence.json`),{...n.report,...o?{screenshotPath:o}:{}})}function Ge(e){if(e.dataBase64)return`sha256:${_.createHash("sha256").update(Buffer.from(e.dataBase64,"base64")).digest("hex")}`}function ze(e){return oe({blocks:(e.blocks??[]).map(t=>({text:t.text??"",bbox:t.bbox??null,confidence:typeof t.confidence=="number"?Number(t.confidence.toFixed(4)):null})),visibleConversationFingerprints:e.visibleConversationFingerprints??[]})}function Q(e,t){let n=t,o=0,r=0,s="";const a=[];return{actionLog:a,setScenario(u){n=u,o=0,r=0},async request(u,c,f){if(a.push(u),u==="activity.snapshot"){if(o+=1,o<=n.preflightBusySnapshots)return{id:`human-${o}`,ok:!0,result:{keyDownSecondsAgo:.2,mouseMovedSecondsAgo:.2,scrollWheelSecondsAgo:.2,privacy:{capturesKeyContent:!1,capturesMousePath:!1}},latencyMs:0,traceId:f};if(n.forceIdleAfterBusy)return{id:`human-${o}`,ok:!0,result:{keyDownSecondsAgo:60,mouseMovedSecondsAgo:60,leftMouseDownSecondsAgo:60,rightMouseDownSecondsAgo:60,scrollWheelSecondsAgo:60,privacy:{capturesKeyContent:!1,capturesMousePath:!1}},latencyMs:0,traceId:f}}if(u==="automation.lease.acquire"){const h=await e.request(u,c,f),p=h.result&&typeof h.result=="object"?h.result:{};return s=typeof p.leaseId=="string"?p.leaseId:"",h}return u==="automation.lease.status"?(r+=1,n.simulateInterruptionAtLeaseStatus===r?(a.push("automation.lease.simulateInterruption"),{id:`human-lease-${r}`,ok:!0,result:{active:!0,leaseId:s,interrupted:!0,interruptReason:n.interruptionReason||"recent_mouse_activity"},latencyMs:0,traceId:f}):{id:`human-lease-${r}`,ok:!0,result:{active:!0,leaseId:s,interrupted:!1},latencyMs:0,traceId:f}):e.request(u,c,f)}}}function Z(e){return e==="human-send-preflight-busy"||e==="human-send-preflight-busy-then-idle"||e==="human-send-user-active-timeout"||e==="human-observe-deferred"?{preflightBusySnapshots:100}:e==="human-send-takeover-during-run"||e==="human-send-takeover-then-idle"?{preflightBusySnapshots:0,forceIdleAfterBusy:!0,simulateInterruptionAtLeaseStatus:2,interruptionReason:"recent_mouse_activity"}:{preflightBusySnapshots:0,forceIdleAfterBusy:!0}}function Ve(){return{preflightBusySnapshots:0,forceIdleAfterBusy:!0}}function Je(e,t){return t.sendStatus!=="sent_unconfirmed"?!1:e==="human-send-normal"||e==="human-send-preflight-busy-then-idle"||e==="human-send-takeover-then-idle"}async function O(e){const t=await C(e.helper,e.traceId),n=await k(e.helper,t,e.traceId);if(!(await I({helper:e.helper,window:n,binding:e.binding,traceId:e.traceId,settleToBottom:e.settleToBottom})).opened)return 0;const r=await j(e.helper,n.windowId,e.traceId),s=P(e.outDir,`${e.filePrefix}-observe-marker`,r),a=await E(e.helper,r,e.traceId);return m(i.join(e.outDir,`${e.filePrefix}-observe-marker-ocr.json`),{screenshotPath:s,marker:e.marker,ocr:a}),Qe(a.blocks||[],e.marker)}function Qe(e,t){const n=t.trim();if(!n)return 0;const o=e.map(a=>a.text||"").join(`
|
|
4
|
-
`),
|
|
5
|
-
`)}}function
|
|
6
|
-
${
|
|
7
|
-
`,"utf8"),{text:`codex-product-action file ${
|
|
8
|
-
`,"utf8")}function
|
|
9
|
-
`)}async function
|
|
10
|
-
`),process.exit(1)});export{
|
|
3
|
+
`),o=n.filter(u=>r.includes(u)),s=e.sendResults.map(u=>typeof u.details?.sendStatus=="string"?u.details.sendStatus:"").filter(Boolean),d=e.sendResults.filter(Q).length,a=N(t,"waitingRecords"),l=N(t,"failedRecords"),c=N(t,"manualReviewRecords"),w=t.find(u=>!u.ok||u.skipped),h=s.length===n.length&&s.every(u=>u==="sent_unconfirmed"||u==="confirmed_echo"),g=!w&&n.length>0&&o.length>0&&h&&a===0&&l===0&&c===0;return{ok:g,reasonCode:g?void 0:w?.reasonCode||(a>0?"outbound_send_waiting":void 0)||(l>0?"outbound_send_failed":void 0)||(c>0?"outbound_manual_review":void 0)||(h?void 0:"outbound_status_not_accepted")||(o.length?"partial_sent_messages_observed":"sent_messages_not_observed"),sentTexts:n,confirmedTexts:o,outboundStatuses:s,skippedFixtureCount:d,pendingOutboundCount:a,failedOutboundCount:l,manualReviewCount:c}}function Q(e){return e.skipped===!0&&e.reasonCode==="ffmpeg_unavailable_for_video_fixture"}function N(e,t){return e.reduce((n,r)=>{const o=r.details?.[t];return n+(typeof o=="number"&&Number.isFinite(o)?o:0)},0)}async function Fe(e){const t=["send-text"],n=[];for(const c of t)n.push(await J({...e,step:c}));await q(1200);const r=await W(e,3,{observePipeline:"edge-structure"}),o=T(r.messages),s=i.join(e.options.outDir,"bottom-page.md"),d=S(r.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(r.attachmentsDir)});m(i.join(e.options.outDir,"bottom-page-summary.json"),o),m(i.join(e.options.outDir,"server-observe-messages.json"),r.messages),A(s,d);const a=Oe({sendResults:n,observedMessages:r.messages}),l=a.ok&&r.messages.length>0;return{step:"send-and-confirm",ok:l,reasonCode:l?void 0:a.reasonCode,errorSummary:n.find(c=>!c.ok||c.skipped)?.errorSummary,details:{sent:n.map(c=>({step:c.step,ok:c.ok,skipped:c.skipped,reasonCode:c.reasonCode,errorSummary:c.errorSummary,text:c.details?.text,attachmentPath:c.details?.attachmentPath,sendStatus:c.details?.sendStatus,deferReason:c.details?.deferReason,failureCode:c.details?.failureCode,commitStage:c.details?.commitStage,attemptCount:c.details?.attemptCount,nextAttemptAt:c.details?.nextAttemptAt,waitingRecords:c.details?.waitingRecords,failedRecords:c.details?.failedRecords,manualReviewRecords:c.details?.manualReviewRecords})),sentTexts:a.sentTexts,confirmedTexts:a.confirmedTexts,outboundStatuses:a.outboundStatuses,skippedFixtureCount:a.skippedFixtureCount,pendingOutboundCount:a.pendingOutboundCount,failedOutboundCount:a.failedOutboundCount,manualReviewCount:a.manualReviewCount,observedCount:r.messages.length,byKind:o.byKind,attachmentSummary:o.attachmentSummary,attachmentsDir:r.attachmentsDir,reportPath:i.join(e.options.outDir,"bottom-page-summary.json"),markdownPath:s,markdown:d}}}async function W(e,t,n={}){let r;const o=[];for(let s=1;s<=t;s+=1)try{const d=await X(e,n);return o.length&&(o.push({phase:"observe",attempt:s,ok:!0,observedCount:d.messages.length,at:new Date().toISOString()}),m(i.join(e.options.outDir,"observe-retry-events.json"),o)),d}catch(d){if(r=d,o.push({phase:"observe",attempt:s,ok:!1,errorSummary:d instanceof Error?d.message:String(d||""),at:new Date().toISOString()}),s>=t||!Le(d))break;try{const a=await y(e.helper,e.options.traceId),l=await I(e.helper,a,e.options.traceId),c=await x({helper:e.helper,window:l,binding:e.binding,runtime:e.runtime,api:k({serverUrl:e.options.serverUrl}),workDir:e.options.workDir,traceId:e.options.traceId});o.push({phase:"recover",attempt:s,ok:c.opened,reason:c.reason,windowId:l.windowId,at:new Date().toISOString()})}catch(a){o.push({phase:"recover",attempt:s,ok:!1,errorSummary:a instanceof Error?a.message:String(a||""),at:new Date().toISOString()})}m(i.join(e.options.outDir,"observe-retry-events.json"),o),await V("observe-retry",`${e.options.traceId}:observe-retry:${s}`,1500*s)}throw o.length&&m(i.join(e.options.outDir,"observe-retry-events.json"),o),r}function Le(e){const t=e instanceof Error?e.message:String(e||"");return/conversation_not_visible|wechat_window_unavailable|wechat_window_not_found|title_not_confirmed|server_observe_failed|timeout/i.test(t)}async function He(e){const t=await W(e,3),n=T(t.messages),r=i.join(e.options.outDir,"bottom-page.md"),o=S(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});return m(i.join(e.options.outDir,"bottom-page-summary.json"),n),m(i.join(e.options.outDir,"server-observe-messages.json"),t.messages),A(r,o),{step:"read-bottom-page",ok:n.messageCount>0,reasonCode:n.messageCount>0?void 0:"no_observed_messages",details:{messageCount:n.messageCount,byKind:n.byKind,attachmentSummary:n.attachmentSummary,attachmentsDir:t.attachmentsDir,reportPath:i.join(e.options.outDir,"bottom-page-summary.json"),markdownPath:r,markdown:o}}}async function Ue(e){const t=await W(e,3,{observePipeline:"edge-structure",persistLocalLedger:!0});O(e.options.outDir,"download-visible",t.observationEvidence);const n=T(t.messages),r=i.join(e.options.outDir,"download-visible.md"),o=S(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)}),s=K(t.messages,t.attachmentsDir,{observePipeline:t.observePipeline,downloadAnchorText:e.options.downloadAnchorText,ledgerPath:t.ledgerPath,ledgerBinding:t.ledgerBinding,traceHashes:t.traceHashes});m(i.join(e.options.outDir,"bottom-page-summary.json"),n),m(i.join(e.options.outDir,"download-visible-summary.json"),s),m(i.join(e.options.outDir,"download-visible-messages.json"),t.messages),A(r,o);const d=!!(e.options.allowEmptyMedia&&s.reasonCode==="no_visible_media_candidates"&&t.messages.length>0),a=s.ok||d;return{step:"download-visible-media",ok:a,reasonCode:a?void 0:s.reasonCode,details:{mediaCandidateCount:s.mediaCandidateCount,localAttachmentCount:s.localAttachmentCount,originalLocalAttachmentCount:s.originalLocalAttachmentCount,previewAttachmentCount:s.previewAttachmentCount,missingLocalPathCount:s.missingLocalPathCount,pendingAttachmentCount:s.pendingAttachmentCount,byKind:s.byKind,byAvailability:s.byAvailability,reasonCodes:s.reasonCodes,mediaReasonCode:s.reasonCode,allowEmptyMediaRead:d,attachmentsDir:t.attachmentsDir,reportPath:i.join(e.options.outDir,"download-visible-summary.json"),markdownPath:r,markdown:o,phases:s.phases,observePipeline:s.observePipeline,ledgerPath:s.ledgerPath,ledgerRevision:s.ledger?.revision,traceHashes:s.traceHashes,traceEvents:s.traceEvents}}}async function qe(e){const t=await W(e,3,{observePipeline:"server-observe"});O(e.options.outDir,"server-observe",t.observationEvidence),m(i.join(e.options.outDir,"server-observe-messages.json"),t.messages);const n=i.join(e.options.outDir,"server-observe.md"),r=S(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});A(n,r);const o=ne(t.messages);return{step:"server-observe",ok:t.messages.length>0,reasonCode:t.messages.length>0?void 0:"no_observed_messages",details:{observedCount:t.messages.length,byKind:H(t.messages.map(s=>s.kind||"unknown")),attachmentSummary:o,attachmentsDir:t.attachmentsDir,markdownPath:n,markdown:r}}}async function Ke(e){const t=await X(e,{observePipeline:"edge-structure",downloadMedia:!1});O(e.options.outDir,"structure-window",t.observationEvidence),m(i.join(e.options.outDir,"structure-window-messages.json"),t.messages);const n=i.join(e.options.outDir,"structure-window.md"),r=S(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});A(n,r);const o=ne(t.messages);return{step:"structure-window",ok:t.messages.length>0,reasonCode:t.messages.length>0?void 0:"no_observed_messages",details:{observedCount:t.messages.length,byKind:H(t.messages.map(s=>s.kind||"unknown")),attachmentSummary:o,attachmentsDir:t.attachmentsDir,markdownPath:n,markdown:r}}}async function X(e,t={}){const n=Se({sessionId:e.options.sessionId,observePipeline:t.observePipeline}),r=k({serverUrl:e.options.serverUrl});e.options.skipRuntimeUpsert||(n==="direct-edge-structure"?await r.upsertRuntime(e.runtime):await r.upsertRuntime(e.runtime,{...e.binding,enabled:!1,allowReply:!1}));const o=i.join(e.options.outDir,"inbound-attachments");p.mkdirSync(o,{recursive:!0});const s=t.persistLocalLedger?pt(e.options):void 0,d=s?ge(s,e.runtime.runtimeId):void 0;let a,l,c;const w=await ve({runtime:e.runtime,binding:{...e.binding,downloadMedia:t.downloadMedia??e.binding.downloadMedia},helper:e.helper,api:r,workDir:e.options.workDir,attachmentsDir:o,traceId:e.options.traceId,mediaAnchorText:e.options.downloadAnchorText,activityGuard:e.options.activityGuard,observePipeline:t.observePipeline,localLedgerTailAnchors:d?bt(d.bindings[e.binding.bindingId]):void 0,onObservationEvidence:({capture:u,ocr:b})=>{a=Ve(u),l=ze(b),c=Ge(u,b,{captureHash:a,ocrHash:l})}});let h,g;if(d&&s){const u=pe({ledger:d,bindingId:e.binding.bindingId,observedMessages:w});h=u.binding,g=se({bindingId:e.binding.bindingId,revision:h.revision,messages:u.newMessages}),we(s,d)}return{messages:w,attachmentsDir:o,observePipeline:t.observePipeline,...s?{ledgerPath:s}:{},...h?{ledgerBinding:h}:{},traceHashes:{...a?{captureHash:a}:{},...l?{ocrHash:l}:{},...g?{ingestPayloadHash:g}:{}},...c?{observationEvidence:c}:{}}}function Ge(e,t,n){return{capture:e,report:{screenshot:{width:e.width,height:e.height,mimeType:e.mimeType,...e.windowId?{windowId:e.windowId}:{}},hashes:n,ocrBlockCount:t.blocks?.length??0,visibleConversationFingerprintCount:t.visibleConversationFingerprints?.length??0,topTexts:(t.blocks??[]).slice(0,40).map(r=>({text:r.text,...r.bbox?{bbox:r.bbox}:{},...typeof r.confidence=="number"?{confidence:r.confidence}:{}}))}}}function O(e,t,n){if(!n)return;const r=n.capture.dataBase64?D(e,`${t}-observation-window`,n.capture):void 0;m(i.join(e,`${t}-observation-evidence.json`),{...n.report,...r?{screenshotPath:r}:{}})}function Ve(e){if(e.dataBase64)return`sha256:${M.createHash("sha256").update(Buffer.from(e.dataBase64,"base64")).digest("hex")}`}function ze(e){return se({blocks:(e.blocks??[]).map(t=>({text:t.text??"",bbox:t.bbox??null,confidence:typeof t.confidence=="number"?Number(t.confidence.toFixed(4)):null})),visibleConversationFingerprints:e.visibleConversationFingerprints??[]})}function Z(e,t){let n=t,r=0,o=0,s="";const d=[];return{actionLog:d,setScenario(l){n=l,r=0,o=0},async request(l,c,w){if(d.push(l),l==="activity.snapshot"){if(r+=1,r<=n.preflightBusySnapshots)return{id:`human-${r}`,ok:!0,result:{keyDownSecondsAgo:.2,mouseMovedSecondsAgo:.2,scrollWheelSecondsAgo:.2,privacy:{capturesKeyContent:!1,capturesMousePath:!1}},latencyMs:0,traceId:w};if(n.forceIdleAfterBusy)return{id:`human-${r}`,ok:!0,result:{keyDownSecondsAgo:60,mouseMovedSecondsAgo:60,leftMouseDownSecondsAgo:60,rightMouseDownSecondsAgo:60,scrollWheelSecondsAgo:60,privacy:{capturesKeyContent:!1,capturesMousePath:!1}},latencyMs:0,traceId:w}}if(l==="automation.lease.acquire"){const h=await e.request(l,c,w),g=h.result&&typeof h.result=="object"?h.result:{};return s=typeof g.leaseId=="string"?g.leaseId:"",h}return l==="automation.lease.status"?(o+=1,n.simulateInterruptionAtLeaseStatus===o?(d.push("automation.lease.simulateInterruption"),{id:`human-lease-${o}`,ok:!0,result:{active:!0,leaseId:s,interrupted:!0,interruptReason:n.interruptionReason||"recent_mouse_activity"},latencyMs:0,traceId:w}):{id:`human-lease-${o}`,ok:!0,result:{active:!0,leaseId:s,interrupted:!1},latencyMs:0,traceId:w}):e.request(l,c,w)}}}function Y(e){return e==="human-send-preflight-busy"||e==="human-send-preflight-busy-then-idle"||e==="human-send-user-active-timeout"||e==="human-observe-deferred"?{preflightBusySnapshots:100}:e==="human-send-takeover-during-run"||e==="human-send-takeover-then-idle"?{preflightBusySnapshots:0,forceIdleAfterBusy:!0,simulateInterruptionAtLeaseStatus:2,interruptionReason:"recent_mouse_activity"}:{preflightBusySnapshots:0,forceIdleAfterBusy:!0}}function Je(){return{preflightBusySnapshots:0,forceIdleAfterBusy:!0}}function Qe(e,t){return t.sendStatus!=="sent_unconfirmed"?!1:e==="human-send-normal"||e==="human-send-preflight-busy-then-idle"||e==="human-send-takeover-then-idle"}async function Xe(e){try{const t=await y(e.helper,e.traceId),n=await j(e.helper,t.windowId,e.traceId,t.bounds),r=D(e.outDir,e.filePrefix,n),o=await E(e.helper,n,e.traceId);m(i.join(e.outDir,`${e.filePrefix}-ocr.json`),{screenshotPath:r,ocr:o})}catch(t){m(i.join(e.outDir,`${e.filePrefix}-error.json`),{errorSummary:t instanceof Error?t.message:String(t||"after paste evidence failed")})}}async function F(e){const t=await y(e.helper,e.traceId),n=await I(e.helper,t,e.traceId);if(!(await x({helper:e.helper,window:n,binding:e.binding,runtime:e.runtime,api:e.api,workDir:e.workDir,traceId:e.traceId,settleToBottom:e.settleToBottom})).opened)return 0;const o=await j(e.helper,n.windowId,e.traceId),s=D(e.outDir,`${e.filePrefix}-observe-marker`,o),d=await E(e.helper,o,e.traceId);return m(i.join(e.outDir,`${e.filePrefix}-observe-marker-ocr.json`),{screenshotPath:s,marker:e.marker,ocr:d}),Ye(d.blocks||[],e.marker)}function Ze(e,t){const n=t.trim();if(!n)return 0;const r=e.map(d=>d.text||"").join(`
|
|
4
|
+
`),o=te(r,n);if(o>0)return o;const s=ee(n);return s.length<8?0:te(ee(r),s)}function Ye(e,t){const n=e.filter(et);return Ze(n,t)}function et(e){const t=e.bbox;if(!t)return!0;const n=Number(t.x),r=Number(t.y),o=Number(t.width);return[n,r,o].every(Number.isFinite)?n+o/2>=560&&r>=100:!0}function ee(e){return e.normalize("NFKC").replace(/[\s\u200B-\u200D\uFEFF]+/g,"")}function te(e,t){if(!t)return 0;let n=0,r=0;for(;;){const o=e.indexOf(t,r);if(o<0)break;n+=1,r=o+t.length}return n}async function tt(e){const t=Math.max(1,e.attempts??3),n=typeof e.targetGreaterThan=="number"&&Number.isFinite(e.targetGreaterThan)?e.targetGreaterThan:null;let r=0;for(let o=0;o<t;o+=1){if(r=await F({helper:e.helper,runtime:e.runtime,binding:e.binding,api:e.api,workDir:e.workDir,marker:e.marker,traceId:e.traceId,outDir:e.outDir,filePrefix:`${e.filePrefix}-${o+1}`,settleToBottom:e.settleToBottom}),n==null?r>0:r>n)return r;o<t-1&&await q(800)}return r}function nt(e,t,n){return n.length>0||e.sendStatus==="confirmed_echo"?"confirmed_echo":t.waitingRecords.length>0?"send_waiting_user_idle":t.failedRecords.length>0?e.failureCode==="user_active_timeout"?"failed:user_active_timeout":"outbound_send_failed":t.manualReviewRecords.length>0||e.sendStatus==="manual_review"?"manual_review":e.sendStatus==="sent_unconfirmed"?"sent_unconfirmed":e.sendStatus}function rt(e,t){return e==="human-send-preflight-busy"?t.outboundStatus==="queued"&&t.observedMarkerCount===0&&!t.actionLog.includes("clipboard.setText")&&!t.actionLog.includes("keyboard.shortcut"):e==="human-send-user-active-timeout"?t.outboundStatus==="failed"&&t.runStatus==="failed:user_active_timeout"&&t.observedMarkerCount===0&&!t.actionLog.includes("clipboard.setText")&&!t.actionLog.includes("keyboard.shortcut"):e==="human-send-takeover-during-run"?(t.outboundStatus==="queued"||t.outboundStatus==="manual_review")&&t.observedMarkerCount===0:e==="human-send-preflight-busy-then-idle"||e==="human-send-takeover-then-idle"||e==="human-send-normal"?t.outboundStatus==="confirmed_echo"||t.outboundStatus==="sent_unconfirmed"&&t.observedMarkerCount===1:t.runStatus==="observe_deferred_user_active"}function ot(e){return ye({runtimeId:e.runtimeId,machineId:e.machineId,pollIntervalMs:6e4,platform:e.platform,foregroundPolicy:"work",bindings:[{bindingId:`action-smoke:${_(e.conversation)}`,sessionId:e.sessionId||`action-smoke:${_(e.runtimeId)}`,conversationDisplayName:e.conversation,enabled:!0,allowReply:!0,downloadMedia:!0}]})}function st(e,t){const n=ue({platform:e.platform});if(!n.ok)throw new Error(`${n.reasonCode}: ${n.message}`);return new he({helperPath:n.helperPath,expectedHelperVersion:n.version||me,requiredCapabilities:ct(e),guardUnsafeWindowsCommands:(e.platform??process.platform)==="win32",skipUserActivityGuard:!0,cleanupWindowsOverlays:(e.platform??process.platform)==="win32",requestLogger:at(t)})}function at(e){return t=>{p.appendFileSync(e,`${JSON.stringify(it(t))}
|
|
5
|
+
`)}}function it(e){const t={phase:e.phase,at:e.at,id:e.id,command:e.command};return e.traceId&&(t.traceId=e.traceId),e.timeoutMs!=null&&(t.timeoutMs=e.timeoutMs),e.durationMs!=null&&(t.durationMs=e.durationMs),e.params!==void 0&&(t.params=$(e.params)),e.ok!==void 0&&(t.ok=e.ok),e.errorCode&&(t.errorCode=e.errorCode),e.errorSummary&&(t.errorSummary=e.errorSummary),e.latencyMs!=null&&(t.latencyMs=e.latencyMs),e.result!==void 0&&(t.result=$(e.result)),t}function $(e,t="",n=0){if(e==null||typeof e=="number"||typeof e=="boolean")return e;if(typeof e=="string")return dt(t,e)?{type:"string",length:e.length,sha256:M.createHash("sha256").update(e).digest("hex").slice(0,16),preview:e.slice(0,120)}:e;if(Array.isArray(e)){const s=e.slice(0,10).map(d=>$(d,t,n+1));return e.length>s.length?{type:"array",length:e.length,items:s}:s}if(typeof e!="object")return String(e);if(n>=5)return{type:"object",truncated:!0};const r=e,o={};for(const[s,d]of Object.entries(r))o[s]=$(d,s,n+1);return o}function dt(e,t){return t.length>240?!0:/(base64|bytes|data|image|screenshot|png|jpeg|jpg|buffer)/i.test(e)&&t.length>48}function ct(e){if((e.platform??process.platform)==="win32")return e.steps.some(t=>t.startsWith("send")||t.startsWith("human-send"))?B("send"):e.steps.some(t=>t==="download-visible-media")?B("download"):B("observe")}function lt(e){const t=String(e||"").trim().toLowerCase();if(t){if(t==="windows"||t==="win32")return"win32";if(t==="macos"||t==="darwin")return"darwin";throw new Error(`unsupported_wechat_smoke_platform:${e}`)}}function ut(e,t){const n=i.join(t.outDir,"fixtures");p.mkdirSync(n,{recursive:!0});const r=new Date().toISOString().replace(/[-:.TZ]/g,"").slice(0,14);if(e==="send-text")return{text:t.text||`codex-product-action text ${r}`};if(e==="send-file"){const o=t.filePath||i.join(n,`wechat-action-smoke-${r}.txt`);return t.filePath||p.writeFileSync(o,`Shennian WeChat product action smoke
|
|
6
|
+
${r}
|
|
7
|
+
`,"utf8"),{text:`codex-product-action file ${r}`,attachmentPath:o}}if(e==="send-image"){const o=t.imagePath||i.join(n,`wechat-action-smoke-${r}.png`);return t.imagePath||vt(o),{text:`codex-product-action image ${r}`,attachmentPath:o}}if(e==="send-video"){const o=t.videoPath||i.join(n,`wechat-action-smoke-${r}.mp4`);return!t.videoPath&&!yt(o)?{skipped:!0,reasonCode:"ffmpeg_unavailable_for_video_fixture"}:{text:`codex-product-action video ${r}`,attachmentPath:o}}throw new Error(`step ${e} is not a send step`)}function ne(e){const t=e.flatMap(n=>mt(n.mediaMetadata));return{count:t.length,byAvailability:H(t.map(n=>re(n,"availability")||"unknown")),localPaths:t.map(n=>re(n,"localPath")).filter(n=>!!n)}}function mt(e){if(!e||typeof e!="object")return[];const t=e;return Array.isArray(t.attachments)?t.attachments.filter(oe):oe(t.attachment)?[t.attachment]:t.localPath||t.url||t.availability||t.name||t.fileName?[t]:[]}function ht(e){const t=f(e,"--mode")||(e[0]?.startsWith("--")?"":e[0]);return t==="send"||t==="observe"||t==="all"||t==="open-read"?t:"open-read"}function ft(e){return e==="open-read"||e==="send-text"||e==="send-file"||e==="send-image"||e==="send-video"||e==="structure-window"||e==="server-observe"||e==="read-bottom-page"||e==="download-visible-media"||e==="send-and-confirm"||e==="human-send-preflight-busy"||e==="human-send-preflight-busy-then-idle"||e==="human-send-user-active-timeout"||e==="human-send-takeover-during-run"||e==="human-send-takeover-then-idle"||e==="human-send-normal"||e==="human-observe-deferred"?e:null}function gt(e,t){const n=[];for(let r=0;r<e.length;r+=1)e[r]===t&&e[r+1]&&n.push(e[r+1]);return n}function f(e,t){const n=e.indexOf(t),r=n>=0?e[n+1]:void 0;return r&&!r.startsWith("--")?r:void 0}function L(e){return e?i.resolve(e):void 0}function wt(e){return Array.from(new Set(e))}function D(e,t,n){const r=n.mimeType.includes("jpeg")?".jpg":".png",o=i.join(e,`${t}${r}`);return p.writeFileSync(o,Buffer.from(n.dataBase64,"base64")),o}function m(e,t){p.mkdirSync(i.dirname(e),{recursive:!0}),p.writeFileSync(e,`${JSON.stringify(t,null,2)}
|
|
8
|
+
`,"utf8")}function A(e,t){p.mkdirSync(i.dirname(e),{recursive:!0}),p.writeFileSync(e,t,"utf8")}function pt(e){return i.join(e.outDir,"wechat-channel-ledger.json")}function bt(e,t=3){return(e?.recent??[]).slice(-t).map(n=>({stableMessageKey:n.stableMessageKey,senderRole:n.senderRole,kind:n.kind,anchorText:n.anchorText??n.normalizedText??n.textExcerpt??null,anchorMetadata:n.anchorMetadata??null}))}function vt(e){p.writeFileSync(e,Buffer.from("iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAAVElEQVR4nO3PMQ0AMAgAMUTof2kOKWzo8mCqkmeX9waYtwOwG4DbANwG4DYAtwG4DcBtAG4DcBuA2wDcBuA2ALcBuA3AbQBuA3AbgNsA3AbgNgC3AbgNwG0AbgNwG8BPDyCqAzmh3yHRAAAAAElFTkSuQmCC","base64"))}function yt(e){return de("ffmpeg",["-y","-f","lavfi","-i","testsrc=size=160x120:rate=5","-t","1","-pix_fmt","yuv420p",e],{encoding:"utf8",stdio:"ignore",timeout:2e4}).status===0&&p.existsSync(e)}function H(e){const t={};for(const n of e)t[n]=(t[n]??0)+1;return t}function re(e,t){return typeof e[t]=="string"?e[t].trim():""}function oe(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function _(e){return M.createHash("sha256").update(e).digest("hex").slice(0,16)}function se(e){return`sha256:${M.createHash("sha256").update(St(e)).digest("hex")}`}function St(e){return JSON.stringify(U(e))}function U(e){if(Array.isArray(e))return e.map(U);if(!e||typeof e!="object")return e;const t=e;return Object.fromEntries(Object.keys(t).sort().map(n=>[n,U(t[n])]))}function kt(e){const t=e instanceof Error?e.message:String(e),n=t.split(":",1)[0]?.trim();return n&&/^[a-z0-9_/-]+$/i.test(n)?n.replace(/\//g,"_"):/permission|accessibility|screen|automation/i.test(t)?"permission_missing":/wechat.*window|window.*unavailable/i.test(t)?"wechat_window_unavailable":/observe|VLM|server|api/i.test(t)?"server_observe_failed":"action_smoke_failed"}function Ct(e){if(e==="wechat_duplicate_instance")return"\u8BF7\u5173\u95ED\u91CD\u590D\u767B\u5F55\u3001\u5DF2\u767B\u5F55\u63D0\u793A\u6216\u7B2C\u4E8C\u4E2A\u5FAE\u4FE1\u4E3B\u7A97\u53E3\uFF0C\u53EA\u4FDD\u7559\u4E00\u4E2A\u5DF2\u767B\u5F55\u7684 Windows \u5FAE\u4FE1\u4E3B\u7A97\u53E3\u540E\u91CD\u8BD5\u3002"}function q(e){return new Promise(t=>setTimeout(t,e))}function It(e){process.stdout.write(`${JSON.stringify({ok:e.ok,conversation:e.conversation,outDir:e.outDir,durationMs:e.durationMs,steps:e.steps.map(t=>({step:t.step,ok:t.ok,skipped:t.skipped,reasonCode:t.reasonCode,userAction:t.userAction,details:t.details,errorSummary:t.errorSummary}))},null,2)}
|
|
9
|
+
`)}async function xt(){const e=Ie(process.argv.slice(2)),t=await De(e);It(t),(!t.ok||e.requireServer&&t.steps.some(n=>n.step==="server-observe"&&!n.ok))&&process.exit(1)}process.argv[1]&&i.resolve(process.argv[1])===ce(import.meta.url)&&xt().catch(e=>{process.stderr.write(`${e instanceof Error?e.stack||e.message:String(e)}
|
|
10
|
+
`),process.exit(1)});export{T as buildBottomPageReport,K as buildDownloadVisibleMediaReport,Oe as buildSendAndConfirmEvidence,$e as buildSendStepAcceptance,Ye as countMarkerOccurrencesInChatContentBlocks,Ze as countMarkerOccurrencesInOcrBlocks,Ne as nextSmokeDrainWaitMs,Ie as parseWeChatChannelActionSmokeArgs,Se as resolveWeChatSmokeObserveSessionMode,De as runWeChatChannelActionSmoke,xe as stepsForMode};
|
package/dist/src/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Command as
|
|
2
|
-
Disconnecting...`)),v({level:"info",wsEvent:"daemon.stop"}),clearInterval(o)
|
|
1
|
+
import{Command as M}from"commander";import u from"chalk";import G from"node:os";import R from"node:fs";import{loadConfig as I,saveConfig as J,getConfigPath as j,getShennianDir as H,resolveShennianPath as N}from"./config/index.js";import{CliRelayClient as K}from"./relay/client.js";import{registerPairCommand as B,runSmartStart as W}from"./commands/pair.js";import{clearDaemonPidIfOwner as O,createDaemonInstanceId as Y,clearDaemonLauncher as T,findRunningDaemonProcessIds as q,isRemoteAccessDisabled as z,registerDaemonCommand as Q,writeDaemonPid as _,writeDaemonLauncher as P}from"./commands/daemon.js";import{registerAgentCommand as X}from"./commands/agent.js";import{registerManagerCommand as Z}from"./commands/manager.js";import{registerExternalCommand as ee}from"./commands/external.js";import{registerWeChatCommand as ne}from"./commands/wechat.js";import{registerRuntimeCommand as te}from"./commands/runtime.js";import{registerUpgradeCommand as oe}from"./commands/upgrade.js";import{registerToolsCommand as re}from"./commands/tools.js";import{SessionManager as se}from"./session/manager.js";import{SERVERS as k,regionToUrl as ae,urlToRegion as ie}from"./region.js";import{getCurrentVersion as L,handleStartupCrashCheck as ce,checkForUpdate as le,isUpgradeVersionInCooldown as me,recordUpgradeFailure as pe}from"./upgrade/engine.js";import{detectAgents as de}from"./agents/detect.js";import{augmentProcessPath as b}from"./env-path.js";b();const x=L(),ge=3e4,ue=5*6e4;import{getCachedAgentInfos as fe,resolveAgentInfos as he}from"./agents/model-registry.js";import{initCliLogReporter as ve,reportLog as v}from"./log-reporter.js";import{isNativeFusionEnabled as Se}from"./native-fusion/config.js";import{NativeSessionFusionService as we}from"./native-fusion/service.js";import{startDaemonLogRetention as Ie}from"./daemon-log.js";const ye=H(),De=N("daemon.pid");function $e(){try{const n=R.readFileSync(De,"utf-8").trim();if(n.startsWith("{")){const o=JSON.parse(n),r=Number(o.pid);return Number.isInteger(r)&&r>0?r:null}const t=parseInt(n,10);return Number.isInteger(t)&&t>0?t:null}catch{return null}}function Re(n){return n.replace(/^https:\/\//,"wss://").replace(/^http:\/\//,"ws://")}function ke(n){const t=[`trigger=${n.trigger??"unknown"}`,`phase=${n.phase}`,`code=${n.code??"unknown"}`,`attempt=${n.reconnectAttempt}`];return n.reason&&t.push(`reason=${n.reason}`),n.error&&t.push(`error=${n.error}`),t.join(" ")}async function F(n,t=5e3){const o=Date.now();for(;Date.now()-o<t;){try{process.kill(n,0)}catch{return!0}await new Promise(r=>setTimeout(r,100))}try{return process.kill(n,0),!1}catch{return!0}}const a=new M;a.name("shennian").description("Shennian \u2014 AI Agent Control Plane").version(x),a.option("--api <url>","Server URL override").option("--name <name>","Machine name",G.hostname()).action(async n=>{const t=I(),o=n.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??t.serverUrl??void 0;await W(o,n.name)}),a.command("run-service",{hidden:!0}).description("(internal) Connect to relay server, called by the background service").option("--api <url>","Server URL override").action(async n=>{const t=N("env.json");try{const e=JSON.parse(R.readFileSync(t,"utf-8"));for(const[g,m]of Object.entries(e))process.env[g]||(process.env[g]=m);b()}catch{}const o=Ie();z()&&(console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`),clearInterval(o),process.exit(0));const r=!!(process.env.INVOCATION_ID||process.env.JOURNAL_STREAM||process.env.SHENNIAN_DESKTOP_SERVER_URL),f=async(e,g)=>{console.log(`[${new Date().toISOString()}] ${g} (PID ${e})`),process.kill(e,"SIGTERM"),await F(e)||(process.kill(e,"SIGKILL"),await F(e,2e3))};try{const e=$e();if(e&&e!==process.pid)try{process.kill(e,0),r?await f(e,"managed start taking over from existing daemon"):(console.log(`[${new Date().toISOString()}] daemon already running (PID ${e}), skipping duplicate start`),process.exit(0))}catch{}}catch{}const p=q(process.pid);if(p.length>0)if(r)for(const e of p)try{await f(e,"managed start taking over from orphan daemon")}catch{}else console.log(`[${new Date().toISOString()}] daemon already running (PID ${p[0]}), skipping duplicate start`),process.exit(0);const i=Y();_(process.pid,i,{version:x}),P(process.pid,void 0,i),process.on("exit",()=>{O(process.pid,i),T(i)}),await ce()&&(console.log(`[${new Date().toISOString()}] Rolled back to previous version, restarting...`),process.exit(0));const s=I();s.machineToken||(console.error(u.red("\u2717 Not paired yet. Run: shennian")),process.exit(1));const c=n.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??s.serverUrl??k.cn.url,S=`${Re(c)}/relay/machine`,d=L(),D=de(),h=D.map(e=>e.type),$=fe(D);s.machineId&&ve(c,s.machineId),console.log(`[${new Date().toISOString()}] Connecting to ${S}... (v${d}) agents: ${h.join(",")}`),v({level:"info",wsEvent:"daemon.start",metadata:{version:d,agents:h}});let w=null;const l=new K({serverUrl:S,machineToken:s.machineToken,cliVersion:d,agentList:h,onConnected:()=>{console.log(`[${new Date().toISOString()}] \u2713 Connected`),v({level:"info",wsEvent:"daemon.connected"}),$.some(e=>e.models.length>0)&&l.sendEvent({type:"event",event:"machine.agents",payload:{agentList:h,agents:$}}),he(D,{serverUrl:s.serverUrl??c,authToken:s.machineToken??s.accessToken}).then(e=>{JSON.stringify(e)!==JSON.stringify($)&&l.sendEvent({type:"event",event:"machine.agents",payload:{agentList:h,agents:e}})}).catch(()=>{}),import("./upgrade/engine.js").then(({readUpgradeAttempt:e,clearUpgradeAttempt:g})=>{const m=e();g(),m&&(console.log(`[${new Date().toISOString()}] [upgrade] Reporting success: ${m.from} \u2192 ${m.to}`),l.sendEvent({type:"event",event:"upgrade",payload:{state:"success",machineId:"self",from:m.from,to:m.to}}))}).catch(()=>{}),Ee(l,s.autoUpgrade??"patch",d),w?.handleConnected()},onDisconnected:e=>{console.log(`[${new Date().toISOString()}] \u26A0 Disconnected, reconnecting... ${ke(e)}`),v({level:"warn",wsEvent:"daemon.disconnected",metadata:{code:e.code,reason:e.reason,error:e.error,phase:e.phase,trigger:e.trigger,reconnectAttempt:e.reconnectAttempt}})},onReq:e=>{console.log(`[${new Date().toISOString()}] [req] ${e.method}`),v({level:"info",type:"ws",wsEvent:e.method,wsDirection:"in",traceId:e.traceId}),C.handleReq(e)}});w=Se()?new we(l):null;const C=new se(l,w,d);R.mkdirSync(ye,{recursive:!0}),_(process.pid,i,{version:d}),P(process.pid,void 0,i),l.connect(),process.stdin.resume();let U=!1;const A=async()=>{if(!U){U=!0,console.log(u.gray(`
|
|
2
|
+
Disconnecting...`)),v({level:"info",wsEvent:"daemon.stop"}),clearInterval(o);try{await C.cleanup(),w?.stop(),l.disconnect(),O(process.pid,i),T(i)}finally{process.exit(0)}}};process.on("SIGINT",()=>{A()}),process.on("SIGTERM",()=>{A()})});const V=a.command("config").description("View or modify configuration");V.command("show",{isDefault:!0}).description("Show current configuration").action(()=>{console.log(`Config file: ${j()}`);const t={...I()};if(t.machineToken&&(t.machineToken=t.machineToken.slice(0,12)+"..."),t.serverUrl){const o=ie(t.serverUrl);console.log(`Region: ${o} (${k[o].label})`)}console.log(JSON.stringify(t,null,2))}),V.command("set").description("Update a config value").argument("<key>",'Config key (e.g. "server")').argument("<value>",'Config value (e.g. "cn" or "global")').action((n,t)=>{const o=I();if(n==="server"){t!=="cn"&&t!=="global"&&(console.error(u.red('\u2717 Value must be "cn" or "global"')),process.exit(1));const r=t;o.serverUrl=ae(r),J(o),console.log(u.green(`\u2713 Server set to ${k[r].label}`)),console.log(u.yellow(" Restart the background service for this to take effect: shennian stop && shennian start"));return}console.error(u.red(`\u2717 Unknown config key: ${n}. Supported: server`)),process.exit(1)}),B(a),Q(a),X(a),Z(a),ee(a),ne(a),te(a),oe(a),re(a),a.parse();async function Ee(n,t,o){if(t==="none")return;let r=!1;const f=async()=>{if(r)return;let p;try{p=await le(o)}catch{return}if(!p.hasUpdate)return;const{changeType:i,current:E,latest:s}=p;if(!(t==="patch"&&i!=="patch")&&!(t==="minor"&&i==="major")&&!me(s)){console.log(`[${new Date().toISOString()}] [upgrade] ${E} \u2192 ${s} (${i}), auto-upgrading...`),r=!0;try{const{handleUpgradeStart:c}=await import("./commands/upgrade.js");await c(n,"auto-upgrade",s,{currentVersion:o})}catch(c){const y=c instanceof Error?c.message:String(c),S=pe(s,y);console.log(`[${new Date().toISOString()}] [upgrade] ${s} failed, retry after ${new Date(S.nextRetryAt).toISOString()}: ${y}`)}finally{r=!1}}};setTimeout(()=>{f()},ge),setInterval(()=>{f()},ue)}
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import
|
|
2
|
-
`).trim()}function le(r){try{const e=JSON.parse(r),a=e.type==="tool_result"||e.result?"tool_result":"tool_call",n=e.name||"tool",t=typeof e.result=="string"?e.result.replace(/\s+/g," ").trim():"",i=t.length>220?`${t.slice(0,220)}...`:t;return i?`[${a}] ${n}: ${i}`:`[${a}] ${n}`}catch{return"[tool]"}}function P(r){if(!r||typeof r!="object")return;const e=r,a=String(e.kind||""),n=String(e.name||""),t=String(e.mimeType||""),i=String(e.dataBase64||""),o=String(e.localPath||""),s=String(e.url||""),l=Number(e.size||0);if(i)throw new Error("Manager IPC external attachments must use localPath or url; dataBase64 is not accepted");if(!(a!=="image"&&a!=="video"&&a!=="file")&&!(!n||!t||!Number.isFinite(l)||l<0)&&!(!o&&!s))return{kind:a,name:n,mimeType:t,size:l,...o?{localPath:o}:{},...s?{url:s}:{}}}function W(r){const e=r.binding&&typeof r.binding=="object"&&!Array.isArray(r.binding)?r.binding:{},a=String(e.sessionId||r.managerSessionId||"").trim(),n=String(e.channelId||"").trim(),t=String(e.conversationId||"").trim(),i=String(e.conversationName||r.conversation||"").trim(),o=String(e.workDir||r.workDir||"").trim();if(!a)throw new Error("WeChat tool sessionId is required");if(!n)throw new Error("WeChat tool channelId is required");if(!t)throw new Error("WeChat tool conversationId is required");if(!i)throw new Error("WeChat tool conversationName is required");if(!o)throw new Error("WeChat tool workDir is required");return{sessionId:a,channelId:n,conversationId:t,conversationName:i,workDir:o}}function de(r,e){const a=[...r].sort((d,c)=>d.ts-c.ts),n=[];let t=null,i=null,o=null,s="";const l=()=>{if(!t)return;const d=s.trim();d&&n.push({...t,id:`${t.id}-compact`,payload:d}),t=null,i=null,o=null,s=""};for(const d of a){if(Y(d.payload)){l();continue}if(d.role==="user"){l(),n.push(d);continue}if(V(d.payload)){l(),n.push({...d,payload:le(d.payload)});continue}const c=G(d.payload);if(!c.trim())continue;const h=ie(d.id),g=ce(d.id);t&&t.role===d.role&&i===h&&h&&g!==null&&o!==null&&g===o+1?(s+=c,t.ts=d.ts,o=g):(l(),t=d,i=h,o=g,s=c)}return l(),n.slice(-e).sort((d,c)=>c.ts-d.ts)}async function ue(r){const e=[];let a=0;for await(const t of r){const i=Buffer.from(t);if(a+=i.byteLength,Number.isFinite(C)&&C>0&&a>C)throw new Error(`Manager IPC request body is too large. Max: ${C} bytes.`);e.push(i)}const n=Buffer.concat(e).toString("utf-8");return n?JSON.parse(n):{}}function w(r,e,a,n){r.client.sendRes({type:"res",id:e,ok:a,...a?{payload:n}:{error:String(n.error||"unknown error")}})}function v(r){return/binding not found|unknown method|not supported|relay is not connected|no external channel/i.test(r)}function $(){return he()?y.join(x.tmpdir(),"shennian-vitest-runtime",String(process.pid),"manager-ipc.json"):te("runtime","manager-ipc.json")}function he(){return(process.env.VITEST==="true"||!!process.env.VITEST_WORKER_ID)&&!process.env.SHENNIAN_HOME?.trim()}class Fe{opts;registry=new Q;channelRuntime;server=null;ipcUrl=null;ipcToken=K(24).toString("hex");healthTimer=null;startPromise=null;workerTextAcc=new Map;weChatAutomationLane;constructor(e){this.opts=e,this.weChatAutomationLane=e.weChatAutomationLane??se(),this.channelRuntime=e.channelRuntime??new Z((a,n)=>{this.handleExternalMessage(a,n)},a=>this.registry.createReplyTarget(a).replyTarget,{createWeChatRpaProductRunner:e.createWeChatRpaProductRunner,weChatAutomationLane:this.weChatAutomationLane})}async start(){return this.startPromise?this.startPromise:(this.startPromise=this.doStart(),this.startPromise)}async doStart(){if(this.server)return;this.server=U.createServer((a,n)=>{this.handleIpc(a,n)}),await new Promise((a,n)=>{this.server.once("error",n),this.server.listen(0,"127.0.0.1",()=>a())});const e=this.server.address();typeof e=="object"&&e&&(this.ipcUrl=`http://127.0.0.1:${e.port}`,this.writeIpcRuntimeFile()),this.server.unref(),await this.channelRuntime.start(),this.broadcastConfiguredChannelStatuses(),this.healthTimer=setInterval(()=>this.scanWorkerHealth(),6e4),this.healthTimer.unref()}async ready(){await this.start()}async stop(){this.healthTimer&&clearInterval(this.healthTimer),this.healthTimer=null,await this.channelRuntime.stop(),await new Promise(e=>{if(!this.server)return e();this.server.close(()=>e())}),this.server=null,this.ipcUrl=null,this.removeIpcRuntimeFile()}writeIpcRuntimeFile(){if(this.ipcUrl)try{const e=$();k.mkdirSync(y.dirname(e),{recursive:!0}),k.writeFileSync(e,JSON.stringify({url:this.ipcUrl,token:this.ipcToken,pid:process.pid,updatedAt:new Date().toISOString()},null,2),{mode:384}),k.chmodSync(e,384)}catch{}}removeIpcRuntimeFile(){try{const e=$(),a=JSON.parse(k.readFileSync(e,"utf-8"));(a.url===this.ipcUrl||a.token===this.ipcToken)&&k.unlinkSync(e)}catch{}}getInjectedEnv(e,a,n,t){return this.ipcUrl?{SHENNIAN_MANAGER_SESSION_ID:e,SHENNIAN_MANAGER_AGENT_SESSION_ID:a??"",SHENNIAN_MANAGER_WORKDIR:S(n),SHENNIAN_MANAGER_MODEL:t,SHENNIAN_MANAGER_IPC_URL:this.ipcUrl,SHENNIAN_MANAGER_IPC_TOKEN:this.ipcToken}:{}}registerManager(e){this.registry.upsertManager({...e,workDir:S(e.workDir),machineId:process.env.SHENNIAN_MACHINE_ID??null})}setManagerWorkerDefaults(e,a,n){const t=this.registry.getManager(e);t&&this.registry.upsertManager({...t,defaultWorkerAgentType:a??null,defaultWorkerModelId:n??null})}getManagerWorkerDefaults(e){const a=this.registry.getManager(e);return{agentType:a?.defaultWorkerAgentType??null,modelId:a?.defaultWorkerModelId??null}}noteManagerAgentSession(e,a,n,t){this.registry.upsertManager({sessionId:e,agentSessionId:a,workDir:S(n),machineId:process.env.SHENNIAN_MACHINE_ID??null,modelId:t})}noteAgentEvent(e,a){if(!this.findWorker(e))return;const t={lastActivityAt:new Date().toISOString(),runId:a.runId};a.agentSessionId&&(t.agentSessionId=a.agentSessionId);const i=`${e}:${a.runId}`;if(a.state==="delta"&&a.text&&!a.thinking){const s=(this.workerTextAcc.get(i)??"")+a.text;this.workerTextAcc.set(i,s);const l=D(s);l&&(t.summary=l.length>160?`${l.slice(0,160)}...`:l)}if(a.state==="final"||a.state==="error"||a.state==="aborted"){t.status=a.state;const s=D(this.workerTextAcc.get(i)??"");s&&(t.summary=s.length>240?`${s.slice(0,240)}...`:s),this.workerTextAcc.delete(i)}else a.state==="start"&&(t.status="running");const o=this.registry.updateWorker(e,t);o&&(a.state==="final"||a.state==="error"||a.state==="aborted")&&this.wakeManagerForWorker(o.managedBy,o,a.state,a.message)}findWorker(e){return this.registry.load().workers[e]}async handleAppReq(e){const a=this.opts.getRuntime(),n=e.params??{};try{const t=String(n.managerSessionId||n.sessionId||"");if(!t)throw new Error("sessionId is required");const i=this.registry.getManager(t),o=e.method==="session.wechat-rpa.channel.get"||e.method==="manager.wechat-rpa.channel.get",s=e.method==="session.wechat-rpa.channel.upsert"||e.method==="manager.wechat-rpa.channel.upsert",l=e.method==="session.wechat-rpa.channel.sync"||e.method==="manager.wechat-rpa.channel.sync",d=e.method==="session.wechat-rpa.outbound.cancel"||e.method==="manager.wechat-rpa.outbound.cancel";if(e.method==="manager.channel.get"){w(a,e.id,!0,{channel:this.channelRuntime.getManagerChannel(t,"websocket",{includeSecret:!0})});return}if(e.method==="manager.channel.upsert"){const c=await this.channelRuntime.upsertManagerChannel({id:String(n.id||`websocket:${t}`),managerSessionId:t,sessionId:t,workDir:String(n.workDir||i?.workDir||""),type:"websocket",name:typeof n.name=="string"?n.name:void 0,agentType:typeof n.agentType=="string"?n.agentType:void 0,agentSessionId:typeof n.agentSessionId=="string"?n.agentSessionId:null,modelId:typeof n.modelId=="string"?n.modelId:null,enabled:!!n.enabled,wsUrl:typeof n.wsUrl=="string"?n.wsUrl:void 0,token:typeof n.token=="string"?n.token:void 0,canReply:n.canReply===void 0?void 0:!!n.canReply,systemPrompt:typeof n.systemPrompt=="string"?n.systemPrompt:void 0});this.broadcastManagerChannelStatus(t),w(a,e.id,!0,{channel:c});return}if(o){w(a,e.id,!0,{channel:this.channelRuntime.getManagerChannel(t,"wechat-rpa",{includeSecret:!0})});return}if(s){const c=await this.channelRuntime.upsertManagerWeChatRpaChannel({id:String(n.id||`wechat-rpa:${t}`),managerSessionId:t,sessionId:t,workDir:S(String(n.workDir||i?.workDir||"")),name:typeof n.name=="string"?n.name:void 0,agentType:typeof n.agentType=="string"?n.agentType:void 0,agentSessionId:typeof n.agentSessionId=="string"?n.agentSessionId:null,modelId:typeof n.modelId=="string"?n.modelId:null,enabled:!!n.enabled,groups:_(n.groups),canReply:n.canReply===void 0?void 0:!!n.canReply,systemPrompt:typeof n.systemPrompt=="string"?n.systemPrompt:void 0,source:B(n.source),pollIntervalMs:m(n.pollIntervalMs),recentLimit:m(n.recentLimit),idleSeconds:m(n.idleSeconds),forceForeground:n.forceForeground===void 0?void 0:!!n.forceForeground,noRestore:n.noRestore===void 0?void 0:!!n.noRestore,downloadAttachments:n.downloadAttachments===void 0?void 0:!!n.downloadAttachments,downloadAttachmentsDir:typeof n.downloadAttachmentsDir=="string"?n.downloadAttachmentsDir:void 0,selfNickname:typeof n.selfNickname=="string"?n.selfNickname:void 0,privacyConsentAccepted:n.privacyConsentAccepted===void 0?void 0:!!n.privacyConsentAccepted,flowScriptPath:typeof n.flowScriptPath=="string"?n.flowScriptPath:void 0});this.broadcastManagerChannelStatus(t),w(a,e.id,!0,{channel:c});return}if(l){const c=await this.channelRuntime.syncManagerWeChatRpaChannel(t);this.broadcastManagerChannelStatus(t),w(a,e.id,!0,c);return}if(d){const c=await this.channelRuntime.cancelManagerWeChatRpaOutbound({managerSessionId:t,idempotencyKey:typeof n.idempotencyKey=="string"?n.idempotencyKey:null,replyId:typeof n.replyId=="string"?n.replyId:null,reason:typeof n.reason=="string"?n.reason:"user_cancelled"});this.broadcastManagerChannelStatus(t),w(a,e.id,!0,c);return}throw new Error(`Unsupported manager app method: ${e.method}`)}catch(t){w(a,e.id,!1,{error:t instanceof Error?t.message:String(t)})}}broadcastConfiguredChannelStatuses(){for(const e of this.channelRuntime.listManagerChannelStatuses())this.broadcastManagerChannelStatus(e.managerSessionId)}broadcastManagerChannelStatus(e){const a=this.opts.getRuntime();if(!a.client?.sendEvent)return;const n=this.registry.getManager(e),t=this.channelRuntime.getManagerChannelStatus(e),i=this.channelRuntime.getManagerChannel(e,"wechat-rpa")??this.channelRuntime.getManagerChannel(e,"websocket");a.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e,agentType:n?"manager":i?.agentType,agentSessionId:n?.agentSessionId??i?.agentSessionId??null,modelId:n?.modelId??i?.modelId??null,workDir:n?.workDir??i?.workDir,externalChannel:t}}})}async handleIpc(e,a){if(e.headers.authorization!==`Bearer ${this.ipcToken}`){u(a,401,{ok:!1,error:"Unauthorized"});return}try{const n=new URL(e.url??"/","http://127.0.0.1"),t=await ue(e),i=String(t.managerSessionId||e.headers["x-shennian-manager-session-id"]||"");if(!i)throw new Error("managerSessionId is required");const o=this.registry.getManager(i);if(n.pathname==="/sessions/list"){if(!o)throw new Error("Manager runtime is not registered");const s=new Set(this.opts.getRuntime().sessions.keys());u(a,200,{ok:!0,sessions:this.registry.listWorkers(i,{runningSessionIds:s})});return}if(n.pathname==="/sessions/start"){if(!o)throw new Error("Manager runtime is not registered");const s=String(t.agentType||t.agent||o.defaultWorkerAgentType||"codex");if(!oe(s))throw new Error(`Unsupported manager worker agent: ${s}`);const l=S(String(t.workDir||o.workDir));if(l!==o.workDir)throw new Error("Manager can only start workers in the same workDir");const d=String(t.message||"");if(!d)throw new Error("message is required");const c=this.registry.addWorker({managerSessionId:i,agentType:s,workDir:l,summary:d.slice(0,120)}),h=String(t.modelId||(s===o.defaultWorkerAgentType?o.defaultWorkerModelId??"":""));await this.dispatchChatSend(c.sessionId,s,l,d,null,h),u(a,200,{ok:!0,session:c});return}if(n.pathname==="/sessions/send"){const s=String(t.sessionId||""),l=String(t.message||""),d=t.enqueue===void 0?!0:!!t.enqueue,c=this.registry.getWorkerForManager(i,s);if(!c)throw new Error("Worker not found in this manager scope");const h=String(t.modelId||(c.agentType===o?.defaultWorkerAgentType?o.defaultWorkerModelId??"":""));d?await this.dispatchChatEnqueue(c.sessionId,c.agentType,c.workDir,l,c.agentSessionId??null,h):await this.dispatchChatSend(c.sessionId,c.agentType,c.workDir,l,c.agentSessionId??null,h),u(a,200,{ok:!0});return}if(n.pathname==="/sessions/queue"){const s=String(t.sessionId||"");if(!this.registry.getWorkerForManager(i,s))throw new Error("Worker not found in this manager scope");const d=this.opts.getRuntime().chatQueue?.getSnapshot(s);u(a,200,{ok:!0,queue:d});return}if(n.pathname==="/sessions/queue/edit"){const s=String(t.sessionId||"");if(!this.registry.getWorkerForManager(i,s))throw new Error("Worker not found in this manager scope");await this.opts.dispatchReq({type:"req",id:`manager-queue-edit-${p()}`,method:"chat.queue.edit",params:{sessionId:s,queueMessageId:String(t.queueMessageId||t.messageId||""),text:String(t.message||t.text||"")}}),u(a,200,{ok:!0,queue:this.opts.getRuntime().chatQueue?.getSnapshot(s)});return}if(n.pathname==="/sessions/queue/delete"){const s=String(t.sessionId||"");if(!this.registry.getWorkerForManager(i,s))throw new Error("Worker not found in this manager scope");await this.opts.dispatchReq({type:"req",id:`manager-queue-delete-${p()}`,method:"chat.queue.delete",params:{sessionId:s,queueMessageId:String(t.queueMessageId||t.messageId||"")}}),u(a,200,{ok:!0,queue:this.opts.getRuntime().chatQueue?.getSnapshot(s)});return}if(n.pathname==="/sessions/stop"||n.pathname==="/sessions/terminate"){const s=String(t.sessionId||"");if(!this.registry.getWorkerForManager(i,s))throw new Error("Worker not found in this manager scope");await this.opts.dispatchReq({type:"req",id:`manager-abort-${p()}`,method:"chat.abort",params:{sessionId:s}}),this.registry.updateWorker(s,{status:"aborted"}),u(a,200,{ok:!0});return}if(n.pathname==="/sessions/read"){const s=String(t.sessionId||""),l=Number(t.limit||200);if(!this.registry.getWorkerForManager(i,s))throw new Error("Worker not found in this manager scope");const c=X(s,{limit:Math.max(l*20,l)});u(a,200,{ok:!0,messages:de(c,l),rawMessageCount:c.length});return}if(n.pathname==="/memory/path"){if(!o)throw new Error("Manager runtime is not registered");u(a,200,{ok:!0,path:y.join(o.workDir,".shennian")});return}if(n.pathname==="/external/reply"){const s=typeof t.replyTarget=="string"?this.registry.getReplyTarget(t.replyTarget):this.registry.getLatestReplyTargetForManager(i),l=String(t.text||""),d=P(t.attachment),c=String(t.idempotencyKey||p()),h=String(t.channelId||""),g=String(t.conversationId||""),R=!s&&(!h||!g)?await this.channelRuntime.getDefaultReplyTarget(i).catch(()=>null):null,M=s?.channelId||h||R?.channelId||"",b=s?.conversationId||g||R?.conversationId||"";if(M&&this.channelRuntime.getChannelById(M)){if(!b)throw new Error("No external channel target is available for this Manager");const f=await this.channelRuntime.reply({managerSessionId:i,channelId:M,conversationId:b,messageId:s?.messageId??void 0,text:l,attachment:d,idempotencyKey:c});u(a,f.ok?200:400,f);return}let I;try{I=await this.sendManagedWeComReply({managerSessionId:i,text:l,attachment:d,idempotencyKey:c})}catch(f){const T=f instanceof Error?f.message:String(f);if(!v(T))throw f;I={ok:!1,error:T}}if(I.ok){u(a,200,{ok:!0,payload:I.payload});return}if(!v(I.error||"")||!M||!b){u(a,400,{ok:!1,error:I.error||"External send failed"});return}u(a,400,{ok:!1,error:`No local external channel is configured for ${M}`});return}if(n.pathname==="/channel/get"){u(a,200,{ok:!0,channel:this.channelRuntime.getManagerChannel(i,"websocket")});return}if(n.pathname==="/channel/upsert"){if(!o)throw new Error("Manager runtime is not registered");const s=await this.channelRuntime.upsertManagerChannel({id:String(t.id||`websocket:${i}`),managerSessionId:i,workDir:o.workDir,type:"websocket",name:typeof t.name=="string"?t.name:void 0,enabled:!!t.enabled,wsUrl:typeof t.wsUrl=="string"?t.wsUrl:void 0,token:typeof t.token=="string"?t.token:void 0,canReply:t.canReply===void 0?void 0:!!t.canReply,systemPrompt:typeof t.systemPrompt=="string"?t.systemPrompt:void 0});this.registry.upsertManager({...o,status:o.status}),this.broadcastManagerChannelStatus(i),u(a,200,{ok:!0,channel:s});return}if(n.pathname==="/wechat-rpa/tool/read"){const s=W(t),l=m(t.limit)??10,d=typeof t.traceId=="string"?t.traceId:void 0;let c;try{c=await this.weChatAutomationLane.run(`wechat-tool:read:${s.channelId}`,()=>re(s,{conversation:s.conversationName,workDir:s.workDir,sessionId:s.sessionId,limit:l,recentLimit:l,download:t.download==="never"?"never":"auto",traceId:d,timeoutMs:m(t.timeoutMs)}))}catch(h){u(a,400,{ok:!1,...O(h,d)});return}u(a,200,{ok:!0,messages:c.messages,outDir:c.outDir,helperTracePath:c.helperTracePath,activityGuardPath:c.activityGuardPath});return}if(n.pathname==="/wechat-rpa/tool/send"){const s=W(t),l=String(t.text||""),d=P(t.attachment),c=typeof t.traceId=="string"?t.traceId:void 0;let h;try{h=await this.weChatAutomationLane.run(`wechat-tool:send:${s.channelId}`,()=>ae(s,{conversation:s.conversationName,workDir:s.workDir,sessionId:s.sessionId,text:l,attachment:d,traceId:c,timeoutMs:m(t.timeoutMs)}))}catch(g){u(a,400,{ok:!1,...O(g,c)});return}u(a,200,{ok:!0,...h});return}if(n.pathname==="/wechat-rpa/channel/get"){u(a,200,{ok:!0,channel:this.channelRuntime.getManagerChannel(i,"wechat-rpa",{includeSecret:!0})});return}if(n.pathname==="/wechat-rpa/channel/upsert"){const s=S(String(t.workDir||o?.workDir||""));if(!s)throw new Error("workDir is required");const l=await this.channelRuntime.upsertManagerWeChatRpaChannel({id:String(t.id||`wechat-rpa:${i}`),managerSessionId:i,sessionId:i,workDir:s,name:typeof t.name=="string"?t.name:void 0,agentType:typeof t.agentType=="string"?t.agentType:void 0,agentSessionId:typeof t.agentSessionId=="string"?t.agentSessionId:null,modelId:typeof t.modelId=="string"?t.modelId:null,enabled:!!t.enabled,groups:_(t.groups),canReply:t.canReply===void 0?void 0:!!t.canReply,systemPrompt:typeof t.systemPrompt=="string"?t.systemPrompt:void 0,source:B(t.source),pollIntervalMs:m(t.pollIntervalMs),recentLimit:m(t.recentLimit),idleSeconds:m(t.idleSeconds),forceForeground:t.forceForeground===void 0?void 0:!!t.forceForeground,noRestore:t.noRestore===void 0?void 0:!!t.noRestore,downloadAttachments:t.downloadAttachments===void 0?void 0:!!t.downloadAttachments,downloadAttachmentsDir:typeof t.downloadAttachmentsDir=="string"?t.downloadAttachmentsDir:void 0,selfNickname:typeof t.selfNickname=="string"?t.selfNickname:void 0,privacyConsentAccepted:t.privacyConsentAccepted===void 0?void 0:!!t.privacyConsentAccepted,flowScriptPath:typeof t.flowScriptPath=="string"?t.flowScriptPath:void 0});o&&this.registry.upsertManager({...o,status:o.status}),this.broadcastManagerChannelStatus(i),u(a,200,{ok:!0,channel:l});return}if(n.pathname==="/wechat-rpa/channel/sync"){const{channel:s,messages:l}=await this.channelRuntime.syncManagerWeChatRpaChannel(i);this.broadcastManagerChannelStatus(i),u(a,200,{ok:!0,channel:s,messages:l});return}if(n.pathname==="/wechat-rpa/outbound/cancel"){const s=await this.channelRuntime.cancelManagerWeChatRpaOutbound({managerSessionId:i,idempotencyKey:typeof t.idempotencyKey=="string"?t.idempotencyKey:null,replyId:typeof t.replyId=="string"?t.replyId:null,reason:typeof t.reason=="string"?t.reason:"user_cancelled"});this.broadcastManagerChannelStatus(i),u(a,200,{ok:!0,...s});return}u(a,404,{ok:!1,error:`Unknown manager IPC path: ${n.pathname}`})}catch(n){u(a,400,{ok:!1,error:n instanceof Error?n.message:String(n)})}}async dispatchChatSend(e,a,n,t,i,o){await this.opts.dispatchReq({type:"req",id:`manager-send-${p()}`,method:"chat.send",params:{sessionId:e,text:t,agentType:a,workDir:n,agentSessionId:i,modelId:o}})}async dispatchChatEnqueue(e,a,n,t,i,o){await this.opts.dispatchReq({type:"req",id:`manager-enqueue-${p()}`,method:"chat.enqueue",params:{sessionId:e,text:t,agentType:a,workDir:n,agentSessionId:i,modelId:o}})}async sendManagedWeComReply(e){const a=ee(e.text);if(!a.length&&!e.attachment)return{ok:!1,error:"text or attachment is required"};const n=this.opts.getRuntime().client;if(!n||typeof n.sendReq!="function")return{ok:!1,error:"Relay is not connected"};const t=[];for(const[i,o]of a.entries()){const s=await n.sendReq({type:"req",id:`external-send-${p()}`,method:"external.send",params:{managerSessionId:e.managerSessionId,text:o,idempotencyKey:a.length>1?`${e.idempotencyKey}:${i+1}`:e.idempotencyKey}});if(!s.ok)return{ok:!1,error:s.error||"External send failed"};t.push(s.payload)}if(e.attachment){const i=await n.sendReq({type:"req",id:`external-send-${p()}`,method:"external.send",params:{managerSessionId:e.managerSessionId,attachment:e.attachment,idempotencyKey:a.length?`${e.idempotencyKey}:attachment`:e.idempotencyKey}});if(!i.ok)return{ok:!1,error:i.error||"External send failed"};t.push(i.payload)}return{ok:!0,payload:t.length===1?t[0]:t}}wakeManagerForWorker(e,a,n,t){const i=this.registry.getManager(e);if(!i)return;const o=`\u4F60\u7BA1\u7406\u7684 worker \u5DF2\u7ED3\u675F\u3002
|
|
1
|
+
import K from"node:http";import{randomBytes as G,randomUUID as p}from"node:crypto";import k from"node:fs";import N from"node:os";import y from"node:path";import{AVAILABLE_BUILTIN_AGENT_TYPES as H,extractPayloadText as j,formatExternalConversationText as z,formatExternalMessageLine as J,formatExternalAttachmentReference as Y,isAgentHiddenPayload as V,isToolPayload as Q}from"@shennian/wire";import{ManagerRegistry as X}from"./registry.js";import{readMessages as Z}from"../session/store.js";import{ChannelRuntime as ee}from"../channels/runtime.js";import{splitExternalReplyText as te}from"../channels/reply-split.js";import{resolveShennianPath as ne}from"../config/index.js";import{buildExternalChannelInstructions as re}from"../agents/external-channel-instructions.js";import{readDirectWeChatLatestOnce as ae,sendDirectWeChatMessageOnce as se}from"../commands/wechat.js";import{createWeChatAutomationLane as ie}from"../channels/wechat-channel/automation-lane.js";const C=Number(process.env.SHENNIAN_MANAGER_IPC_BODY_MAX_BYTES||2*1024*1024),A=12*6e4;let P=null;function qe(r){P=r}function Fe(){return P}function S(r){return y.resolve(r||N.homedir())}function u(r,e,a){r.writeHead(e,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify(a))}function oe(r){return/^agent-(.+)-\d+$/.exec(r)?.[1]??null}function le(r){return r==="manager"?!1:r.startsWith("custom:")?!0:H.includes(r)}function ce(r){const e=/^agent-.+-(\d+)$/.exec(r);if(!e)return null;const a=Number(e[1]);return Number.isInteger(a)&&a>=0?a:null}function D(r){return r.replace(/\r\n/g,`
|
|
2
|
+
`).trim()}function de(r){try{const e=JSON.parse(r),a=e.type==="tool_result"||e.result?"tool_result":"tool_call",n=e.name||"tool",t=typeof e.result=="string"?e.result.replace(/\s+/g," ").trim():"",i=t.length>220?`${t.slice(0,220)}...`:t;return i?`[${a}] ${n}: ${i}`:`[${a}] ${n}`}catch{return"[tool]"}}function W(r){if(!r||typeof r!="object")return;const e=r,a=String(e.kind||""),n=String(e.name||""),t=String(e.mimeType||""),i=String(e.dataBase64||""),o=String(e.localPath||""),s=String(e.url||""),c=Number(e.size||0);if(i)throw new Error("Manager IPC external attachments must use localPath or url; dataBase64 is not accepted");if(!(a!=="image"&&a!=="video"&&a!=="file")&&!(!n||!t||!Number.isFinite(c)||c<0)&&!(!o&&!s))return{kind:a,name:n,mimeType:t,size:c,...o?{localPath:o}:{},...s?{url:s}:{}}}function v(r){const e=r.binding&&typeof r.binding=="object"&&!Array.isArray(r.binding)?r.binding:{},a=String(e.sessionId||r.managerSessionId||"").trim(),n=String(e.channelId||"").trim(),t=String(e.conversationId||"").trim(),i=String(e.conversationName||r.conversation||"").trim(),o=String(e.workDir||r.workDir||"").trim();if(!a)throw new Error("WeChat tool sessionId is required");if(!n)throw new Error("WeChat tool channelId is required");if(!t)throw new Error("WeChat tool conversationId is required");if(!i)throw new Error("WeChat tool conversationName is required");if(!o)throw new Error("WeChat tool workDir is required");return{sessionId:a,channelId:n,conversationId:t,conversationName:i,workDir:o}}function ue(r,e){const a=[...r].sort((d,l)=>d.ts-l.ts),n=[];let t=null,i=null,o=null,s="";const c=()=>{if(!t)return;const d=s.trim();d&&n.push({...t,id:`${t.id}-compact`,payload:d}),t=null,i=null,o=null,s=""};for(const d of a){if(V(d.payload)){c();continue}if(d.role==="user"){c(),n.push(d);continue}if(Q(d.payload)){c(),n.push({...d,payload:de(d.payload)});continue}const l=j(d.payload);if(!l.trim())continue;const h=oe(d.id),g=ce(d.id);t&&t.role===d.role&&i===h&&h&&g!==null&&o!==null&&g===o+1?(s+=l,t.ts=d.ts,o=g):(c(),t=d,i=h,o=g,s=l)}return c(),n.slice(-e).sort((d,l)=>l.ts-d.ts)}async function he(r){const e=[];let a=0;for await(const t of r){const i=Buffer.from(t);if(a+=i.byteLength,Number.isFinite(C)&&C>0&&a>C)throw new Error(`Manager IPC request body is too large. Max: ${C} bytes.`);e.push(i)}const n=Buffer.concat(e).toString("utf-8");return n?JSON.parse(n):{}}function w(r,e,a,n){r.client.sendRes({type:"res",id:e,ok:a,...a?{payload:n}:{error:String(n.error||"unknown error")}})}function $(r){return/binding not found|unknown method|not supported|relay is not connected|no external channel/i.test(r)}function _(){return ge()?y.join(N.tmpdir(),"shennian-vitest-runtime",String(process.pid),"manager-ipc.json"):ne("runtime","manager-ipc.json")}function ge(){return(process.env.VITEST==="true"||!!process.env.VITEST_WORKER_ID)&&!process.env.SHENNIAN_HOME?.trim()}class Le{opts;registry=new X;channelRuntime;server=null;ipcUrl=null;ipcToken=G(24).toString("hex");healthTimer=null;startPromise=null;workerTextAcc=new Map;weChatAutomationLane;constructor(e){this.opts=e,this.weChatAutomationLane=e.weChatAutomationLane??ie(),this.channelRuntime=e.channelRuntime??new ee((a,n)=>{this.handleExternalMessage(a,n)},a=>this.registry.createReplyTarget(a).replyTarget,{createWeChatRpaProductRunner:e.createWeChatRpaProductRunner,weChatAutomationLane:this.weChatAutomationLane})}async start(){return this.startPromise?this.startPromise:(this.startPromise=this.doStart(),this.startPromise)}async doStart(){if(this.server)return;this.server=K.createServer((a,n)=>{this.handleIpc(a,n)}),this.server.requestTimeout=A,this.server.timeout=A,this.server.keepAliveTimeout=A,this.server.headersTimeout=A+5e3,await new Promise((a,n)=>{this.server.once("error",n),this.server.listen(0,"127.0.0.1",()=>a())});const e=this.server.address();typeof e=="object"&&e&&(this.ipcUrl=`http://127.0.0.1:${e.port}`,this.writeIpcRuntimeFile()),this.server.unref(),await this.channelRuntime.start(),this.broadcastConfiguredChannelStatuses(),this.healthTimer=setInterval(()=>this.scanWorkerHealth(),6e4),this.healthTimer.unref()}async ready(){await this.start()}async stop(){this.healthTimer&&clearInterval(this.healthTimer),this.healthTimer=null,await this.channelRuntime.stop(),await new Promise(e=>{if(!this.server)return e();this.server.close(()=>e())}),this.server=null,this.ipcUrl=null,this.removeIpcRuntimeFile()}writeIpcRuntimeFile(){if(this.ipcUrl)try{const e=_();k.mkdirSync(y.dirname(e),{recursive:!0}),k.writeFileSync(e,JSON.stringify({url:this.ipcUrl,token:this.ipcToken,pid:process.pid,updatedAt:new Date().toISOString()},null,2),{mode:384}),k.chmodSync(e,384)}catch{}}removeIpcRuntimeFile(){try{const e=_(),a=JSON.parse(k.readFileSync(e,"utf-8"));(a.url===this.ipcUrl||a.token===this.ipcToken)&&k.unlinkSync(e)}catch{}}getInjectedEnv(e,a,n,t){return this.ipcUrl?{SHENNIAN_MANAGER_SESSION_ID:e,SHENNIAN_MANAGER_AGENT_SESSION_ID:a??"",SHENNIAN_MANAGER_WORKDIR:S(n),SHENNIAN_MANAGER_MODEL:t,SHENNIAN_MANAGER_IPC_URL:this.ipcUrl,SHENNIAN_MANAGER_IPC_TOKEN:this.ipcToken}:{}}registerManager(e){this.registry.upsertManager({...e,workDir:S(e.workDir),machineId:process.env.SHENNIAN_MACHINE_ID??null})}setManagerWorkerDefaults(e,a,n){const t=this.registry.getManager(e);t&&this.registry.upsertManager({...t,defaultWorkerAgentType:a??null,defaultWorkerModelId:n??null})}getManagerWorkerDefaults(e){const a=this.registry.getManager(e);return{agentType:a?.defaultWorkerAgentType??null,modelId:a?.defaultWorkerModelId??null}}noteManagerAgentSession(e,a,n,t){this.registry.upsertManager({sessionId:e,agentSessionId:a,workDir:S(n),machineId:process.env.SHENNIAN_MACHINE_ID??null,modelId:t})}noteAgentEvent(e,a){if(!this.findWorker(e))return;const t={lastActivityAt:new Date().toISOString(),runId:a.runId};a.agentSessionId&&(t.agentSessionId=a.agentSessionId);const i=`${e}:${a.runId}`;if(a.state==="delta"&&a.text&&!a.thinking){const s=(this.workerTextAcc.get(i)??"")+a.text;this.workerTextAcc.set(i,s);const c=D(s);c&&(t.summary=c.length>160?`${c.slice(0,160)}...`:c)}if(a.state==="final"||a.state==="error"||a.state==="aborted"){t.status=a.state;const s=D(this.workerTextAcc.get(i)??"");s&&(t.summary=s.length>240?`${s.slice(0,240)}...`:s),this.workerTextAcc.delete(i)}else a.state==="start"&&(t.status="running");const o=this.registry.updateWorker(e,t);o&&(a.state==="final"||a.state==="error"||a.state==="aborted")&&this.wakeManagerForWorker(o.managedBy,o,a.state,a.message)}findWorker(e){return this.registry.load().workers[e]}async handleAppReq(e){const a=this.opts.getRuntime(),n=e.params??{};try{const t=String(n.managerSessionId||n.sessionId||"");if(!t)throw new Error("sessionId is required");const i=this.registry.getManager(t),o=e.method==="session.wechat-rpa.channel.get"||e.method==="manager.wechat-rpa.channel.get",s=e.method==="session.wechat-rpa.channel.upsert"||e.method==="manager.wechat-rpa.channel.upsert",c=e.method==="session.wechat-rpa.channel.sync"||e.method==="manager.wechat-rpa.channel.sync",d=e.method==="session.wechat-rpa.outbound.cancel"||e.method==="manager.wechat-rpa.outbound.cancel";if(e.method==="manager.channel.get"){w(a,e.id,!0,{channel:this.channelRuntime.getManagerChannel(t,"websocket",{includeSecret:!0})});return}if(e.method==="manager.channel.upsert"){const l=await this.channelRuntime.upsertManagerChannel({id:String(n.id||`websocket:${t}`),managerSessionId:t,sessionId:t,workDir:String(n.workDir||i?.workDir||""),type:"websocket",name:typeof n.name=="string"?n.name:void 0,agentType:typeof n.agentType=="string"?n.agentType:void 0,agentSessionId:typeof n.agentSessionId=="string"?n.agentSessionId:null,modelId:typeof n.modelId=="string"?n.modelId:null,enabled:!!n.enabled,wsUrl:typeof n.wsUrl=="string"?n.wsUrl:void 0,token:typeof n.token=="string"?n.token:void 0,canReply:n.canReply===void 0?void 0:!!n.canReply,systemPrompt:typeof n.systemPrompt=="string"?n.systemPrompt:void 0});this.broadcastManagerChannelStatus(t),w(a,e.id,!0,{channel:l});return}if(o){w(a,e.id,!0,{channel:this.channelRuntime.getManagerChannel(t,"wechat-rpa",{includeSecret:!0})});return}if(s){const l=await this.channelRuntime.upsertManagerWeChatRpaChannel({id:String(n.id||`wechat-rpa:${t}`),managerSessionId:t,sessionId:t,workDir:S(String(n.workDir||i?.workDir||"")),name:typeof n.name=="string"?n.name:void 0,agentType:typeof n.agentType=="string"?n.agentType:void 0,agentSessionId:typeof n.agentSessionId=="string"?n.agentSessionId:null,modelId:typeof n.modelId=="string"?n.modelId:null,enabled:!!n.enabled,groups:B(n.groups),canReply:n.canReply===void 0?void 0:!!n.canReply,systemPrompt:typeof n.systemPrompt=="string"?n.systemPrompt:void 0,source:q(n.source),pollIntervalMs:m(n.pollIntervalMs),recentLimit:m(n.recentLimit),idleSeconds:m(n.idleSeconds),forceForeground:n.forceForeground===void 0?void 0:!!n.forceForeground,noRestore:n.noRestore===void 0?void 0:!!n.noRestore,downloadAttachments:n.downloadAttachments===void 0?void 0:!!n.downloadAttachments,downloadAttachmentsDir:typeof n.downloadAttachmentsDir=="string"?n.downloadAttachmentsDir:void 0,selfNickname:typeof n.selfNickname=="string"?n.selfNickname:void 0,selfTriggerMarker:typeof n.selfTriggerMarker=="string"?n.selfTriggerMarker:void 0,deferInitialPoll:n.deferInitialPoll===void 0?void 0:!!n.deferInitialPoll,privacyConsentAccepted:n.privacyConsentAccepted===void 0?void 0:!!n.privacyConsentAccepted,flowScriptPath:typeof n.flowScriptPath=="string"?n.flowScriptPath:void 0});this.broadcastManagerChannelStatus(t),w(a,e.id,!0,{channel:l});return}if(c){const l=await this.channelRuntime.syncManagerWeChatRpaChannel(t);this.broadcastManagerChannelStatus(t),w(a,e.id,!0,l);return}if(d){const l=await this.channelRuntime.cancelManagerWeChatRpaOutbound({managerSessionId:t,idempotencyKey:typeof n.idempotencyKey=="string"?n.idempotencyKey:null,replyId:typeof n.replyId=="string"?n.replyId:null,reason:typeof n.reason=="string"?n.reason:"user_cancelled"});this.broadcastManagerChannelStatus(t),w(a,e.id,!0,l);return}throw new Error(`Unsupported manager app method: ${e.method}`)}catch(t){w(a,e.id,!1,{error:t instanceof Error?t.message:String(t)})}}broadcastConfiguredChannelStatuses(){for(const e of this.channelRuntime.listManagerChannelStatuses())this.broadcastManagerChannelStatus(e.managerSessionId)}broadcastManagerChannelStatus(e){const a=this.opts.getRuntime();if(!a.client?.sendEvent)return;const n=this.registry.getManager(e),t=this.channelRuntime.getManagerChannelStatus(e),i=this.channelRuntime.getManagerChannel(e,"wechat-rpa")??this.channelRuntime.getManagerChannel(e,"websocket");a.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e,agentType:n?"manager":i?.agentType,agentSessionId:n?.agentSessionId??i?.agentSessionId??null,modelId:n?.modelId??i?.modelId??null,workDir:n?.workDir??i?.workDir,externalChannel:t}}})}async handleIpc(e,a){if(e.headers.authorization!==`Bearer ${this.ipcToken}`){u(a,401,{ok:!1,error:"Unauthorized"});return}try{const n=new URL(e.url??"/","http://127.0.0.1"),t=await he(e),i=String(t.managerSessionId||e.headers["x-shennian-manager-session-id"]||"");if(!i)throw new Error("managerSessionId is required");const o=this.registry.getManager(i);if(n.pathname==="/sessions/list"){if(!o)throw new Error("Manager runtime is not registered");const s=new Set(this.opts.getRuntime().sessions.keys());u(a,200,{ok:!0,sessions:this.registry.listWorkers(i,{runningSessionIds:s})});return}if(n.pathname==="/sessions/start"){if(!o)throw new Error("Manager runtime is not registered");const s=String(t.agentType||t.agent||o.defaultWorkerAgentType||"codex");if(!le(s))throw new Error(`Unsupported manager worker agent: ${s}`);const c=S(String(t.workDir||o.workDir));if(c!==o.workDir)throw new Error("Manager can only start workers in the same workDir");const d=String(t.message||"");if(!d)throw new Error("message is required");const l=this.registry.addWorker({managerSessionId:i,agentType:s,workDir:c,summary:d.slice(0,120)}),h=String(t.modelId||(s===o.defaultWorkerAgentType?o.defaultWorkerModelId??"":""));await this.dispatchChatSend(l.sessionId,s,c,d,null,h),u(a,200,{ok:!0,session:l});return}if(n.pathname==="/sessions/send"){const s=String(t.sessionId||""),c=String(t.message||""),d=t.enqueue===void 0?!0:!!t.enqueue,l=this.registry.getWorkerForManager(i,s);if(!l)throw new Error("Worker not found in this manager scope");const h=String(t.modelId||(l.agentType===o?.defaultWorkerAgentType?o.defaultWorkerModelId??"":""));d?await this.dispatchChatEnqueue(l.sessionId,l.agentType,l.workDir,c,l.agentSessionId??null,h):await this.dispatchChatSend(l.sessionId,l.agentType,l.workDir,c,l.agentSessionId??null,h),u(a,200,{ok:!0});return}if(n.pathname==="/sessions/queue"){const s=String(t.sessionId||"");if(!this.registry.getWorkerForManager(i,s))throw new Error("Worker not found in this manager scope");const d=this.opts.getRuntime().chatQueue?.getSnapshot(s);u(a,200,{ok:!0,queue:d});return}if(n.pathname==="/sessions/queue/edit"){const s=String(t.sessionId||"");if(!this.registry.getWorkerForManager(i,s))throw new Error("Worker not found in this manager scope");await this.opts.dispatchReq({type:"req",id:`manager-queue-edit-${p()}`,method:"chat.queue.edit",params:{sessionId:s,queueMessageId:String(t.queueMessageId||t.messageId||""),text:String(t.message||t.text||"")}}),u(a,200,{ok:!0,queue:this.opts.getRuntime().chatQueue?.getSnapshot(s)});return}if(n.pathname==="/sessions/queue/delete"){const s=String(t.sessionId||"");if(!this.registry.getWorkerForManager(i,s))throw new Error("Worker not found in this manager scope");await this.opts.dispatchReq({type:"req",id:`manager-queue-delete-${p()}`,method:"chat.queue.delete",params:{sessionId:s,queueMessageId:String(t.queueMessageId||t.messageId||"")}}),u(a,200,{ok:!0,queue:this.opts.getRuntime().chatQueue?.getSnapshot(s)});return}if(n.pathname==="/sessions/stop"||n.pathname==="/sessions/terminate"){const s=String(t.sessionId||"");if(!this.registry.getWorkerForManager(i,s))throw new Error("Worker not found in this manager scope");await this.opts.dispatchReq({type:"req",id:`manager-abort-${p()}`,method:"chat.abort",params:{sessionId:s}}),this.registry.updateWorker(s,{status:"aborted"}),u(a,200,{ok:!0});return}if(n.pathname==="/sessions/read"){const s=String(t.sessionId||""),c=Number(t.limit||200);if(!this.registry.getWorkerForManager(i,s))throw new Error("Worker not found in this manager scope");const l=Z(s,{limit:Math.max(c*20,c)});u(a,200,{ok:!0,messages:ue(l,c),rawMessageCount:l.length});return}if(n.pathname==="/memory/path"){if(!o)throw new Error("Manager runtime is not registered");u(a,200,{ok:!0,path:y.join(o.workDir,".shennian")});return}if(n.pathname==="/external/reply"){const s=typeof t.replyTarget=="string"?this.registry.getReplyTarget(t.replyTarget):this.registry.getLatestReplyTargetForManager(i),c=String(t.text||""),d=W(t.attachment),l=String(t.idempotencyKey||p()),h=String(t.channelId||""),g=String(t.conversationId||""),M=!s&&(!h||!g)?await this.channelRuntime.getDefaultReplyTarget(i).catch(()=>null):null,R=s?.channelId||h||M?.channelId||"",E=s?.conversationId||g||M?.conversationId||"";if(R&&this.channelRuntime.getChannelById(R)){if(!E)throw new Error("No external channel target is available for this Manager");const f=await this.channelRuntime.reply({managerSessionId:i,channelId:R,conversationId:E,messageId:s?.messageId??void 0,text:c,attachment:d,idempotencyKey:l});u(a,f.ok?200:400,f);return}let I;try{I=await this.sendManagedWeComReply({managerSessionId:i,text:c,attachment:d,idempotencyKey:l})}catch(f){const x=f instanceof Error?f.message:String(f);if(!$(x))throw f;I={ok:!1,error:x}}if(I.ok){u(a,200,{ok:!0,payload:I.payload});return}if(!$(I.error||"")||!R||!E){u(a,400,{ok:!1,error:I.error||"External send failed"});return}u(a,400,{ok:!1,error:`No local external channel is configured for ${R}`});return}if(n.pathname==="/channel/get"){u(a,200,{ok:!0,channel:this.channelRuntime.getManagerChannel(i,"websocket")});return}if(n.pathname==="/channel/upsert"){if(!o)throw new Error("Manager runtime is not registered");const s=await this.channelRuntime.upsertManagerChannel({id:String(t.id||`websocket:${i}`),managerSessionId:i,workDir:o.workDir,type:"websocket",name:typeof t.name=="string"?t.name:void 0,enabled:!!t.enabled,wsUrl:typeof t.wsUrl=="string"?t.wsUrl:void 0,token:typeof t.token=="string"?t.token:void 0,canReply:t.canReply===void 0?void 0:!!t.canReply,systemPrompt:typeof t.systemPrompt=="string"?t.systemPrompt:void 0});this.registry.upsertManager({...o,status:o.status}),this.broadcastManagerChannelStatus(i),u(a,200,{ok:!0,channel:s});return}if(n.pathname==="/wechat-rpa/tool/read"){const s=v(t),c=m(t.limit)??10,d=typeof t.traceId=="string"?t.traceId:void 0;let l;try{l=await this.weChatAutomationLane.run(`wechat-tool:read:${s.channelId}`,()=>ae(s,{conversation:s.conversationName,workDir:s.workDir,sessionId:s.sessionId,limit:c,recentLimit:c,download:t.download==="never"?"never":"auto",traceId:d,timeoutMs:m(t.timeoutMs)}))}catch(h){u(a,400,{ok:!1,...U(h,d)});return}u(a,200,{ok:!0,messages:l.messages,outDir:l.outDir,helperTracePath:l.helperTracePath,activityGuardPath:l.activityGuardPath});return}if(n.pathname==="/wechat-rpa/tool/send"){const s=v(t),c=String(t.text||""),d=W(t.attachment),l=typeof t.traceId=="string"?t.traceId:void 0;let h;try{h=await this.weChatAutomationLane.run(`wechat-tool:send:${s.channelId}`,()=>se(s,{conversation:s.conversationName,workDir:s.workDir,sessionId:s.sessionId,text:c,attachment:d,traceId:l,timeoutMs:m(t.timeoutMs)}))}catch(g){u(a,400,{ok:!1,...U(g,l)});return}u(a,200,{ok:!0,...h});return}if(n.pathname==="/wechat-rpa/channel/get"){u(a,200,{ok:!0,channel:this.channelRuntime.getManagerChannel(i,"wechat-rpa",{includeSecret:!0})});return}if(n.pathname==="/wechat-rpa/channel/upsert"){const s=S(String(t.workDir||o?.workDir||""));if(!s)throw new Error("workDir is required");const c=await this.channelRuntime.upsertManagerWeChatRpaChannel({id:String(t.id||`wechat-rpa:${i}`),managerSessionId:i,sessionId:i,workDir:s,name:typeof t.name=="string"?t.name:void 0,agentType:typeof t.agentType=="string"?t.agentType:void 0,agentSessionId:typeof t.agentSessionId=="string"?t.agentSessionId:null,modelId:typeof t.modelId=="string"?t.modelId:null,enabled:!!t.enabled,groups:B(t.groups),canReply:t.canReply===void 0?void 0:!!t.canReply,systemPrompt:typeof t.systemPrompt=="string"?t.systemPrompt:void 0,source:q(t.source),pollIntervalMs:m(t.pollIntervalMs),recentLimit:m(t.recentLimit),idleSeconds:m(t.idleSeconds),forceForeground:t.forceForeground===void 0?void 0:!!t.forceForeground,noRestore:t.noRestore===void 0?void 0:!!t.noRestore,downloadAttachments:t.downloadAttachments===void 0?void 0:!!t.downloadAttachments,downloadAttachmentsDir:typeof t.downloadAttachmentsDir=="string"?t.downloadAttachmentsDir:void 0,selfNickname:typeof t.selfNickname=="string"?t.selfNickname:void 0,selfTriggerMarker:typeof t.selfTriggerMarker=="string"?t.selfTriggerMarker:void 0,deferInitialPoll:t.deferInitialPoll===void 0?void 0:!!t.deferInitialPoll,privacyConsentAccepted:t.privacyConsentAccepted===void 0?void 0:!!t.privacyConsentAccepted,flowScriptPath:typeof t.flowScriptPath=="string"?t.flowScriptPath:void 0});o&&this.registry.upsertManager({...o,status:o.status}),this.broadcastManagerChannelStatus(i),u(a,200,{ok:!0,channel:c});return}if(n.pathname==="/wechat-rpa/channel/sync"){const{channel:s,messages:c}=await this.channelRuntime.syncManagerWeChatRpaChannel(i);this.broadcastManagerChannelStatus(i),u(a,200,{ok:!0,channel:s,messages:c});return}if(n.pathname==="/wechat-rpa/outbound/cancel"){const s=await this.channelRuntime.cancelManagerWeChatRpaOutbound({managerSessionId:i,idempotencyKey:typeof t.idempotencyKey=="string"?t.idempotencyKey:null,replyId:typeof t.replyId=="string"?t.replyId:null,reason:typeof t.reason=="string"?t.reason:"user_cancelled"});this.broadcastManagerChannelStatus(i),u(a,200,{ok:!0,...s});return}u(a,404,{ok:!1,error:`Unknown manager IPC path: ${n.pathname}`})}catch(n){u(a,400,{ok:!1,error:n instanceof Error?n.message:String(n)})}}async dispatchChatSend(e,a,n,t,i,o){await this.opts.dispatchReq({type:"req",id:`manager-send-${p()}`,method:"chat.send",params:{sessionId:e,text:t,agentType:a,workDir:n,agentSessionId:i,modelId:o}})}async dispatchChatEnqueue(e,a,n,t,i,o){await this.opts.dispatchReq({type:"req",id:`manager-enqueue-${p()}`,method:"chat.enqueue",params:{sessionId:e,text:t,agentType:a,workDir:n,agentSessionId:i,modelId:o}})}async sendManagedWeComReply(e){const a=te(e.text);if(!a.length&&!e.attachment)return{ok:!1,error:"text or attachment is required"};const n=this.opts.getRuntime().client;if(!n||typeof n.sendReq!="function")return{ok:!1,error:"Relay is not connected"};const t=[];for(const[i,o]of a.entries()){const s=await n.sendReq({type:"req",id:`external-send-${p()}`,method:"external.send",params:{managerSessionId:e.managerSessionId,text:o,idempotencyKey:a.length>1?`${e.idempotencyKey}:${i+1}`:e.idempotencyKey}});if(!s.ok)return{ok:!1,error:s.error||"External send failed"};t.push(s.payload)}if(e.attachment){const i=await n.sendReq({type:"req",id:`external-send-${p()}`,method:"external.send",params:{managerSessionId:e.managerSessionId,attachment:e.attachment,idempotencyKey:a.length?`${e.idempotencyKey}:attachment`:e.idempotencyKey}});if(!i.ok)return{ok:!1,error:i.error||"External send failed"};t.push(i.payload)}return{ok:!0,payload:t.length===1?t[0]:t}}wakeManagerForWorker(e,a,n,t){const i=this.registry.getManager(e);if(!i)return;const o=`\u4F60\u7BA1\u7406\u7684 worker \u5DF2\u7ED3\u675F\u3002
|
|
3
3
|
|
|
4
4
|
Worker: ${a.sessionId}
|
|
5
5
|
\u72B6\u6001\uFF1A${n}
|
|
6
6
|
\u6700\u7EC8\u7ED3\u679C\uFF1A
|
|
7
7
|
${t||a.summary||"(\u65E0\u53EF\u89C1\u6458\u8981)"}
|
|
8
8
|
|
|
9
|
-
\u8BF7\u51B3\u5B9A\u4E0B\u4E00\u6B65\uFF1A\u7EE7\u7EED\u7B49\u5F85\u3001\u521B\u5EFA/\u6307\u6D3E worker\u3001\u505C\u6B62 worker\u3001\u8BE2\u95EE\u7528\u6237\uFF0C\u6216\u5411\u7528\u6237\u6C47\u62A5\u3002`;this.interruptAndResumeManager(i,o,n==="final"?"worker.final":`worker.${n}`)}handleExternalMessage(e,a){const n=this.channelRuntime.getChannelById(a.channelId)??this.channelRuntime.getManagerChannel(e,a.channelType),t=this.channelRuntime.getChannelStatusById(a.channelId)??this.channelRuntime.getManagerChannelStatus(e),i=this.registry.getManager(e),o=n?.agentType||(i?"manager":"codex"),s=n?.workDir||i?.workDir||process.cwd(),
|
|
9
|
+
\u8BF7\u51B3\u5B9A\u4E0B\u4E00\u6B65\uFF1A\u7EE7\u7EED\u7B49\u5F85\u3001\u521B\u5EFA/\u6307\u6D3E worker\u3001\u505C\u6B62 worker\u3001\u8BE2\u95EE\u7528\u6237\uFF0C\u6216\u5411\u7528\u6237\u6C47\u62A5\u3002`;this.interruptAndResumeManager(i,o,n==="final"?"worker.final":`worker.${n}`)}handleExternalMessage(e,a){const n=this.channelRuntime.getChannelById(a.channelId)??this.channelRuntime.getManagerChannel(e,a.channelType),t=this.channelRuntime.getChannelStatusById(a.channelId)??this.channelRuntime.getManagerChannelStatus(e),i=this.registry.getManager(e),o=n?.agentType||(i?"manager":"codex"),s=n?.workDir||i?.workDir||process.cwd(),c=n?.agentSessionId??i?.agentSessionId??null,d=n?.modelId||i?.modelId||"",l=pe(a.attachments,a.channelType),h=fe(a);this.dispatchExternalMessage({sessionId:e,agentType:o,workDir:s,agentSessionId:c,modelId:d,text:h,attachments:l,externalChannel:Ie(t),replyTarget:a.replyTarget})}async dispatchExternalMessage(e){await this.opts.dispatchReq({type:"req",id:`external-enqueue-${p()}`,method:"chat.enqueue",params:{sessionId:e.sessionId,text:e.text,agentType:e.agentType,workDir:e.workDir,agentSessionId:e.agentSessionId,modelId:e.modelId,origin:"external",attachments:e.attachments,externalChannel:e.externalChannel??null,replyTarget:e.replyTarget}})}scanWorkerHealth(){const e=Date.now(),a=this.registry.load();for(const n of Object.values(a.workers)){if(n.status!=="running")continue;const t=e-Date.parse(n.createdAt);if(t<10*6e4)continue;const i=n.healthNotifiedAt?Date.parse(n.healthNotifiedAt):0;if(i&&e-i<10*6e4)continue;const o=a.managers[n.managedBy];if(!o)continue;const s=Math.max(0,Math.floor((e-Date.parse(n.lastActivityAt))/6e4)),c=`Worker ${n.sessionId} \u5DF2\u8FD0\u884C ${Math.floor(t/6e4)} \u5206\u949F\uFF0C\u5C1A\u672A\u7ED3\u675F\u3002
|
|
10
10
|
|
|
11
11
|
\u5F53\u524D\u53EF\u89C1\u8FDB\u5C55\uFF1A
|
|
12
12
|
- \u6700\u8FD1\u6587\u672C\u6458\u8981\uFF1A${n.summary||"(\u65E0\u53EF\u89C1\u6458\u8981)"}
|
|
13
13
|
- \u6700\u8FD1\u6D3B\u52A8\u65F6\u95F4\uFF1A${n.lastActivityAt}
|
|
14
14
|
- \u6700\u8FD1 ${s} \u5206\u949F\u6CA1\u6709\u65B0\u6D3B\u52A8\u3002
|
|
15
15
|
|
|
16
|
-
\u8BF7\u51B3\u5B9A\u662F\u5426\u7EE7\u7EED\u7B49\u5F85\u3001\u8BE2\u95EE\u7528\u6237\u3001\u505C\u6B62 worker\u3001\u6216\u521B\u5EFA\u5176\u4ED6 worker \u534F\u52A9\u3002`;this.registry.updateWorker(n.sessionId,{healthNotifiedAt:new Date(e).toISOString(),lastHealthSummary:
|
|
16
|
+
\u8BF7\u51B3\u5B9A\u662F\u5426\u7EE7\u7EED\u7B49\u5F85\u3001\u8BE2\u95EE\u7528\u6237\u3001\u505C\u6B62 worker\u3001\u6216\u521B\u5EFA\u5176\u4ED6 worker \u534F\u52A9\u3002`;this.registry.updateWorker(n.sessionId,{healthNotifiedAt:new Date(e).toISOString(),lastHealthSummary:c}),o.status==="idle"&&this.dispatchChatSend(o.sessionId,"manager",o.workDir,c,o.agentSessionId,o.modelId)}}async interruptAndResumeManager(e,a,n){this.opts.getRuntime().sessions.get(e.sessionId)?.currentRunId&&(this.registry.upsertManager({...e,status:"interrupting"}),await this.opts.dispatchReq({type:"req",id:`manager-interrupt-${p()}`,method:"chat.abort",params:{sessionId:e.sessionId}}));const o=n?`\u4E8B\u4EF6\u7C7B\u578B\uFF1A${n}
|
|
17
17
|
|
|
18
|
-
${a}`:a;await this.dispatchChatSend(e.sessionId,"manager",e.workDir,o,e.agentSessionId,e.modelId)}bindManagerAdapterEvents(e,a){a.on("agentEvent",n=>{if(n.state==="start"&&n.agentSessionId){const t=this.registry.getManager(e);t&&this.noteManagerAgentSession(e,n.agentSessionId,t.workDir,t.modelId)}n.state==="start"&&this.updateManagerStatus(e,"running"),(n.state==="final"||n.state==="error"||n.state==="aborted")&&this.updateManagerStatus(e,"idle")})}updateManagerStatus(e,a){const n=this.registry.getManager(e);n&&this.registry.upsertManager({...n,status:a})}getExternalChannelStatus(e){return this.channelRuntime.getManagerChannelStatus(e)}getManagerExternalChannelSystemPrompt(e){return this.channelRuntime.listManagerExternalChannels(e).map(a=>
|
|
18
|
+
${a}`:a;await this.dispatchChatSend(e.sessionId,"manager",e.workDir,o,e.agentSessionId,e.modelId)}bindManagerAdapterEvents(e,a){a.on("agentEvent",n=>{if(n.state==="start"&&n.agentSessionId){const t=this.registry.getManager(e);t&&this.noteManagerAgentSession(e,n.agentSessionId,t.workDir,t.modelId)}n.state==="start"&&this.updateManagerStatus(e,"running"),(n.state==="final"||n.state==="error"||n.state==="aborted")&&this.updateManagerStatus(e,"idle")})}updateManagerStatus(e,a){const n=this.registry.getManager(e);n&&this.registry.upsertManager({...n,status:a})}getExternalChannelStatus(e){return this.channelRuntime.getManagerChannelStatus(e)}getManagerExternalChannelSystemPrompt(e){return this.channelRuntime.listManagerExternalChannels(e).map(a=>re(a,void 0,e,"manager")).join(`
|
|
19
19
|
|
|
20
|
-
`).trim()}}function
|
|
21
|
-
${h}`;return i.has(
|
|
22
|
-
`)}function
|
|
23
|
-
`);return[
|
|
24
|
-
`)}function
|
|
20
|
+
`).trim()}}function B(r){return Array.isArray(r)?r.map(e=>({name:String(e?.name||"").trim()})).filter(e=>e.name):[]}function q(r){return r==="wechat-channel"||r==="macos-flow"||r==="macos-probe"||r==="windows-visual-flow"||r==="wechat-rpa-lab"||r==="fixture-jsonl"?r:void 0}function pe(r,e){const a=r.map(n=>F(n,e)).filter(n=>n!=null);return a.length?a:void 0}function me(r,e,a,n){const t=e||"",i=new Set;return r.map((s,c)=>{const d=F(s,n),l=Y({type:s.type,name:d?.name||s.name,path:d?.path,mimeType:d?.mimeType||s.mimeType,availability:s.availability,providerError:s.providerError||we(s)},c),h=d?.path||"";if(h){const M=`${l}
|
|
21
|
+
${h}`;return i.has(M)||t.includes(h)?"":(i.add(M),`${a}: ${l}`)}const g=l;return i.has(g)?"":(i.add(g),`${a}: ${l}`)}).filter(s=>!t.includes(s)).join(`
|
|
22
|
+
`)}function fe(r){const a=(r.channelType==="wechat-rpa"?ye(r.sender.name):r.sender.name||r.sender.id)||(r.channelType==="wechat-rpa"?"\u5BF9\u65B9":r.sender.id)||"\u5BF9\u65B9",n=me(r.attachments,r.text,a,r.channelType),i=[r.text?J({senderName:a,senderId:r.sender.id,text:r.text}):n?"":`${a}:`,n].filter(Boolean).join(`
|
|
23
|
+
`);return[z({conversationName:r.conversationName||r.conversationId,messages:[]}),i].filter(Boolean).join(`
|
|
24
|
+
`)}function ye(r){const e=r?.trim()||"";return!e||/^(contact|self|system|unknown)$/i.test(e)||/^wechat-sender:/i.test(e)?"":e}function we(r){return!r.localPath||r.availability&&r.availability!=="edge-local"||b(r.localPath)?"":"edge-local-unavailable"}function F(r,e){return r.localPath&&ke(r,e)&&b(r.localPath)?{path:r.localPath,name:r.name||y.basename(r.localPath)||"attachment",mimeType:r.mimeType||O(r)}:r.url&&Se(r)?{path:r.url,name:r.name||r.url.split("/").filter(Boolean).at(-1)||"attachment",mimeType:r.mimeType||O(r)}:r.thumbnailPath&&!L(r,e)&&b(r.thumbnailPath)?{path:r.thumbnailPath,name:r.name?`${r.name}-preview.png`:y.basename(r.thumbnailPath)||"preview.png",mimeType:"image/png"}:null}function Ie(r){return r?r.type!=="wechat-rpa"?r:{configured:r.configured,connected:r.connected,type:r.type,channelId:r.channelId,name:r.name,canReply:r.canReply,systemPrompt:r.systemPrompt,wechatRpaSource:r.wechatRpaSource,wechatRpaGroups:r.wechatRpaGroups,pollIntervalMs:r.pollIntervalMs,recentLimit:r.recentLimit,idleSeconds:r.idleSeconds,forceForeground:r.forceForeground,noRestore:r.noRestore,downloadAttachments:r.downloadAttachments,selfNickname:r.selfNickname,wechatRpaPrivacyConsentAccepted:r.wechatRpaPrivacyConsentAccepted,wechatRpaServerDecisionAvailable:r.wechatRpaServerDecisionAvailable,wechatRpaPreflightChecks:r.wechatRpaPreflightChecks,wechatRpaRuntimeState:r.wechatRpaRuntimeState,wechatRpaLastMessageAt:r.wechatRpaLastMessageAt,wechatRpaPendingReplyCount:r.wechatRpaPendingReplyCount,wechatRpaLastError:r.wechatRpaLastError}:null}function ke(r,e){return r.providerError||r.availability&&r.availability!=="edge-local"?!1:L(r,e)?r.materializationKind==="original-file"&&r.isOriginal===!0&&r.mimeKindMatches===!0&&!Me(r.localPath):!0}function Se(r){return!r.providerError&&(!r.availability||r.availability==="server-url")}function L(r,e){if(e!=="wechat-rpa")return!1;const a=String(r.type||"").toLowerCase();return a==="file"||a==="video"||a==="video-file"}function Me(r){const e=String(r||"").replace(/\\/g,"/"),a=y.basename(e).toLowerCase();return/(^|\/)\.uploads(\/|$)/.test(e)||/(^|-)preview([-.]|$)/i.test(a)}function b(r){try{return k.statSync(r).isFile()}catch{return!1}}function O(r){return r.type==="image"?"image/*":r.type==="video"?"video/*":r.type==="audio"?"audio/*":"application/octet-stream"}function m(r){const e=Number(r);return Number.isFinite(e)?e:void 0}function U(r,e){const a=T(r,"reasonCode")||Re(r),n=T(r,"outDir"),t=T(r,"helperTracePath"),i=T(r,"activityGuardPath");return{error:r instanceof Error?r.message:String(r||a),reasonCode:a,...n?{outDir:n}:{},...t?{helperTracePath:t}:{},...i?{activityGuardPath:i}:{},...e?{traceId:e}:{}}}function T(r,e){if(!r||typeof r!="object")return"";const a=r[e];return typeof a=="string"&&a.trim()?a.trim():""}function Re(r){const e=r instanceof Error?r.message:String(r||"");return/^([a-z][a-z0-9_]*)(?::|\b)/i.exec(e.trim())?.[1]||"wechat_tool_failed"}export{Le as ManagerRuntimeService,Fe as getManagerRuntimeService,qe as setManagerRuntimeService};
|