shennian 0.2.94 → 0.2.96

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/publish-build-manifest.json +44 -34
  2. package/dist/src/channels/wechat-channel/fingerprint.js +1 -1
  3. package/dist/src/channels/wechat-channel/helper-assets.d.ts +1 -0
  4. package/dist/src/channels/wechat-channel/helper-assets.js +1 -1
  5. package/dist/src/channels/wechat-channel/helper-client.d.ts +17 -0
  6. package/dist/src/channels/wechat-channel/helper-client.js +3 -3
  7. package/dist/src/channels/wechat-channel/helper-protocol.d.ts +1 -1
  8. package/dist/src/channels/wechat-channel/helper-protocol.js +1 -1
  9. package/dist/src/channels/wechat-channel/macos-helper-app-bridge.d.ts +1 -0
  10. package/dist/src/channels/wechat-channel/macos-helper-app-bridge.js +2 -0
  11. package/dist/src/channels/wechat-channel/observer.d.ts +23 -3
  12. package/dist/src/channels/wechat-channel/observer.js +6 -6
  13. package/dist/src/channels/wechat-channel/outbound-sender.d.ts +3 -1
  14. package/dist/src/channels/wechat-channel/outbound-sender.js +1 -1
  15. package/dist/src/channels/wechat-channel/preflight.js +1 -1
  16. package/dist/src/channels/wechat-channel/runner.js +1 -1
  17. package/dist/src/commands/daemon.d.ts +3 -0
  18. package/dist/src/commands/daemon.js +7 -7
  19. package/dist/src/commands/pair.js +8 -8
  20. package/dist/src/commands/wechat.d.ts +26 -2
  21. package/dist/src/commands/wechat.js +8 -3
  22. package/dist/src/devtools/wechat-channel-action-smoke.d.ts +18 -0
  23. package/dist/src/devtools/wechat-channel-action-smoke.js +8 -7
  24. package/dist/src/devtools/wechat-channel-markdown-report.d.ts +6 -0
  25. package/dist/src/devtools/wechat-channel-markdown-report.js +5 -0
  26. package/dist/src/devtools/wechat-channel-product-steps.d.ts +3 -2
  27. package/dist/src/devtools/wechat-channel-product-steps.js +8 -4
  28. package/dist/src/manager/registry.js +1 -1
  29. package/dist/src/native-fusion/parsers.js +4 -4
  30. package/dist/src/session/handlers/tool-detail.d.ts +1 -1
  31. package/dist/src/session/handlers/tool-detail.js +1 -1
  32. package/node_modules/@shennian/wire/dist/machine.d.ts +25 -0
  33. package/node_modules/@shennian/wire/dist/machine.d.ts.map +1 -1
  34. package/node_modules/@shennian/wire/dist/message-payload.d.ts.map +1 -1
  35. package/node_modules/@shennian/wire/dist/message-payload.js +10 -2
  36. package/node_modules/@shennian/wire/dist/message-payload.js.map +1 -1
  37. package/package.json +9 -10
@@ -1,7 +1,12 @@
1
- import O from"node:crypto";import k from"node:fs";import P from"node:path";import{SERVERS as L}from"../region.js";import{loadConfig as M,resolveShennianPath as h}from"../config/index.js";import{createWeChatRpaProductSourceConnection as j,enqueueWeChatRpaProductOutboundReply as B,listWeChatRpaProductRecentMessages as T,weChatChannelConversationId as U}from"../channels/wechat-rpa/product-channel.js";import{createWeChatChannelProductRunner as J}from"../channels/wechat-channel/runner.js";import{createWeChatChannelApiClient as K}from"../channels/wechat-channel/client.js";async function q(e={}){const n=M(),t=V(e.serverUrl||n.serverUrl||L.cn.url),o=e.machineToken||n.machineToken,r=e.machineId||n.machineId,s=e.fetchImpl||fetch,a=[u("cli_installed","Shennian CLI is installed."),o?u("machine_paired","Machine token is configured."):p("machine_paired","machine_not_paired","Machine is not paired. Run shennian pair first.")];if(!o)return f({checks:a,serverUrl:t,machineId:r});try{const i=await s(`${t}/api/channels/wechat/runtime-policy`,{headers:{authorization:`Bearer ${o}`}}),c=await i.json().catch(()=>null);if(!i.ok||c?.ok===!1){const w=v(c?.reasonCode)||i.statusText||"request_failed";return a.push(p("server_policy",w,`WeChat runtime policy is blocked: ${w}`)),f({checks:a,serverUrl:t,machineId:r})}const l=y(c?.usagePolicy)?c.usagePolicy:{};a.push(u("server_policy","Server WeChat policy is reachable.")),a.push(u("entitlement","Account has Pro / Team external channel entitlement.")),a.push(u("credits",l.billingMode==="credits"?"Credit billing is enabled; balance is checked by server calls.":"Credits are not metered in current billing mode."));const d=y(c?.runtime)&&y(c.runtime.current)?c.runtime.current:null;a.push(d?u("runtime_registered","Local WeChat runtime is registered on the server."):H("runtime_registered","runtime_not_registered","Local WeChat runtime is not registered yet; open Shennian Desktop/daemon and enable Use WeChat."))}catch(i){a.push(p("server_policy","network_unavailable",i instanceof Error?i.message:"Unable to reach Shennian server."))}return f({checks:a,serverUrl:t,machineId:r})}async function F(e){const n=e.text.trim();if(!n)throw new Error("Message text is required");const t=$(e),o=e.directRuntime||e.ipc?null:await C("send",t,e,n);if(o)return{ok:!0,conversationName:t.conversationName,conversationId:t.conversationId,sessionId:t.sessionId,channelId:t.channelId,sendStatus:o.sendStatus??(o.pending?"pending":"sent"),pending:o.pending===!0};if(!x(e)){const a=await(e.directRuntime??S).send(t,e);return{ok:!0,conversationName:t.conversationName,conversationId:t.conversationId,sessionId:t.sessionId,channelId:t.channelId,sendStatus:a.sendStatus??(a.pending?"pending":"sent"),pending:a.pending===!0}}const r=e.ipc??N();await _(r,t,e);const s=await I(r,"/external/reply",{managerSessionId:t.sessionId,channelId:t.channelId,conversationId:t.conversationId,text:n,idempotencyKey:e.idempotencyKey||g("wechat-cli-send",`${t.channelId}
1
+ import j from"node:crypto";import q from"node:fs";import W from"node:path";import{SERVERS as U}from"../region.js";import{loadConfig as B,resolveShennianPath as R}from"../config/index.js";import{createWeChatRpaProductSourceConnection as z,listWeChatRpaProductRecentMessages as F,weChatChannelConversationId as J}from"../channels/wechat-rpa/product-channel.js";import{createWeChatChannelProductRunner as H}from"../channels/wechat-channel/runner.js";import{createWeChatChannelApiClient as K}from"../channels/wechat-channel/client.js";import{readExternalAttachment as V}from"./external-attachments.js";import{resolveWeChatChannelHelperAsset as Q,WECHAT_CHANNEL_HELPER_VERSION as Z}from"../channels/wechat-channel/helper-assets.js";import{WeChatChannelHelperClient as G}from"../channels/wechat-channel/helper-client.js";import{requiredWindowsWeChatChannelHelperCapabilitiesForProfile as X}from"../channels/wechat-channel/helper-protocol.js";import{ensureWeChatWindowReady as Y,fallbackWeChatMessageInputPointForWindow as ee,focusKnownWeChatWindow as ne,openConversationBySearch as te}from"../channels/wechat-channel/observer.js";import{enqueueWeChatOutboundReply as re}from"../channels/wechat-channel/outbound-ledger.js";import{sendQueuedWeChatOutboundRecords as _,WeChatChannelOutboundSender as ae}from"../channels/wechat-channel/outbound-sender.js";async function oe(e={}){const n=B(),t=he(e.serverUrl||n.serverUrl||U.cn.url),a=e.machineToken||n.machineToken,r=e.machineId||n.machineId,s=e.fetchImpl||fetch,o=[f("cli_installed","Shennian CLI is installed."),a?f("machine_paired","Machine token is configured."):v("machine_paired","machine_not_paired","Machine is not paired. Run shennian pair first.")];if(!a)return y({checks:o,serverUrl:t,machineId:r});try{const d=await s(`${t}/api/channels/wechat/runtime-policy`,{headers:{authorization:`Bearer ${a}`}}),i=await d.json().catch(()=>null);if(!d.ok||i?.ok===!1){const l=I(i?.reasonCode)||d.statusText||"request_failed";return o.push(v("server_policy",l,`WeChat runtime policy is blocked: ${l}`)),y({checks:o,serverUrl:t,machineId:r})}const c=g(i?.usagePolicy)?i.usagePolicy:{};o.push(f("server_policy","Server WeChat policy is reachable.")),o.push(f("entitlement","Account has Pro / Team external channel entitlement.")),o.push(f("credits",c.billingMode==="credits"?"Credit billing is enabled; balance is checked by server calls.":"Credits are not metered in current billing mode."));const h=g(i?.runtime)&&g(i.runtime.current)?i.runtime.current:null;o.push(h?f("runtime_registered","Local WeChat runtime is registered on the server."):me("runtime_registered","runtime_not_registered","Local WeChat runtime is not registered yet; open Shennian Desktop/daemon and enable Use WeChat."))}catch(d){o.push(v("server_policy","network_unavailable",d instanceof Error?d.message:"Unable to reach Shennian server."))}return y({checks:o,serverUrl:t,machineId:r})}async function ie(e){const n=e.text.trim();if(!n&&!e.attachment)throw new Error("Message text or attachment is required");const t=x(e),a=e.attachment?We(e.attachment):void 0;if(e.dryRun)return{ok:!0,operation:"write",conversation:t.conversationName,conversationName:t.conversationName,conversationId:t.conversationId,sessionId:t.sessionId,channelId:t.channelId,traceId:e.traceId,outDir:t.workDir,helperTracePath:null,sendStatus:"dry_run",pending:!1,attachment:a,attachments:a?[a]:[],dryRun:!0,reasonCode:null,message:"Dry run completed. No WeChat message was sent."};if(!M(e)){const c=await(e.directRuntime??b).send(t,e);return{ok:!0,operation:"write",conversation:t.conversationName,conversationName:t.conversationName,conversationId:t.conversationId,sessionId:t.sessionId,channelId:t.channelId,traceId:e.traceId,outDir:t.workDir,helperTracePath:null,sendStatus:c.sendStatus??(c.pending?"pending":"sent"),pending:c.pending===!0,attachment:a,attachments:a?[a]:[],reasonCode:null,message:c.pending?"WeChat message is queued or waiting for confirmation.":"WeChat message sent."}}const r=e.ipc??$();await N(r,t,e);const s=e.idempotencyKey||C("wechat-cli-send",`${t.channelId}
2
2
  ${t.conversationId}
3
3
  ${n}
4
- ${Date.now()}`)},e.fetchImpl);return{ok:!0,conversationName:t.conversationName,conversationId:t.conversationId,sessionId:t.sessionId,channelId:t.channelId,sendStatus:s.pending?"pending":"ok",pending:s.pending===!0}}async function z(e){const n=m(e.limit,10),t=$(e);if(!e.directRuntime&&!e.ipc){const i=await C("read-latest",t,e,void 0,n);if(i)return i}if(!x(e)){const c=(await(e.directRuntime??S).readLatest(t,{...e,limit:n,recentLimit:e.recentLimit??n})).filter(l=>l.conversationId===t.conversationId||l.conversationName===t.conversationName).slice(-n);return{ok:!0,conversationName:t.conversationName,conversationId:t.conversationId,sessionId:t.sessionId,channelId:t.channelId,messages:c,count:c.length}}const o=e.ipc??N();await _(o,t,{...e,recentLimit:e.recentLimit??n});const r=await I(o,"/wechat-rpa/channel/sync",{managerSessionId:t.sessionId},e.fetchImpl),a=(Array.isArray(r.messages)?r.messages.filter(E):[]).filter(i=>i.conversationId===t.conversationId||i.conversationName===t.conversationName).slice(-n);return{ok:!0,conversationName:t.conversationName,conversationId:t.conversationId,sessionId:t.sessionId,channelId:t.channelId,messages:a,count:a.length}}async function C(e,n,t,o,r=10){if(!Y())return null;const s=A();if(!s)return null;const a={conversation:n.conversationName,sessionId:n.sessionId,workDir:n.workDir,...e==="send"?{text:o,idempotencyKey:t.idempotencyKey}:{limit:r}},c=await(t.fetchImpl??fetch)(`${s.url}/wechat/direct/${e}`,{method:"POST",headers:{authorization:`Bearer ${s.token}`,"content-type":"application/json"},body:JSON.stringify(a)}).catch(()=>null);if(!c)throw new Error("desktop_direct_bridge_unavailable: Open Shennian Desktop before using `shennian wechat`.");const l=await c.json().catch(()=>null);if(!c.ok||!l?.ok){const d=v(l?.error)||c.statusText||"desktop_direct_bridge_failed";throw new Error(d)}return e==="send"?{pending:l.pending===!0,sendStatus:v(l.sendStatus)}:{ok:!0,conversationName:n.conversationName,conversationId:String(l.conversationId||n.conversationId),sessionId:n.sessionId,channelId:n.channelId,messages:Array.isArray(l.messages)?l.messages.filter(E):[],count:m(l.count,0)}}const S={async readLatest(e,n){const{config:t,secret:o}=D(e,n),r=R(t,o,n);try{return await r.runner.tick(),T({config:t,product:r,limit:n.limit??n.recentLimit??10})}finally{await r.runner.stop().catch(()=>{})}},async send(e,n){const{config:t,secret:o}=D(e,n),r=R(t,o,n),s={channelId:e.channelId,conversationId:e.conversationId,text:n.text,idempotencyKey:n.idempotencyKey||g("wechat-cli-send",`${e.channelId}
4
+ ${Date.now()}`),o=await w(r,"/external/reply",{managerSessionId:t.sessionId,channelId:t.channelId,conversationId:t.conversationId,text:n,attachment:e.attachment,idempotencyKey:s},e.fetchImpl,e.timeoutMs),d=await w(r,"/wechat-rpa/channel/sync",{managerSessionId:t.sessionId},e.fetchImpl,e.timeoutMs),i=Ie(d,s,o.pending===!0);return{ok:!0,operation:"write",conversation:t.conversationName,conversationName:t.conversationName,conversationId:t.conversationId,sessionId:t.sessionId,channelId:t.channelId,traceId:e.traceId,outDir:t.workDir,helperTracePath:null,sendStatus:i,pending:o.pending===!0&&(i==="queued"||i==="pending"),attachment:a,attachments:a?[a]:[],reasonCode:null,message:i==="confirmed_echo"?"WeChat message sent and confirmed.":i==="manual_review"?"WeChat message was submitted but needs manual review.":"WeChat message submitted to local daemon."}}async function se(e){const n=m(e.limit,10),t=x(e);if(!M(e)){const c=(await(e.directRuntime??b).readLatest(t,{...e,limit:n,recentLimit:e.recentLimit??n})).filter(l=>l.conversationId===t.conversationId||l.conversationName===t.conversationName).slice(-n),h=T(c);return{ok:!0,operation:"read",conversation:t.conversationName,conversationName:t.conversationName,conversationId:t.conversationId,sessionId:t.sessionId,channelId:t.channelId,traceId:e.traceId,outDir:t.workDir,helperTracePath:null,messages:c,attachments:h,count:c.length,reasonCode:null,message:`Read ${c.length} WeChat message(s).`}}const a=e.ipc??$();await N(a,t,{...e,recentLimit:e.recentLimit??n});const r=await w(a,"/wechat-rpa/channel/sync",{managerSessionId:t.sessionId},e.fetchImpl,e.timeoutMs),o=(Array.isArray(r.messages)?r.messages.filter(Ne):[]).filter(i=>i.conversationId===t.conversationId||i.conversationName===t.conversationName).slice(-n),d=T(o);return{ok:!0,operation:"read",conversation:t.conversationName,conversationName:t.conversationName,conversationId:t.conversationId,sessionId:t.sessionId,channelId:t.channelId,traceId:e.traceId,outDir:t.workDir,helperTracePath:null,messages:o,attachments:d,count:o.length,reasonCode:null,message:`Read ${o.length} WeChat message(s).`}}const b={async readLatest(e,n){const{config:t,secret:a}=D(e,n),r=P(t,a,n);try{return await r.runner.tick(),F({config:t,product:r,limit:n.limit??n.recentLimit??10})}finally{await r.runner.stop().catch(()=>{})}},async send(e,n){return ce(e,n)}};async function ce(e,n){const{config:t,secret:a}=D(e,n),r=P(t,a,n),s=r.runtime.bindings.find(l=>l.conversationDisplayName===e.conversationName)??r.runtime.bindings[0];if(!s)throw new Error("wechat_direct_binding_missing");const o=r.runtime.policy.platform,d=Q({platform:o});if(!d.ok)throw new Error(`${d.reasonCode}: ${d.message}`);const i=new G({helperPath:d.helperPath,expectedHelperVersion:d.version||Z,requiredCapabilities:o==="win32"?X("send"):void 0,guardUnsafeWindowsCommands:o==="win32",cleanupWindowsOverlays:o==="win32"}),c={version:1,runtimeId:r.runtime.runtimeId,records:[]},h=n.idempotencyKey||C("wechat-cli-send",`${e.channelId}
5
5
  ${e.conversationId}
6
6
  ${n.text}
7
- ${Date.now()}`)};B({config:t,secret:o,reply:s,conversationName:e.conversationName});try{const a=await r.runner.tick(),i=Array.isArray(a)?a:[];if(i.some(d=>Number(d.failedOutboundCount??0)>0||Number(d.manualReviewCount??0)>0))throw new Error("wechat_direct_send_failed");return i.some(d=>Number(d.outboundSentCount??0)>0||Number(d.confirmedEchoCount??0)>0)?{pending:!0,sendStatus:"pending"}:{pending:!0,sendStatus:"queued"}}finally{await r.runner.stop().catch(()=>{})}}};function ce(e){const n=e.command("wechat").description("Use WeChat through Shennian local runtime");n.option("--conversation <name>","WeChat conversation/group name"),n.command("doctor").description("Check local Shennian, pairing, entitlement, credits, and WeChat runtime readiness").option("--json","Output JSON",!1).action(async o=>{const r=await q();if(o.json)console.log(JSON.stringify(r,null,2));else for(const s of r.checks){const a=s.ok?"\u2713":s.status==="warning"?"!":"\u2717";console.log(`${a} ${s.id}: ${s.message}`)}r.ok||(process.exitCode=1)}),n.command("send").description("Send a message to a local WeChat conversation through Shennian").argument("[text...]","Message text").option("--conversation <name>","WeChat conversation/group name").option("--text <text>","Message text").option("--session-id <id>","Bind to an existing Shennian chat/session; omit for direct local WeChat tool mode").option("--work-dir <path>","Local tool work dir; defaults under ~/.shennian/wechat-cli").option("--idempotency-key <key>","Idempotency key").option("--json","Output JSON",!1).action(async(o,r,s)=>{const a=W(s,r.conversation),i=r.text??o.join(" "),c=await F({conversation:a,text:i,sessionId:r.sessionId,workDir:r.workDir,idempotencyKey:r.idempotencyKey});Z(c,r.json)}),n.command("read-latest").aliases(["read_latest","latest","read"]).description("Read the latest messages from a local WeChat conversation through Shennian").argument("[count]","Number of latest messages","10").option("--conversation <name>","WeChat conversation/group name").option("--limit <n>","Number of latest messages").option("--session-id <id>","Bind to an existing Shennian chat/session; omit for direct local WeChat tool mode").option("--work-dir <path>","Local tool work dir; defaults under ~/.shennian/wechat-cli").option("--json","Output JSON",!1).action(async(o,r,s)=>{const a=W(s,r.conversation),i=await z({conversation:a,limit:m(r.limit??o,10),sessionId:r.sessionId,workDir:r.workDir});Q(i,r.json)})}function f(e){return{ok:e.checks.every(n=>n.ok||n.status==="warning"),checks:e.checks,serverUrl:e.serverUrl,machineId:e.machineId}}function u(e,n){return{id:e,ok:!0,status:"ready",message:n}}function H(e,n,t){return{id:e,ok:!1,status:"warning",reasonCode:n,message:t}}function p(e,n,t){return{id:e,ok:!1,status:"blocked",reasonCode:n,message:t}}function V(e){return e.replace(/\/+$/,"")}function N(){const e=h("runtime","manager-ipc.json");let n;try{n=JSON.parse(k.readFileSync(e,"utf-8"))}catch{throw new Error("Manager IPC is not available. Open Shennian Desktop or run `shennian start` first.")}const t=Number(n.pid);if(Number.isInteger(t)&&t>0&&!b(t))throw new Error(`Manager IPC runtime file is stale for PID ${t}. Restart Shennian Desktop or run \`shennian restart\`.`);const o=typeof n.url=="string"?n.url.replace(/\/+$/,""):"",r=typeof n.token=="string"?n.token:"";if(!o||!r)throw new Error(`Manager IPC runtime file is incomplete: ${e}`);return{url:o,token:r}}async function _(e,n,t){return I(e,"/wechat-rpa/channel/upsert",{managerSessionId:n.sessionId,id:n.channelId,name:`WeChat ${n.conversationName}`,workDir:n.workDir,enabled:!0,groups:[{name:n.conversationName}],canReply:!0,source:t.source||"wechat-channel",recentLimit:m(t.recentLimit,20),pollIntervalMs:m(t.pollIntervalMs,3e4),forceForeground:!0,downloadAttachments:!0,privacyConsentAccepted:!0},t.fetchImpl)}async function I(e,n,t,o=fetch){const r=String(t.managerSessionId||"");if(!r)throw new Error("managerSessionId is required");const s=await o(`${e.url}${n}`,{method:"POST",headers:{authorization:`Bearer ${e.token}`,"content-type":"application/json","x-shennian-manager-session-id":r},body:JSON.stringify(t)}),a=await s.json().catch(()=>({ok:!1,error:s.statusText}));if(!s.ok||!a.ok)throw new Error(a.error||`Manager IPC failed: ${s.status}`);return a}function $(e){const n=e.conversation.trim();if(!n)throw new Error("--conversation is required");const t=g("wechat-cli-conversation",n),o=e.sessionId?.trim()||`wechat-cli-${t.slice(-24)}`,r=`wechat-rpa:${o}`;return{sessionId:o,channelId:r,conversationId:U(n),conversationName:n,workDir:P.resolve(e.workDir||h("wechat-cli",X(n)))}}function x(e){return!!e.sessionId?.trim()}function D(e,n){return{config:{id:e.channelId,type:"wechat-rpa",name:`WeChat ${e.conversationName}`,sessionId:e.sessionId,managerSessionId:e.sessionId,workDir:e.workDir,enabled:!0,secretRef:`wechat-cli:${e.channelId}`},secret:{groups:[{name:e.conversationName}],pollIntervalMs:m(n.pollIntervalMs,3e4),forceForeground:!0,downloadAttachments:!0,canReply:!0}}}function R(e,n,t){const o=G(t);return j({config:e,secret:n,createRunner:r=>J({...r,api:o})})}function G(e){return{...K({fetchImpl:e.fetchImpl}),upsertRuntime:async()=>({ok:!0,status:"local_direct_tool"}),ingest:async()=>({ok:!0,status:"local_direct_tool"}),reportRunStatus:async()=>({ok:!0,status:"local_direct_tool"}),reportOutboundStatus:async()=>({ok:!0,status:"local_direct_tool"})}}function W(e,n){const t=e.parent?.opts()??{},o=n||t.conversation||"";if(!o.trim())throw new Error("--conversation is required");return o}function Z(e,n){if(n){console.log(JSON.stringify(e,null,2));return}console.log(e.pending?"queued":"ok")}function Q(e,n){if(n){console.log(JSON.stringify(e,null,2));return}for(const t of e.messages){const o=t.sender.name||t.sender.id,r=t.text||t.attachments.map(s=>s.name||s.type).filter(Boolean).join(", ");console.log(`${t.receivedAt} ${o} ${r}`)}}function b(e){try{return process.kill(e,0),!0}catch{return!1}}function g(e,n){return`${e}:${O.createHash("sha256").update(n).digest("hex").slice(0,32)}`}function X(e){return e.trim().replace(/[^a-zA-Z0-9._-]+/g,"_").replace(/^_+|_+$/g,"")||"conversation"}function m(e,n){const t=Number(e);return!Number.isFinite(t)||t<=0?n:Math.floor(t)}function E(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&e.type==="external.message"&&typeof e.channelId=="string"&&typeof e.conversationId=="string"&&typeof e.messageId=="string"&&typeof e.text=="string"}function y(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function v(e){return typeof e=="string"&&e?e:void 0}function Y(){return process.platform!=="darwin"&&process.platform!=="win32"||process.env.SHENNIAN_WECHAT_DIRECT_DISABLE_BRIDGE==="1"?!1:!!A()}function A(){const e=h("runtime","desktop-direct-ipc.json");let n;try{n=JSON.parse(k.readFileSync(e,"utf8"))}catch{return null}const t=Number(n.pid);if(Number.isInteger(t)&&t>0&&!b(t))return null;const o=typeof n.url=="string"?n.url.replace(/\/+$/,""):"",r=typeof n.token=="string"?n.token:"";return!/^https?:\/\/127\.0\.0\.1:\d+$/i.test(o)||!r?null:{url:o,token:r}}export{ce as registerWeChatCommand,q as runWeChatDoctor,z as runWeChatReadLatest,F as runWeChatSend};
7
+ ${n.attachment?.localPath||""}
8
+ ${Date.now()}`);re({ledger:c,replyId:`wechat-cli:${h}`,idempotencyKey:h,bindingId:s.bindingId,runtimeId:r.runtime.runtimeId,sessionId:s.sessionId,conversationName:s.conversationDisplayName,replyBaseRevision:0,text:n.text,attachmentLocalRefs:n.attachment?.localPath?[n.attachment.localPath]:[]});try{await i.start();const l=new ae({helper:i,platform:o,traceId:n.traceId,openConversation:async L=>{const O=await Y(i,n.traceId),S=await ne(i,O,n.traceId);return{...await te({helper:i,window:S,settleToBottom:!1,binding:{...s,conversationDisplayName:L},traceId:n.traceId}),inputPoint:ee(S)}}}),u=await de({ledger:c,bindingId:s.bindingId,sender:l,maxWaitMs:n.timeoutMs??9e4}),k=c.records[0];if(u.sentRecords.length>0)return{pending:!0,sendStatus:"sent_unconfirmed"};if(u.manualReviewRecords.length>0)return{pending:!1,sendStatus:"manual_review"};if(u.waitingRecords.length>0)return{pending:!0,sendStatus:"pending"};if(u.staleRecords.length>0)throw new Error(u.staleRecords[0]?.failureCode||"reply_revision_stale");if(u.failedRecords.length>0)throw new Error(u.failedRecords[0]?.failureCode||u.failedRecords[0]?.lastErrorSummary||"wechat_direct_send_failed");return{pending:k?.sendStatus==="queued",sendStatus:k?.sendStatus==="queued"?"queued":"pending"}}finally{await i.stop().catch(()=>{}),await r.runner.stop().catch(()=>{})}}async function de(e){const n=e.maxAttempts??24,t=e.maxWaitMs??9e4,a=Date.now();let r=await _({ledger:e.ledger,bindingId:e.bindingId,currentLastInboundRevision:0,sender:e.sender,maxUserActivityWaitMs:t});for(let s=2;r.waitingRecords.length>0&&s<=n&&!(Date.now()-a>=t);s+=1){const o=le(r.waitingRecords[0]?.nextAttemptAt,a,t);await ue(o),r=await _({ledger:e.ledger,bindingId:e.bindingId,currentLastInboundRevision:0,sender:e.sender,maxUserActivityWaitMs:t})}return r}function le(e,n,t){const a=Math.max(0,n+t-Date.now());if(a<=0)return 0;if(!e)return Math.min(1200,a);const r=new Date(e).getTime();return Number.isFinite(r)?Math.max(250,Math.min(r-Date.now(),a)):Math.min(1200,a)}function ue(e){return new Promise(n=>setTimeout(n,Math.max(0,e)))}function He(e){const n=e.command("wechat").description("Use WeChat through Shennian local runtime");n.option("--conversation <name>","WeChat conversation/group name"),n.command("doctor").description("Check local Shennian, pairing, entitlement, credits, and WeChat runtime readiness").option("--json","Output JSON",!1).action(async a=>{const r=await oe();if(a.json)console.log(JSON.stringify(r,null,2));else for(const s of r.checks){const o=s.ok?"\u2713":s.status==="warning"?"!":"\u2717";console.log(`${o} ${s.id}: ${s.message}`)}r.ok||(process.exitCode=1)}),n.command("write").aliases(["send"]).description("Write a message to a local WeChat conversation through Shennian").argument("[text...]","Message text").option("--conversation <name>","WeChat conversation/group name").option("--text <text>","Message text").option("--file <path>","File attachment path").option("--image <path>","Image attachment path").option("--video <path>","Video attachment path").option("--session-id <id>","Bind to an existing Shennian chat/session; omit for direct local WeChat tool mode").option("--work-dir <path>","Local tool work dir; defaults under ~/.shennian/wechat-cli").option("--idempotency-key <key>","Idempotency key").option("--dry-run","Validate the request and output the planned write without sending",!1).option("--trace-id <id>","Trace id included in JSON output").option("--timeout <ms>","Manager IPC request timeout in milliseconds").option("--format <format>","Output format: json or text","text").option("--json","Output JSON",!1).action(async(a,r,s)=>{const o=A(s,r.conversation),d=r.text??a.join(" "),i=Ce(r),c=await ie({conversation:o,text:d,attachment:i,sessionId:r.sessionId,workDir:r.workDir,idempotencyKey:r.idempotencyKey,dryRun:r.dryRun,traceId:r.traceId,timeoutMs:r.timeout?m(r.timeout,24e4):void 0});ge(c,r.json||r.format==="json")}),n.command("read").aliases(["read-latest","read_latest","latest"]).description("Read recent messages from a local WeChat conversation through Shennian").argument("[count]","Number of latest messages","10").option("--conversation <name>","WeChat conversation/group name").option("--limit <n>","Number of latest messages").option("--format <format>","Output format: markdown or json","markdown").option("--download <mode>","Attachment download mode: auto or never","auto").option("--trace-id <id>","Trace id included in JSON output").option("--timeout <ms>","Manager IPC request timeout in milliseconds").option("--session-id <id>","Bind to an existing Shennian chat/session; omit for direct local WeChat tool mode").option("--work-dir <path>","Local tool work dir; defaults under ~/.shennian/wechat-cli").option("--json","Output JSON",!1).action(async(a,r,s)=>{const o=A(s,r.conversation),d=ke(r.json?"json":r.format),i=await se({conversation:o,limit:m(r.limit??a,10),download:Se(r.download),traceId:r.traceId,timeoutMs:r.timeout?m(r.timeout,24e4):void 0,sessionId:r.sessionId,workDir:r.workDir});pe(i,d)})}function y(e){return{ok:e.checks.every(n=>n.ok||n.status==="warning"),checks:e.checks,serverUrl:e.serverUrl,machineId:e.machineId}}function f(e,n){return{id:e,ok:!0,status:"ready",message:n}}function me(e,n,t){return{id:e,ok:!1,status:"warning",reasonCode:n,message:t}}function v(e,n,t){return{id:e,ok:!1,status:"blocked",reasonCode:n,message:t}}function he(e){return e.replace(/\/+$/,"")}function $(){const e=R("runtime","manager-ipc.json");let n;try{n=JSON.parse(q.readFileSync(e,"utf-8"))}catch{throw new Error("Manager IPC is not available. Open Shennian Desktop or run `shennian start` first.")}const t=Number(n.pid);if(Number.isInteger(t)&&t>0&&!be(t))throw new Error(`Manager IPC runtime file is stale for PID ${t}. Restart Shennian Desktop or run \`shennian restart\`.`);const a=typeof n.url=="string"?n.url.replace(/\/+$/,""):"",r=typeof n.token=="string"?n.token:"";if(!a||!r)throw new Error(`Manager IPC runtime file is incomplete: ${e}`);return{url:a,token:r}}async function N(e,n,t){return w(e,"/wechat-rpa/channel/upsert",{managerSessionId:n.sessionId,id:n.channelId,name:`WeChat ${n.conversationName}`,workDir:n.workDir,enabled:!0,groups:[{name:n.conversationName}],canReply:!0,source:t.source||"wechat-channel",recentLimit:m(t.recentLimit,20),pollIntervalMs:m(t.pollIntervalMs,3e4),forceForeground:!0,downloadAttachments:t.download!=="never",privacyConsentAccepted:!0},t.fetchImpl,t.timeoutMs)}async function w(e,n,t,a=fetch,r){const s=String(t.managerSessionId||"");if(!s)throw new Error("managerSessionId is required");const o=r?new AbortController:null,d=o?setTimeout(()=>o.abort(),r):null;try{const i=await a(`${e.url}${n}`,{method:"POST",headers:{authorization:`Bearer ${e.token}`,"content-type":"application/json","x-shennian-manager-session-id":s},body:JSON.stringify(t),signal:o?.signal}),c=await i.json().catch(()=>({ok:!1,error:i.statusText}));if(!i.ok||!c.ok)throw new Error(c.error||`Manager IPC failed: ${i.status}`);return c}finally{d&&clearTimeout(d)}}function x(e){const n=e.conversation.trim();if(!n)throw new Error("--conversation is required");const t=C("wechat-cli-conversation",n),a=e.sessionId?.trim()||`wechat-cli-${t.slice(-24)}`,r=`wechat-rpa:${a}`;return{sessionId:a,channelId:r,conversationId:J(n),conversationName:n,workDir:W.resolve(e.workDir||R("wechat-cli",$e(n)))}}function M(e){return!e.directRuntime}function D(e,n){return{config:{id:e.channelId,type:"wechat-rpa",name:`WeChat ${e.conversationName}`,sessionId:e.sessionId,managerSessionId:e.sessionId,workDir:e.workDir,enabled:!0,secretRef:`wechat-cli:${e.channelId}`},secret:{groups:[{name:e.conversationName}],pollIntervalMs:m(n.pollIntervalMs,3e4),forceForeground:!0,downloadAttachments:n.download!=="never",canReply:!0}}}function P(e,n,t){const a=fe(t);return z({config:e,secret:n,createRunner:r=>H({...r,api:a})})}function fe(e){return{...K({fetchImpl:e.fetchImpl}),upsertRuntime:async()=>({ok:!0,status:"local_direct_tool"}),ingest:async()=>({ok:!0,status:"local_direct_tool"}),reportRunStatus:async()=>({ok:!0,status:"local_direct_tool"}),reportOutboundStatus:async()=>({ok:!0,status:"local_direct_tool"})}}function A(e,n){const t=e.parent?.opts()??{},a=n||t.conversation||"";if(!a.trim())throw new Error("--conversation is required");return a}function ge(e,n){if(n){console.log(JSON.stringify(e,null,2));return}console.log(e.sendStatus)}function pe(e,n){if(n==="json"){console.log(JSON.stringify(e,null,2));return}console.log(we(e).trimEnd())}function we(e){const n=[];if(n.push(`${p(e.conversationName||e.conversation)}:`),e.messages.length===0)return n.push("\u6D88\u606F: \uFF08\u6CA1\u6709\u8BFB\u5230\uFF09"),`${n.join(`
9
+ `)}
10
+ `;for(const t of e.messages)n.push(`${ve(t)}: ${ye(t)}`);return`${n.join(`
11
+ `)}
12
+ `}function Ie(e,n,t){const a=g(e.channel)?e.channel:{},s=(Array.isArray(a.wechatRpaPendingReplies)?a.wechatRpaPendingReplies:[]).filter(g).find(c=>I(c.idempotencyKey)===n),o=I(s?.status);if(o==="confirmed_echo"||o==="sent_unconfirmed"||o==="manual_review"||o==="queued")return o;const i=(Array.isArray(a.wechatRpaRecentTaskSummaries)?a.wechatRpaRecentTaskSummaries:[]).filter(g).map(c=>I(c.status)).find(Boolean);return i==="sent"?"sent":i==="confirmed_echo"?"confirmed_echo":i==="manual_review"?"manual_review":t?"pending":"ok"}function ye(e){const n=e.attachments||[],t=p(e.text);return t&&n.length===0?t:t&&n.length>0?`${t} ${n.map(E).join("\u3001")}`:n.length>0?n.map(E).join("\u3001"):"\uFF08\u6D88\u606F\uFF09"}function ve(e){return p(e.sender.name||e.sender.id||"\u5BF9\u65B9")}function E(e){const n=p(e.name||W.basename(e.localPath||"")||e.type||"\u9644\u4EF6"),t=e.localPath||e.url||"",a=e.availability&&e.availability!=="edge-local"?` (${e.availability})`:"";return t?`[${_e(n)}](${Re(t)})${a}`:`${n}${a}`}function Ce(e){const n=[e.file?{kind:"file",path:e.file}:null,e.image?{kind:"image",path:e.image}:null,e.video?{kind:"video",path:e.video}:null].filter(t=>!!t);if(n.length>1)throw new Error("Pass only one of --file, --image, or --video");if(n.length!==0)return V(n[0].path,n[0].kind)}function ke(e){const n=String(e||"markdown").trim().toLowerCase();if(n==="json")return"json";if(n==="markdown"||n==="md"||n==="text")return"markdown";throw new Error(`Unsupported --format: ${e}. Use markdown or json.`)}function Se(e){const n=String(e||"auto").trim().toLowerCase();if(n==="auto"||n==="never")return n;throw new Error(`Unsupported --download: ${e}. Use auto or never.`)}function We(e){return{kind:e.kind,name:e.name,mimeType:e.mimeType,size:e.size,localPath:e.localPath}}function T(e){return e.flatMap(n=>n.attachments??[])}function Re(e){const n=e.replace(/\\/g,"/");return/[\s()<>]/.test(n)?`<${n.replace(/[<>]/g,"")}>`:n}function _e(e){return p(e).replace(/([\\\]])/g,"\\$1")}function p(e){return String(e||"").replace(/\s+/g," ").trim()}function be(e){try{return process.kill(e,0),!0}catch{return!1}}function C(e,n){return`${e}:${j.createHash("sha256").update(n).digest("hex").slice(0,32)}`}function $e(e){return e.trim().replace(/[^a-zA-Z0-9._-]+/g,"_").replace(/^_+|_+$/g,"")||"conversation"}function m(e,n){const t=Number(e);return!Number.isFinite(t)||t<=0?n:Math.floor(t)}function Ne(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&e.type==="external.message"&&typeof e.channelId=="string"&&typeof e.conversationId=="string"&&typeof e.messageId=="string"&&typeof e.text=="string"}function g(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function I(e){return typeof e=="string"&&e?e:void 0}export{we as buildWeChatReadMarkdown,He as registerWeChatCommand,oe as runWeChatDoctor,se as runWeChatReadLatest,ie as runWeChatSend};
@@ -18,12 +18,14 @@ export type WeChatChannelActionSmokeOptions = {
18
18
  imagePath?: string;
19
19
  videoPath?: string;
20
20
  downloadAnchorText?: string;
21
+ allowEmptyMedia?: boolean;
21
22
  requireServer: boolean;
22
23
  };
23
24
  export type WeChatChannelActionSmokeResult = {
24
25
  ok: boolean;
25
26
  conversation: string;
26
27
  outDir: string;
28
+ helperTracePath: string;
27
29
  traceId: string;
28
30
  runtimeId: string;
29
31
  machineId: string;
@@ -40,10 +42,26 @@ export type WeChatChannelActionSmokeResult = {
40
42
  details?: Record<string, unknown>;
41
43
  }>;
42
44
  };
45
+ export type WeChatChannelSmokeObservePipeline = 'edge-structure' | 'server-observe';
46
+ export declare function resolveWeChatSmokeObserveSessionMode(input: {
47
+ sessionId?: string;
48
+ observePipeline?: WeChatChannelSmokeObservePipeline;
49
+ }): 'direct-edge-structure' | 'session-bound';
43
50
  export { buildBottomPageReport, buildDownloadVisibleMediaReport };
44
51
  export declare function parseWeChatChannelActionSmokeArgs(argv: string[]): WeChatChannelActionSmokeOptions;
45
52
  export declare function stepsForMode(mode: WeChatChannelActionSmokeOptions['mode']): WeChatChannelActionSmokeStep[];
46
53
  export declare function runWeChatChannelActionSmoke(options: WeChatChannelActionSmokeOptions): Promise<WeChatChannelActionSmokeResult>;
54
+ export declare function buildSendStepAcceptance(input: {
55
+ sendAccepted: boolean;
56
+ text?: string | null;
57
+ beforeTextCount?: number | null;
58
+ afterTextCount?: number | null;
59
+ }): {
60
+ ok: boolean;
61
+ reasonCode?: string;
62
+ sendAccepted: boolean;
63
+ confirmationRequired: boolean;
64
+ };
47
65
  export declare function nextSmokeDrainWaitMs(nextAttemptAt: string | undefined, startedAtMs: number, maxWaitMs: number): number;
48
66
  export type WeChatChannelSendAndConfirmEvidenceInput = {
49
67
  sendResults: Array<{
@@ -1,9 +1,10 @@
1
- import R from"node:crypto";import{spawnSync as X}from"node:child_process";import w from"node:fs";import d from"node:path";import{fileURLToPath as Y}from"node:url";import{buildBottomPageReport as k,buildDownloadVisibleMediaReport as F}from"./wechat-channel-download-report.js";import{loadConfig as ee}from"../config/index.js";import{createWeChatChannelApiClient as te}from"../channels/wechat-channel/client.js";import{resolveWeChatChannelHelperAsset as ne,WECHAT_CHANNEL_HELPER_VERSION as oe}from"../channels/wechat-channel/helper-assets.js";import{WeChatChannelHelperClient as re}from"../channels/wechat-channel/helper-client.js";import{requiredWindowsWeChatChannelHelperCapabilitiesForProfile as D}from"../channels/wechat-channel/helper-protocol.js";import{classifyWeChatOutboundEchoes as se,enqueueWeChatOutboundReply as O}from"../channels/wechat-channel/outbound-ledger.js";import{loadWeChatChannelLedger as ae,saveWeChatChannelLedger as ie,updateWeChatChannelBindingLedger as de}from"../channels/wechat-channel/ledger.js";import{WeChatChannelOutboundSender as B,sendQueuedWeChatOutboundRecords as b}from"../channels/wechat-channel/outbound-sender.js";import{captureWeChatWindow as M,ensureWeChatWindowReady as v,focusKnownWeChatWindow as y,observeWeChatChannelBindingViaHelper as ce,openConversationBySearch as C,recognizeWeChatScreenshot as P}from"../channels/wechat-channel/observer.js";import{createWeChatChannelRuntime as ue}from"../channels/wechat-channel/runtime.js";const le="ABC",me="wechat-channel-action-smoke";function he(e){const t=e.filter(u=>u!=="--"),n=Ve(t),o=Ge(t,"--step").map(ze).filter(u=>u!=null),r=ee(),s=m(t,"--trace-id")||`wechat-action-smoke-${Date.now().toString(36)}`,a=d.resolve(m(t,"--out")||m(t,"--output")||d.join(process.cwd(),".dev-runtime","wechat-channel","action-smoke",s)),i=o.length?Je(o):fe(n);return{conversation:m(t,"--conversation")||m(t,"--group")||le,mode:o.length?"custom":n,steps:i,outDir:a,workDir:d.resolve(m(t,"--work-dir")||process.cwd()),traceId:s,runtimeId:m(t,"--runtime-id")||me,machineId:m(t,"--machine-id")||process.env.SHENNIAN_MACHINE_ID||r.machineId||"local",sessionId:m(t,"--session-id")||process.env.SHENNIAN_EXTERNAL_SESSION_ID||process.env.SHENNIAN_MANAGER_SESSION_ID,serverUrl:m(t,"--server-url")||r.serverUrl,platform:Ke(m(t,"--platform")),text:m(t,"--text"),filePath:T(m(t,"--file")),imagePath:T(m(t,"--image")),videoPath:T(m(t,"--video")),downloadAnchorText:m(t,"--download-anchor-text")||m(t,"--media-anchor-text"),requireServer:t.includes("--require-server")}}function fe(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 ge(e){const t=Date.now(),n=new Date(t).toISOString();w.mkdirSync(e.outDir,{recursive:!0});const o=Be(e),r=o.bindings[0],s=Le(e);await s.start();const a={ok:!1,conversation:e.conversation,outDir:e.outDir,traceId:e.traceId,runtimeId:e.runtimeId,machineId:e.machineId,startedAt:n,finishedAt:n,durationMs:0,steps:[]};try{for(const i of e.steps)a.steps.push(await pe({step:i,options:e,runtime:o,binding:r,helper:s}))}finally{await s.stop().catch(()=>{}),a.finishedAt=new Date().toISOString(),a.durationMs=Date.now()-t,a.ok=a.steps.every(i=>i.ok||i.skipped),h(d.join(e.outDir,"summary.json"),a)}return a}async function pe(e){try{return e.step==="open-read"?await ve(e):e.step==="structure-window"?await Pe(e):e.step==="server-observe"?await Me(e):e.step==="read-bottom-page"?await Re(e):e.step==="download-visible-media"?await De(e):e.step==="send-and-confirm"?await ke(e):e.step.startsWith("human-")?await we(e):await L(e)}catch(t){const n=tt(t);return{step:e.step,ok:!1,reasonCode:n,errorSummary:t instanceof Error?t.message:String(t),userAction:nt(n)}}}async function we(e){if(e.step==="human-observe-deferred")return await be(e);const t=e.step,n=`human-${I(`${e.options.traceId}:${t}:${Date.now()}`)}`,o={version:1,runtimeId:e.runtime.runtimeId,records:[]},r=O({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=K(e.helper,q(t)),a=s.actionLog,i=async N=>{a.push(`openConversation:${N}`);const Q=await v(s,e.options.traceId),Z=await y(s,Q,e.options.traceId);return C({helper:s,window:Z,binding:{...e.binding,conversationDisplayName:N},traceId:e.options.traceId})},u=new B({helper:s,platform:e.runtime.policy.platform,openConversation:i,traceId:e.options.traceId,activityGatePolicy:e.step==="human-send-user-active-timeout"?{keyDownThresholdMs:3e4,mouseMovedThresholdMs:3e4,mouseClickThresholdMs:3e4,scrollWheelThresholdMs:3e4}:void 0});let l=await b({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"&&(l=await b({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(Ee()),l=await b({ledger:o,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:u,now:new Date("2026-06-15T00:00:06.000Z")}));const f=$e(e.step,r)?await Ne({helper:s,binding:e.binding,marker:n,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:e.step}):0,g=f>0?se({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:[]},c=o.records[0],J=Fe(c,l,g.confirmedRecords),A={case:e.step,marker:n,runStatus:J,reasonCode:c.deferReason||c.failureCode||null,outboundStatus:c.sendStatus,attemptCount:c.attemptCount??0,nextAttemptAt:c.nextAttemptAt??null,observedMarkerCount:f,actionLog:a,clipboardRestore:a.includes("clipboard.restore")?"attempted":"not_needed",commitStage:c.commitStage??null};return h(d.join(e.options.outDir,`${e.step}-summary.json`),A),{step:e.step,ok:Oe(e.step,A),reasonCode:A.reasonCode||void 0,details:A}}async function be(e){const t=K(e.helper,q("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 h(d.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 ve(e){const t=await v(e.helper,e.options.traceId),n=await y(e.helper,t,e.options.traceId),o=await C({helper:e.helper,window:n,binding:e.binding,traceId:e.options.traceId});if(!o.opened)throw await ye({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 M(e.helper,n.windowId,e.options.traceId),s=x(e.options.outDir,"open-read-full-window",r),a=await P(e.helper,r,e.options.traceId);return h(d.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 ye(e){try{const t=await M(e.helper,e.window.windowId,e.traceId,e.window.bounds),n=x(e.outDir,"open-read-failure-window",t),o=await P(e.helper,t,e.traceId);h(d.join(e.outDir,"open-read-failure-ocr.json"),o),h(d.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){h(d.join(e.outDir,"open-read-failure-summary.json"),{reason:e.reason,captureError:t instanceof Error?t.message:String(t)})}}async function L(e){return await Ce(e,qe(e.step,e.options))}async function Ce(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||""}`;O({ledger:n,replyId:`action-smoke:${e.step}:${I(o)}`,idempotencyKey:`action-smoke:${I(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 r=new B({helper:e.helper,platform:e.runtime.policy.platform,traceId:e.options.traceId,openConversation:async u=>{const p=await v(e.helper,e.options.traceId),l=await y(e.helper,p,e.options.traceId);return C({helper:e.helper,window:l,binding:{...e.binding,conversationDisplayName:u},traceId:e.options.traceId})}}),s=await Se({ledger:n,bindingId:e.binding.bindingId,sender:r});await _(900);const a=n.records[0],i=s.failedRecords[0]?.failureCode||s.manualReviewRecords[0]?.failureCode||s.waitingRecords[0]?.deferReason||s.staleRecords[0]?.failureCode;return{step:e.step,ok:s.sentRecords.length===1&&s.failedRecords.length===0,reasonCode:i,errorSummary:s.failedRecords[0]?.lastErrorSummary||s.manualReviewRecords[0]?.lastErrorSummary,details:{text:t.text,attachmentPath:t.attachmentPath??null,sentRecords:s.sentRecords.length,failedRecords:s.failedRecords.length,waitingRecords:s.waitingRecords.length,manualReviewRecords:s.manualReviewRecords.length,staleRecords:s.staleRecords.length,sendStatus:a?.sendStatus,failureCode:a?.failureCode??null,lastErrorSummary:a?.lastErrorSummary??null,deferReason:a?.deferReason,commitStage:a?.commitStage??null,attemptCount:a?.attemptCount??0,nextAttemptAt:a?.nextAttemptAt??null}}}async function Se(e){const t=e.maxAttempts??24,n=e.maxWaitMs??9e4,o=Date.now();let r=await b({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=Ie(r.waitingRecords[0]?.nextAttemptAt,o,n);await _(a),r=await b({ledger:e.ledger,bindingId:e.bindingId,currentLastInboundRevision:0,sender:e.sender,maxUserActivityWaitMs:n})}return r}function Ie(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 Ae(e){const t=e.sendResults.filter(c=>!H(c)),n=e.sendResults.filter(c=>!c.skipped).map(c=>c.details?.text&&typeof c.details.text=="string"?c.details.text:"").filter(Boolean),o=e.observedMessages.map(c=>[c.normalizedText||"",c.anchorText||"",c.textExcerpt||""].join(`
1
+ import D from"node:crypto";import{spawnSync as ne}from"node:child_process";import w from"node:fs";import i from"node:path";import{fileURLToPath as oe}from"node:url";import{buildBottomPageReport as M,buildDownloadVisibleMediaReport as q}from"./wechat-channel-download-report.js";import{buildWeChatMessagesMarkdown as y}from"./wechat-channel-markdown-report.js";import{loadConfig as re}from"../config/index.js";import{createWeChatChannelApiClient as se}from"../channels/wechat-channel/client.js";import{resolveWeChatChannelHelperAsset as ae,WECHAT_CHANNEL_HELPER_VERSION as ie}from"../channels/wechat-channel/helper-assets.js";import{WeChatChannelHelperClient as de}from"../channels/wechat-channel/helper-client.js";import{requiredWindowsWeChatChannelHelperCapabilitiesForProfile as j}from"../channels/wechat-channel/helper-protocol.js";import{classifyWeChatOutboundEchoes as ce,enqueueWeChatOutboundReply as K}from"../channels/wechat-channel/outbound-ledger.js";import{loadWeChatChannelLedger as le,saveWeChatChannelLedger as ue,updateWeChatChannelBindingLedger as me}from"../channels/wechat-channel/ledger.js";import{WeChatChannelOutboundSender as U,sendQueuedWeChatOutboundRecords as S}from"../channels/wechat-channel/outbound-sender.js";import{captureWeChatWindow as W,ensureWeChatWindowReady as C,fallbackWeChatMessageInputPointForWindow as he,focusKnownWeChatWindow as k,observeWeChatChannelBindingViaHelper as fe,openConversationBySearch as I,recognizeWeChatScreenshot as E}from"../channels/wechat-channel/observer.js";import{createWeChatChannelRuntime as ge}from"../channels/wechat-channel/runtime.js";function pe(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 we="ABC",be="wechat-channel-action-smoke";function ve(e){const t=e.filter(l=>l!=="--"),n=st(t),o=it(t,"--step").map(at).filter(l=>l!=null),r=re(),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?dt(o):ye(n);return{conversation:g(t,"--conversation")||g(t,"--group")||we,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")||be,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:nt(g(t,"--platform")),text:g(t,"--text"),filePath:F(g(t,"--file")),imagePath:F(g(t,"--image")),videoPath:F(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 ye(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 Se(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=Qe(e),s=r.bindings[0],a=Ze(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 l of e.steps){if(Ce(l)&&d.steps.some(c=>c.step==="open-read"&&!c.ok&&!c.skipped)){d.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}d.steps.push(await ke({step:l,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(l=>l.ok||l.skipped),f(i.join(e.outDir,"summary.json"),d)}return d}function Ce(e){return e==="send-text"||e==="send-file"||e==="send-image"||e==="send-video"||e==="send-and-confirm"}async function ke(e){try{return e.step==="open-read"?await Re(e):e.step==="structure-window"?await Le(e):e.step==="server-observe"?await Oe(e):e.step==="read-bottom-page"?await Ne(e):e.step==="download-visible-media"?await Fe(e):e.step==="send-and-confirm"?await Ee(e):e.step.startsWith("human-")?await Ae(e):await V(e)}catch(t){const n=ft(t),o=await Ie(e,n,t);return{step:e.step,ok:!1,reasonCode:n,errorSummary:t instanceof Error?t.message:String(t),userAction:gt(n),...o?{details:o}:{}}}}async function Ie(e,t,n){if(!xe(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 f(o,r),{failureDiagnosticsPath:o}}function xe(e){return e.startsWith("wechat_")||e.startsWith("permission_")||e.startsWith("user_active")}async function Ae(e){if(e.step==="human-observe-deferred")return await _e(e);const t=e.step,n=`human-${_(`${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=G(e.helper,J(t)),a=s.actionLog,d=async H=>{a.push(`openConversation:${H}`);const ee=await C(s,e.options.traceId),te=await k(s,ee,e.options.traceId);return I({helper:s,window:te,settleToBottom:!1,binding:{...e.binding,conversationDisplayName:H},traceId:e.options.traceId})},l=new U({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 h=await S({ledger:o,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:l,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 S({ledger:o,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:l,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(Ue()),h=await S({ledger:o,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:l,now:new Date("2026-06-15T00:00:06.000Z")}));const m=Ve(e.step,r)?await N({helper:s,binding:e.binding,marker:n,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:e.step}):0,p=m>0?ce({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:[]},u=o.records[0],b=Ge(u,h,p.confirmedRecords),v={case:e.step,marker:n,runStatus:b,reasonCode:u.deferReason||u.failureCode||null,outboundStatus:u.sendStatus,attemptCount:u.attemptCount??0,nextAttemptAt:u.nextAttemptAt??null,observedMarkerCount:m,actionLog:a,clipboardRestore:a.includes("clipboard.restore")?"attempted":"not_needed",commitStage:u.commitStage??null};return f(i.join(e.options.outDir,`${e.step}-summary.json`),v),{step:e.step,ok:Je(e.step,v),reasonCode:v.reasonCode||void 0,details:v}}async function _e(e){const t=G(e.helper,J("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 f(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 Re(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 De({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 W(e.helper,n.windowId,e.options.traceId),s=T(e.options.outDir,"open-read-full-window",r),a=await E(e.helper,r,e.options.traceId);return f(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 De(e){try{const t=await W(e.helper,e.window.windowId,e.traceId,e.window.bounds),n=T(e.outDir,"open-read-failure-window",t),o=await E(e.helper,t,e.traceId);f(i.join(e.outDir,"open-read-failure-ocr.json"),o),f(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){f(i.join(e.outDir,"open-read-failure-summary.json"),{reason:e.reason,captureError:t instanceof Error?t.message:String(t)})}}async function V(e){return await Me(e,ot(e.step,e.options))}async function Me(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 N({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}:${_(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 s=new U({helper:e.helper,platform:e.runtime.policy.platform,traceId:e.options.traceId,openConversation:async p=>{const u=await C(e.helper,e.options.traceId),b=await k(e.helper,u,e.options.traceId);return{...await I({helper:e.helper,window:b,settleToBottom:!1,binding:{...e.binding,conversationDisplayName:p},traceId:e.options.traceId}),inputPoint:he(b)}}}),a=await Te({ledger:n,bindingId:e.binding.bindingId,sender:s});await R(900);const d=n.records[0],l=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,h=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,m=Pe({sendAccepted:c,text:t.text,beforeTextCount:r,afterTextCount:h});return{step:e.step,ok:m.ok,reasonCode:l||m.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:m.confirmationRequired,sendAccepted:m.sendAccepted,beforeTextCount:r,afterTextCount:h,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 Pe(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 Te(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=je(r.waitingRecords[0]?.nextAttemptAt,o,n);await R(a),r=await S({ledger:e.ledger,bindingId:e.bindingId,currentLastInboundRevision:0,sender:e.sender,maxUserActivityWaitMs:n})}return r}function je(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 We(e){const t=e.sendResults.filter(u=>!z(u)),n=e.sendResults.filter(u=>!u.skipped).map(u=>u.details?.text&&typeof u.details.text=="string"?u.details.text:"").filter(Boolean),o=e.observedMessages.map(u=>[u.normalizedText||"",u.anchorText||"",u.textExcerpt||""].join(`
2
2
  `)).join(`
3
- `),r=n.filter(c=>o.includes(c)),s=e.sendResults.map(c=>typeof c.details?.sendStatus=="string"?c.details.sendStatus:"").filter(Boolean),a=e.sendResults.filter(H).length,i=j(t,"waitingRecords"),u=j(t,"failedRecords"),p=j(t,"manualReviewRecords"),l=t.find(c=>!c.ok||c.skipped),f=s.length===n.length&&s.every(c=>c==="sent_unconfirmed"||c==="confirmed_echo"),g=!l&&n.length>0&&r.length>0&&f&&i===0&&u===0&&p===0;return{ok:g,reasonCode:g?void 0:l?.reasonCode||(i>0?"outbound_send_waiting":void 0)||(u>0?"outbound_send_failed":void 0)||(p>0?"outbound_manual_review":void 0)||(f?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:i,failedOutboundCount:u,manualReviewCount:p}}function H(e){return e.skipped===!0&&e.reasonCode==="ffmpeg_unavailable_for_video_fixture"}function j(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 ke(e){const t=["send-text","send-file","send-image","send-video"],n=[];for(const i of t)n.push(await L({...e,step:i}));await _(1200);const o=await xe(e,3),r=k(o.messages);h(d.join(e.options.outDir,"bottom-page-summary.json"),r),h(d.join(e.options.outDir,"server-observe-messages.json"),o.messages);const s=Ae({sendResults:n,observedMessages:o.messages}),a=s.ok&&o.messages.length>0;return{step:"send-and-confirm",ok:a,reasonCode:a?void 0:s.reasonCode,errorSummary:n.find(i=>!i.ok||i.skipped)?.errorSummary,details:{sent:n.map(i=>({step:i.step,ok:i.ok,skipped:i.skipped,reasonCode:i.reasonCode,errorSummary:i.errorSummary,text:i.details?.text,attachmentPath:i.details?.attachmentPath,sendStatus:i.details?.sendStatus,deferReason:i.details?.deferReason,failureCode:i.details?.failureCode,commitStage:i.details?.commitStage,attemptCount:i.details?.attemptCount,nextAttemptAt:i.details?.nextAttemptAt,waitingRecords:i.details?.waitingRecords,failedRecords:i.details?.failedRecords,manualReviewRecords:i.details?.manualReviewRecords})),sentTexts:s.sentTexts,confirmedTexts:s.confirmedTexts,outboundStatuses:s.outboundStatuses,skippedFixtureCount:s.skippedFixtureCount,pendingOutboundCount:s.pendingOutboundCount,failedOutboundCount:s.failedOutboundCount,manualReviewCount:s.manualReviewCount,observedCount:o.messages.length,byKind:r.byKind,attachmentSummary:r.attachmentSummary,attachmentsDir:o.attachmentsDir,reportPath:d.join(e.options.outDir,"bottom-page-summary.json")}}}async function xe(e,t){let n;for(let o=1;o<=t;o+=1)try{return await S(e)}catch(r){if(n=r,o>=t||!_e(r))break;try{const s=await v(e.helper,e.options.traceId),a=await y(e.helper,s,e.options.traceId);await C({helper:e.helper,window:a,binding:e.binding,traceId:e.options.traceId})}catch{}await _(1500*o)}throw n}function _e(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 Re(e){const t=await S(e),n=k(t.messages);return h(d.join(e.options.outDir,"bottom-page-summary.json"),n),h(d.join(e.options.outDir,"server-observe-messages.json"),t.messages),{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:d.join(e.options.outDir,"bottom-page-summary.json")}}}async function De(e){const t=await S(e,{observePipeline:"edge-structure",persistLocalLedger:!0});W(e.options.outDir,"download-visible",t.observationEvidence);const n=k(t.messages),o=F(t.messages,t.attachmentsDir,{observePipeline:t.observePipeline,downloadAnchorText:e.options.downloadAnchorText,ledgerPath:t.ledgerPath,ledgerBinding:t.ledgerBinding,traceHashes:t.traceHashes});return h(d.join(e.options.outDir,"bottom-page-summary.json"),n),h(d.join(e.options.outDir,"download-visible-summary.json"),o),h(d.join(e.options.outDir,"download-visible-messages.json"),t.messages),{step:"download-visible-media",ok:o.ok,reasonCode:o.ok?void 0:o.reasonCode,details:{mediaCandidateCount:o.mediaCandidateCount,localAttachmentCount:o.localAttachmentCount,originalLocalAttachmentCount:o.originalLocalAttachmentCount,previewAttachmentCount:o.previewAttachmentCount,missingLocalPathCount:o.missingLocalPathCount,pendingAttachmentCount:o.pendingAttachmentCount,byKind:o.byKind,byAvailability:o.byAvailability,reasonCodes:o.reasonCodes,attachmentsDir:t.attachmentsDir,reportPath:d.join(e.options.outDir,"download-visible-summary.json"),phases:o.phases,observePipeline:o.observePipeline,ledgerPath:o.ledgerPath,ledgerRevision:o.ledger?.revision,traceHashes:o.traceHashes,traceEvents:o.traceEvents}}}async function Me(e){const t=await S(e,{observePipeline:"server-observe"});W(e.options.outDir,"server-observe",t.observationEvidence),h(d.join(e.options.outDir,"server-observe-messages.json"),t.messages);const n=U(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:E(t.messages.map(o=>o.kind||"unknown")),attachmentSummary:n,attachmentsDir:t.attachmentsDir}}}async function Pe(e){const t=await S(e,{observePipeline:"edge-structure",downloadMedia:!1});W(e.options.outDir,"structure-window",t.observationEvidence),h(d.join(e.options.outDir,"structure-window-messages.json"),t.messages);const n=U(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:E(t.messages.map(o=>o.kind||"unknown")),attachmentSummary:n,attachmentsDir:t.attachmentsDir}}}async function S(e,t={}){if(!e.options.sessionId)throw new Error("session_id_required: pass --session-id <existing Shennian session id> for server observe steps");const n=te({serverUrl:e.options.serverUrl});await n.upsertRuntime(e.runtime,{...e.binding,enabled:!1,allowReply:!1});const o=d.join(e.options.outDir,"inbound-attachments"),r=t.persistLocalLedger?Qe(e.options):void 0,s=r?ae(r,e.runtime.runtimeId):void 0;let a,i,u;const p=await ce({runtime:e.runtime,binding:{...e.binding,downloadMedia:t.downloadMedia??e.binding.downloadMedia},helper:e.helper,api:n,workDir:e.options.workDir,attachmentsDir:o,traceId:e.options.traceId,mediaAnchorText:e.options.downloadAnchorText,observePipeline:t.observePipeline,localLedgerTailAnchors:s?Ze(s.bindings[e.binding.bindingId]):void 0,onObservationEvidence:({capture:g,ocr:c})=>{a=We(g),i=Te(c),u=je(g,c,{captureHash:a,ocrHash:i})}});let l,f;if(s&&r){const g=de({ledger:s,bindingId:e.binding.bindingId,observedMessages:p});l=g.binding,f=G({bindingId:e.binding.bindingId,revision:l.revision,messages:g.newMessages}),ie(r,s)}return{messages:p,attachmentsDir:o,observePipeline:t.observePipeline,...r?{ledgerPath:r}:{},...l?{ledgerBinding:l}:{},traceHashes:{...a?{captureHash:a}:{},...i?{ocrHash:i}:{},...f?{ingestPayloadHash:f}:{}},...u?{observationEvidence:u}:{}}}function je(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 W(e,t,n){if(!n)return;const o=x(e,`${t}-observation-window`,n.capture);h(d.join(e,`${t}-observation-evidence.json`),{...n.report,screenshotPath:o})}function We(e){return`sha256:${R.createHash("sha256").update(Buffer.from(e.dataBase64,"base64")).digest("hex")}`}function Te(e){return G({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 K(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,p,l){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:l};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:l}}if(u==="automation.lease.acquire"){const f=await e.request(u,p,l),g=f.result&&typeof f.result=="object"?f.result:{};return s=typeof g.leaseId=="string"?g.leaseId:"",f}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:l}):{id:`human-lease-${r}`,ok:!0,result:{active:!0,leaseId:s,interrupted:!1},latencyMs:0,traceId:l}):e.request(u,p,l)}}}function q(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 Ee(){return{preflightBusySnapshots:0,forceIdleAfterBusy:!0}}function $e(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 Ne(e){const t=await v(e.helper,e.traceId),n=await y(e.helper,t,e.traceId);if(!(await C({helper:e.helper,window:n,binding:e.binding,traceId:e.traceId})).opened)return 0;const r=await M(e.helper,n.windowId,e.traceId),s=x(e.outDir,`${e.filePrefix}-observe-marker`,r),a=await P(e.helper,r,e.traceId);return h(d.join(e.outDir,`${e.filePrefix}-observe-marker-ocr.json`),{screenshotPath:s,marker:e.marker,ocr:a}),(a.blocks||[]).map(u=>u.text||"").join(`
4
- `).split(e.marker).length-1}function Fe(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 Oe(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 Be(e){return ue({runtimeId:e.runtimeId,machineId:e.machineId,pollIntervalMs:6e4,platform:e.platform,foregroundPolicy:"work",bindings:[{bindingId:`action-smoke:${I(e.conversation)}`,sessionId:e.sessionId||`action-smoke:${I(e.runtimeId)}`,conversationDisplayName:e.conversation,enabled:!0,allowReply:!0,downloadMedia:!0}]})}function Le(e){const t=ne({platform:e.platform});if(!t.ok)throw new Error(`${t.reasonCode}: ${t.message}`);return new re({helperPath:t.helperPath,expectedHelperVersion:t.version||oe,requiredCapabilities:He(e),guardUnsafeWindowsCommands:(e.platform??process.platform)==="win32",cleanupWindowsOverlays:(e.platform??process.platform)==="win32"})}function He(e){if((e.platform??process.platform)==="win32")return e.steps.some(t=>t.startsWith("send")||t.startsWith("human-send"))?D("send"):e.steps.some(t=>t==="download-visible-media")?D("download"):D("observe")}function Ke(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 qe(e,t){const n=d.join(t.outDir,"fixtures");w.mkdirSync(n,{recursive:!0});const o=new Date().toISOString().replace(/[-:.TZ]/g,"").slice(0,14);if(e==="send-text")return{text:t.text||`codex-product-action text ${o}`};if(e==="send-file"){const r=t.filePath||d.join(n,`wechat-action-smoke-${o}.txt`);return t.filePath||w.writeFileSync(r,`Shennian WeChat product action smoke
3
+ `),r=n.filter(u=>o.includes(u)),s=e.sendResults.map(u=>typeof u.details?.sendStatus=="string"?u.details.sendStatus:"").filter(Boolean),a=e.sendResults.filter(z).length,d=$(t,"waitingRecords"),l=$(t,"failedRecords"),c=$(t,"manualReviewRecords"),h=t.find(u=>!u.ok||u.skipped),m=s.length===n.length&&s.every(u=>u==="sent_unconfirmed"||u==="confirmed_echo"),p=!h&&n.length>0&&r.length>0&&m&&d===0&&l===0&&c===0;return{ok:p,reasonCode:p?void 0:h?.reasonCode||(d>0?"outbound_send_waiting":void 0)||(l>0?"outbound_send_failed":void 0)||(c>0?"outbound_manual_review":void 0)||(m?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:l,manualReviewCount:c}}function z(e){return e.skipped===!0&&e.reasonCode==="ffmpeg_unavailable_for_video_fixture"}function $(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 Ee(e){const t=["send-text","send-file","send-image","send-video"],n=[];for(const c of t)n.push(await V({...e,step:c}));await R(1200);const o=await $e(e,3),r=M(o.messages),s=i.join(e.options.outDir,"bottom-page.md"),a=y(o.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(o.attachmentsDir)});f(i.join(e.options.outDir,"bottom-page-summary.json"),r),f(i.join(e.options.outDir,"server-observe-messages.json"),o.messages),A(s,a);const d=We({sendResults:n,observedMessages:o.messages}),l=d.ok&&o.messages.length>0;return{step:"send-and-confirm",ok:l,reasonCode:l?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 $e(e,t){let n;for(let o=1;o<=t;o+=1)try{return await x(e)}catch(r){if(n=r,o>=t||!Be(r))break;try{const s=await C(e.helper,e.options.traceId),a=await k(e.helper,s,e.options.traceId);await I({helper:e.helper,window:a,binding:e.binding,traceId:e.options.traceId})}catch{}await R(1500*o)}throw n}function Be(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 Ne(e){const t=await x(e),n=M(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 f(i.join(e.options.outDir,"bottom-page-summary.json"),n),f(i.join(e.options.outDir,"server-observe-messages.json"),t.messages),A(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 Fe(e){const t=await x(e,{observePipeline:"edge-structure",persistLocalLedger:!0});B(e.options.outDir,"download-visible",t.observationEvidence);const n=M(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});f(i.join(e.options.outDir,"bottom-page-summary.json"),n),f(i.join(e.options.outDir,"download-visible-summary.json"),s),f(i.join(e.options.outDir,"download-visible-messages.json"),t.messages),A(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 Oe(e){const t=await x(e,{observePipeline:"server-observe"});B(e.options.outDir,"server-observe",t.observationEvidence),f(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)});A(n,o);const r=Q(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:O(t.messages.map(s=>s.kind||"unknown")),attachmentSummary:r,attachmentsDir:t.attachmentsDir,markdownPath:n,markdown:o}}}async function Le(e){const t=await x(e,{observePipeline:"edge-structure",downloadMedia:!1});B(e.options.outDir,"structure-window",t.observationEvidence),f(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)});A(n,o);const r=Q(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:O(t.messages.map(s=>s.kind||"unknown")),attachmentSummary:r,attachmentsDir:t.attachmentsDir,markdownPath:n,markdown:o}}}async function x(e,t={}){const n=pe({sessionId:e.options.sessionId,observePipeline:t.observePipeline}),o=se({serverUrl:e.options.serverUrl});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"),s=t.persistLocalLedger?ct(e.options):void 0,a=s?le(s,e.runtime.runtimeId):void 0;let d,l,c;const h=await fe({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,observePipeline:t.observePipeline,localLedgerTailAnchors:a?lt(a.bindings[e.binding.bindingId]):void 0,onObservationEvidence:({capture:u,ocr:b})=>{d=qe(u),l=Ke(b),c=He(u,b,{captureHash:d,ocrHash:l})}});let m,p;if(a&&s){const u=me({ledger:a,bindingId:e.binding.bindingId,observedMessages:h});m=u.binding,p=Y({bindingId:e.binding.bindingId,revision:m.revision,messages:u.newMessages}),ue(s,a)}return{messages:h,attachmentsDir:r,observePipeline:t.observePipeline,...s?{ledgerPath:s}:{},...m?{ledgerBinding:m}:{},traceHashes:{...d?{captureHash:d}:{},...l?{ocrHash:l}:{},...p?{ingestPayloadHash:p}:{}},...c?{observationEvidence:c}:{}}}function He(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 B(e,t,n){if(!n)return;const o=n.capture.dataBase64?T(e,`${t}-observation-window`,n.capture):void 0;f(i.join(e,`${t}-observation-evidence.json`),{...n.report,...o?{screenshotPath:o}:{}})}function qe(e){if(e.dataBase64)return`sha256:${D.createHash("sha256").update(Buffer.from(e.dataBase64,"base64")).digest("hex")}`}function Ke(e){return Y({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 G(e,t){let n=t,o=0,r=0,s="";const a=[];return{actionLog:a,setScenario(l){n=l,o=0,r=0},async request(l,c,h){if(a.push(l),l==="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:h};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:h}}if(l==="automation.lease.acquire"){const m=await e.request(l,c,h),p=m.result&&typeof m.result=="object"?m.result:{};return s=typeof p.leaseId=="string"?p.leaseId:"",m}return l==="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:h}):{id:`human-lease-${r}`,ok:!0,result:{active:!0,leaseId:s,interrupted:!1},latencyMs:0,traceId:h}):e.request(l,c,h)}}}function J(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 Ue(){return{preflightBusySnapshots:0,forceIdleAfterBusy:!0}}function Ve(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 N(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 W(e.helper,n.windowId,e.traceId),s=T(e.outDir,`${e.filePrefix}-observe-marker`,r),a=await E(e.helper,r,e.traceId);return f(i.join(e.outDir,`${e.filePrefix}-observe-marker-ocr.json`),{screenshotPath:s,marker:e.marker,ocr:a}),(a.blocks||[]).map(l=>l.text||"").join(`
4
+ `).split(e.marker).length-1}async function ze(e){const t=Math.max(1,e.attempts??3),n=typeof e.targetGreaterThan=="number"&&Number.isFinite(e.targetGreaterThan)?e.targetGreaterThan:null;let o=0;for(let r=0;r<t;r+=1){if(o=await N({helper:e.helper,binding:e.binding,marker:e.marker,traceId:e.traceId,outDir:e.outDir,filePrefix:`${e.filePrefix}-${r+1}`,settleToBottom:e.settleToBottom}),n==null?o>0:o>n)return o;r<t-1&&await R(800)}return o}function Ge(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 Je(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 Qe(e){return ge({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 Ze(e,t){const n=ae({platform:e.platform});if(!n.ok)throw new Error(`${n.reasonCode}: ${n.message}`);return new de({helperPath:n.helperPath,expectedHelperVersion:n.version||ie,requiredCapabilities:tt(e),guardUnsafeWindowsCommands:(e.platform??process.platform)==="win32",cleanupWindowsOverlays:(e.platform??process.platform)==="win32",requestLogger:Xe(t)})}function Xe(e){return t=>{w.appendFileSync(e,`${JSON.stringify(Ye(t))}
5
+ `)}}function Ye(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=P(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=P(e.result)),t}function P(e,t="",n=0){if(e==null||typeof e=="number"||typeof e=="boolean")return e;if(typeof e=="string")return et(t,e)?{type:"string",length:e.length,sha256:D.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(a=>P(a,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 o=e,r={};for(const[s,a]of Object.entries(o))r[s]=P(a,s,n+1);return r}function et(e,t){return t.length>240?!0:/(base64|bytes|data|image|screenshot|png|jpeg|jpg|buffer)/i.test(e)&&t.length>48}function tt(e){if((e.platform??process.platform)==="win32")return e.steps.some(t=>t.startsWith("send")||t.startsWith("human-send"))?j("send"):e.steps.some(t=>t==="download-visible-media")?j("download"):j("observe")}function nt(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 ot(e,t){const n=i.join(t.outDir,"fixtures");w.mkdirSync(n,{recursive:!0});const o=new Date().toISOString().replace(/[-:.TZ]/g,"").slice(0,14);if(e==="send-text")return{text:t.text||`codex-product-action text ${o}`};if(e==="send-file"){const r=t.filePath||i.join(n,`wechat-action-smoke-${o}.txt`);return t.filePath||w.writeFileSync(r,`Shennian WeChat product action smoke
5
6
  ${o}
6
- `,"utf8"),{text:`codex-product-action file ${o}`,attachmentPath:r}}if(e==="send-image"){const r=t.imagePath||d.join(n,`wechat-action-smoke-${o}.png`);return t.imagePath||Xe(r),{text:`codex-product-action image ${o}`,attachmentPath:r}}if(e==="send-video"){const r=t.videoPath||d.join(n,`wechat-action-smoke-${o}.mp4`);return!t.videoPath&&!Ye(r)?{skipped:!0,reasonCode:"ffmpeg_unavailable_for_video_fixture"}:{text:`codex-product-action video ${o}`,attachmentPath:r}}throw new Error(`step ${e} is not a send step`)}function U(e){const t=e.flatMap(n=>Ue(n.mediaMetadata));return{count:t.length,byAvailability:E(t.map(n=>V(n,"availability")||"unknown")),localPaths:t.map(n=>V(n,"localPath")).filter(n=>!!n)}}function Ue(e){if(!e||typeof e!="object")return[];const t=e;return Array.isArray(t.attachments)?t.attachments.filter(z):z(t.attachment)?[t.attachment]:t.localPath||t.url||t.availability||t.name||t.fileName?[t]:[]}function Ve(e){const t=m(e,"--mode")||(e[0]?.startsWith("--")?"":e[0]);return t==="send"||t==="observe"||t==="all"||t==="open-read"?t:"open-read"}function ze(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 Ge(e,t){const n=[];for(let o=0;o<e.length;o+=1)e[o]===t&&e[o+1]&&n.push(e[o+1]);return n}function m(e,t){const n=e.indexOf(t),o=n>=0?e[n+1]:void 0;return o&&!o.startsWith("--")?o:void 0}function T(e){return e?d.resolve(e):void 0}function Je(e){return Array.from(new Set(e))}function x(e,t,n){const o=n.mimeType.includes("jpeg")?".jpg":".png",r=d.join(e,`${t}${o}`);return w.writeFileSync(r,Buffer.from(n.dataBase64,"base64")),r}function h(e,t){w.mkdirSync(d.dirname(e),{recursive:!0}),w.writeFileSync(e,`${JSON.stringify(t,null,2)}
7
- `,"utf8")}function Qe(e){return d.join(e.outDir,"wechat-channel-ledger.json")}function Ze(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 Xe(e){w.writeFileSync(e,Buffer.from("iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAAVElEQVR4nO3PMQ0AMAgAMUTof2kOKWzo8mCqkmeX9waYtwOwG4DbANwG4DYAtwG4DcBtAG4DcBuA2wDcBuA2ALcBuA3AbQBuA3AbgNsA3AbgNgC3AbgNwG0AbgNwG8BPDyCqAzmh3yHRAAAAAElFTkSuQmCC","base64"))}function Ye(e){return X("ffmpeg",["-y","-f","lavfi","-i","testsrc=size=160x120:rate=5","-t","1","-pix_fmt","yuv420p",e],{encoding:"utf8",stdio:"ignore",timeout:2e4}).status===0&&w.existsSync(e)}function E(e){const t={};for(const n of e)t[n]=(t[n]??0)+1;return t}function V(e,t){return typeof e[t]=="string"?e[t].trim():""}function Ct(e,t){const n=Number(e[t]);return Number.isFinite(n)?n:null}function z(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function I(e){return R.createHash("sha256").update(e).digest("hex").slice(0,16)}function G(e){return`sha256:${R.createHash("sha256").update(et(e)).digest("hex")}`}function et(e){return JSON.stringify($(e))}function $(e){if(Array.isArray(e))return e.map($);if(!e||typeof e!="object")return e;const t=e;return Object.fromEntries(Object.keys(t).sort().map(n=>[n,$(t[n])]))}function tt(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 nt(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 _(e){return new Promise(t=>setTimeout(t,e))}function ot(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)}
8
- `)}async function rt(){const e=he(process.argv.slice(2)),t=await ge(e);ot(t),(!t.ok||e.requireServer&&t.steps.some(n=>n.step==="server-observe"&&!n.ok))&&process.exit(1)}process.argv[1]&&d.resolve(process.argv[1])===Y(import.meta.url)&&rt().catch(e=>{process.stderr.write(`${e instanceof Error?e.stack||e.message:String(e)}
9
- `),process.exit(1)});export{k as buildBottomPageReport,F as buildDownloadVisibleMediaReport,Ae as buildSendAndConfirmEvidence,Ie as nextSmokeDrainWaitMs,he as parseWeChatChannelActionSmokeArgs,ge as runWeChatChannelActionSmoke,fe as stepsForMode};
7
+ `,"utf8"),{text:`codex-product-action file ${o}`,attachmentPath:r}}if(e==="send-image"){const r=t.imagePath||i.join(n,`wechat-action-smoke-${o}.png`);return t.imagePath||ut(r),{text:`codex-product-action image ${o}`,attachmentPath:r}}if(e==="send-video"){const r=t.videoPath||i.join(n,`wechat-action-smoke-${o}.mp4`);return!t.videoPath&&!mt(r)?{skipped:!0,reasonCode:"ffmpeg_unavailable_for_video_fixture"}:{text:`codex-product-action video ${o}`,attachmentPath:r}}throw new Error(`step ${e} is not a send step`)}function Q(e){const t=e.flatMap(n=>rt(n.mediaMetadata));return{count:t.length,byAvailability:O(t.map(n=>Z(n,"availability")||"unknown")),localPaths:t.map(n=>Z(n,"localPath")).filter(n=>!!n)}}function rt(e){if(!e||typeof e!="object")return[];const t=e;return Array.isArray(t.attachments)?t.attachments.filter(X):X(t.attachment)?[t.attachment]:t.localPath||t.url||t.availability||t.name||t.fileName?[t]:[]}function st(e){const t=g(e,"--mode")||(e[0]?.startsWith("--")?"":e[0]);return t==="send"||t==="observe"||t==="all"||t==="open-read"?t:"open-read"}function at(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 it(e,t){const n=[];for(let o=0;o<e.length;o+=1)e[o]===t&&e[o+1]&&n.push(e[o+1]);return n}function g(e,t){const n=e.indexOf(t),o=n>=0?e[n+1]:void 0;return o&&!o.startsWith("--")?o:void 0}function F(e){return e?i.resolve(e):void 0}function dt(e){return Array.from(new Set(e))}function T(e,t,n){const o=n.mimeType.includes("jpeg")?".jpg":".png",r=i.join(e,`${t}${o}`);return w.writeFileSync(r,Buffer.from(n.dataBase64,"base64")),r}function f(e,t){w.mkdirSync(i.dirname(e),{recursive:!0}),w.writeFileSync(e,`${JSON.stringify(t,null,2)}
8
+ `,"utf8")}function A(e,t){w.mkdirSync(i.dirname(e),{recursive:!0}),w.writeFileSync(e,t,"utf8")}function ct(e){return i.join(e.outDir,"wechat-channel-ledger.json")}function lt(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 ut(e){w.writeFileSync(e,Buffer.from("iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAAVElEQVR4nO3PMQ0AMAgAMUTof2kOKWzo8mCqkmeX9waYtwOwG4DbANwG4DYAtwG4DcBtAG4DcBuA2wDcBuA2ALcBuA3AbQBuA3AbgNsA3AbgNgC3AbgNwG0AbgNwG8BPDyCqAzmh3yHRAAAAAElFTkSuQmCC","base64"))}function mt(e){return ne("ffmpeg",["-y","-f","lavfi","-i","testsrc=size=160x120:rate=5","-t","1","-pix_fmt","yuv420p",e],{encoding:"utf8",stdio:"ignore",timeout:2e4}).status===0&&w.existsSync(e)}function O(e){const t={};for(const n of e)t[n]=(t[n]??0)+1;return t}function Z(e,t){return typeof e[t]=="string"?e[t].trim():""}function X(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function _(e){return D.createHash("sha256").update(e).digest("hex").slice(0,16)}function Y(e){return`sha256:${D.createHash("sha256").update(ht(e)).digest("hex")}`}function ht(e){return JSON.stringify(L(e))}function L(e){if(Array.isArray(e))return e.map(L);if(!e||typeof e!="object")return e;const t=e;return Object.fromEntries(Object.keys(t).sort().map(n=>[n,L(t[n])]))}function ft(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 gt(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 R(e){return new Promise(t=>setTimeout(t,e))}function pt(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 wt(){const e=ve(process.argv.slice(2)),t=await Se(e);pt(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])===oe(import.meta.url)&&wt().catch(e=>{process.stderr.write(`${e instanceof Error?e.stack||e.message:String(e)}
10
+ `),process.exit(1)});export{M as buildBottomPageReport,q as buildDownloadVisibleMediaReport,We as buildSendAndConfirmEvidence,Pe as buildSendStepAcceptance,je as nextSmokeDrainWaitMs,ve as parseWeChatChannelActionSmokeArgs,pe as resolveWeChatSmokeObserveSessionMode,Se as runWeChatChannelActionSmoke,ye as stepsForMode};
@@ -0,0 +1,6 @@
1
+ import type { WeChatChannelObservedMessage } from '../channels/wechat-channel/client.js';
2
+ export type WeChatMessagesMarkdownOptions = {
3
+ conversation?: string;
4
+ attachmentsDirName?: string;
5
+ };
6
+ export declare function buildWeChatMessagesMarkdown(messages: WeChatChannelObservedMessage[], options?: WeChatMessagesMarkdownOptions): string;
@@ -0,0 +1,5 @@
1
+ import d from"node:path";function x(n,t={}){const e=[];if(t.conversation?.trim()&&e.push(`${i(t.conversation)}:`),n.length===0)return e.push("\u6D88\u606F: \uFF08\u6CA1\u6709\u8BFB\u5230\uFF09"),`${e.join(`
2
+ `)}
3
+ `;for(const r of n)e.push(`${l(r)}: ${m(r,t)}`);return`${e.join(`
4
+ `)}
5
+ `}function l(n){return n.senderName?.trim()?i(n.senderName):n.senderRole==="self"?"\u6211":n.senderRole==="system"?"\u7CFB\u7EDF":n.senderRole==="contact"?"\u5BF9\u65B9":"\u672A\u77E5"}function m(n,t){const e=$(n);if(e.length>0)return e.map(a=>h(a,n,t)).join("\u3001");const r=n.normalizedText||n.anchorText||n.textExcerpt;return r?.trim()?i(r):`\uFF08${s(n.kind)}\uFF09`}function h(n,t,e){const r=o(n,"localPath"),a=o(n,"name")||o(n,"fileName")||f(r)||s(o(n,"type")||t.kind),u=p(r,e);return u?`[${y(a)}](${k(u)})`:i(a)}function p(n,t){if(!n)return"";const e=f(n);return e&&t.attachmentsDirName?`${t.attachmentsDirName.replace(/\\/g,"/")}/${e}`:n.replace(/\\/g,"/")}function $(n){const t=c(n.mediaMetadata)?n.mediaMetadata:{},e=[];return c(t.attachment)&&e.push(t.attachment),Array.isArray(t.attachments)&&e.push(...t.attachments.filter(c)),e}function f(n){return n?d.posix.basename(n.replace(/\\/g,"/")):""}function s(n){const t=String(n||"").toLowerCase();return t.includes("image")||t.includes("photo")?"\u56FE\u7247":t.includes("video")?"\u89C6\u9891":t.includes("file")||t.includes("document")?"\u6587\u4EF6":"\u6D88\u606F"}function k(n){return/[\s()<>]/.test(n)?`<${n.replace(/[<>]/g,"")}>`:n}function y(n){return i(n).replace(/([\\\]])/g,"\\$1")}function i(n){return String(n||"").replace(/\s+/g," ").trim()}function o(n,t){const e=n[t];return typeof e=="string"?e:""}function c(n){return!!n&&typeof n=="object"&&!Array.isArray(n)}export{x as buildWeChatMessagesMarkdown};
@@ -1,8 +1,9 @@
1
- import { type WeChatChannelActionSmokeOptions, type WeChatChannelActionSmokeStep } from './wechat-channel-action-smoke.js';
2
- export type WeChatChannelProductStepName = 'open-conversation' | 'fingerprint' | 'visible-structure' | 'server-observe' | 'download-visible' | 'read-bottom-page' | 'send-message' | 'send-and-confirm' | 'send-text' | 'send-file' | 'send-image' | 'send-video' | 'observe' | 'human-coordination' | 'human-send-core' | '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' | 'all';
1
+ import { runWeChatChannelActionSmoke, type WeChatChannelActionSmokeOptions, type WeChatChannelActionSmokeStep } from './wechat-channel-action-smoke.js';
2
+ export type WeChatChannelProductStepName = 'open-conversation' | 'fingerprint' | 'visible-structure' | 'server-observe' | 'download-visible' | 'read-visible' | 'read-bottom-page' | 'send-message' | 'send-and-confirm' | 'send-text' | 'send-file' | 'send-image' | 'send-video' | 'observe' | 'human-coordination' | 'human-send-core' | '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' | 'all';
3
3
  export type WeChatChannelProductStepsOptions = WeChatChannelActionSmokeOptions & {
4
4
  productStep: WeChatChannelProductStepName;
5
5
  };
6
6
  export declare function parseWeChatChannelProductStepsArgs(argv: string[]): WeChatChannelProductStepsOptions;
7
7
  export declare function stepsForProductStep(step: WeChatChannelProductStepName): WeChatChannelActionSmokeStep[];
8
+ export declare function collectWeChatProductStepMarkdown(result: Awaited<ReturnType<typeof runWeChatChannelActionSmoke>>): string;
8
9
  export declare function isWeChatChannelProductStepsEntrypoint(metaUrl: string, argvPath?: string): boolean;
@@ -1,4 +1,4 @@
1
- import u from"node:path";import{fileURLToPath as l}from"node:url";import{parseWeChatChannelActionSmokeArgs as m,runWeChatChannelActionSmoke as c}from"./wechat-channel-action-smoke.js";const h={open:"open-conversation","open-read":"open-conversation","open-conversation":"open-conversation",fingerprint:"fingerprint","visible-structure":"visible-structure",structure:"visible-structure","structure-window":"visible-structure","server-observe":"server-observe","legacy-observe":"server-observe","download-visible":"download-visible",download:"download-visible","read-bottom-page":"read-bottom-page","bottom-page":"read-bottom-page","read-bottom":"read-bottom-page","send-message":"send-message",send:"send-message","send-and-confirm":"send-and-confirm","send-confirm":"send-and-confirm","send-text":"send-text","send-file":"send-file","send-image":"send-image","send-video":"send-video",observe:"observe","human-coordination":"human-coordination","human-send-core":"human-send-core","human-send-preflight-busy":"human-send-preflight-busy","human-send-preflight-busy-then-idle":"human-send-preflight-busy-then-idle","human-send-user-active-timeout":"human-send-user-active-timeout","human-send-takeover-during-run":"human-send-takeover-during-run","human-send-takeover-then-idle":"human-send-takeover-then-idle","human-send-normal":"human-send-normal","human-observe-deferred":"human-observe-deferred",all:"all"};function f(e){const n=e.filter(o=>o!=="--"),r=v(n),t=n.filter((o,d)=>!(d===0&&!o.startsWith("--")));return{...m(["--mode",r==="all"?"all":"custom",...t,...p(r)]),productStep:r,mode:r==="all"?"all":"custom",steps:i(r)}}function i(e){return e==="open-conversation"||e==="fingerprint"?["open-read"]:e==="visible-structure"||e==="observe"?["structure-window"]:e==="server-observe"?["server-observe"]:e==="download-visible"?["download-visible-media"]:e==="read-bottom-page"?["read-bottom-page"]:e==="send-text"?["open-read","send-text"]:e==="send-file"?["open-read","send-file"]:e==="send-image"?["open-read","send-image"]:e==="send-video"?["open-read","send-video"]:e==="send-message"?["open-read","send-text","send-file","send-image","send-video"]:e==="send-and-confirm"?["open-read","send-and-confirm"]:e==="human-send-preflight-busy"?["human-send-preflight-busy"]:e==="human-send-preflight-busy-then-idle"?["human-send-preflight-busy-then-idle"]:e==="human-send-user-active-timeout"?["human-send-user-active-timeout"]:e==="human-send-takeover-during-run"?["human-send-takeover-during-run"]:e==="human-send-takeover-then-idle"?["human-send-takeover-then-idle"]:e==="human-send-normal"?["human-send-normal"]:e==="human-observe-deferred"?["human-observe-deferred"]:e==="human-send-core"||e==="human-coordination"?["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"]:["open-read","send-text","send-file","send-image","send-video","structure-window"]}function p(e){return i(e).flatMap(n=>["--step",n])}function v(e){const n=a(e,"--product-step")||a(e,"--step-name"),r=e[0]&&!e[0].startsWith("--")?e[0]:"",t=String(n||r||"open-conversation").trim(),s=t.toLowerCase().replace(/_/g,"-"),o=h[s];if(!o)throw new Error(`unknown_product_step: ${t}`);return o}function a(e,n){const r=e.indexOf(n),t=r>=0?e[r+1]:void 0;return t&&!t.startsWith("--")?t:void 0}function g(){process.stdout.write(`Usage:
1
+ import u from"node:path";import{fileURLToPath as l}from"node:url";import{parseWeChatChannelActionSmokeArgs as m,runWeChatChannelActionSmoke as c}from"./wechat-channel-action-smoke.js";const h={open:"open-conversation","open-read":"open-conversation","open-conversation":"open-conversation",fingerprint:"fingerprint","visible-structure":"visible-structure",structure:"visible-structure","structure-window":"visible-structure","server-observe":"server-observe","legacy-observe":"server-observe","download-visible":"download-visible",download:"download-visible",read:"read-visible","read-visible":"read-visible","read-messages":"read-visible",messages:"read-visible","read-bottom-page":"read-bottom-page","bottom-page":"read-bottom-page","read-bottom":"read-bottom-page","send-message":"send-message",send:"send-message","send-and-confirm":"send-and-confirm","send-confirm":"send-and-confirm","send-text":"send-text","send-file":"send-file","send-image":"send-image","send-video":"send-video",observe:"observe","human-coordination":"human-coordination","human-send-core":"human-send-core","human-send-preflight-busy":"human-send-preflight-busy","human-send-preflight-busy-then-idle":"human-send-preflight-busy-then-idle","human-send-user-active-timeout":"human-send-user-active-timeout","human-send-takeover-during-run":"human-send-takeover-during-run","human-send-takeover-then-idle":"human-send-takeover-then-idle","human-send-normal":"human-send-normal","human-observe-deferred":"human-observe-deferred",all:"all"};function p(e){const n=e.filter(o=>o!=="--"),r=v(n),t=n.filter((o,d)=>!(d===0&&!o.startsWith("--"))),s=m(["--mode",r==="all"?"all":"custom",...t,...f(r)]);return{...s,allowEmptyMedia:s.allowEmptyMedia||r==="read-visible",productStep:r,mode:r==="all"?"all":"custom",steps:i(r)}}function i(e){return e==="open-conversation"||e==="fingerprint"?["open-read"]:e==="visible-structure"||e==="observe"?["structure-window"]:e==="server-observe"?["server-observe"]:e==="download-visible"?["download-visible-media"]:e==="read-visible"?["download-visible-media"]:e==="read-bottom-page"?["read-bottom-page"]:e==="send-text"?["open-read","send-text"]:e==="send-file"?["open-read","send-file"]:e==="send-image"?["open-read","send-image"]:e==="send-video"?["open-read","send-video"]:e==="send-message"?["open-read","send-text","send-file","send-image","send-video"]:e==="send-and-confirm"?["open-read","send-and-confirm"]:e==="human-send-preflight-busy"?["human-send-preflight-busy"]:e==="human-send-preflight-busy-then-idle"?["human-send-preflight-busy-then-idle"]:e==="human-send-user-active-timeout"?["human-send-user-active-timeout"]:e==="human-send-takeover-during-run"?["human-send-takeover-during-run"]:e==="human-send-takeover-then-idle"?["human-send-takeover-then-idle"]:e==="human-send-normal"?["human-send-normal"]:e==="human-observe-deferred"?["human-observe-deferred"]:e==="human-send-core"||e==="human-coordination"?["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"]:["open-read","send-text","send-file","send-image","send-video","structure-window"]}function f(e){return i(e).flatMap(n=>["--step",n])}function v(e){const n=a(e,"--product-step")||a(e,"--step-name"),r=e[0]&&!e[0].startsWith("--")?e[0]:"",t=String(n||r||"open-conversation").trim(),s=t.toLowerCase().replace(/_/g,"-"),o=h[s];if(!o)throw new Error(`unknown_product_step: ${t}`);return o}function a(e,n){const r=e.indexOf(n),t=r>=0?e[r+1]:void 0;return t&&!t.startsWith("--")?t:void 0}function b(){process.stdout.write(`Usage:
2
2
  pnpm wechat:rpa:product-steps -- <step> [options]
3
3
 
4
4
  Product steps:
@@ -7,6 +7,7 @@ Product steps:
7
7
  visible-structure Run structure-window on the full WeChat window.
8
8
  server-observe Run the legacy /observe compatibility path for debug only.
9
9
  download-visible Run the full visible-media edge flow and validate local attachments.
10
+ read-visible Default read: structure recent messages and download visible attachments when present.
10
11
  read-bottom-page Observe the current bottom page and write bottom-page-summary.json.
11
12
  send-message Send text, file, image and video fixtures.
12
13
  send-and-confirm Send fixtures, observe bottom page, and confirm at least one sent text is visible.
@@ -31,6 +32,9 @@ Common options:
31
32
 
32
33
  This devtool runs the product helper/runtime from the workspace. It does not enable
33
34
  the long-running WeChat channel and does not require changing the global shennian CLI.
34
- `)}async function b(){if(process.argv.includes("--help")||process.argv.includes("-h")){g();return}const e=f(process.argv.slice(2)),n=await c(e);process.stdout.write(`${JSON.stringify({ok:n.ok,productStep:e.productStep,conversation:n.conversation,outDir:n.outDir,durationMs:n.durationMs,steps:n.steps},null,2)}
35
- `),n.ok||(process.exitCode=1)}function w(e,n=process.argv[1]){if(!n)return!1;try{return u.resolve(n)===l(e)}catch{return!1}}w(import.meta.url)&&b().catch(e=>{process.stderr.write(`${e.stack||e.message||String(e)}
36
- `),process.exit(1)});export{w as isWeChatChannelProductStepsEntrypoint,f as parseWeChatChannelProductStepsArgs,i as stepsForProductStep};
35
+ `)}async function g(){if(process.argv.includes("--help")||process.argv.includes("-h")){b();return}const e=p(process.argv.slice(2)),n=await c(e),r=w(n);r&&process.stdout.write(`${r}
36
+ `),process.stdout.write(`${JSON.stringify({ok:n.ok,productStep:e.productStep,conversation:n.conversation,outDir:n.outDir,helperTracePath:n.helperTracePath,durationMs:n.durationMs,steps:n.steps},null,2)}
37
+ `),n.ok||(process.exitCode=1)}function w(e){return e.steps.map(n=>typeof n.details?.markdown=="string"?n.details.markdown.trim():"").filter(Boolean).join(`
38
+
39
+ `)}function k(e,n=process.argv[1]){if(!n)return!1;try{return u.resolve(n)===l(e)}catch{return!1}}k(import.meta.url)&&g().catch(e=>{process.stderr.write(`${e.stack||e.message||String(e)}
40
+ `),process.exit(1)});export{w as collectWeChatProductStepMarkdown,k as isWeChatChannelProductStepsEntrypoint,p as parseWeChatChannelProductStepsArgs,i as stepsForProductStep};
@@ -1,2 +1,2 @@
1
- import u from"node:fs";import h from"node:path";import{randomUUID as y}from"node:crypto";import{extractPayloadText as k,isAgentHiddenPayload as A,isToolPayload as T}from"@shennian/wire";import{resolveShennianPath as w}from"../config/index.js";import{listSessionRecords as I,readMessages as v}from"../session/store.js";import{listProjectedSessions as M}from"../session/projection.js";const g=w("manager-registry.json");function l(){return new Date().toISOString()}function W(){return{managers:{},workers:{},replyTargets:{}}}class O{load(){try{const e=JSON.parse(u.readFileSync(g,"utf-8"));return{managers:e.managers??{},workers:e.workers??{},replyTargets:e.replyTargets??{}}}catch{return W()}}save(e){u.mkdirSync(h.dirname(g),{recursive:!0}),u.writeFileSync(g,JSON.stringify(e,null,2))}upsertManager(e){const t=this.load(),r=t.managers[e.sessionId],a=l(),s={sessionId:e.sessionId,agentSessionId:e.agentSessionId??r?.agentSessionId??null,workDir:e.workDir,machineId:e.machineId??r?.machineId??null,modelId:e.modelId,defaultWorkerAgentType:e.defaultWorkerAgentType??r?.defaultWorkerAgentType??null,defaultWorkerModelId:e.defaultWorkerModelId??r?.defaultWorkerModelId??null,status:e.status??r?.status??"idle",managedWorkerSessionIds:r?.managedWorkerSessionIds??[],attachedExternalChannels:r?.attachedExternalChannels??[],createdAt:r?.createdAt??a,updatedAt:a};return t.managers[e.sessionId]=s,this.save(t),s}getManager(e){return this.load().managers[e]}addWorker(e){const t=this.load(),r=t.managers[e.managerSessionId];if(!r)throw new Error("Manager runtime is not registered");const a=e.sessionId??`sess_worker_${y()}`,s=l(),o={sessionId:a,agentType:e.agentType,workDir:e.workDir,managedBy:e.managerSessionId,status:"running",createdAt:s,updatedAt:s,lastActivityAt:s,summary:e.summary??null,agentSessionId:null,runId:null};return t.workers[a]=o,r.managedWorkerSessionIds.includes(a)||r.managedWorkerSessionIds.push(a),r.updatedAt=s,this.save(t),o}updateWorker(e,t){const r=this.load(),a=r.workers[e];if(!a)return;const s={...a,...t,updatedAt:l()};return r.workers[e]=s,this.save(r),s}listWorkers(e,t={}){const r=this.load(),a=r.managers[e];if(!a)return[];const s=Object.values(r.workers).filter(n=>n.workDir===a.workDir).filter(n=>t.includeManagers||n.agentType!=="manager").map(n=>this.decorateManagedWorker(n,t.runningSessionIds)),o=new Set(s.map(n=>n.sessionId)),i=I().filter(n=>n.workDir===a.workDir).filter(n=>t.includeManagers||n.agentType!=="manager").filter(n=>!o.has(n.sessionId)).map(n=>this.sessionRecordToWorker(n,t.runningSessionIds)),c=new Set([...s,...i].map(n=>n.sessionId)),f=(t.projectedSessions??M()).filter(n=>n.workDir===a.workDir).filter(n=>t.includeManagers||n.agentType!=="manager").filter(n=>!c.has(n.id)).map(n=>this.projectedSessionToWorker(n,t.runningSessionIds));return[...s,...i,...f].sort((n,S)=>S.lastActivityAt.localeCompare(n.lastActivityAt))}getWorkerForManager(e,t){const r=this.load(),a=r.managers[e],s=r.workers[t];if(!a)return;if(s)return s.workDir!==a.workDir||s.agentType==="manager"?void 0:this.decorateManagedWorker(s);const o=I().find(i=>i.sessionId===t);if(!(!o||o.workDir!==a.workDir||o.agentType==="manager"))return this.sessionRecordToWorker(o)}decorateManagedWorker(e,t){const r=t?.has(e.sessionId)?"running":e.status,a=this.readTranscriptSummary(e.sessionId,e.summary??null),s=a.lastMessagePreview??e.lastMessagePreview??e.summary??null,o=e.userGoal??a.userGoal??null;return{...e,managedBy:e.managedBy??null,status:r,title:e.title??o??s??e.summary??e.sessionId,userGoal:o,lastMessagePreview:s,summary:e.summary??s,canResume:e.canResume??e.status!=="aborted",source:e.source??"manager_registry",role:"managed_worker"}}sessionRecordToWorker(e,t){const r=this.readTranscriptSummary(e.sessionId,e.lastMessagePreview??null),a=r.lastMessagePreview??e.lastMessagePreview??null,s=r.userGoal,o=t?.has(e.sessionId)?"running":e.status==="failed"?"error":e.status==="completed"?"final":"idle";return{sessionId:e.sessionId,agentType:e.agentType,workDir:e.workDir,managedBy:null,status:o,createdAt:e.createdAt,updatedAt:e.updatedAt,lastActivityAt:e.lastActivityAt,title:s??a??e.sessionId,userGoal:s,lastMessagePreview:a,summary:a??s??null,agentSessionId:e.agentSessionId??null,runId:null,canResume:!!e.agentSessionId,source:"local_index",role:"project_session"}}projectedSessionToWorker(e,t){const r=e.lastMessagePreview??null,a=e.title?.trim()||r,s=t?.has(e.id)?"running":e.status==="failed"?"error":e.status==="completed"?"final":"idle";return{sessionId:e.id,agentType:e.agentType,workDir:e.workDir,managedBy:null,status:s,createdAt:e.createdAt,updatedAt:e.updatedAt,lastActivityAt:e.lastActivityAt||e.updatedAt,title:a??e.id,userGoal:a??null,lastMessagePreview:r,summary:r??a??null,agentSessionId:e.agentSessionId??null,runId:e.activity?.runId??null,canResume:!0,source:"app_projection",role:"project_session"}}readTranscriptSummary(e,t){const r=v(e,{limit:200});if(!r.length)return{userGoal:null,lastMessagePreview:t};const a=[...r].sort((i,c)=>i.ts-c.ts),s=a.find(i=>i.role==="user"),o=[...a].reverse().find(i=>m(i));return{userGoal:s?p(m(s),160):null,lastMessagePreview:p(m(o),180)??t}}createReplyTarget(e){const t=this.load(),r={replyTarget:`rt_${y()}`,managerSessionId:e.managerSessionId,channelId:e.channelId,conversationId:e.conversationId,messageId:e.messageId??null,createdAt:l()};return t.replyTargets[r.replyTarget]=r,this.save(t),r}getReplyTarget(e){return this.load().replyTargets[e]}getLatestReplyTargetForManager(e){return Object.values(this.load().replyTargets).filter(t=>t.managerSessionId===e).sort((t,r)=>r.createdAt.localeCompare(t.createdAt))[0]}}function m(d){return!d||T(d.payload)||A(d.payload)?null:k(d.payload).replace(/\r\n/g,`
1
+ import u from"node:fs";import h from"node:path";import{randomUUID as y}from"node:crypto";import{extractPayloadText as k,isAgentHiddenPayload as A,isSystemControlPayload as T,isToolPayload as w}from"@shennian/wire";import{resolveShennianPath as v}from"../config/index.js";import{listSessionRecords as I,readMessages as M}from"../session/store.js";import{listProjectedSessions as W}from"../session/projection.js";const g=v("manager-registry.json");function l(){return new Date().toISOString()}function D(){return{managers:{},workers:{},replyTargets:{}}}class O{load(){try{const e=JSON.parse(u.readFileSync(g,"utf-8"));return{managers:e.managers??{},workers:e.workers??{},replyTargets:e.replyTargets??{}}}catch{return D()}}save(e){u.mkdirSync(h.dirname(g),{recursive:!0}),u.writeFileSync(g,JSON.stringify(e,null,2))}upsertManager(e){const t=this.load(),r=t.managers[e.sessionId],a=l(),s={sessionId:e.sessionId,agentSessionId:e.agentSessionId??r?.agentSessionId??null,workDir:e.workDir,machineId:e.machineId??r?.machineId??null,modelId:e.modelId,defaultWorkerAgentType:e.defaultWorkerAgentType??r?.defaultWorkerAgentType??null,defaultWorkerModelId:e.defaultWorkerModelId??r?.defaultWorkerModelId??null,status:e.status??r?.status??"idle",managedWorkerSessionIds:r?.managedWorkerSessionIds??[],attachedExternalChannels:r?.attachedExternalChannels??[],createdAt:r?.createdAt??a,updatedAt:a};return t.managers[e.sessionId]=s,this.save(t),s}getManager(e){return this.load().managers[e]}addWorker(e){const t=this.load(),r=t.managers[e.managerSessionId];if(!r)throw new Error("Manager runtime is not registered");const a=e.sessionId??`sess_worker_${y()}`,s=l(),o={sessionId:a,agentType:e.agentType,workDir:e.workDir,managedBy:e.managerSessionId,status:"running",createdAt:s,updatedAt:s,lastActivityAt:s,summary:e.summary??null,agentSessionId:null,runId:null};return t.workers[a]=o,r.managedWorkerSessionIds.includes(a)||r.managedWorkerSessionIds.push(a),r.updatedAt=s,this.save(t),o}updateWorker(e,t){const r=this.load(),a=r.workers[e];if(!a)return;const s={...a,...t,updatedAt:l()};return r.workers[e]=s,this.save(r),s}listWorkers(e,t={}){const r=this.load(),a=r.managers[e];if(!a)return[];const s=Object.values(r.workers).filter(n=>n.workDir===a.workDir).filter(n=>t.includeManagers||n.agentType!=="manager").map(n=>this.decorateManagedWorker(n,t.runningSessionIds)),o=new Set(s.map(n=>n.sessionId)),i=I().filter(n=>n.workDir===a.workDir).filter(n=>t.includeManagers||n.agentType!=="manager").filter(n=>!o.has(n.sessionId)).map(n=>this.sessionRecordToWorker(n,t.runningSessionIds)),c=new Set([...s,...i].map(n=>n.sessionId)),f=(t.projectedSessions??W()).filter(n=>n.workDir===a.workDir).filter(n=>t.includeManagers||n.agentType!=="manager").filter(n=>!c.has(n.id)).map(n=>this.projectedSessionToWorker(n,t.runningSessionIds));return[...s,...i,...f].sort((n,S)=>S.lastActivityAt.localeCompare(n.lastActivityAt))}getWorkerForManager(e,t){const r=this.load(),a=r.managers[e],s=r.workers[t];if(!a)return;if(s)return s.workDir!==a.workDir||s.agentType==="manager"?void 0:this.decorateManagedWorker(s);const o=I().find(i=>i.sessionId===t);if(!(!o||o.workDir!==a.workDir||o.agentType==="manager"))return this.sessionRecordToWorker(o)}decorateManagedWorker(e,t){const r=t?.has(e.sessionId)?"running":e.status,a=this.readTranscriptSummary(e.sessionId,e.summary??null),s=a.lastMessagePreview??e.lastMessagePreview??e.summary??null,o=e.userGoal??a.userGoal??null;return{...e,managedBy:e.managedBy??null,status:r,title:e.title??o??s??e.summary??e.sessionId,userGoal:o,lastMessagePreview:s,summary:e.summary??s,canResume:e.canResume??e.status!=="aborted",source:e.source??"manager_registry",role:"managed_worker"}}sessionRecordToWorker(e,t){const r=this.readTranscriptSummary(e.sessionId,e.lastMessagePreview??null),a=r.lastMessagePreview??e.lastMessagePreview??null,s=r.userGoal,o=t?.has(e.sessionId)?"running":e.status==="failed"?"error":e.status==="completed"?"final":"idle";return{sessionId:e.sessionId,agentType:e.agentType,workDir:e.workDir,managedBy:null,status:o,createdAt:e.createdAt,updatedAt:e.updatedAt,lastActivityAt:e.lastActivityAt,title:s??a??e.sessionId,userGoal:s,lastMessagePreview:a,summary:a??s??null,agentSessionId:e.agentSessionId??null,runId:null,canResume:!!e.agentSessionId,source:"local_index",role:"project_session"}}projectedSessionToWorker(e,t){const r=e.lastMessagePreview??null,a=e.title?.trim()||r,s=t?.has(e.id)?"running":e.status==="failed"?"error":e.status==="completed"?"final":"idle";return{sessionId:e.id,agentType:e.agentType,workDir:e.workDir,managedBy:null,status:s,createdAt:e.createdAt,updatedAt:e.updatedAt,lastActivityAt:e.lastActivityAt||e.updatedAt,title:a??e.id,userGoal:a??null,lastMessagePreview:r,summary:r??a??null,agentSessionId:e.agentSessionId??null,runId:e.activity?.runId??null,canResume:!0,source:"app_projection",role:"project_session"}}readTranscriptSummary(e,t){const r=M(e,{limit:200});if(!r.length)return{userGoal:null,lastMessagePreview:t};const a=[...r].sort((i,c)=>i.ts-c.ts),s=a.find(i=>i.role==="user"),o=[...a].reverse().find(i=>m(i));return{userGoal:s?p(m(s),160):null,lastMessagePreview:p(m(o),180)??t}}createReplyTarget(e){const t=this.load(),r={replyTarget:`rt_${y()}`,managerSessionId:e.managerSessionId,channelId:e.channelId,conversationId:e.conversationId,messageId:e.messageId??null,createdAt:l()};return t.replyTargets[r.replyTarget]=r,this.save(t),r}getReplyTarget(e){return this.load().replyTargets[e]}getLatestReplyTargetForManager(e){return Object.values(this.load().replyTargets).filter(t=>t.managerSessionId===e).sort((t,r)=>r.createdAt.localeCompare(t.createdAt))[0]}}function m(d){return!d||w(d.payload)||A(d.payload)||T(d.payload)?null:k(d.payload).replace(/\r\n/g,`
2
2
  `).trim()||null}function p(d,e){return d?d.length>e?`${d.slice(0,e)}...`:d:null}export{O as ManagerRegistry};
@@ -1,8 +1,8 @@
1
1
  import T from"node:fs";import j from"node:os";import x from"node:path";import{buildApprovalPendingPayload as V,buildUserMessagePayload as k,isSystemControlPayload as A,isToolPayload as F}from"@shennian/wire";import{listOpenCodeSessionFiles as jt,parseOpenCodeSessionFile as At,parseOpenCodeSessionSnapshot as Mt}from"./opencode-parser.js";import{buildImagePayload as X,buildToolPayload as Y,inferMimeType as E,makeCursor as I,makeEventKey as w,normalizeText as h,parseStructuredString as Z,readClaudeEventCwd as N,readJsonlLines as v,readTimestamp as q,safeParse as M,isClaudeSubagentTranscript as D,shouldIgnoreClaudeProjectDir as K,shouldIgnoreClaudeTranscriptPath as O,shouldIgnoreNativeScanPath as R}from"./parser-common.js";function P(e){if(typeof e=="string"){const s=e.trim();return s?{path:s,name:x.basename(s)||"image.png",mimeType:E(s),kind:"image"}:null}if(typeof e!="object"||e===null)return null;const r=e,n=typeof r.path=="string"?r.path:typeof r.file_path=="string"?r.file_path:typeof r.saved_path=="string"?r.saved_path:"";if(!n.trim())return null;const t=typeof r.name=="string"&&r.name.trim()?r.name:x.basename(n)||"image.png",o=typeof r.mimeType=="string"&&r.mimeType.trim()?r.mimeType:E(n);return{path:n,name:t,mimeType:o,kind:"image"}}function U(e){return Array.isArray(e)?e.map(n=>{if(typeof n=="string")return n;if(typeof n=="object"&&n!==null){const t=n;return typeof t.text=="string"?t.text:""}return""}).map(n=>h(n)).filter(Boolean).join(`
2
2
 
3
- `):""}function B(e){const r=h(e);if(!r)return{text:"",strippedWrapper:!1};const n=r.match(/My request for Codex:\s*([\s\S]*)$/i);return n&&n[1]?{text:tt(n[1]),strippedWrapper:!0}:{text:r,strippedWrapper:!1}}function tt(e){return h(e.replace(/<image>\s*<\/image>/gi,""))}function z(e){const r=h(e);if(!r)return!1;const n=r.startsWith("# AGENTS.md instructions for ")&&r.includes("<INSTRUCTIONS>")&&r.includes("</INSTRUCTIONS>"),t=r.includes("<environment_context>")&&r.includes("</environment_context>");return n&&t}function H(e){const r=U(e.text_elements),n=Array.isArray(e.input)?U(e.input):"",t=typeof e.message=="string"?B(e.message):{text:"",strippedWrapper:!1},o=t.text,s=r||n||o,u=t.strippedWrapper?"codex_app_context_wrapper":void 0,a=Array.isArray(e.local_images)?e.local_images.map(P).filter(l=>l!=null):[];return!s&&a.length===0||A(s)&&a.length===0||z(s)&&a.length===0?null:a.length>0?{payload:k(s,a),titleText:s,repairHint:u}:{payload:s,titleText:s,repairHint:u}}function et(e){return e==="turn_completed"||e==="turn_complete"||e==="task_complete"}function nt(e){return/approval|permission|confirm|user[_-]?input|input[_-]?required/i.test(e)}function rt(e){const r=typeof e.command=="string"?e.command:Array.isArray(e.command)?e.command.join(" "):"",n=typeof e.prompt=="string"?e.prompt:typeof e.reason=="string"?e.reason:typeof e.message=="string"?e.message:r?`Codex \u8BF7\u6C42\u6267\u884C\u547D\u4EE4\uFF1A${r}`:"Codex \u6B63\u5728\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u540E\u7EE7\u7EED\u3002";return V({title:"\u9700\u8981\u7528\u6237\u786E\u8BA4",content:n,source:"codex",actionHint:"\u5F53\u524D\u795E\u5FF5\u6682\u4E0D\u652F\u6301\u8FDC\u7A0B\u786E\u8BA4\uFF0C\u8BF7\u56DE\u5230\u8FD0\u884C Codex \u7684\u7535\u8111/\u7EC8\u7AEF\u5B8C\u6210\u786E\u8BA4\u3002"})}function $(e,r){return Array.isArray(e)?h(e.map(n=>{if(typeof n=="string")return n;if(typeof n!="object"||n===null)return"";const t=n;return t.type!==r?"":typeof t.text=="string"?t.text:""}).filter(Boolean).join(`
3
+ `):""}function B(e){const r=h(e);if(!r)return{text:"",strippedWrapper:!1};const n=r.match(/My request for Codex:\s*([\s\S]*)$/i);return n&&n[1]?{text:tt(n[1]),strippedWrapper:!0}:{text:r,strippedWrapper:!1}}function tt(e){return h(e.replace(/<image>\s*<\/image>/gi,""))}function z(e){const r=h(e);if(!r)return!1;if(A(r))return!0;const n=r.startsWith("# AGENTS.md instructions for ")&&r.includes("<INSTRUCTIONS>")&&r.includes("</INSTRUCTIONS>"),t=r.includes("<environment_context>")&&r.includes("</environment_context>");return n&&t}function H(e){const r=U(e.text_elements),n=Array.isArray(e.input)?U(e.input):"",t=typeof e.message=="string"?B(e.message):{text:"",strippedWrapper:!1},o=t.text,s=r||n||o,u=t.strippedWrapper?"codex_app_context_wrapper":void 0,a=Array.isArray(e.local_images)?e.local_images.map(P).filter(f=>f!=null):[];return!s&&a.length===0||A(s)&&a.length===0||z(s)&&a.length===0?null:a.length>0?{payload:k(s,a),titleText:s,repairHint:u}:{payload:s,titleText:s,repairHint:u}}function et(e){return e==="turn_completed"||e==="turn_complete"||e==="task_complete"}function nt(e){return/approval|permission|confirm|user[_-]?input|input[_-]?required/i.test(e)}function rt(e){const r=typeof e.command=="string"?e.command:Array.isArray(e.command)?e.command.join(" "):"",n=typeof e.prompt=="string"?e.prompt:typeof e.reason=="string"?e.reason:typeof e.message=="string"?e.message:r?`Codex \u8BF7\u6C42\u6267\u884C\u547D\u4EE4\uFF1A${r}`:"Codex \u6B63\u5728\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u540E\u7EE7\u7EED\u3002";return V({title:"\u9700\u8981\u7528\u6237\u786E\u8BA4",content:n,source:"codex",actionHint:"\u5F53\u524D\u795E\u5FF5\u6682\u4E0D\u652F\u6301\u8FDC\u7A0B\u786E\u8BA4\uFF0C\u8BF7\u56DE\u5230\u8FD0\u884C Codex \u7684\u7535\u8111/\u7EC8\u7AEF\u5B8C\u6210\u786E\u8BA4\u3002"})}function $(e,r){return Array.isArray(e)?h(e.map(n=>{if(typeof n=="string")return n;if(typeof n!="object"||n===null)return"";const t=n;return t.type!==r?"":typeof t.text=="string"?t.text:""}).filter(Boolean).join(`
4
4
 
5
- `)):""}function ot(e){if(!Array.isArray(e))return[];const r=[];for(const n of e){if(typeof n!="object"||n===null)continue;const t=n;if(t.type!=="input_image")continue;const o=typeof t.path=="string"?t.path:typeof t.file_path=="string"?t.file_path:typeof t.saved_path=="string"?t.saved_path:typeof t.image_path=="string"?t.image_path:"";o.trim()&&r.push({path:o,name:x.basename(o)||"image.png",mimeType:E(o),kind:"image"})}return r}function L(e){if(e.type!=="message")return null;const r=e.role==="assistant"?"agent":e.role==="user"?"user":null;if(!r)return null;if(r==="agent"){const s=$(e.content,"output_text");return A(s)?null:s?{role:r,payload:s,titleText:s}:null}const n=B($(e.content,"input_text")),t=n.text,o=ot(e.content);return!t&&o.length===0||A(t)&&o.length===0||z(t)&&o.length===0?null:{role:r,payload:o.length>0?k(t,o):t,titleText:t,repairHint:n.strippedWrapper?"codex_app_context_wrapper":void 0}}function J(e){if(!e)return"";try{const r=JSON.parse(e);if(typeof r=="object"&&r!==null){const n=r;if(n.type==="user"&&typeof n.content=="string")return h(n.content)}}catch{}return h(e)}function st(e,r,n,t){return e.agentType!=="codex"||e.role!==r||F(e.payload)||Math.abs(e.ts-t)>300*1e3?!1:J(e.payload)===J(n)}function W(e,r,n,t){for(let o=e.length-1;o>=0;o-=1){const s=e[o];if(s){if(st(s,r,n,t))return o;if(s.agentType==="codex"&&Math.abs(s.ts-t)>300*1e3)break}}return-1}function b(e,r,n,t,o,s,u,a,l,c,i="agent",f=!1,m){u&&e.push({agentType:"codex",sourceMode:"codex_rollout_import",sourceSessionKey:o,sourceEventKey:w(r,n,t),cursor:I(r,n),role:i,ts:s,payload:u,title:a,modelId:l,workDir:c,terminal:f,repairHint:m})}function C(e,r,n,t,o,s,u,a,l,c,i,f){b(e,r,n,t,o,s,Y(u,i,f),a,l,c)}function it(e,r,n,t,o,s,u,a,l){const c=typeof t.type=="string"?t.type:"";if(c){if(c==="message"){const i=L(t);if(!i||W(e,i.role,i.payload,s)>=0)return;b(e,r,n,`${c}:${i.role}`,o,s,i.payload,u,a,l,i.role,!1,i.repairHint);return}if(c==="function_call"){const i=typeof t.name=="string"?t.name:"function_call";C(e,r,n,c,o,s,i,u,a,l,Z(t.arguments));return}if(c==="function_call_output"){C(e,r,n,c,o,s,"function_call_output",u,a,l,t.call_id,t.output);return}if(c==="custom_tool_call"){const i=typeof t.name=="string"?t.name:"custom_tool_call",f=t.input!==void 0?{input:t.input}:void 0;C(e,r,n,c,o,s,i,u,a,l,f);return}if(c==="custom_tool_call_output"){const i=typeof t.name=="string"?t.name:"custom_tool_call_output",f=t.output??t.result??t.content;C(e,r,n,c,o,s,i,u,a,l,t.call_id,f);return}if(c==="web_search_call"){const i=typeof t.action=="object"&&t.action!==null?t.action:null;C(e,r,n,c,o,s,"web_search",u,a,l,i??t.query);return}}}function ct(e,r,n,t,o,s,u,a,l){const c=typeof t.type=="string"?t.type:"";if(c){if(c==="user_message"){const i=H(t);if(!i)return;b(e,r,n,c,o,s,i.payload,u,a,l,"user",!1,i.repairHint);return}if(c==="agent_message"){const i=typeof t.message=="string"?h(t.message):"";if(!i||A(i))return;b(e,r,n,c,o,s,i,u,a,l);return}if(c==="turn_aborted"||c==="error"){const i=typeof t.message=="string"?h(t.message):typeof t.error=="string"?h(t.error):"";if(!i)return;b(e,r,n,c,o,s,i,u,a,l,"agent",!0);return}if(nt(c)){b(e,r,n,c,o,s,rt(t),u,a,l,"agent");return}if(c==="exec_command_end"){const i=Array.isArray(t.command)?t.command:t.parsed_cmd??t.command,f=t.exit_code??t.exitCode,m=[typeof t.aggregated_output=="string"?t.aggregated_output:"",f!=null?`
6
- (exit ${String(f)})`:""].join("");C(e,r,n,c,o,s,"command_execution",u,a,l,{command:i},m);return}if(c==="patch_apply_end"){C(e,r,n,c,o,s,"apply_patch",u,a,l,t.changes,{success:t.success,stdout:t.stdout,stderr:t.stderr});return}if(c==="mcp_tool_call_end"){const i=typeof t.invocation=="object"&&t.invocation!==null?t.invocation:null,f=typeof i?.tool=="string"?i.tool:"mcp_tool_call",m={server:i?.server,...typeof i?.arguments=="object"&&i.arguments!==null?i.arguments:{}};C(e,r,n,c,o,s,f,u,a,l,m,t.result);return}if(c==="dynamic_tool_call_request"){const i=typeof t.tool=="string"?t.tool:"dynamic_tool_call";C(e,r,n,c,o,s,i,u,a,l,t.arguments);return}if(c==="dynamic_tool_call_response"){const i=typeof t.tool=="string"?t.tool:"dynamic_tool_call";C(e,r,n,c,o,s,i,u,a,l,t.callId??t.call_id,t.result??t.output);return}if(c==="web_search_end"){const i=typeof t.action=="object"&&t.action!==null?t.action:null;C(e,r,n,c,o,s,"web_search",u,a,l,i??t.query,t.query);return}if(c==="image_generation_end"){const i=typeof t.saved_path=="string"?t.saved_path.trim():"";if(!i)return;b(e,r,n,c,o,s,X(i),u,a,l);return}c==="view_image_tool_call"&&C(e,r,n,c,o,s,"view_image",u,a,l,t.path??t.image_path??t)}}function ut(e){const r=j.homedir();return e.startsWith(r)?e.slice(r.length).replace(/^\//,"")||"~":e.replace(/\//g,"-")}function at(e){const r=T.openSync(e,"r");try{const n=[];let t=0,o="";for(;t<1024*1024;){const l=Buffer.alloc(16384),c=T.readSync(r,l,0,l.length,t);if(c<=0)break;const i=l.subarray(0,c);n.push(i),t+=c;const f=Buffer.concat(n),m=f.indexOf(10);if(m>=0){o=f.subarray(0,m).toString("utf8");break}}!o&&n.length>0&&(o=Buffer.concat(n).toString("utf8"));const s=M(o);if(!s||s.type!=="session_meta")return{sourceSessionKey:"",workDir:"",modelId:null,title:""};const u=typeof s.payload=="object"&&s.payload!==null?s.payload:null;if(!u)return{sourceSessionKey:"",workDir:"",modelId:null,title:""};const a=typeof u.id=="string"?u.id:"";return{sourceSessionKey:a,workDir:typeof u.cwd=="string"?u.cwd:"",modelId:G(u),title:Q(a)??""}}finally{T.closeSync(r)}return{sourceSessionKey:"",workDir:"",modelId:null,title:""}}function G(e){return(typeof e.model=="string"?e.model.trim():"")||null}function lt(e,r){if((typeof e.id=="string"?e.id:typeof e.thread_id=="string"?e.thread_id:typeof e.session_id=="string"?e.session_id:"")!==r)return null;const o=(typeof e.thread_name=="string"?e.thread_name:typeof e.title=="string"?e.title:"").trim();return o?o.slice(0,120):null}function Q(e){if(!e)return null;const r=x.join(j.homedir(),".codex","session_index.jsonl");if(!T.existsSync(r))return null;let n=null;return v(r,0,t=>{if(!t.trim())return;const o=M(t);if(!o)return;const s=lt(o,e);s&&(n=s)}),n}function _t(){const e=[x.join(j.homedir(),".codex","sessions"),x.join(j.homedir(),".codex","archived_sessions")],r=[],n=t=>{for(const o of T.readdirSync(t,{withFileTypes:!0})){const s=x.join(t,o.name);o.isDirectory()?n(s):o.isFile()&&o.name.endsWith(".jsonl")&&r.push(s)}};for(const t of e)T.existsSync(t)&&n(t);return[...new Set(r)].sort()}function ft(){const e=x.join(j.homedir(),".claude","projects");if(!T.existsSync(e))return[];const r=[],n=t=>{for(const o of T.readdirSync(t,{withFileTypes:!0})){const s=x.join(t,o.name);if(o.isDirectory()){if(t===e&&K(o.name))continue;n(s)}else o.isFile()&&o.name.endsWith(".jsonl")&&r.push(s)}};return n(e),r.sort()}function yt(e){if(!e)return null;const r=ft().find(t=>x.basename(t,".jsonl")===e);if(!r)return null;let n=null;return v(r,0,t=>{if(n||!t.trim())return;const o=M(t);if(!o)return;const s=N(o);s&&(n=s)}),n}function ht(e,r){const n=[];let{sourceSessionKey:t,workDir:o,modelId:s,title:u}=at(e),a=!1;return{nextOffset:v(e,r,(c,i)=>{const f=M(c);if(!f)return;const m=typeof f.type=="string"?f.type:"",p=typeof f.payload=="object"&&f.payload!==null?f.payload:null,_=q(f.timestamp);if(!(!p||!_)){if(m==="session_meta"){t=typeof p.id=="string"?p.id:t,o=typeof p.cwd=="string"?p.cwd:o,s=G(p)??s,u||(u=Q(t)??"");return}if(t){if(m==="response_item"){const y=L(p);y?.role==="user"&&y.titleText&&!u&&(u=y.titleText.slice(0,80)),it(n,e,i,p,t,_,u,s,o);return}if(m==="event_msg"){const y=typeof p.type=="string"?p.type:"";if(et(y)){for(let d=n.length-1;d>=0;d-=1){const g=n[d];if(g?.agentType==="codex"&&g.role==="agent"&&!F(g.payload)){g.terminal=!0,a=!1;break}}return}if(y==="user_message"){const d=H(p);if(d?.titleText&&!u&&(u=d.titleText.slice(0,80)),d){const g=W(n,"user",d.payload,_);g>=0&&n.splice(g,1)}}else if(y==="agent_message"){const d=typeof p.message=="string"?h(p.message):"";if(d&&!A(d)){const g=W(n,"agent",d,_);g>=0&&n.splice(g,1)}}const S=n.length;ct(n,e,i,p,t,_,u,s,o),a&&n.length>S&&(n[n.length-1].terminal=!0,a=!1)}}}}),events:n}}function Ct(e,r){const n=T.statSync(e).size;if(D(e)||O(e))return{nextOffset:n,events:[]};const t=[],o=x.basename(e,".jsonl"),s=ut(x.dirname(e).replace(x.join(j.homedir(),".claude","projects")+x.sep,""));if(R(s))return{nextOffset:n,events:[]};let u="";return{nextOffset:v(e,r,(l,c)=>{const i=M(l);if(!i)return;const f=q(i.timestamp),m=typeof i.type=="string"?i.type:"";if(!f||!m)return;const p=N(i);if(!(p&&R(p))){if(m==="user"){const _=typeof i.message=="object"&&i.message!==null?i.message:null,y=typeof _?.content=="string"?h(_.content):"";if(!y)return;u||(u=y.slice(0,80)),t.push({agentType:"claude",sourceMode:"claude_transcript_import",sourceSessionKey:o,sourceEventKey:w(e,c,"user"),cursor:I(e,c),role:"user",ts:f,payload:y,title:u,workDir:p??s})}else if(m==="assistant"){const _=typeof i.message=="object"&&i.message!==null?i.message:null,y=Array.isArray(_?.content)?_.content:[],S=h(y.map(g=>typeof g=="object"&&g!==null&&typeof g.text=="string"?g.text:"").filter(Boolean).join(`
5
+ `)):""}function ot(e){if(!Array.isArray(e))return[];const r=[];for(const n of e){if(typeof n!="object"||n===null)continue;const t=n;if(t.type!=="input_image")continue;const o=typeof t.path=="string"?t.path:typeof t.file_path=="string"?t.file_path:typeof t.saved_path=="string"?t.saved_path:typeof t.image_path=="string"?t.image_path:"";o.trim()&&r.push({path:o,name:x.basename(o)||"image.png",mimeType:E(o),kind:"image"})}return r}function L(e){if(e.type!=="message")return null;const r=e.role==="assistant"?"agent":e.role==="user"?"user":null;if(!r)return null;if(r==="agent"){const s=$(e.content,"output_text");return A(s)?null:s?{role:r,payload:s,titleText:s}:null}const n=B($(e.content,"input_text")),t=n.text,o=ot(e.content);return!t&&o.length===0||A(t)&&o.length===0||z(t)&&o.length===0?null:{role:r,payload:o.length>0?k(t,o):t,titleText:t,repairHint:n.strippedWrapper?"codex_app_context_wrapper":void 0}}function J(e){if(!e)return"";try{const r=JSON.parse(e);if(typeof r=="object"&&r!==null){const n=r;if(n.type==="user"&&typeof n.content=="string")return h(n.content)}}catch{}return h(e)}function st(e,r,n,t){return e.agentType!=="codex"||e.role!==r||F(e.payload)||Math.abs(e.ts-t)>300*1e3?!1:J(e.payload)===J(n)}function W(e,r,n,t){for(let o=e.length-1;o>=0;o-=1){const s=e[o];if(s){if(st(s,r,n,t))return o;if(s.agentType==="codex"&&Math.abs(s.ts-t)>300*1e3)break}}return-1}function b(e,r,n,t,o,s,u,a,f,c,i="agent",l=!1,m){u&&e.push({agentType:"codex",sourceMode:"codex_rollout_import",sourceSessionKey:o,sourceEventKey:w(r,n,t),cursor:I(r,n),role:i,ts:s,payload:u,title:a,modelId:f,workDir:c,terminal:l,repairHint:m})}function C(e,r,n,t,o,s,u,a,f,c,i,l){b(e,r,n,t,o,s,Y(u,i,l),a,f,c)}function it(e,r,n,t,o,s,u,a,f){const c=typeof t.type=="string"?t.type:"";if(c){if(c==="message"){const i=L(t);if(!i||W(e,i.role,i.payload,s)>=0)return;b(e,r,n,`${c}:${i.role}`,o,s,i.payload,u,a,f,i.role,!1,i.repairHint);return}if(c==="function_call"){const i=typeof t.name=="string"?t.name:"function_call";C(e,r,n,c,o,s,i,u,a,f,Z(t.arguments));return}if(c==="function_call_output"){C(e,r,n,c,o,s,"function_call_output",u,a,f,t.call_id,t.output);return}if(c==="custom_tool_call"){const i=typeof t.name=="string"?t.name:"custom_tool_call",l=t.input!==void 0?{input:t.input}:void 0;C(e,r,n,c,o,s,i,u,a,f,l);return}if(c==="custom_tool_call_output"){const i=typeof t.name=="string"?t.name:"custom_tool_call_output",l=t.output??t.result??t.content;C(e,r,n,c,o,s,i,u,a,f,t.call_id,l);return}if(c==="web_search_call"){const i=typeof t.action=="object"&&t.action!==null?t.action:null;C(e,r,n,c,o,s,"web_search",u,a,f,i??t.query);return}}}function ct(e,r,n,t,o,s,u,a,f){const c=typeof t.type=="string"?t.type:"";if(c){if(c==="user_message"){const i=H(t);if(!i)return;b(e,r,n,c,o,s,i.payload,u,a,f,"user",!1,i.repairHint);return}if(c==="agent_message"){const i=typeof t.message=="string"?h(t.message):"";if(!i||A(i))return;b(e,r,n,c,o,s,i,u,a,f);return}if(c==="turn_aborted"||c==="error"){const i=typeof t.message=="string"?h(t.message):typeof t.error=="string"?h(t.error):"";if(!i)return;b(e,r,n,c,o,s,i,u,a,f,"agent",!0);return}if(nt(c)){b(e,r,n,c,o,s,rt(t),u,a,f,"agent");return}if(c==="exec_command_end"){const i=Array.isArray(t.command)?t.command:t.parsed_cmd??t.command,l=t.exit_code??t.exitCode,m=[typeof t.aggregated_output=="string"?t.aggregated_output:"",l!=null?`
6
+ (exit ${String(l)})`:""].join("");C(e,r,n,c,o,s,"command_execution",u,a,f,{command:i},m);return}if(c==="patch_apply_end"){C(e,r,n,c,o,s,"apply_patch",u,a,f,t.changes,{success:t.success,stdout:t.stdout,stderr:t.stderr});return}if(c==="mcp_tool_call_end"){const i=typeof t.invocation=="object"&&t.invocation!==null?t.invocation:null,l=typeof i?.tool=="string"?i.tool:"mcp_tool_call",m={server:i?.server,...typeof i?.arguments=="object"&&i.arguments!==null?i.arguments:{}};C(e,r,n,c,o,s,l,u,a,f,m,t.result);return}if(c==="dynamic_tool_call_request"){const i=typeof t.tool=="string"?t.tool:"dynamic_tool_call";C(e,r,n,c,o,s,i,u,a,f,t.arguments);return}if(c==="dynamic_tool_call_response"){const i=typeof t.tool=="string"?t.tool:"dynamic_tool_call";C(e,r,n,c,o,s,i,u,a,f,t.callId??t.call_id,t.result??t.output);return}if(c==="web_search_end"){const i=typeof t.action=="object"&&t.action!==null?t.action:null;C(e,r,n,c,o,s,"web_search",u,a,f,i??t.query,t.query);return}if(c==="image_generation_end"){const i=typeof t.saved_path=="string"?t.saved_path.trim():"";if(!i)return;b(e,r,n,c,o,s,X(i),u,a,f);return}c==="view_image_tool_call"&&C(e,r,n,c,o,s,"view_image",u,a,f,t.path??t.image_path??t)}}function ut(e){const r=j.homedir();return e.startsWith(r)?e.slice(r.length).replace(/^\//,"")||"~":e.replace(/\//g,"-")}function at(e){const r=T.openSync(e,"r");try{const n=[];let t=0,o="";for(;t<1024*1024;){const f=Buffer.alloc(16384),c=T.readSync(r,f,0,f.length,t);if(c<=0)break;const i=f.subarray(0,c);n.push(i),t+=c;const l=Buffer.concat(n),m=l.indexOf(10);if(m>=0){o=l.subarray(0,m).toString("utf8");break}}!o&&n.length>0&&(o=Buffer.concat(n).toString("utf8"));const s=M(o);if(!s||s.type!=="session_meta")return{sourceSessionKey:"",workDir:"",modelId:null,title:""};const u=typeof s.payload=="object"&&s.payload!==null?s.payload:null;if(!u)return{sourceSessionKey:"",workDir:"",modelId:null,title:""};const a=typeof u.id=="string"?u.id:"";return{sourceSessionKey:a,workDir:typeof u.cwd=="string"?u.cwd:"",modelId:G(u),title:Q(a)??""}}finally{T.closeSync(r)}return{sourceSessionKey:"",workDir:"",modelId:null,title:""}}function G(e){return(typeof e.model=="string"?e.model.trim():"")||null}function ft(e,r){if((typeof e.id=="string"?e.id:typeof e.thread_id=="string"?e.thread_id:typeof e.session_id=="string"?e.session_id:"")!==r)return null;const o=(typeof e.thread_name=="string"?e.thread_name:typeof e.title=="string"?e.title:"").trim();return o?o.slice(0,120):null}function Q(e){if(!e)return null;const r=x.join(j.homedir(),".codex","session_index.jsonl");if(!T.existsSync(r))return null;let n=null;return v(r,0,t=>{if(!t.trim())return;const o=M(t);if(!o)return;const s=ft(o,e);s&&(n=s)}),n}function _t(){const e=[x.join(j.homedir(),".codex","sessions"),x.join(j.homedir(),".codex","archived_sessions")],r=[],n=t=>{for(const o of T.readdirSync(t,{withFileTypes:!0})){const s=x.join(t,o.name);o.isDirectory()?n(s):o.isFile()&&o.name.endsWith(".jsonl")&&r.push(s)}};for(const t of e)T.existsSync(t)&&n(t);return[...new Set(r)].sort()}function lt(){const e=x.join(j.homedir(),".claude","projects");if(!T.existsSync(e))return[];const r=[],n=t=>{for(const o of T.readdirSync(t,{withFileTypes:!0})){const s=x.join(t,o.name);if(o.isDirectory()){if(t===e&&K(o.name))continue;n(s)}else o.isFile()&&o.name.endsWith(".jsonl")&&r.push(s)}};return n(e),r.sort()}function yt(e){if(!e)return null;const r=lt().find(t=>x.basename(t,".jsonl")===e);if(!r)return null;let n=null;return v(r,0,t=>{if(n||!t.trim())return;const o=M(t);if(!o)return;const s=N(o);s&&(n=s)}),n}function ht(e,r){const n=[];let{sourceSessionKey:t,workDir:o,modelId:s,title:u}=at(e),a=!1;return{nextOffset:v(e,r,(c,i)=>{const l=M(c);if(!l)return;const m=typeof l.type=="string"?l.type:"",p=typeof l.payload=="object"&&l.payload!==null?l.payload:null,_=q(l.timestamp);if(!(!p||!_)){if(m==="session_meta"){t=typeof p.id=="string"?p.id:t,o=typeof p.cwd=="string"?p.cwd:o,s=G(p)??s,u||(u=Q(t)??"");return}if(t){if(m==="response_item"){const y=L(p);y?.role==="user"&&y.titleText&&!u&&(u=y.titleText.slice(0,80)),it(n,e,i,p,t,_,u,s,o);return}if(m==="event_msg"){const y=typeof p.type=="string"?p.type:"";if(et(y)){for(let d=n.length-1;d>=0;d-=1){const g=n[d];if(g?.agentType==="codex"&&g.role==="agent"&&!F(g.payload)){g.terminal=!0,a=!1;break}}return}if(y==="user_message"){const d=H(p);if(d?.titleText&&!u&&(u=d.titleText.slice(0,80)),d){const g=W(n,"user",d.payload,_);g>=0&&n.splice(g,1)}}else if(y==="agent_message"){const d=typeof p.message=="string"?h(p.message):"";if(d&&!A(d)){const g=W(n,"agent",d,_);g>=0&&n.splice(g,1)}}const S=n.length;ct(n,e,i,p,t,_,u,s,o),a&&n.length>S&&(n[n.length-1].terminal=!0,a=!1)}}}}),events:n}}function Ct(e,r){const n=T.statSync(e).size;if(D(e)||O(e))return{nextOffset:n,events:[]};const t=[],o=x.basename(e,".jsonl"),s=ut(x.dirname(e).replace(x.join(j.homedir(),".claude","projects")+x.sep,""));if(R(s))return{nextOffset:n,events:[]};let u="";return{nextOffset:v(e,r,(f,c)=>{const i=M(f);if(!i)return;const l=q(i.timestamp),m=typeof i.type=="string"?i.type:"";if(!l||!m)return;const p=N(i);if(!(p&&R(p))){if(m==="user"){const _=typeof i.message=="object"&&i.message!==null?i.message:null,y=typeof _?.content=="string"?h(_.content):"";if(!y)return;u||(u=y.slice(0,80)),t.push({agentType:"claude",sourceMode:"claude_transcript_import",sourceSessionKey:o,sourceEventKey:w(e,c,"user"),cursor:I(e,c),role:"user",ts:l,payload:y,title:u,workDir:p??s})}else if(m==="assistant"){const _=typeof i.message=="object"&&i.message!==null?i.message:null,y=Array.isArray(_?.content)?_.content:[],S=h(y.map(g=>typeof g=="object"&&g!==null&&typeof g.text=="string"?g.text:"").filter(Boolean).join(`
7
7
 
8
- `));if(!S)return;const d=typeof _?.model=="string"?_.model:null;t.push({agentType:"claude",sourceMode:"claude_transcript_import",sourceSessionKey:o,sourceEventKey:w(e,c,"assistant"),cursor:I(e,c),role:"agent",ts:f,payload:S,title:u,modelId:d,workDir:p??s})}}}),events:t}}export{ft as listClaudeTranscriptFiles,_t as listCodexRolloutFiles,jt as listOpenCodeSessionFiles,yt as lookupClaudeTranscriptCwd,Ct as parseClaudeTranscriptChunk,ht as parseCodexRolloutChunk,At as parseOpenCodeSessionFile,Mt as parseOpenCodeSessionSnapshot};
8
+ `));if(!S)return;const d=typeof _?.model=="string"?_.model:null;t.push({agentType:"claude",sourceMode:"claude_transcript_import",sourceSessionKey:o,sourceEventKey:w(e,c,"assistant"),cursor:I(e,c),role:"agent",ts:l,payload:S,title:u,modelId:d,workDir:p??s})}}}),events:t}}export{lt as listClaudeTranscriptFiles,_t as listCodexRolloutFiles,jt as listOpenCodeSessionFiles,yt as lookupClaudeTranscriptCwd,Ct as parseClaudeTranscriptChunk,ht as parseCodexRolloutChunk,At as parseOpenCodeSessionFile,Mt as parseOpenCodeSessionSnapshot};
@@ -1,3 +1,3 @@
1
- import type { ReqFrame } from '@shennian/wire';
1
+ import { type ReqFrame } from '@shennian/wire';
2
2
  import type { SessionManagerRuntime } from '../types.js';
3
3
  export declare function handleSessionToolDetail(runtime: SessionManagerRuntime, req: ReqFrame): Promise<void>;
@@ -1 +1 @@
1
- import{readMessages as R}from"../store.js";const E=2e3,A=8e3,_=/(?:token|api[-_]?key|password|passwd|pwd|secret|authorization|cookie|credential|private[-_]?key)/i,b=/\b([A-Z0-9_]*(?:TOKEN|KEY|SECRET|PASSWORD|PASSWD|PWD|AUTH)[A-Z0-9_]*)=("[^"]*"|'[^']*'|[^\s]+)/gi,x=/\bBearer\s+[A-Za-z0-9._~+/=-]+/gi,h=/\bsk-[A-Za-z0-9_-]{12,}\b/g;function m(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function d(e){if(!e)return null;if(typeof e=="string")try{return d(JSON.parse(e))}catch{return null}const t=m(e);if(!t)return null;const s=typeof t.runId=="string"?t.runId:void 0,o=typeof t.sourceSeq=="number"?t.sourceSeq:typeof t.seq=="number"?t.seq:void 0,n=typeof t.toolIndex=="number"?t.toolIndex:void 0;return{...s?{runId:s}:{},...o!=null?{sourceSeq:o}:{},...n!=null?{toolIndex:n}:{}}}function p(e){return/^agent-(.+)-\d+$/.exec(e)?.[1]??null}function I(e){const t=/^agent-.+-(\d+)$/.exec(e);return t?Number(t[1]):null}function y(e){const t=typeof e=="number"?e:Number(e);return!Number.isFinite(t)||t<=0?E:Math.min(Math.max(200,Math.floor(t)),A)}function c(e,t){const s=e.replace(b,"$1=[REDACTED]").replace(x,"Bearer [REDACTED]").replace(h,"sk-[REDACTED]");return s.length>t?`${s.slice(0,t)}\u2026`:s}function u(e,t,s=0){if(e==null)return e;if(typeof e=="string")return c(e,t);if(typeof e=="number"||typeof e=="boolean")return e;if(s>=4)return"[Truncated]";if(Array.isArray(e))return e.slice(0,20).map(o=>u(o,t,s+1));if(typeof e=="object"){const o={};for(const[n,r]of Object.entries(e).slice(0,50)){if(_.test(n)){o[n]="[REDACTED]";continue}o[n]=u(r,t,s+1)}return o}return String(e)}function D(e,t){const o=m(e)?.command;if(typeof o=="string")return c(o,t);if(Array.isArray(o)){const n=o.map(r=>String(r)).join(" ");return c(n,t)}}function T(e){const t=R(e),s=[];for(const o of t)if(!(o.role!=="agent"||!o.payload.trim().startsWith("{")))try{const n=JSON.parse(o.payload),r=n.type;if(r!=="tool"&&r!=="tool_use"&&r!=="tool_result")continue;const a=typeof n.name=="string"&&n.name.trim()?n.name.trim():"tool";s.push({id:o.id,ts:o.ts,name:a,args:n.args,result:n.result,status:r==="tool_result"||Object.prototype.hasOwnProperty.call(n,"result")?"completed":n.status==="completed"||n.status==="failed"||n.status==="running"?n.status:"running",detailRef:d(n.detailRef)})}catch{}return s}function k(e,t,s){let o=0;e.id===t.messageId&&(o+=100),t.name&&e.name===t.name&&(o+=20);const n=s?.runId??t.runId??p(t.messageId),r=s?.sourceSeq??t.sourceSeq??I(t.messageId)??void 0;return n&&(e.detailRef?.runId??p(e.id))===n&&(o+=20),r!=null&&(e.detailRef?.sourceSeq??I(e.id))===r&&(o+=80),e.args!=null&&(o+=5),o}function q(e){const t=d(e.detailRef)??d({runId:e.runId,sourceSeq:e.sourceSeq,toolIndex:e.toolIndex}),s=T(e.sessionId);return s.length===0?null:s.map(n=>({candidate:n,score:k(n,e,t)})).filter(n=>n.score>0).sort((n,r)=>r.score-n.score||r.candidate.ts-n.candidate.ts)[0]?.candidate??null}async function M(e,t){const s=t.params,o=typeof s.sessionId=="string"?s.sessionId:"",n=typeof s.messageId=="string"?s.messageId:"";if(!o||!n){e.client.sendRes({type:"res",id:t.id,ok:!1,error:"sessionId and messageId are required"});return}const r={sessionId:o,messageId:n,...typeof s.name=="string"?{name:s.name}:{},...typeof s.toolIndex=="number"?{toolIndex:s.toolIndex}:{},...typeof s.runId=="string"?{runId:s.runId}:{},...typeof s.sourceSeq=="number"?{sourceSeq:s.sourceSeq}:{},...s.detailRef!==void 0?{detailRef:s.detailRef}:{},maxChars:y(s.maxChars)},a=y(r.maxChars),i=q(r);if(!i||i.args==null){const S={detailStatus:"not_found",messageId:n,toolIndex:r.toolIndex??0,name:r.name,resultOmitted:!0,source:"unavailable",reason:"tool detail is not available on this machine"};e.client.sendRes({type:"res",id:t.id,ok:!0,payload:S});return}const l=i.args==null?void 0:u(i.args,a),f=D(i.args,a),g={detailStatus:"available",messageId:n,toolIndex:r.toolIndex??0,name:i.name,status:i.status,...l!==void 0?{argsSummary:l}:{},...f?{command:f}:{},resultOmitted:!0,source:"local-session-store"};e.client.sendRes({type:"res",id:t.id,ok:!0,payload:g})}export{M as handleSessionToolDetail};
1
+ import{isSystemControlPayload as R}from"@shennian/wire";import{readMessages as E}from"../store.js";const A=2e3,_=8e3,b=/(?:token|api[-_]?key|password|passwd|pwd|secret|authorization|cookie|credential|private[-_]?key)/i,T=/\b([A-Z0-9_]*(?:TOKEN|KEY|SECRET|PASSWORD|PASSWD|PWD|AUTH)[A-Z0-9_]*)=("[^"]*"|'[^']*'|[^\s]+)/gi,x=/\bBearer\s+[A-Za-z0-9._~+/=-]+/gi,D=/\bsk-[A-Za-z0-9_-]{12,}\b/g;function m(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function d(e){if(!e)return null;if(typeof e=="string")try{return d(JSON.parse(e))}catch{return null}const t=m(e);if(!t)return null;const s=typeof t.runId=="string"?t.runId:void 0,o=typeof t.sourceSeq=="number"?t.sourceSeq:typeof t.seq=="number"?t.seq:void 0,n=typeof t.toolIndex=="number"?t.toolIndex:void 0;return{...s?{runId:s}:{},...o!=null?{sourceSeq:o}:{},...n!=null?{toolIndex:n}:{}}}function p(e){return/^agent-(.+)-\d+$/.exec(e)?.[1]??null}function I(e){const t=/^agent-.+-(\d+)$/.exec(e);return t?Number(t[1]):null}function y(e){const t=typeof e=="number"?e:Number(e);return!Number.isFinite(t)||t<=0?A:Math.min(Math.max(200,Math.floor(t)),_)}function c(e,t){if(R(e))return"[SYSTEM CONTEXT REDACTED]";const s=e.replace(T,"$1=[REDACTED]").replace(x,"Bearer [REDACTED]").replace(D,"sk-[REDACTED]");return s.length>t?`${s.slice(0,t)}\u2026`:s}function u(e,t,s=0){if(e==null)return e;if(typeof e=="string")return c(e,t);if(typeof e=="number"||typeof e=="boolean")return e;if(s>=4)return"[Truncated]";if(Array.isArray(e))return e.slice(0,20).map(o=>u(o,t,s+1));if(typeof e=="object"){const o={};for(const[n,r]of Object.entries(e).slice(0,50)){if(b.test(n)){o[n]="[REDACTED]";continue}o[n]=u(r,t,s+1)}return o}return String(e)}function h(e,t){const o=m(e)?.command;if(typeof o=="string")return c(o,t);if(Array.isArray(o)){const n=o.map(r=>String(r)).join(" ");return c(n,t)}}function C(e){const t=E(e),s=[];for(const o of t)if(!(o.role!=="agent"||!o.payload.trim().startsWith("{")))try{const n=JSON.parse(o.payload),r=n.type;if(r!=="tool"&&r!=="tool_use"&&r!=="tool_result")continue;const a=typeof n.name=="string"&&n.name.trim()?n.name.trim():"tool";s.push({id:o.id,ts:o.ts,name:a,args:n.args,result:n.result,status:r==="tool_result"||Object.prototype.hasOwnProperty.call(n,"result")?"completed":n.status==="completed"||n.status==="failed"||n.status==="running"?n.status:"running",detailRef:d(n.detailRef)})}catch{}return s}function k(e,t,s){let o=0;e.id===t.messageId&&(o+=100),t.name&&e.name===t.name&&(o+=20);const n=s?.runId??t.runId??p(t.messageId),r=s?.sourceSeq??t.sourceSeq??I(t.messageId)??void 0;return n&&(e.detailRef?.runId??p(e.id))===n&&(o+=20),r!=null&&(e.detailRef?.sourceSeq??I(e.id))===r&&(o+=80),e.args!=null&&(o+=5),o}function q(e){const t=d(e.detailRef)??d({runId:e.runId,sourceSeq:e.sourceSeq,toolIndex:e.toolIndex}),s=C(e.sessionId);return s.length===0?null:s.map(n=>({candidate:n,score:k(n,e,t)})).filter(n=>n.score>0).sort((n,r)=>r.score-n.score||r.candidate.ts-n.candidate.ts)[0]?.candidate??null}async function O(e,t){const s=t.params,o=typeof s.sessionId=="string"?s.sessionId:"",n=typeof s.messageId=="string"?s.messageId:"";if(!o||!n){e.client.sendRes({type:"res",id:t.id,ok:!1,error:"sessionId and messageId are required"});return}const r={sessionId:o,messageId:n,...typeof s.name=="string"?{name:s.name}:{},...typeof s.toolIndex=="number"?{toolIndex:s.toolIndex}:{},...typeof s.runId=="string"?{runId:s.runId}:{},...typeof s.sourceSeq=="number"?{sourceSeq:s.sourceSeq}:{},...s.detailRef!==void 0?{detailRef:s.detailRef}:{},maxChars:y(s.maxChars)},a=y(r.maxChars),i=q(r);if(!i||i.args==null){const S={detailStatus:"not_found",messageId:n,toolIndex:r.toolIndex??0,name:r.name,resultOmitted:!0,source:"unavailable",reason:"tool detail is not available on this machine"};e.client.sendRes({type:"res",id:t.id,ok:!0,payload:S});return}const l=i.args==null?void 0:u(i.args,a),f=h(i.args,a),g={detailStatus:"available",messageId:n,toolIndex:r.toolIndex??0,name:i.name,status:i.status,...l!==void 0?{argsSummary:l}:{},...f?{command:f}:{},resultOmitted:!0,source:"local-session-store"};e.client.sendRes({type:"res",id:t.id,ok:!0,payload:g})}export{O as handleSessionToolDetail};