shennian 0.2.115 → 0.2.117

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 +48 -48
  2. package/dist/src/agents/external-channel-instructions.js +5 -5
  3. package/dist/src/agents/model-registry/discovery.js +2 -2
  4. package/dist/src/agents/pi-context.d.ts +1 -1
  5. package/dist/src/agents/pi-context.js +3 -3
  6. package/dist/src/channels/registry.js +1 -1
  7. package/dist/src/channels/runtime.d.ts +1 -0
  8. package/dist/src/channels/runtime.js +3 -3
  9. package/dist/src/channels/secret-registry.js +1 -1
  10. package/dist/src/channels/wechat-channel/anchor.js +1 -1
  11. package/dist/src/channels/wechat-channel/automation-lane.js +2 -2
  12. package/dist/src/channels/wechat-channel/fingerprint.d.ts +3 -0
  13. package/dist/src/channels/wechat-channel/fingerprint.js +1 -1
  14. package/dist/src/channels/wechat-channel/helper-assets.d.ts +1 -1
  15. package/dist/src/channels/wechat-channel/helper-assets.js +1 -1
  16. package/dist/src/channels/wechat-channel/helper-client.js +3 -3
  17. package/dist/src/channels/wechat-channel/ledger.js +2 -1
  18. package/dist/src/channels/wechat-channel/media-resolver.d.ts +1 -1
  19. package/dist/src/channels/wechat-channel/media-resolver.js +1 -1
  20. package/dist/src/channels/wechat-channel/observer.js +6 -6
  21. package/dist/src/channels/wechat-channel/outbound-ledger.d.ts +1 -0
  22. package/dist/src/channels/wechat-channel/outbound-ledger.js +2 -2
  23. package/dist/src/channels/wechat-channel/outbound-sender.js +1 -1
  24. package/dist/src/channels/wechat-channel/runner.js +1 -1
  25. package/dist/src/channels/wechat-channel/scheduler.js +1 -1
  26. package/dist/src/channels/wechat-rpa.js +3 -3
  27. package/dist/src/commands/daemon.js +3 -3
  28. package/dist/src/commands/wechat/direct.js +2 -2
  29. package/dist/src/commands/wechat/operations.js +3 -3
  30. package/dist/src/commands/wechat/output.js +3 -3
  31. package/dist/src/commands/wechat/utils.d.ts +2 -0
  32. package/dist/src/commands/wechat/utils.js +1 -1
  33. package/dist/src/config/index.d.ts +1 -1
  34. package/dist/src/devtools/wechat-channel-action-smoke.d.ts +1 -0
  35. package/dist/src/devtools/wechat-channel-action-smoke.js +8 -8
  36. package/dist/src/index.js +2 -2
  37. package/package.json +1 -1
@@ -2,6 +2,8 @@ import type { ExternalMessageEvent } from '../../channels/base.js';
2
2
  import type { WeChatChannelRuntimePlatform } from '../../channels/wechat-channel/runtime.js';
3
3
  import type { WeChatSendResult } from './types.js';
4
4
  export declare function normalizeSendStatus(value: unknown): WeChatSendResult['sendStatus'] | null;
5
+ export declare function isPendingSendStatus(status: WeChatSendResult['sendStatus']): boolean;
6
+ export declare function describeSendStatus(status: WeChatSendResult['sendStatus']): string;
5
7
  export declare function currentWeChatPlatform(): WeChatChannelRuntimePlatform | undefined;
6
8
  export declare function cleanInline(value: unknown): string;
7
9
  export declare function processExists(pid: number): boolean;
@@ -1 +1 @@
1
- import o from"node:crypto";function i(t){return t==="dry_run"||t==="queued"||t==="sent"||t==="sent_unconfirmed"||t==="confirmed_echo"||t==="manual_review"||t==="pending"||t==="ok"?t:null}function c(){if(process.platform==="darwin")return"darwin";if(process.platform==="win32")return"win32"}function f(t){return String(t||"").replace(/\s+/g," ").trim()}function p(t){try{return process.kill(t,0),!0}catch{return!1}}function a(t){if(!t||typeof t!="object")return!1;const r=t,e=typeof r.name=="string"?r.name:"",n=typeof r.message=="string"?r.message:"";return e==="AbortError"||r.code==="ABORT_ERR"||/aborted|abort/i.test(n)}function u(t,r){return`${t}:${o.createHash("sha256").update(r).digest("hex").slice(0,32)}`}function m(t){return t.trim().replace(/[^a-zA-Z0-9._-]+/g,"_").replace(/^_+|_+$/g,"")||"conversation"}function d(t,r){const e=Number(t);return!Number.isFinite(e)||e<=0?r:Math.floor(e)}function g(t){return!!t&&typeof t=="object"&&!Array.isArray(t)&&t.type==="external.message"&&typeof t.channelId=="string"&&typeof t.conversationId=="string"&&typeof t.messageId=="string"&&typeof t.text=="string"}function y(t){return!!t&&typeof t=="object"&&!Array.isArray(t)}function x(t){return typeof t=="string"&&t?t:void 0}export{d as clampPositiveInteger,f as cleanInline,c as currentWeChatPlatform,a as isAbortError,g as isExternalMessageEvent,y as isRecord,i as normalizeSendStatus,p as processExists,m as safePathSegment,u as stableId,x as stringValue};
1
+ import o from"node:crypto";function s(e){return e==="dry_run"||e==="queued"||e==="sent"||e==="sent_unconfirmed"||e==="confirmed_echo"||e==="manual_review"||e==="pending"||e==="ok"?e:null}function c(e){return e==="queued"||e==="pending"}function u(e){switch(e){case"dry_run":return"dry_run: \u6F14\u7EC3\u5B8C\u6210\uFF0C\u672A\u771F\u6B63\u53D1\u9001\u3002";case"queued":return"queued: \u5DF2\u6392\u961F\uFF0C\u7B49\u5F85\u672C\u673A\u53D1\u9001\uFF0C\u65E0\u9700\u91CD\u53D1\u3002";case"pending":return"pending: \u5DF2\u63D0\u4EA4\u672C\u673A\u53D1\u9001\uFF0C\u65E0\u9700\u91CD\u53D1\u3002";case"sent":return"sent: \u5DF2\u53D1\u9001\uFF0C\u8BF7\u52FF\u91CD\u53D1\u3002";case"sent_unconfirmed":return"sent_unconfirmed: \u6D88\u606F\u5DF2\u53D1\u51FA\uFF0C\u8BF7\u52FF\u91CD\u53D1\u3002";case"confirmed_echo":return"confirmed_echo: \u5DF2\u53D1\u9001\u5E76\u786E\u8BA4\uFF0C\u8BF7\u52FF\u91CD\u53D1\u3002";case"manual_review":return"manual_review: \u5DF2\u63D0\u4EA4\uFF0C\u4F46\u9700\u4EBA\u5DE5\u6838\u5BF9\uFF0C\u8BF7\u52FF\u91CD\u53D1\u3002";case"ok":return"ok: \u5DF2\u53D1\u9001\uFF0C\u8BF7\u52FF\u91CD\u53D1\u3002";default:return String(e)}}function f(){if(process.platform==="darwin")return"darwin";if(process.platform==="win32")return"win32"}function a(e){return String(e||"").replace(/\s+/g," ").trim()}function p(e){try{return process.kill(e,0),!0}catch{return!1}}function d(e){if(!e||typeof e!="object")return!1;const r=e,n=typeof r.name=="string"?r.name:"",t=typeof r.message=="string"?r.message:"";return n==="AbortError"||r.code==="ABORT_ERR"||/aborted|abort/i.test(t)}function m(e,r){return`${e}:${o.createHash("sha256").update(r).digest("hex").slice(0,32)}`}function g(e){return e.trim().replace(/[^a-zA-Z0-9._-]+/g,"_").replace(/^_+|_+$/g,"")||"conversation"}function y(e,r){const n=Number(e);return!Number.isFinite(n)||n<=0?r:Math.floor(n)}function x(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 _(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function b(e){return typeof e=="string"&&e?e:void 0}export{y as clampPositiveInteger,a as cleanInline,f as currentWeChatPlatform,u as describeSendStatus,d as isAbortError,x as isExternalMessageEvent,c as isPendingSendStatus,_ as isRecord,s as normalizeSendStatus,p as processExists,g as safePathSegment,m as stableId,b as stringValue};
@@ -25,7 +25,7 @@ export type ShennianConfig = {
25
25
  refreshToken?: string;
26
26
  serverUrl?: string;
27
27
  customAgents?: Record<string, CustomAgentEntry>;
28
- /** Auto-upgrade policy: 'none' | 'patch' | 'minor' (default: 'patch') */
28
+ /** Auto-upgrade policy: 'none' | 'patch' | 'minor' (default: 'none' — 用户在 app 里点更新才升级) */
29
29
  autoUpgrade?: 'none' | 'patch' | 'minor';
30
30
  };
31
31
  export declare function loadConfig(): ShennianConfig;
@@ -60,6 +60,7 @@ export declare function buildSendStepAcceptance(input: {
60
60
  attachmentPath?: string | null;
61
61
  beforeTextCount?: number | null;
62
62
  afterTextCount?: number | null;
63
+ skipPostSendVerify?: boolean;
63
64
  }): {
64
65
  ok: boolean;
65
66
  reasonCode?: string;
@@ -1,10 +1,10 @@
1
- import M from"node:crypto";import{spawnSync as de}from"node:child_process";import p from"node:fs";import i from"node:path";import{fileURLToPath as ce}from"node:url";import{buildBottomPageReport as T,buildDownloadVisibleMediaReport as K}from"./wechat-channel-download-report.js";import{buildWeChatMessagesMarkdown as S}from"./wechat-channel-markdown-report.js";import{loadConfig as le}from"../config/index.js";import{createWeChatChannelApiClient as k}from"../channels/wechat-channel/client.js";import{resolveWeChatChannelHelperAsset as ue,WECHAT_CHANNEL_HELPER_VERSION as me}from"../channels/wechat-channel/helper-assets.js";import{WeChatChannelHelperClient as he}from"../channels/wechat-channel/helper-client.js";import{requiredWindowsWeChatChannelHelperCapabilitiesForProfile as B}from"../channels/wechat-channel/helper-protocol.js";import{classifyWeChatOutboundEchoes as fe,enqueueWeChatOutboundReply as G}from"../channels/wechat-channel/outbound-ledger.js";import{loadWeChatChannelLedger as ge,saveWeChatChannelLedger as we,updateWeChatChannelBindingLedger as pe}from"../channels/wechat-channel/ledger.js";import{waitForWeChatChannelPacing as V}from"../channels/wechat-channel/pacing.js";import{WeChatChannelOutboundSender as z,sendQueuedWeChatOutboundRecords as C}from"../channels/wechat-channel/outbound-sender.js";import{captureWeChatWindow as j,detectWeChatMessageInputPointByServerVision as be,ensureWeChatWindowReady as y,focusKnownWeChatWindow as I,observeWeChatChannelBindingViaHelper as ve,openConversationBySearch as x,recognizeWeChatScreenshot as E}from"../channels/wechat-channel/observer.js";import{createWeChatChannelRuntime as ye}from"../channels/wechat-channel/runtime.js";function Se(e){const t=!e.sessionId&&e.observePipeline==="edge-structure";if(!e.sessionId&&!t)throw new Error("session_id_required: pass --session-id <existing Shennian session id> for server observe steps");return t?"direct-edge-structure":"session-bound"}const ke="ABC",Ce="wechat-channel-action-smoke";function Ie(e){const t=e.filter(l=>l!=="--"),n=ht(t),r=gt(t,"--step").map(ft).filter(l=>l!=null),o=le(),s=f(t,"--trace-id")||`wechat-action-smoke-${Date.now().toString(36)}`,d=i.resolve(f(t,"--out")||f(t,"--output")||i.join(process.cwd(),".dev-runtime","wechat-channel","action-smoke",s)),a=r.length?wt(r):xe(n);return{conversation:f(t,"--conversation")||f(t,"--group")||ke,mode:r.length?"custom":n,steps:a,outDir:d,workDir:i.resolve(f(t,"--work-dir")||process.cwd()),traceId:s,runtimeId:f(t,"--runtime-id")||Ce,machineId:f(t,"--machine-id")||process.env.SHENNIAN_MACHINE_ID||o.machineId||"local",sessionId:f(t,"--session-id")||process.env.SHENNIAN_EXTERNAL_SESSION_ID||process.env.SHENNIAN_MANAGER_SESSION_ID,serverUrl:f(t,"--server-url")||o.serverUrl,platform:lt(f(t,"--platform")),text:f(t,"--text"),filePath:L(f(t,"--file")),imagePath:L(f(t,"--image")),videoPath:L(f(t,"--video")),downloadAnchorText:f(t,"--download-anchor-text")||f(t,"--media-anchor-text"),allowEmptyMedia:t.includes("--allow-empty-media"),requireServer:t.includes("--require-server")}}function xe(e){return e==="send"?["open-read","send-text","send-file","send-image","send-video"]:e==="observe"?["structure-window"]:e==="all"?["open-read","send-text","send-file","send-image","send-video","structure-window"]:["open-read"]}async function De(e){const t=Date.now(),n=new Date(t).toISOString();p.mkdirSync(e.outDir,{recursive:!0});const r=i.join(e.outDir,"helper-trace.jsonl");p.writeFileSync(r,"");const o=ot(e),s=o.bindings[0],d=st(e,r);await d.start();const a={ok:!1,conversation:e.conversation,outDir:e.outDir,helperTracePath:r,traceId:e.traceId,runtimeId:e.runtimeId,machineId:e.machineId,startedAt:n,finishedAt:n,durationMs:0,steps:[]};try{for(const l of e.steps){if(Ae(l)&&a.steps.some(c=>c.step==="open-read"&&!c.ok&&!c.skipped)){a.steps.push({step:l,ok:!1,reasonCode:"open_read_required",errorSummary:"open-read failed; refusing to run send step against the current WeChat window"});continue}a.steps.push(await _e({step:l,options:e,runtime:o,binding:s,helper:d}))}}finally{await d.stop().catch(()=>{}),a.finishedAt=new Date().toISOString(),a.durationMs=Date.now()-t,a.ok=a.steps.every(l=>l.ok||l.skipped),m(i.join(e.outDir,"summary.json"),a)}return a}function Ae(e){return e==="send-text"||e==="send-file"||e==="send-image"||e==="send-video"||e==="send-and-confirm"}async function _e(e){try{return e.step==="open-read"?await je(e):e.step==="structure-window"?await Ke(e):e.step==="server-observe"?await qe(e):e.step==="read-bottom-page"?await He(e):e.step==="download-visible-media"?await Ue(e):e.step==="send-and-confirm"?await Fe(e):e.step.startsWith("human-")?await Me(e):await J(e)}catch(t){const n=kt(t),r=await Re(e,n,t);return{step:e.step,ok:!1,reasonCode:n,errorSummary:t instanceof Error?t.message:String(t),userAction:Ct(n),...r?{details:r}:{}}}}async function Re(e,t,n){if(!Pe(t))return;const r=i.join(e.options.outDir,`${e.step}-failure-diagnostics.json`),o={step:e.step,reasonCode:t,errorSummary:n instanceof Error?n.message:String(n),capturedAt:new Date().toISOString()};try{o.permissions=await e.helper.request("permissions.check",{},e.options.traceId)}catch(s){o.permissionsError=s instanceof Error?s.message:String(s)}try{o.windows=await e.helper.request("windows.list",{},e.options.traceId)}catch(s){o.windowsError=s instanceof Error?s.message:String(s)}return m(r,o),{failureDiagnosticsPath:r}}function Pe(e){return e.startsWith("wechat_")||e.startsWith("permission_")||e.startsWith("user_active")}async function Me(e){if(e.step==="human-observe-deferred")return await Te(e);const t=e.step,n=`human-${_(`${e.options.traceId}:${t}:${Date.now()}`)}`,r={version:1,runtimeId:e.runtime.runtimeId,records:[]},o=G({ledger:r,replyId:`human:${t}:${n}`,idempotencyKey:`human:${n}`,bindingId:e.binding.bindingId,runtimeId:e.runtime.runtimeId,sessionId:e.binding.sessionId,conversationName:e.binding.conversationDisplayName,replyBaseRevision:0,text:`${n} ${e.options.text||"Shennian WeChat human coordination smoke"}`}),s=Z(e.helper,Y(t)),d=s.actionLog,a=k({serverUrl:e.options.serverUrl}),l=async P=>{d.push(`openConversation:${P}`);const ae=await y(s,e.options.traceId),ie=await I(s,ae,e.options.traceId);return x({helper:s,window:ie,settleToBottom:!1,binding:{...e.binding,conversationDisplayName:P},runtime:e.runtime,api:a,workDir:e.options.workDir,traceId:e.options.traceId})},c=new z({helper:s,platform:e.runtime.policy.platform,openConversation:l,traceId:e.options.traceId,activityGatePolicy:e.step==="human-send-user-active-timeout"?{keyDownThresholdMs:3e4,mouseMovedThresholdMs:3e4,mouseClickThresholdMs:3e4,scrollWheelThresholdMs:3e4}:void 0});let h=await C({ledger:r,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:c,now:new Date("2026-06-15T00:00:00.000Z"),maxUserActivityWaitMs:e.step==="human-send-user-active-timeout"?1e3:void 0});e.step==="human-send-user-active-timeout"&&(h=await C({ledger:r,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:c,now:new Date("2026-06-15T00:00:02.000Z"),maxUserActivityWaitMs:1e3})),(e.step==="human-send-preflight-busy-then-idle"||e.step==="human-send-takeover-then-idle")&&(s.setScenario(Je()),h=await C({ledger:r,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:c,now:new Date("2026-06-15T00:00:06.000Z")}));const g=Qe(e.step,o)?await F({helper:s,runtime:e.runtime,binding:e.binding,api:a,workDir:e.options.workDir,marker:n,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:e.step}):0,u=g>0?fe({ledger:r,bindingId:e.binding.bindingId,messages:[{stableMessageKey:`human-echo:${n}`,senderRole:"self",kind:"text",anchorText:o.text,normalizedText:o.text,textExcerpt:o.text,observedAt:new Date().toISOString()}]}):{confirmedRecords:[],manualReviewRecords:[],remainingMessages:[]},b=r.records[0],R=nt(b,h,u.confirmedRecords),v={case:e.step,marker:n,runStatus:R,reasonCode:b.deferReason||b.failureCode||null,outboundStatus:b.sendStatus,attemptCount:b.attemptCount??0,nextAttemptAt:b.nextAttemptAt??null,observedMarkerCount:g,actionLog:d,clipboardRestore:d.includes("clipboard.restore")?"attempted":"not_needed",commitStage:b.commitStage??null};return m(i.join(e.options.outDir,`${e.step}-summary.json`),v),{step:e.step,ok:rt(e.step,v),reasonCode:v.reasonCode||void 0,details:v}}async function Te(e){const t=Z(e.helper,Y("human-observe-deferred")),n=await t.request("activity.snapshot",{},e.options.traceId),r=!!(n.ok&&n.result&&typeof n.result=="object"&&Number(n.result.keyDownSecondsAgo)<5),o={case:e.step,marker:null,runStatus:r?"observe_deferred_user_active":"baseline_or_no_change",reasonCode:r?"recent_keyboard_activity":null,outboundStatus:null,attemptCount:0,nextAttemptAt:null,observedMarkerCount:0,actionLog:t.actionLog,clipboardRestore:"not_needed"};return m(i.join(e.options.outDir,`${e.step}-summary.json`),o),{step:e.step,ok:r&&!t.actionLog.some(s=>s.startsWith("windows.")||s.startsWith("wechat.")||s.startsWith("clipboard.")),reasonCode:o.reasonCode||void 0,details:o}}async function je(e){const t=await y(e.helper,e.options.traceId),n=await I(e.helper,t,e.options.traceId),r=k({serverUrl:e.options.serverUrl}),o=await x({helper:e.helper,window:n,binding:e.binding,runtime:e.runtime,api:r,workDir:e.options.workDir,traceId:e.options.traceId});if(!o.opened)throw await Ee({helper:e.helper,window:n,outDir:e.options.outDir,traceId:e.options.traceId,reason:o.reason||"conversation_not_opened"}),new Error(o.reason||"conversation_not_opened");const s=await j(e.helper,n.windowId,e.options.traceId),d=D(e.options.outDir,"open-read-full-window",s),a=await E(e.helper,s,e.options.traceId);return m(i.join(e.options.outDir,"open-read-ocr.json"),a),{step:"open-read",ok:!0,details:{openedReason:o.reason,windowId:n.windowId,screenshotPath:d,screenshot:{width:s.width,height:s.height,mimeType:s.mimeType},ocrBlockCount:a.blocks?.length??0,visibleConversationFingerprintCount:a.visibleConversationFingerprints?.length??0}}}async function Ee(e){try{const t=await j(e.helper,e.window.windowId,e.traceId,e.window.bounds),n=D(e.outDir,"open-read-failure-window",t),r=await E(e.helper,t,e.traceId);m(i.join(e.outDir,"open-read-failure-ocr.json"),r),m(i.join(e.outDir,"open-read-failure-summary.json"),{reason:e.reason,windowId:e.window.windowId,screenshotPath:n,screenshot:{width:t.width,height:t.height,mimeType:t.mimeType},ocrBlockCount:r.blocks?.length??0,visibleConversationFingerprintCount:r.visibleConversationFingerprints?.length??0,topTexts:(r.blocks??[]).slice(0,30).map(o=>({text:o.text,bbox:o.bbox}))})}catch(t){m(i.join(e.outDir,"open-read-failure-summary.json"),{reason:e.reason,captureError:t instanceof Error?t.message:String(t)})}}async function J(e){return await We(e,ut(e.step,e.options))}async function We(e,t){if(t.skipped)return{step:e.step,ok:!0,skipped:!0,reasonCode:t.reasonCode};const n=k({serverUrl:e.options.serverUrl}),r={version:1,runtimeId:e.runtime.runtimeId,records:[]},o=`${e.options.traceId}:${e.step}:${t.text}:${t.attachmentPath||""}`,s=t.text?await F({helper:e.helper,runtime:e.runtime,binding:e.binding,api:n,workDir:e.options.workDir,marker:t.text,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:`${e.step}-before-send`,settleToBottom:!1}).catch(()=>null):null;G({ledger:r,replyId:`action-smoke:${e.step}:${_(o)}`,idempotencyKey:`action-smoke:${_(o)}`,bindingId:e.binding.bindingId,runtimeId:e.runtime.runtimeId,sessionId:e.binding.sessionId,conversationName:e.binding.conversationDisplayName,replyBaseRevision:0,text:t.text,attachmentLocalRefs:t.attachmentPath?[t.attachmentPath]:[]});const d=new z({helper:e.helper,platform:e.runtime.policy.platform,traceId:e.options.traceId,activityGatePolicy:e.runtime.foregroundPolicy==="work"?{mouseMovedThresholdMs:0,mouseClickThresholdMs:0,scrollWheelThresholdMs:0,keyDownThresholdMs:0}:void 0,takeoverCheck:e.runtime.foregroundPolicy!=="work",onAfterPaste:async({kind:u})=>{await Xe({helper:e.helper,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:`${e.step}-after-paste-${u}`})},openConversation:async u=>{const b=await y(e.helper,e.options.traceId),R=await I(e.helper,b,e.options.traceId),v=await x({helper:e.helper,window:R,settleToBottom:!1,binding:{...e.binding,conversationDisplayName:u},runtime:e.runtime,api:n,workDir:e.options.workDir,traceId:e.options.traceId});if(!v.opened)return{...v,inputPoint:null};const P=await be({runtime:e.runtime,binding:{...e.binding,conversationDisplayName:u},helper:e.helper,api:n,workDir:e.options.workDir,traceId:e.options.traceId,window:R});return{...v,inputPoint:P}}}),a=await Be({ledger:r,bindingId:e.binding.bindingId,sender:d});await V("send-after-submit",`${e.options.traceId}:${e.step}:after-submit`);const l=r.records[0],c=a.failedRecords[0]?.failureCode||a.manualReviewRecords[0]?.failureCode||a.waitingRecords[0]?.deferReason||a.staleRecords[0]?.failureCode,w=a.sentRecords.length===1&&a.failedRecords.length===0&&a.waitingRecords.length===0&&a.manualReviewRecords.length===0&&a.staleRecords.length===0,h=w&&t.text?await tt({helper:e.helper,runtime:e.runtime,binding:e.binding,api:n,workDir:e.options.workDir,marker:t.text,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:`${e.step}-after-send`,settleToBottom:!1,attempts:3,targetGreaterThan:s}):null,g=$e({sendAccepted:w,text:t.text,attachmentPath:t.attachmentPath,beforeTextCount:s,afterTextCount:h});return{step:e.step,ok:g.ok,reasonCode:c||g.reasonCode,errorSummary:a.failedRecords[0]?.lastErrorSummary||a.manualReviewRecords[0]?.lastErrorSummary,details:{text:t.text,attachmentPath:t.attachmentPath??null,helperTracePath:i.join(e.options.outDir,"helper-trace.jsonl"),confirmationRequired:g.confirmationRequired,sendAccepted:g.sendAccepted,beforeTextCount:s,afterTextCount:h,sentRecords:a.sentRecords.length,failedRecords:a.failedRecords.length,waitingRecords:a.waitingRecords.length,manualReviewRecords:a.manualReviewRecords.length,staleRecords:a.staleRecords.length,sendStatus:l?.sendStatus,failureCode:l?.failureCode??null,lastErrorSummary:l?.lastErrorSummary??null,deferReason:l?.deferReason,commitStage:l?.commitStage??null,attemptCount:l?.attemptCount??0,nextAttemptAt:l?.nextAttemptAt??null}}}function $e(e){const t=!!(e.text&&e.text.trim()&&!e.attachmentPath);if(!e.sendAccepted)return{ok:!1,reasonCode:void 0,sendAccepted:!1,confirmationRequired:t};if(!t)return{ok:!0,sendAccepted:!0,confirmationRequired:t};const n=typeof e.beforeTextCount=="number"&&Number.isFinite(e.beforeTextCount)?e.beforeTextCount:null,r=typeof e.afterTextCount=="number"&&Number.isFinite(e.afterTextCount)?e.afterTextCount:0,o=n==null?r>0:r>n;return{ok:o,reasonCode:o?void 0:"sent_text_not_observed",sendAccepted:!0,confirmationRequired:t}}async function Be(e){const t=e.maxAttempts??24,n=e.maxWaitMs??9e4,r=Date.now();let o=await C({ledger:e.ledger,bindingId:e.bindingId,currentLastInboundRevision:0,sender:e.sender,maxUserActivityWaitMs:n});for(let s=2;o.waitingRecords.length>0&&s<=t&&!(Date.now()-r>=n);s+=1){const d=Ne(o.waitingRecords[0]?.nextAttemptAt,r,n);await q(d),o=await C({ledger:e.ledger,bindingId:e.bindingId,currentLastInboundRevision:0,sender:e.sender,maxUserActivityWaitMs:n})}return o}function Ne(e,t,n){const r=Math.max(0,n-(Date.now()-t));if(r<=0)return 0;const o=e?new Date(e).getTime():Number.NaN,s=Number.isFinite(o)?o-Date.now():1e3;return Math.max(500,Math.min(Math.max(500,s),Math.min(5e3,r)))}function Oe(e){const t=e.sendResults.filter(u=>!Q(u)),n=e.sendResults.filter(u=>!u.skipped).map(u=>u.details?.text&&typeof u.details.text=="string"?u.details.text:"").filter(Boolean),r=e.observedMessages.map(u=>[u.normalizedText||"",u.anchorText||"",u.textExcerpt||""].join(`
1
+ import M from"node:crypto";import{spawnSync as ce}from"node:child_process";import p from"node:fs";import i from"node:path";import{fileURLToPath as le}from"node:url";import{buildBottomPageReport as T,buildDownloadVisibleMediaReport as G}from"./wechat-channel-download-report.js";import{buildWeChatMessagesMarkdown as k}from"./wechat-channel-markdown-report.js";import{loadConfig as ue}from"../config/index.js";import{createWeChatChannelApiClient as C}from"../channels/wechat-channel/client.js";import{resolveWeChatChannelHelperAsset as me,WECHAT_CHANNEL_HELPER_VERSION as he}from"../channels/wechat-channel/helper-assets.js";import{WeChatChannelHelperClient as fe}from"../channels/wechat-channel/helper-client.js";import{requiredWindowsWeChatChannelHelperCapabilitiesForProfile as O}from"../channels/wechat-channel/helper-protocol.js";import{classifyWeChatOutboundEchoes as ge,enqueueWeChatOutboundReply as z}from"../channels/wechat-channel/outbound-ledger.js";import{loadWeChatChannelLedger as we,saveWeChatChannelLedger as be,updateWeChatChannelBindingLedger as pe}from"../channels/wechat-channel/ledger.js";import{waitForWeChatChannelPacing as J}from"../channels/wechat-channel/pacing.js";import{WeChatChannelOutboundSender as Q,sendQueuedWeChatOutboundRecords as I}from"../channels/wechat-channel/outbound-sender.js";import{captureWeChatWindow as j,detectWeChatMessageInputPointByServerVision as ve,ensureWeChatWindowReady as S,focusKnownWeChatWindow as x,observeWeChatChannelBindingViaHelper as ye,openConversationBySearch as D,recognizeWeChatScreenshot as E}from"../channels/wechat-channel/observer.js";import{createWeChatChannelRuntime as Se}from"../channels/wechat-channel/runtime.js";function ke(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 Ce="ABC",Ie="wechat-channel-action-smoke";function xe(e){const t=e.filter(l=>l!=="--"),n=ft(t),r=wt(t,"--step").map(gt).filter(l=>l!=null),o=ue(),s=b(t,"--trace-id")||`wechat-action-smoke-${Date.now().toString(36)}`,d=i.resolve(b(t,"--out")||b(t,"--output")||i.join(process.cwd(),".dev-runtime","wechat-channel","action-smoke",s)),a=r.length?bt(r):De(n);return{conversation:A(t,"--conversation")||A(t,"--group")||Ce,mode:r.length?"custom":n,steps:a,outDir:d,workDir:i.resolve(b(t,"--work-dir")||process.cwd()),traceId:s,runtimeId:b(t,"--runtime-id")||Ie,machineId:b(t,"--machine-id")||process.env.SHENNIAN_MACHINE_ID||o.machineId||"local",sessionId:b(t,"--session-id")||process.env.SHENNIAN_EXTERNAL_SESSION_ID||process.env.SHENNIAN_MANAGER_SESSION_ID,serverUrl:b(t,"--server-url")||o.serverUrl,platform:ut(b(t,"--platform")),text:A(t,"--text"),filePath:U(b(t,"--file")),imagePath:U(b(t,"--image")),videoPath:U(b(t,"--video")),downloadAnchorText:A(t,"--download-anchor-text")||A(t,"--media-anchor-text"),allowEmptyMedia:t.includes("--allow-empty-media"),requireServer:t.includes("--require-server")}}function De(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 Ae(e){const t=Date.now(),n=new Date(t).toISOString();p.mkdirSync(e.outDir,{recursive:!0});const r=i.join(e.outDir,"helper-trace.jsonl");p.writeFileSync(r,"");const o=st(e),s=o.bindings[0],d=at(e,r);await d.start();const a={ok:!1,conversation:e.conversation,outDir:e.outDir,helperTracePath:r,traceId:e.traceId,runtimeId:e.runtimeId,machineId:e.machineId,startedAt:n,finishedAt:n,durationMs:0,steps:[]};try{for(const l of e.steps){if(_e(l)&&a.steps.some(c=>c.step==="open-read"&&!c.ok&&!c.skipped)){a.steps.push({step:l,ok:!1,reasonCode:"open_read_required",errorSummary:"open-read failed; refusing to run send step against the current WeChat window"});continue}a.steps.push(await Re({step:l,options:e,runtime:o,binding:s,helper:d}))}}finally{await d.stop().catch(()=>{}),a.finishedAt=new Date().toISOString(),a.durationMs=Date.now()-t,a.ok=a.steps.every(l=>l.ok||l.skipped),m(i.join(e.outDir,"summary.json"),a)}return a}function _e(e){return e==="send-text"||e==="send-file"||e==="send-image"||e==="send-video"||e==="send-and-confirm"}async function Re(e){try{return e.step==="open-read"?await Ee(e):e.step==="structure-window"?await Ve(e):e.step==="server-observe"?await Ke(e):e.step==="read-bottom-page"?await Ue(e):e.step==="download-visible-media"?await qe(e):e.step==="send-and-confirm"?await Le(e):e.step.startsWith("human-")?await Te(e):await X(e)}catch(t){const n=Ct(t),r=await Pe(e,n,t);return{step:e.step,ok:!1,reasonCode:n,errorSummary:t instanceof Error?t.message:String(t),userAction:It(n),...r?{details:r}:{}}}}async function Pe(e,t,n){if(!Me(t))return;const r=i.join(e.options.outDir,`${e.step}-failure-diagnostics.json`),o={step:e.step,reasonCode:t,errorSummary:n instanceof Error?n.message:String(n),capturedAt:new Date().toISOString()};try{o.permissions=await e.helper.request("permissions.check",{},e.options.traceId)}catch(s){o.permissionsError=s instanceof Error?s.message:String(s)}try{o.windows=await e.helper.request("windows.list",{},e.options.traceId)}catch(s){o.windowsError=s instanceof Error?s.message:String(s)}return m(r,o),{failureDiagnosticsPath:r}}function Me(e){return e.startsWith("wechat_")||e.startsWith("permission_")||e.startsWith("user_active")}async function Te(e){if(e.step==="human-observe-deferred")return await je(e);const t=e.step,n=`human-${P(`${e.options.traceId}:${t}:${Date.now()}`)}`,r={version:1,runtimeId:e.runtime.runtimeId,records:[]},o=z({ledger:r,replyId:`human:${t}:${n}`,idempotencyKey:`human:${n}`,bindingId:e.binding.bindingId,runtimeId:e.runtime.runtimeId,sessionId:e.binding.sessionId,conversationName:e.binding.conversationDisplayName,replyBaseRevision:0,text:`${n} ${e.options.text||"Shennian WeChat human coordination smoke"}`}),s=ee(e.helper,te(t)),d=s.actionLog,a=C({serverUrl:e.options.serverUrl}),l=async y=>{d.push(`openConversation:${y}`);const N=await S(s,e.options.traceId),de=await x(s,N,e.options.traceId);return D({helper:s,window:de,settleToBottom:!1,binding:{...e.binding,conversationDisplayName:y},runtime:e.runtime,api:a,workDir:e.options.workDir,traceId:e.options.traceId})},c=new Q({helper:s,platform:e.runtime.policy.platform,openConversation:l,traceId:e.options.traceId,activityGatePolicy:e.step==="human-send-user-active-timeout"?{keyDownThresholdMs:3e4,mouseMovedThresholdMs:3e4,mouseClickThresholdMs:3e4,scrollWheelThresholdMs:3e4}:void 0});let h=await I({ledger:r,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:c,now:new Date("2026-06-15T00:00:00.000Z"),maxUserActivityWaitMs:e.step==="human-send-user-active-timeout"?1e3:void 0});e.step==="human-send-user-active-timeout"&&(h=await I({ledger:r,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:c,now:new Date("2026-06-15T00:00:02.000Z"),maxUserActivityWaitMs:1e3})),(e.step==="human-send-preflight-busy-then-idle"||e.step==="human-send-takeover-then-idle")&&(s.setScenario(Qe()),h=await I({ledger:r,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:c,now:new Date("2026-06-15T00:00:06.000Z")}));const g=Xe(e.step,o)?await H({helper:s,runtime:e.runtime,binding:e.binding,api:a,workDir:e.options.workDir,marker:n,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:e.step}):0,u=g>0?ge({ledger:r,bindingId:e.binding.bindingId,messages:[{stableMessageKey:`human-echo:${n}`,senderRole:"self",kind:"text",anchorText:o.text,normalizedText:o.text,textExcerpt:o.text,observedAt:new Date().toISOString()}]}):{confirmedRecords:[],manualReviewRecords:[],remainingMessages:[]},w=r.records[0],B=rt(w,h,u.confirmedRecords),v={case:e.step,marker:n,runStatus:B,reasonCode:w.deferReason||w.failureCode||null,outboundStatus:w.sendStatus,attemptCount:w.attemptCount??0,nextAttemptAt:w.nextAttemptAt??null,observedMarkerCount:g,actionLog:d,clipboardRestore:d.includes("clipboard.restore")?"attempted":"not_needed",commitStage:w.commitStage??null};return m(i.join(e.options.outDir,`${e.step}-summary.json`),v),{step:e.step,ok:ot(e.step,v),reasonCode:v.reasonCode||void 0,details:v}}async function je(e){const t=ee(e.helper,te("human-observe-deferred")),n=await t.request("activity.snapshot",{},e.options.traceId),r=!!(n.ok&&n.result&&typeof n.result=="object"&&Number(n.result.keyDownSecondsAgo)<5),o={case:e.step,marker:null,runStatus:r?"observe_deferred_user_active":"baseline_or_no_change",reasonCode:r?"recent_keyboard_activity":null,outboundStatus:null,attemptCount:0,nextAttemptAt:null,observedMarkerCount:0,actionLog:t.actionLog,clipboardRestore:"not_needed"};return m(i.join(e.options.outDir,`${e.step}-summary.json`),o),{step:e.step,ok:r&&!t.actionLog.some(s=>s.startsWith("windows.")||s.startsWith("wechat.")||s.startsWith("clipboard.")),reasonCode:o.reasonCode||void 0,details:o}}async function Ee(e){const t=await S(e.helper,e.options.traceId),n=await x(e.helper,t,e.options.traceId),r=C({serverUrl:e.options.serverUrl}),o=await D({helper:e.helper,window:n,binding:e.binding,runtime:e.runtime,api:r,workDir:e.options.workDir,traceId:e.options.traceId});if(!o.opened)throw await We({helper:e.helper,window:n,outDir:e.options.outDir,traceId:e.options.traceId,reason:o.reason||"conversation_not_opened"}),new Error(o.reason||"conversation_not_opened");const s=await j(e.helper,n.windowId,e.options.traceId),d=_(e.options.outDir,"open-read-full-window",s),a=await E(e.helper,s,e.options.traceId);return m(i.join(e.options.outDir,"open-read-ocr.json"),a),{step:"open-read",ok:!0,details:{openedReason:o.reason,windowId:n.windowId,screenshotPath:d,screenshot:{width:s.width,height:s.height,mimeType:s.mimeType},ocrBlockCount:a.blocks?.length??0,visibleConversationFingerprintCount:a.visibleConversationFingerprints?.length??0}}}async function We(e){try{const t=await j(e.helper,e.window.windowId,e.traceId,e.window.bounds),n=_(e.outDir,"open-read-failure-window",t),r=await E(e.helper,t,e.traceId);m(i.join(e.outDir,"open-read-failure-ocr.json"),r),m(i.join(e.outDir,"open-read-failure-summary.json"),{reason:e.reason,windowId:e.window.windowId,screenshotPath:n,screenshot:{width:t.width,height:t.height,mimeType:t.mimeType},ocrBlockCount:r.blocks?.length??0,visibleConversationFingerprintCount:r.visibleConversationFingerprints?.length??0,topTexts:(r.blocks??[]).slice(0,30).map(o=>({text:o.text,bbox:o.bbox}))})}catch(t){m(i.join(e.outDir,"open-read-failure-summary.json"),{reason:e.reason,captureError:t instanceof Error?t.message:String(t)})}}async function X(e){return await $e(e,mt(e.step,e.options))}async function $e(e,t){if(t.skipped)return{step:e.step,ok:!0,skipped:!0,reasonCode:t.reasonCode};const n=C({serverUrl:e.options.serverUrl}),r={version:1,runtimeId:e.runtime.runtimeId,records:[]},o=`${e.options.traceId}:${e.step}:${t.text}:${t.attachmentPath||""}`,s=t.text?await H({helper:e.helper,runtime:e.runtime,binding:e.binding,api:n,workDir:e.options.workDir,marker:t.text,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:`${e.step}-before-send`,settleToBottom:!1}).catch(()=>null):null;z({ledger:r,replyId:`action-smoke:${e.step}:${P(o)}`,idempotencyKey:`action-smoke:${P(o)}`,bindingId:e.binding.bindingId,runtimeId:e.runtime.runtimeId,sessionId:e.binding.sessionId,conversationName:e.binding.conversationDisplayName,replyBaseRevision:0,text:t.text,attachmentLocalRefs:t.attachmentPath?[t.attachmentPath]:[]});const d=new Q({helper:e.helper,platform:e.runtime.policy.platform,traceId:e.options.traceId,activityGatePolicy:e.runtime.foregroundPolicy==="work"?{mouseMovedThresholdMs:0,mouseClickThresholdMs:0,scrollWheelThresholdMs:0,keyDownThresholdMs:0}:void 0,takeoverCheck:e.runtime.foregroundPolicy!=="work",onAfterPaste:async({kind:w})=>{await Ze({helper:e.helper,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:`${e.step}-after-paste-${w}`})},openConversation:async w=>{const B=await S(e.helper,e.options.traceId),v=await x(e.helper,B,e.options.traceId),y=await D({helper:e.helper,window:v,settleToBottom:!1,binding:{...e.binding,conversationDisplayName:w},runtime:e.runtime,api:n,workDir:e.options.workDir,traceId:e.options.traceId});if(!y.opened)return{...y,inputPoint:null};const N=await ve({runtime:e.runtime,binding:{...e.binding,conversationDisplayName:w},helper:e.helper,api:n,workDir:e.options.workDir,traceId:e.options.traceId,window:v});return{...y,inputPoint:N}}}),a=await Ne({ledger:r,bindingId:e.binding.bindingId,sender:d});await J("send-after-submit",`${e.options.traceId}:${e.step}:after-submit`);const l=r.records[0],c=a.failedRecords[0]?.failureCode||a.manualReviewRecords[0]?.failureCode||a.waitingRecords[0]?.deferReason||a.staleRecords[0]?.failureCode,f=a.sentRecords.length===1&&a.failedRecords.length===0&&a.waitingRecords.length===0&&a.manualReviewRecords.length===0&&a.staleRecords.length===0,h=e.step==="send-text",g=f&&t.text&&!h?await nt({helper:e.helper,runtime:e.runtime,binding:e.binding,api:n,workDir:e.options.workDir,marker:t.text,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:`${e.step}-after-send`,settleToBottom:!1,attempts:3,targetGreaterThan:s}):null,u=Be({sendAccepted:f,text:t.text,attachmentPath:t.attachmentPath,beforeTextCount:s,afterTextCount:g,skipPostSendVerify:h});return{step:e.step,ok:u.ok,reasonCode:c||u.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:u.confirmationRequired,sendAccepted:u.sendAccepted,beforeTextCount:s,afterTextCount:g,sentRecords:a.sentRecords.length,failedRecords:a.failedRecords.length,waitingRecords:a.waitingRecords.length,manualReviewRecords:a.manualReviewRecords.length,staleRecords:a.staleRecords.length,sendStatus:l?.sendStatus,failureCode:l?.failureCode??null,lastErrorSummary:l?.lastErrorSummary??null,deferReason:l?.deferReason,commitStage:l?.commitStage??null,attemptCount:l?.attemptCount??0,nextAttemptAt:l?.nextAttemptAt??null}}}function Be(e){const t=!!(e.text&&e.text.trim()&&!e.attachmentPath);if(!e.sendAccepted)return{ok:!1,reasonCode:void 0,sendAccepted:!1,confirmationRequired:t};if(e.skipPostSendVerify||!t)return{ok:!0,sendAccepted:!0,confirmationRequired:e.skipPostSendVerify?!1:t};const n=typeof e.beforeTextCount=="number"&&Number.isFinite(e.beforeTextCount)?e.beforeTextCount:null,r=typeof e.afterTextCount=="number"&&Number.isFinite(e.afterTextCount)?e.afterTextCount:0,o=n==null?r>0:r>n;return{ok:o,reasonCode:o?void 0:"sent_text_not_observed",sendAccepted:!0,confirmationRequired:t}}async function Ne(e){const t=e.maxAttempts??24,n=e.maxWaitMs??9e4,r=Date.now();let o=await I({ledger:e.ledger,bindingId:e.bindingId,currentLastInboundRevision:0,sender:e.sender,maxUserActivityWaitMs:n});for(let s=2;o.waitingRecords.length>0&&s<=t&&!(Date.now()-r>=n);s+=1){const d=Oe(o.waitingRecords[0]?.nextAttemptAt,r,n);await V(d),o=await I({ledger:e.ledger,bindingId:e.bindingId,currentLastInboundRevision:0,sender:e.sender,maxUserActivityWaitMs:n})}return o}function Oe(e,t,n){const r=Math.max(0,n-(Date.now()-t));if(r<=0)return 0;const o=e?new Date(e).getTime():Number.NaN,s=Number.isFinite(o)?o-Date.now():1e3;return Math.max(500,Math.min(Math.max(500,s),Math.min(5e3,r)))}function Fe(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),r=e.observedMessages.map(u=>[u.normalizedText||"",u.anchorText||"",u.textExcerpt||""].join(`
2
2
  `)).join(`
3
- `),o=n.filter(u=>r.includes(u)),s=e.sendResults.map(u=>typeof u.details?.sendStatus=="string"?u.details.sendStatus:"").filter(Boolean),d=e.sendResults.filter(Q).length,a=N(t,"waitingRecords"),l=N(t,"failedRecords"),c=N(t,"manualReviewRecords"),w=t.find(u=>!u.ok||u.skipped),h=s.length===n.length&&s.every(u=>u==="sent_unconfirmed"||u==="confirmed_echo"),g=!w&&n.length>0&&o.length>0&&h&&a===0&&l===0&&c===0;return{ok:g,reasonCode:g?void 0:w?.reasonCode||(a>0?"outbound_send_waiting":void 0)||(l>0?"outbound_send_failed":void 0)||(c>0?"outbound_manual_review":void 0)||(h?void 0:"outbound_status_not_accepted")||(o.length?"partial_sent_messages_observed":"sent_messages_not_observed"),sentTexts:n,confirmedTexts:o,outboundStatuses:s,skippedFixtureCount:d,pendingOutboundCount:a,failedOutboundCount:l,manualReviewCount:c}}function Q(e){return e.skipped===!0&&e.reasonCode==="ffmpeg_unavailable_for_video_fixture"}function N(e,t){return e.reduce((n,r)=>{const o=r.details?.[t];return n+(typeof o=="number"&&Number.isFinite(o)?o:0)},0)}async function Fe(e){const t=["send-text"],n=[];for(const c of t)n.push(await J({...e,step:c}));await q(1200);const r=await W(e,3,{observePipeline:"edge-structure"}),o=T(r.messages),s=i.join(e.options.outDir,"bottom-page.md"),d=S(r.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(r.attachmentsDir)});m(i.join(e.options.outDir,"bottom-page-summary.json"),o),m(i.join(e.options.outDir,"server-observe-messages.json"),r.messages),A(s,d);const a=Oe({sendResults:n,observedMessages:r.messages}),l=a.ok&&r.messages.length>0;return{step:"send-and-confirm",ok:l,reasonCode:l?void 0:a.reasonCode,errorSummary:n.find(c=>!c.ok||c.skipped)?.errorSummary,details:{sent:n.map(c=>({step:c.step,ok:c.ok,skipped:c.skipped,reasonCode:c.reasonCode,errorSummary:c.errorSummary,text:c.details?.text,attachmentPath:c.details?.attachmentPath,sendStatus:c.details?.sendStatus,deferReason:c.details?.deferReason,failureCode:c.details?.failureCode,commitStage:c.details?.commitStage,attemptCount:c.details?.attemptCount,nextAttemptAt:c.details?.nextAttemptAt,waitingRecords:c.details?.waitingRecords,failedRecords:c.details?.failedRecords,manualReviewRecords:c.details?.manualReviewRecords})),sentTexts:a.sentTexts,confirmedTexts:a.confirmedTexts,outboundStatuses:a.outboundStatuses,skippedFixtureCount:a.skippedFixtureCount,pendingOutboundCount:a.pendingOutboundCount,failedOutboundCount:a.failedOutboundCount,manualReviewCount:a.manualReviewCount,observedCount:r.messages.length,byKind:o.byKind,attachmentSummary:o.attachmentSummary,attachmentsDir:r.attachmentsDir,reportPath:i.join(e.options.outDir,"bottom-page-summary.json"),markdownPath:s,markdown:d}}}async function W(e,t,n={}){let r;const o=[];for(let s=1;s<=t;s+=1)try{const d=await X(e,n);return o.length&&(o.push({phase:"observe",attempt:s,ok:!0,observedCount:d.messages.length,at:new Date().toISOString()}),m(i.join(e.options.outDir,"observe-retry-events.json"),o)),d}catch(d){if(r=d,o.push({phase:"observe",attempt:s,ok:!1,errorSummary:d instanceof Error?d.message:String(d||""),at:new Date().toISOString()}),s>=t||!Le(d))break;try{const a=await y(e.helper,e.options.traceId),l=await I(e.helper,a,e.options.traceId),c=await x({helper:e.helper,window:l,binding:e.binding,runtime:e.runtime,api:k({serverUrl:e.options.serverUrl}),workDir:e.options.workDir,traceId:e.options.traceId});o.push({phase:"recover",attempt:s,ok:c.opened,reason:c.reason,windowId:l.windowId,at:new Date().toISOString()})}catch(a){o.push({phase:"recover",attempt:s,ok:!1,errorSummary:a instanceof Error?a.message:String(a||""),at:new Date().toISOString()})}m(i.join(e.options.outDir,"observe-retry-events.json"),o),await V("observe-retry",`${e.options.traceId}:observe-retry:${s}`,1500*s)}throw o.length&&m(i.join(e.options.outDir,"observe-retry-events.json"),o),r}function Le(e){const t=e instanceof Error?e.message:String(e||"");return/conversation_not_visible|wechat_window_unavailable|wechat_window_not_found|title_not_confirmed|server_observe_failed|timeout/i.test(t)}async function He(e){const t=await W(e,3),n=T(t.messages),r=i.join(e.options.outDir,"bottom-page.md"),o=S(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});return m(i.join(e.options.outDir,"bottom-page-summary.json"),n),m(i.join(e.options.outDir,"server-observe-messages.json"),t.messages),A(r,o),{step:"read-bottom-page",ok:n.messageCount>0,reasonCode:n.messageCount>0?void 0:"no_observed_messages",details:{messageCount:n.messageCount,byKind:n.byKind,attachmentSummary:n.attachmentSummary,attachmentsDir:t.attachmentsDir,reportPath:i.join(e.options.outDir,"bottom-page-summary.json"),markdownPath:r,markdown:o}}}async function Ue(e){const t=await W(e,3,{observePipeline:"edge-structure",persistLocalLedger:!0});O(e.options.outDir,"download-visible",t.observationEvidence);const n=T(t.messages),r=i.join(e.options.outDir,"download-visible.md"),o=S(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)}),s=K(t.messages,t.attachmentsDir,{observePipeline:t.observePipeline,downloadAnchorText:e.options.downloadAnchorText,ledgerPath:t.ledgerPath,ledgerBinding:t.ledgerBinding,traceHashes:t.traceHashes});m(i.join(e.options.outDir,"bottom-page-summary.json"),n),m(i.join(e.options.outDir,"download-visible-summary.json"),s),m(i.join(e.options.outDir,"download-visible-messages.json"),t.messages),A(r,o);const d=!!(e.options.allowEmptyMedia&&s.reasonCode==="no_visible_media_candidates"&&t.messages.length>0),a=s.ok||d;return{step:"download-visible-media",ok:a,reasonCode:a?void 0:s.reasonCode,details:{mediaCandidateCount:s.mediaCandidateCount,localAttachmentCount:s.localAttachmentCount,originalLocalAttachmentCount:s.originalLocalAttachmentCount,previewAttachmentCount:s.previewAttachmentCount,missingLocalPathCount:s.missingLocalPathCount,pendingAttachmentCount:s.pendingAttachmentCount,byKind:s.byKind,byAvailability:s.byAvailability,reasonCodes:s.reasonCodes,mediaReasonCode:s.reasonCode,allowEmptyMediaRead:d,attachmentsDir:t.attachmentsDir,reportPath:i.join(e.options.outDir,"download-visible-summary.json"),markdownPath:r,markdown:o,phases:s.phases,observePipeline:s.observePipeline,ledgerPath:s.ledgerPath,ledgerRevision:s.ledger?.revision,traceHashes:s.traceHashes,traceEvents:s.traceEvents}}}async function qe(e){const t=await W(e,3,{observePipeline:"server-observe"});O(e.options.outDir,"server-observe",t.observationEvidence),m(i.join(e.options.outDir,"server-observe-messages.json"),t.messages);const n=i.join(e.options.outDir,"server-observe.md"),r=S(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});A(n,r);const o=ne(t.messages);return{step:"server-observe",ok:t.messages.length>0,reasonCode:t.messages.length>0?void 0:"no_observed_messages",details:{observedCount:t.messages.length,byKind:H(t.messages.map(s=>s.kind||"unknown")),attachmentSummary:o,attachmentsDir:t.attachmentsDir,markdownPath:n,markdown:r}}}async function Ke(e){const t=await X(e,{observePipeline:"edge-structure",downloadMedia:!1});O(e.options.outDir,"structure-window",t.observationEvidence),m(i.join(e.options.outDir,"structure-window-messages.json"),t.messages);const n=i.join(e.options.outDir,"structure-window.md"),r=S(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});A(n,r);const o=ne(t.messages);return{step:"structure-window",ok:t.messages.length>0,reasonCode:t.messages.length>0?void 0:"no_observed_messages",details:{observedCount:t.messages.length,byKind:H(t.messages.map(s=>s.kind||"unknown")),attachmentSummary:o,attachmentsDir:t.attachmentsDir,markdownPath:n,markdown:r}}}async function X(e,t={}){const n=Se({sessionId:e.options.sessionId,observePipeline:t.observePipeline}),r=k({serverUrl:e.options.serverUrl});e.options.skipRuntimeUpsert||(n==="direct-edge-structure"?await r.upsertRuntime(e.runtime):await r.upsertRuntime(e.runtime,{...e.binding,enabled:!1,allowReply:!1}));const o=i.join(e.options.outDir,"inbound-attachments");p.mkdirSync(o,{recursive:!0});const s=t.persistLocalLedger?pt(e.options):void 0,d=s?ge(s,e.runtime.runtimeId):void 0;let a,l,c;const w=await ve({runtime:e.runtime,binding:{...e.binding,downloadMedia:t.downloadMedia??e.binding.downloadMedia},helper:e.helper,api:r,workDir:e.options.workDir,attachmentsDir:o,traceId:e.options.traceId,mediaAnchorText:e.options.downloadAnchorText,activityGuard:e.options.activityGuard,observePipeline:t.observePipeline,localLedgerTailAnchors:d?bt(d.bindings[e.binding.bindingId]):void 0,onObservationEvidence:({capture:u,ocr:b})=>{a=Ve(u),l=ze(b),c=Ge(u,b,{captureHash:a,ocrHash:l})}});let h,g;if(d&&s){const u=pe({ledger:d,bindingId:e.binding.bindingId,observedMessages:w});h=u.binding,g=se({bindingId:e.binding.bindingId,revision:h.revision,messages:u.newMessages}),we(s,d)}return{messages:w,attachmentsDir:o,observePipeline:t.observePipeline,...s?{ledgerPath:s}:{},...h?{ledgerBinding:h}:{},traceHashes:{...a?{captureHash:a}:{},...l?{ocrHash:l}:{},...g?{ingestPayloadHash:g}:{}},...c?{observationEvidence:c}:{}}}function Ge(e,t,n){return{capture:e,report:{screenshot:{width:e.width,height:e.height,mimeType:e.mimeType,...e.windowId?{windowId:e.windowId}:{}},hashes:n,ocrBlockCount:t.blocks?.length??0,visibleConversationFingerprintCount:t.visibleConversationFingerprints?.length??0,topTexts:(t.blocks??[]).slice(0,40).map(r=>({text:r.text,...r.bbox?{bbox:r.bbox}:{},...typeof r.confidence=="number"?{confidence:r.confidence}:{}}))}}}function O(e,t,n){if(!n)return;const r=n.capture.dataBase64?D(e,`${t}-observation-window`,n.capture):void 0;m(i.join(e,`${t}-observation-evidence.json`),{...n.report,...r?{screenshotPath:r}:{}})}function Ve(e){if(e.dataBase64)return`sha256:${M.createHash("sha256").update(Buffer.from(e.dataBase64,"base64")).digest("hex")}`}function ze(e){return se({blocks:(e.blocks??[]).map(t=>({text:t.text??"",bbox:t.bbox??null,confidence:typeof t.confidence=="number"?Number(t.confidence.toFixed(4)):null})),visibleConversationFingerprints:e.visibleConversationFingerprints??[]})}function Z(e,t){let n=t,r=0,o=0,s="";const d=[];return{actionLog:d,setScenario(l){n=l,r=0,o=0},async request(l,c,w){if(d.push(l),l==="activity.snapshot"){if(r+=1,r<=n.preflightBusySnapshots)return{id:`human-${r}`,ok:!0,result:{keyDownSecondsAgo:.2,mouseMovedSecondsAgo:.2,scrollWheelSecondsAgo:.2,privacy:{capturesKeyContent:!1,capturesMousePath:!1}},latencyMs:0,traceId:w};if(n.forceIdleAfterBusy)return{id:`human-${r}`,ok:!0,result:{keyDownSecondsAgo:60,mouseMovedSecondsAgo:60,leftMouseDownSecondsAgo:60,rightMouseDownSecondsAgo:60,scrollWheelSecondsAgo:60,privacy:{capturesKeyContent:!1,capturesMousePath:!1}},latencyMs:0,traceId:w}}if(l==="automation.lease.acquire"){const h=await e.request(l,c,w),g=h.result&&typeof h.result=="object"?h.result:{};return s=typeof g.leaseId=="string"?g.leaseId:"",h}return l==="automation.lease.status"?(o+=1,n.simulateInterruptionAtLeaseStatus===o?(d.push("automation.lease.simulateInterruption"),{id:`human-lease-${o}`,ok:!0,result:{active:!0,leaseId:s,interrupted:!0,interruptReason:n.interruptionReason||"recent_mouse_activity"},latencyMs:0,traceId:w}):{id:`human-lease-${o}`,ok:!0,result:{active:!0,leaseId:s,interrupted:!1},latencyMs:0,traceId:w}):e.request(l,c,w)}}}function Y(e){return e==="human-send-preflight-busy"||e==="human-send-preflight-busy-then-idle"||e==="human-send-user-active-timeout"||e==="human-observe-deferred"?{preflightBusySnapshots:100}:e==="human-send-takeover-during-run"||e==="human-send-takeover-then-idle"?{preflightBusySnapshots:0,forceIdleAfterBusy:!0,simulateInterruptionAtLeaseStatus:2,interruptionReason:"recent_mouse_activity"}:{preflightBusySnapshots:0,forceIdleAfterBusy:!0}}function Je(){return{preflightBusySnapshots:0,forceIdleAfterBusy:!0}}function Qe(e,t){return t.sendStatus!=="sent_unconfirmed"?!1:e==="human-send-normal"||e==="human-send-preflight-busy-then-idle"||e==="human-send-takeover-then-idle"}async function Xe(e){try{const t=await y(e.helper,e.traceId),n=await j(e.helper,t.windowId,e.traceId,t.bounds),r=D(e.outDir,e.filePrefix,n),o=await E(e.helper,n,e.traceId);m(i.join(e.outDir,`${e.filePrefix}-ocr.json`),{screenshotPath:r,ocr:o})}catch(t){m(i.join(e.outDir,`${e.filePrefix}-error.json`),{errorSummary:t instanceof Error?t.message:String(t||"after paste evidence failed")})}}async function F(e){const t=await y(e.helper,e.traceId),n=await I(e.helper,t,e.traceId);if(!(await x({helper:e.helper,window:n,binding:e.binding,runtime:e.runtime,api:e.api,workDir:e.workDir,traceId:e.traceId,settleToBottom:e.settleToBottom})).opened)return 0;const o=await j(e.helper,n.windowId,e.traceId),s=D(e.outDir,`${e.filePrefix}-observe-marker`,o),d=await E(e.helper,o,e.traceId);return m(i.join(e.outDir,`${e.filePrefix}-observe-marker-ocr.json`),{screenshotPath:s,marker:e.marker,ocr:d}),Ye(d.blocks||[],e.marker)}function Ze(e,t){const n=t.trim();if(!n)return 0;const r=e.map(d=>d.text||"").join(`
4
- `),o=te(r,n);if(o>0)return o;const s=ee(n);return s.length<8?0:te(ee(r),s)}function Ye(e,t){const n=e.filter(et);return Ze(n,t)}function et(e){const t=e.bbox;if(!t)return!0;const n=Number(t.x),r=Number(t.y),o=Number(t.width);return[n,r,o].every(Number.isFinite)?n+o/2>=560&&r>=100:!0}function ee(e){return e.normalize("NFKC").replace(/[\s\u200B-\u200D\uFEFF]+/g,"")}function te(e,t){if(!t)return 0;let n=0,r=0;for(;;){const o=e.indexOf(t,r);if(o<0)break;n+=1,r=o+t.length}return n}async function tt(e){const t=Math.max(1,e.attempts??3),n=typeof e.targetGreaterThan=="number"&&Number.isFinite(e.targetGreaterThan)?e.targetGreaterThan:null;let r=0;for(let o=0;o<t;o+=1){if(r=await F({helper:e.helper,runtime:e.runtime,binding:e.binding,api:e.api,workDir:e.workDir,marker:e.marker,traceId:e.traceId,outDir:e.outDir,filePrefix:`${e.filePrefix}-${o+1}`,settleToBottom:e.settleToBottom}),n==null?r>0:r>n)return r;o<t-1&&await q(800)}return r}function nt(e,t,n){return n.length>0||e.sendStatus==="confirmed_echo"?"confirmed_echo":t.waitingRecords.length>0?"send_waiting_user_idle":t.failedRecords.length>0?e.failureCode==="user_active_timeout"?"failed:user_active_timeout":"outbound_send_failed":t.manualReviewRecords.length>0||e.sendStatus==="manual_review"?"manual_review":e.sendStatus==="sent_unconfirmed"?"sent_unconfirmed":e.sendStatus}function rt(e,t){return e==="human-send-preflight-busy"?t.outboundStatus==="queued"&&t.observedMarkerCount===0&&!t.actionLog.includes("clipboard.setText")&&!t.actionLog.includes("keyboard.shortcut"):e==="human-send-user-active-timeout"?t.outboundStatus==="failed"&&t.runStatus==="failed:user_active_timeout"&&t.observedMarkerCount===0&&!t.actionLog.includes("clipboard.setText")&&!t.actionLog.includes("keyboard.shortcut"):e==="human-send-takeover-during-run"?(t.outboundStatus==="queued"||t.outboundStatus==="manual_review")&&t.observedMarkerCount===0:e==="human-send-preflight-busy-then-idle"||e==="human-send-takeover-then-idle"||e==="human-send-normal"?t.outboundStatus==="confirmed_echo"||t.outboundStatus==="sent_unconfirmed"&&t.observedMarkerCount===1:t.runStatus==="observe_deferred_user_active"}function ot(e){return ye({runtimeId:e.runtimeId,machineId:e.machineId,pollIntervalMs:6e4,platform:e.platform,foregroundPolicy:"work",bindings:[{bindingId:`action-smoke:${_(e.conversation)}`,sessionId:e.sessionId||`action-smoke:${_(e.runtimeId)}`,conversationDisplayName:e.conversation,enabled:!0,allowReply:!0,downloadMedia:!0}]})}function st(e,t){const n=ue({platform:e.platform});if(!n.ok)throw new Error(`${n.reasonCode}: ${n.message}`);return new he({helperPath:n.helperPath,expectedHelperVersion:n.version||me,requiredCapabilities:ct(e),guardUnsafeWindowsCommands:(e.platform??process.platform)==="win32",skipUserActivityGuard:!0,cleanupWindowsOverlays:(e.platform??process.platform)==="win32",requestLogger:at(t)})}function at(e){return t=>{p.appendFileSync(e,`${JSON.stringify(it(t))}
5
- `)}}function it(e){const t={phase:e.phase,at:e.at,id:e.id,command:e.command};return e.traceId&&(t.traceId=e.traceId),e.timeoutMs!=null&&(t.timeoutMs=e.timeoutMs),e.durationMs!=null&&(t.durationMs=e.durationMs),e.params!==void 0&&(t.params=$(e.params)),e.ok!==void 0&&(t.ok=e.ok),e.errorCode&&(t.errorCode=e.errorCode),e.errorSummary&&(t.errorSummary=e.errorSummary),e.latencyMs!=null&&(t.latencyMs=e.latencyMs),e.result!==void 0&&(t.result=$(e.result)),t}function $(e,t="",n=0){if(e==null||typeof e=="number"||typeof e=="boolean")return e;if(typeof e=="string")return dt(t,e)?{type:"string",length:e.length,sha256:M.createHash("sha256").update(e).digest("hex").slice(0,16),preview:e.slice(0,120)}:e;if(Array.isArray(e)){const s=e.slice(0,10).map(d=>$(d,t,n+1));return e.length>s.length?{type:"array",length:e.length,items:s}:s}if(typeof e!="object")return String(e);if(n>=5)return{type:"object",truncated:!0};const r=e,o={};for(const[s,d]of Object.entries(r))o[s]=$(d,s,n+1);return o}function dt(e,t){return t.length>240?!0:/(base64|bytes|data|image|screenshot|png|jpeg|jpg|buffer)/i.test(e)&&t.length>48}function ct(e){if((e.platform??process.platform)==="win32")return e.steps.some(t=>t.startsWith("send")||t.startsWith("human-send"))?B("send"):e.steps.some(t=>t==="download-visible-media")?B("download"):B("observe")}function lt(e){const t=String(e||"").trim().toLowerCase();if(t){if(t==="windows"||t==="win32")return"win32";if(t==="macos"||t==="darwin")return"darwin";throw new Error(`unsupported_wechat_smoke_platform:${e}`)}}function ut(e,t){const n=i.join(t.outDir,"fixtures");p.mkdirSync(n,{recursive:!0});const r=new Date().toISOString().replace(/[-:.TZ]/g,"").slice(0,14);if(e==="send-text")return{text:t.text||`codex-product-action text ${r}`};if(e==="send-file"){const o=t.filePath||i.join(n,`wechat-action-smoke-${r}.txt`);return t.filePath||p.writeFileSync(o,`Shennian WeChat product action smoke
3
+ `),o=n.filter(u=>r.includes(u)),s=e.sendResults.map(u=>typeof u.details?.sendStatus=="string"?u.details.sendStatus:"").filter(Boolean),d=e.sendResults.filter(Z).length,a=F(t,"waitingRecords"),l=F(t,"failedRecords"),c=F(t,"manualReviewRecords"),f=t.find(u=>!u.ok||u.skipped),h=s.length===n.length&&s.every(u=>u==="sent_unconfirmed"||u==="confirmed_echo"),g=!f&&n.length>0&&o.length>0&&h&&a===0&&l===0&&c===0;return{ok:g,reasonCode:g?void 0:f?.reasonCode||(a>0?"outbound_send_waiting":void 0)||(l>0?"outbound_send_failed":void 0)||(c>0?"outbound_manual_review":void 0)||(h?void 0:"outbound_status_not_accepted")||(o.length?"partial_sent_messages_observed":"sent_messages_not_observed"),sentTexts:n,confirmedTexts:o,outboundStatuses:s,skippedFixtureCount:d,pendingOutboundCount:a,failedOutboundCount:l,manualReviewCount:c}}function Z(e){return e.skipped===!0&&e.reasonCode==="ffmpeg_unavailable_for_video_fixture"}function F(e,t){return e.reduce((n,r)=>{const o=r.details?.[t];return n+(typeof o=="number"&&Number.isFinite(o)?o:0)},0)}async function Le(e){const t=["send-text"],n=[];for(const c of t)n.push(await X({...e,step:c}));await V(1200);const r=await W(e,3,{observePipeline:"edge-structure"}),o=T(r.messages),s=i.join(e.options.outDir,"bottom-page.md"),d=k(r.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(r.attachmentsDir)});m(i.join(e.options.outDir,"bottom-page-summary.json"),o),m(i.join(e.options.outDir,"server-observe-messages.json"),r.messages),R(s,d);const a=Fe({sendResults:n,observedMessages:r.messages}),l=a.ok&&r.messages.length>0;return{step:"send-and-confirm",ok:l,reasonCode:l?void 0:a.reasonCode,errorSummary:n.find(c=>!c.ok||c.skipped)?.errorSummary,details:{sent:n.map(c=>({step:c.step,ok:c.ok,skipped:c.skipped,reasonCode:c.reasonCode,errorSummary:c.errorSummary,text:c.details?.text,attachmentPath:c.details?.attachmentPath,sendStatus:c.details?.sendStatus,deferReason:c.details?.deferReason,failureCode:c.details?.failureCode,commitStage:c.details?.commitStage,attemptCount:c.details?.attemptCount,nextAttemptAt:c.details?.nextAttemptAt,waitingRecords:c.details?.waitingRecords,failedRecords:c.details?.failedRecords,manualReviewRecords:c.details?.manualReviewRecords})),sentTexts:a.sentTexts,confirmedTexts:a.confirmedTexts,outboundStatuses:a.outboundStatuses,skippedFixtureCount:a.skippedFixtureCount,pendingOutboundCount:a.pendingOutboundCount,failedOutboundCount:a.failedOutboundCount,manualReviewCount:a.manualReviewCount,observedCount:r.messages.length,byKind:o.byKind,attachmentSummary:o.attachmentSummary,attachmentsDir:r.attachmentsDir,reportPath:i.join(e.options.outDir,"bottom-page-summary.json"),markdownPath:s,markdown:d}}}async function W(e,t,n={}){let r;const o=[];for(let s=1;s<=t;s+=1)try{const d=await Y(e,n);return o.length&&(o.push({phase:"observe",attempt:s,ok:!0,observedCount:d.messages.length,at:new Date().toISOString()}),m(i.join(e.options.outDir,"observe-retry-events.json"),o)),d}catch(d){if(r=d,o.push({phase:"observe",attempt:s,ok:!1,errorSummary:d instanceof Error?d.message:String(d||""),at:new Date().toISOString()}),s>=t||!He(d))break;try{const a=await S(e.helper,e.options.traceId),l=await x(e.helper,a,e.options.traceId),c=await D({helper:e.helper,window:l,binding:e.binding,runtime:e.runtime,api:C({serverUrl:e.options.serverUrl}),workDir:e.options.workDir,traceId:e.options.traceId});o.push({phase:"recover",attempt:s,ok:c.opened,reason:c.reason,windowId:l.windowId,at:new Date().toISOString()})}catch(a){o.push({phase:"recover",attempt:s,ok:!1,errorSummary:a instanceof Error?a.message:String(a||""),at:new Date().toISOString()})}m(i.join(e.options.outDir,"observe-retry-events.json"),o),await J("observe-retry",`${e.options.traceId}:observe-retry:${s}`,1500*s)}throw o.length&&m(i.join(e.options.outDir,"observe-retry-events.json"),o),r}function He(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 Ue(e){const t=await W(e,3),n=T(t.messages),r=i.join(e.options.outDir,"bottom-page.md"),o=k(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});return m(i.join(e.options.outDir,"bottom-page-summary.json"),n),m(i.join(e.options.outDir,"server-observe-messages.json"),t.messages),R(r,o),{step:"read-bottom-page",ok:n.messageCount>0,reasonCode:n.messageCount>0?void 0:"no_observed_messages",details:{messageCount:n.messageCount,byKind:n.byKind,attachmentSummary:n.attachmentSummary,attachmentsDir:t.attachmentsDir,reportPath:i.join(e.options.outDir,"bottom-page-summary.json"),markdownPath:r,markdown:o}}}async function qe(e){const t=await W(e,3,{observePipeline:"edge-structure",persistLocalLedger:!0});L(e.options.outDir,"download-visible",t.observationEvidence);const n=T(t.messages),r=i.join(e.options.outDir,"download-visible.md"),o=k(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)}),s=G(t.messages,t.attachmentsDir,{observePipeline:t.observePipeline,downloadAnchorText:e.options.downloadAnchorText,ledgerPath:t.ledgerPath,ledgerBinding:t.ledgerBinding,traceHashes:t.traceHashes});m(i.join(e.options.outDir,"bottom-page-summary.json"),n),m(i.join(e.options.outDir,"download-visible-summary.json"),s),m(i.join(e.options.outDir,"download-visible-messages.json"),t.messages),R(r,o);const d=!!(e.options.allowEmptyMedia&&s.reasonCode==="no_visible_media_candidates"&&t.messages.length>0),a=s.ok||d;return{step:"download-visible-media",ok:a,reasonCode:a?void 0:s.reasonCode,details:{mediaCandidateCount:s.mediaCandidateCount,localAttachmentCount:s.localAttachmentCount,originalLocalAttachmentCount:s.originalLocalAttachmentCount,previewAttachmentCount:s.previewAttachmentCount,missingLocalPathCount:s.missingLocalPathCount,pendingAttachmentCount:s.pendingAttachmentCount,byKind:s.byKind,byAvailability:s.byAvailability,reasonCodes:s.reasonCodes,mediaReasonCode:s.reasonCode,allowEmptyMediaRead:d,attachmentsDir:t.attachmentsDir,reportPath:i.join(e.options.outDir,"download-visible-summary.json"),markdownPath:r,markdown:o,phases:s.phases,observePipeline:s.observePipeline,ledgerPath:s.ledgerPath,ledgerRevision:s.ledger?.revision,traceHashes:s.traceHashes,traceEvents:s.traceEvents}}}async function Ke(e){const t=await W(e,3,{observePipeline:"server-observe"});L(e.options.outDir,"server-observe",t.observationEvidence),m(i.join(e.options.outDir,"server-observe-messages.json"),t.messages);const n=i.join(e.options.outDir,"server-observe.md"),r=k(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});R(n,r);const o=oe(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:q(t.messages.map(s=>s.kind||"unknown")),attachmentSummary:o,attachmentsDir:t.attachmentsDir,markdownPath:n,markdown:r}}}async function Ve(e){const t=await Y(e,{observePipeline:"edge-structure",downloadMedia:!1});L(e.options.outDir,"structure-window",t.observationEvidence),m(i.join(e.options.outDir,"structure-window-messages.json"),t.messages);const n=i.join(e.options.outDir,"structure-window.md"),r=k(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});R(n,r);const o=oe(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:q(t.messages.map(s=>s.kind||"unknown")),attachmentSummary:o,attachmentsDir:t.attachmentsDir,markdownPath:n,markdown:r}}}async function Y(e,t={}){const n=ke({sessionId:e.options.sessionId,observePipeline:t.observePipeline}),r=C({serverUrl:e.options.serverUrl});e.options.skipRuntimeUpsert||(n==="direct-edge-structure"?await r.upsertRuntime(e.runtime):await r.upsertRuntime(e.runtime,{...e.binding,enabled:!1,allowReply:!1}));const o=i.join(e.options.outDir,"inbound-attachments");p.mkdirSync(o,{recursive:!0});const s=t.persistLocalLedger?pt(e.options):void 0,d=s?we(s,e.runtime.runtimeId):void 0;let a,l,c;const f=await ye({runtime:e.runtime,binding:{...e.binding,downloadMedia:t.downloadMedia??e.binding.downloadMedia},helper:e.helper,api:r,workDir:e.options.workDir,attachmentsDir:o,traceId:e.options.traceId,mediaAnchorText:e.options.downloadAnchorText,activityGuard:e.options.activityGuard,observePipeline:t.observePipeline,localLedgerTailAnchors:d?vt(d.bindings[e.binding.bindingId]):void 0,onObservationEvidence:({capture:u,ocr:w})=>{a=ze(u),l=Je(w),c=Ge(u,w,{captureHash:a,ocrHash:l})}});let h,g;if(d&&s){const u=pe({ledger:d,bindingId:e.binding.bindingId,observedMessages:f});h=u.binding,g=ie({bindingId:e.binding.bindingId,revision:h.revision,messages:u.newMessages}),be(s,d)}return{messages:f,attachmentsDir:o,observePipeline:t.observePipeline,...s?{ledgerPath:s}:{},...h?{ledgerBinding:h}:{},traceHashes:{...a?{captureHash:a}:{},...l?{ocrHash:l}:{},...g?{ingestPayloadHash:g}:{}},...c?{observationEvidence:c}:{}}}function Ge(e,t,n){return{capture:e,report:{screenshot:{width:e.width,height:e.height,mimeType:e.mimeType,...e.windowId?{windowId:e.windowId}:{}},hashes:n,ocrBlockCount:t.blocks?.length??0,visibleConversationFingerprintCount:t.visibleConversationFingerprints?.length??0,topTexts:(t.blocks??[]).slice(0,40).map(r=>({text:r.text,...r.bbox?{bbox:r.bbox}:{},...typeof r.confidence=="number"?{confidence:r.confidence}:{}}))}}}function L(e,t,n){if(!n)return;const r=n.capture.dataBase64?_(e,`${t}-observation-window`,n.capture):void 0;m(i.join(e,`${t}-observation-evidence.json`),{...n.report,...r?{screenshotPath:r}:{}})}function ze(e){if(e.dataBase64)return`sha256:${M.createHash("sha256").update(Buffer.from(e.dataBase64,"base64")).digest("hex")}`}function Je(e){return ie({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 ee(e,t){let n=t,r=0,o=0,s="";const d=[];return{actionLog:d,setScenario(l){n=l,r=0,o=0},async request(l,c,f){if(d.push(l),l==="activity.snapshot"){if(r+=1,r<=n.preflightBusySnapshots)return{id:`human-${r}`,ok:!0,result:{keyDownSecondsAgo:.2,mouseMovedSecondsAgo:.2,scrollWheelSecondsAgo:.2,privacy:{capturesKeyContent:!1,capturesMousePath:!1}},latencyMs:0,traceId:f};if(n.forceIdleAfterBusy)return{id:`human-${r}`,ok:!0,result:{keyDownSecondsAgo:60,mouseMovedSecondsAgo:60,leftMouseDownSecondsAgo:60,rightMouseDownSecondsAgo:60,scrollWheelSecondsAgo:60,privacy:{capturesKeyContent:!1,capturesMousePath:!1}},latencyMs:0,traceId:f}}if(l==="automation.lease.acquire"){const h=await e.request(l,c,f),g=h.result&&typeof h.result=="object"?h.result:{};return s=typeof g.leaseId=="string"?g.leaseId:"",h}return l==="automation.lease.status"?(o+=1,n.simulateInterruptionAtLeaseStatus===o?(d.push("automation.lease.simulateInterruption"),{id:`human-lease-${o}`,ok:!0,result:{active:!0,leaseId:s,interrupted:!0,interruptReason:n.interruptionReason||"recent_mouse_activity"},latencyMs:0,traceId:f}):{id:`human-lease-${o}`,ok:!0,result:{active:!0,leaseId:s,interrupted:!1},latencyMs:0,traceId:f}):e.request(l,c,f)}}}function te(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 Qe(){return{preflightBusySnapshots:0,forceIdleAfterBusy:!0}}function Xe(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 Ze(e){try{const t=await S(e.helper,e.traceId),n=await j(e.helper,t.windowId,e.traceId,t.bounds),r=_(e.outDir,e.filePrefix,n),o=await E(e.helper,n,e.traceId);m(i.join(e.outDir,`${e.filePrefix}-ocr.json`),{screenshotPath:r,ocr:o})}catch(t){m(i.join(e.outDir,`${e.filePrefix}-error.json`),{errorSummary:t instanceof Error?t.message:String(t||"after paste evidence failed")})}}async function H(e){const t=await S(e.helper,e.traceId),n=await x(e.helper,t,e.traceId);if(!(await D({helper:e.helper,window:n,binding:e.binding,runtime:e.runtime,api:e.api,workDir:e.workDir,traceId:e.traceId,settleToBottom:e.settleToBottom})).opened)return 0;const o=await j(e.helper,n.windowId,e.traceId),s=_(e.outDir,`${e.filePrefix}-observe-marker`,o),d=await E(e.helper,o,e.traceId);return m(i.join(e.outDir,`${e.filePrefix}-observe-marker-ocr.json`),{screenshotPath:s,marker:e.marker,ocr:d}),et(d.blocks||[],e.marker)}function Ye(e,t){const n=t.trim();if(!n)return 0;const r=e.map(d=>d.text||"").join(`
4
+ `),o=re(r,n);if(o>0)return o;const s=ne(n);return s.length<8?0:re(ne(r),s)}function et(e,t){const n=e.filter(tt);return Ye(n,t)}function tt(e){const t=e.bbox;if(!t)return!0;const n=Number(t.x),r=Number(t.y),o=Number(t.width);return[n,r,o].every(Number.isFinite)?n+o/2>=560&&r>=100:!0}function ne(e){return e.normalize("NFKC").replace(/[\s\u200B-\u200D\uFEFF]+/g,"")}function re(e,t){if(!t)return 0;let n=0,r=0;for(;;){const o=e.indexOf(t,r);if(o<0)break;n+=1,r=o+t.length}return n}async function nt(e){const t=Math.max(1,e.attempts??3),n=typeof e.targetGreaterThan=="number"&&Number.isFinite(e.targetGreaterThan)?e.targetGreaterThan:null;let r=0;for(let o=0;o<t;o+=1){if(r=await H({helper:e.helper,runtime:e.runtime,binding:e.binding,api:e.api,workDir:e.workDir,marker:e.marker,traceId:e.traceId,outDir:e.outDir,filePrefix:`${e.filePrefix}-${o+1}`,settleToBottom:e.settleToBottom}),n==null?r>0:r>n)return r;o<t-1&&await V(800)}return r}function rt(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 ot(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 st(e){return Se({runtimeId:e.runtimeId,machineId:e.machineId,pollIntervalMs:6e4,platform:e.platform,foregroundPolicy:"work",bindings:[{bindingId:`action-smoke:${P(e.conversation)}`,sessionId:e.sessionId||`action-smoke:${P(e.runtimeId)}`,conversationDisplayName:e.conversation,enabled:!0,allowReply:!0,downloadMedia:!0}]})}function at(e,t){const n=me({platform:e.platform});if(!n.ok)throw new Error(`${n.reasonCode}: ${n.message}`);return new fe({helperPath:n.helperPath,expectedHelperVersion:n.version||he,requiredCapabilities:lt(e),guardUnsafeWindowsCommands:(e.platform??process.platform)==="win32",skipUserActivityGuard:!0,cleanupWindowsOverlays:(e.platform??process.platform)==="win32",requestLogger:it(t)})}function it(e){return t=>{p.appendFileSync(e,`${JSON.stringify(dt(t))}
5
+ `)}}function dt(e){const t={phase:e.phase,at:e.at,id:e.id,command:e.command};return e.traceId&&(t.traceId=e.traceId),e.timeoutMs!=null&&(t.timeoutMs=e.timeoutMs),e.durationMs!=null&&(t.durationMs=e.durationMs),e.params!==void 0&&(t.params=$(e.params)),e.ok!==void 0&&(t.ok=e.ok),e.errorCode&&(t.errorCode=e.errorCode),e.errorSummary&&(t.errorSummary=e.errorSummary),e.latencyMs!=null&&(t.latencyMs=e.latencyMs),e.result!==void 0&&(t.result=$(e.result)),t}function $(e,t="",n=0){if(e==null||typeof e=="number"||typeof e=="boolean")return e;if(typeof e=="string")return ct(t,e)?{type:"string",length:e.length,sha256:M.createHash("sha256").update(e).digest("hex").slice(0,16),preview:e.slice(0,120)}:e;if(Array.isArray(e)){const s=e.slice(0,10).map(d=>$(d,t,n+1));return e.length>s.length?{type:"array",length:e.length,items:s}:s}if(typeof e!="object")return String(e);if(n>=5)return{type:"object",truncated:!0};const r=e,o={};for(const[s,d]of Object.entries(r))o[s]=$(d,s,n+1);return o}function ct(e,t){return t.length>240?!0:/(base64|bytes|data|image|screenshot|png|jpeg|jpg|buffer)/i.test(e)&&t.length>48}function lt(e){if((e.platform??process.platform)==="win32")return e.steps.some(t=>t.startsWith("send")||t.startsWith("human-send"))?O("send"):e.steps.some(t=>t==="download-visible-media")?O("download"):O("observe")}function ut(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 mt(e,t){const n=i.join(t.outDir,"fixtures");p.mkdirSync(n,{recursive:!0});const r=new Date().toISOString().replace(/[-:.TZ]/g,"").slice(0,14);if(e==="send-text")return{text:t.text||`codex-product-action text ${r}`};if(e==="send-file"){const o=t.filePath||i.join(n,`wechat-action-smoke-${r}.txt`);return t.filePath||p.writeFileSync(o,`Shennian WeChat product action smoke
6
6
  ${r}
7
- `,"utf8"),{text:`codex-product-action file ${r}`,attachmentPath:o}}if(e==="send-image"){const o=t.imagePath||i.join(n,`wechat-action-smoke-${r}.png`);return t.imagePath||vt(o),{text:`codex-product-action image ${r}`,attachmentPath:o}}if(e==="send-video"){const o=t.videoPath||i.join(n,`wechat-action-smoke-${r}.mp4`);return!t.videoPath&&!yt(o)?{skipped:!0,reasonCode:"ffmpeg_unavailable_for_video_fixture"}:{text:`codex-product-action video ${r}`,attachmentPath:o}}throw new Error(`step ${e} is not a send step`)}function ne(e){const t=e.flatMap(n=>mt(n.mediaMetadata));return{count:t.length,byAvailability:H(t.map(n=>re(n,"availability")||"unknown")),localPaths:t.map(n=>re(n,"localPath")).filter(n=>!!n)}}function mt(e){if(!e||typeof e!="object")return[];const t=e;return Array.isArray(t.attachments)?t.attachments.filter(oe):oe(t.attachment)?[t.attachment]:t.localPath||t.url||t.availability||t.name||t.fileName?[t]:[]}function ht(e){const t=f(e,"--mode")||(e[0]?.startsWith("--")?"":e[0]);return t==="send"||t==="observe"||t==="all"||t==="open-read"?t:"open-read"}function ft(e){return e==="open-read"||e==="send-text"||e==="send-file"||e==="send-image"||e==="send-video"||e==="structure-window"||e==="server-observe"||e==="read-bottom-page"||e==="download-visible-media"||e==="send-and-confirm"||e==="human-send-preflight-busy"||e==="human-send-preflight-busy-then-idle"||e==="human-send-user-active-timeout"||e==="human-send-takeover-during-run"||e==="human-send-takeover-then-idle"||e==="human-send-normal"||e==="human-observe-deferred"?e:null}function gt(e,t){const n=[];for(let r=0;r<e.length;r+=1)e[r]===t&&e[r+1]&&n.push(e[r+1]);return n}function f(e,t){const n=e.indexOf(t),r=n>=0?e[n+1]:void 0;return r&&!r.startsWith("--")?r:void 0}function L(e){return e?i.resolve(e):void 0}function wt(e){return Array.from(new Set(e))}function D(e,t,n){const r=n.mimeType.includes("jpeg")?".jpg":".png",o=i.join(e,`${t}${r}`);return p.writeFileSync(o,Buffer.from(n.dataBase64,"base64")),o}function m(e,t){p.mkdirSync(i.dirname(e),{recursive:!0}),p.writeFileSync(e,`${JSON.stringify(t,null,2)}
8
- `,"utf8")}function A(e,t){p.mkdirSync(i.dirname(e),{recursive:!0}),p.writeFileSync(e,t,"utf8")}function pt(e){return i.join(e.outDir,"wechat-channel-ledger.json")}function bt(e,t=3){return(e?.recent??[]).slice(-t).map(n=>({stableMessageKey:n.stableMessageKey,senderRole:n.senderRole,kind:n.kind,anchorText:n.anchorText??n.normalizedText??n.textExcerpt??null,anchorMetadata:n.anchorMetadata??null}))}function vt(e){p.writeFileSync(e,Buffer.from("iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAAVElEQVR4nO3PMQ0AMAgAMUTof2kOKWzo8mCqkmeX9waYtwOwG4DbANwG4DYAtwG4DcBtAG4DcBuA2wDcBuA2ALcBuA3AbQBuA3AbgNsA3AbgNgC3AbgNwG0AbgNwG8BPDyCqAzmh3yHRAAAAAElFTkSuQmCC","base64"))}function yt(e){return de("ffmpeg",["-y","-f","lavfi","-i","testsrc=size=160x120:rate=5","-t","1","-pix_fmt","yuv420p",e],{encoding:"utf8",stdio:"ignore",timeout:2e4}).status===0&&p.existsSync(e)}function H(e){const t={};for(const n of e)t[n]=(t[n]??0)+1;return t}function re(e,t){return typeof e[t]=="string"?e[t].trim():""}function oe(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function _(e){return M.createHash("sha256").update(e).digest("hex").slice(0,16)}function se(e){return`sha256:${M.createHash("sha256").update(St(e)).digest("hex")}`}function St(e){return JSON.stringify(U(e))}function U(e){if(Array.isArray(e))return e.map(U);if(!e||typeof e!="object")return e;const t=e;return Object.fromEntries(Object.keys(t).sort().map(n=>[n,U(t[n])]))}function kt(e){const t=e instanceof Error?e.message:String(e),n=t.split(":",1)[0]?.trim();return n&&/^[a-z0-9_/-]+$/i.test(n)?n.replace(/\//g,"_"):/permission|accessibility|screen|automation/i.test(t)?"permission_missing":/wechat.*window|window.*unavailable/i.test(t)?"wechat_window_unavailable":/observe|VLM|server|api/i.test(t)?"server_observe_failed":"action_smoke_failed"}function Ct(e){if(e==="wechat_duplicate_instance")return"\u8BF7\u5173\u95ED\u91CD\u590D\u767B\u5F55\u3001\u5DF2\u767B\u5F55\u63D0\u793A\u6216\u7B2C\u4E8C\u4E2A\u5FAE\u4FE1\u4E3B\u7A97\u53E3\uFF0C\u53EA\u4FDD\u7559\u4E00\u4E2A\u5DF2\u767B\u5F55\u7684 Windows \u5FAE\u4FE1\u4E3B\u7A97\u53E3\u540E\u91CD\u8BD5\u3002"}function q(e){return new Promise(t=>setTimeout(t,e))}function It(e){process.stdout.write(`${JSON.stringify({ok:e.ok,conversation:e.conversation,outDir:e.outDir,durationMs:e.durationMs,steps:e.steps.map(t=>({step:t.step,ok:t.ok,skipped:t.skipped,reasonCode:t.reasonCode,userAction:t.userAction,details:t.details,errorSummary:t.errorSummary}))},null,2)}
9
- `)}async function xt(){const e=Ie(process.argv.slice(2)),t=await De(e);It(t),(!t.ok||e.requireServer&&t.steps.some(n=>n.step==="server-observe"&&!n.ok))&&process.exit(1)}process.argv[1]&&i.resolve(process.argv[1])===ce(import.meta.url)&&xt().catch(e=>{process.stderr.write(`${e instanceof Error?e.stack||e.message:String(e)}
10
- `),process.exit(1)});export{T as buildBottomPageReport,K as buildDownloadVisibleMediaReport,Oe as buildSendAndConfirmEvidence,$e as buildSendStepAcceptance,Ye as countMarkerOccurrencesInChatContentBlocks,Ze as countMarkerOccurrencesInOcrBlocks,Ne as nextSmokeDrainWaitMs,Ie as parseWeChatChannelActionSmokeArgs,Se as resolveWeChatSmokeObserveSessionMode,De as runWeChatChannelActionSmoke,xe as stepsForMode};
7
+ `,"utf8"),{text:t.text||"",attachmentPath:o}}if(e==="send-image"){const o=t.imagePath||i.join(n,`wechat-action-smoke-${r}.png`);return t.imagePath||yt(o),{text:t.text||"",attachmentPath:o}}if(e==="send-video"){const o=t.videoPath||i.join(n,`wechat-action-smoke-${r}.mp4`);return!t.videoPath&&!St(o)?{skipped:!0,reasonCode:"ffmpeg_unavailable_for_video_fixture"}:{text:t.text||"",attachmentPath:o}}throw new Error(`step ${e} is not a send step`)}function oe(e){const t=e.flatMap(n=>ht(n.mediaMetadata));return{count:t.length,byAvailability:q(t.map(n=>se(n,"availability")||"unknown")),localPaths:t.map(n=>se(n,"localPath")).filter(n=>!!n)}}function ht(e){if(!e||typeof e!="object")return[];const t=e;return Array.isArray(t.attachments)?t.attachments.filter(ae):ae(t.attachment)?[t.attachment]:t.localPath||t.url||t.availability||t.name||t.fileName?[t]:[]}function ft(e){const t=b(e,"--mode")||(e[0]?.startsWith("--")?"":e[0]);return t==="send"||t==="observe"||t==="all"||t==="open-read"?t:"open-read"}function gt(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 wt(e,t){const n=[];for(let r=0;r<e.length;r+=1)e[r]===t&&e[r+1]&&n.push(e[r+1]);return n}function b(e,t){const n=e.indexOf(t),r=n>=0?e[n+1]:void 0;return r&&!r.startsWith("--")?r:void 0}function A(e,t){const n=b(e,`${t}-base64`);return n!==void 0?Buffer.from(n,"base64").toString("utf8"):b(e,t)}function U(e){return e?i.resolve(e):void 0}function bt(e){return Array.from(new Set(e))}function _(e,t,n){const r=n.mimeType.includes("jpeg")?".jpg":".png",o=i.join(e,`${t}${r}`);return p.writeFileSync(o,Buffer.from(n.dataBase64,"base64")),o}function m(e,t){p.mkdirSync(i.dirname(e),{recursive:!0}),p.writeFileSync(e,`${JSON.stringify(t,null,2)}
8
+ `,"utf8")}function R(e,t){p.mkdirSync(i.dirname(e),{recursive:!0}),p.writeFileSync(e,t,"utf8")}function pt(e){return i.join(e.outDir,"wechat-channel-ledger.json")}function vt(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 yt(e){p.writeFileSync(e,Buffer.from("iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAAVElEQVR4nO3PMQ0AMAgAMUTof2kOKWzo8mCqkmeX9waYtwOwG4DbANwG4DYAtwG4DcBtAG4DcBuA2wDcBuA2ALcBuA3AbQBuA3AbgNsA3AbgNgC3AbgNwG0AbgNwG8BPDyCqAzmh3yHRAAAAAElFTkSuQmCC","base64"))}function St(e){return ce("ffmpeg",["-y","-f","lavfi","-i","testsrc=size=160x120:rate=5","-t","1","-pix_fmt","yuv420p",e],{encoding:"utf8",stdio:"ignore",timeout:2e4}).status===0&&p.existsSync(e)}function q(e){const t={};for(const n of e)t[n]=(t[n]??0)+1;return t}function se(e,t){return typeof e[t]=="string"?e[t].trim():""}function ae(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function P(e){return M.createHash("sha256").update(e).digest("hex").slice(0,16)}function ie(e){return`sha256:${M.createHash("sha256").update(kt(e)).digest("hex")}`}function kt(e){return JSON.stringify(K(e))}function K(e){if(Array.isArray(e))return e.map(K);if(!e||typeof e!="object")return e;const t=e;return Object.fromEntries(Object.keys(t).sort().map(n=>[n,K(t[n])]))}function Ct(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 It(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 V(e){return new Promise(t=>setTimeout(t,e))}function xt(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 Dt(){const e=xe(process.argv.slice(2)),t=await Ae(e);xt(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])===le(import.meta.url)&&Dt().catch(e=>{process.stderr.write(`${e instanceof Error?e.stack||e.message:String(e)}
10
+ `),process.exit(1)});export{T as buildBottomPageReport,G as buildDownloadVisibleMediaReport,Fe as buildSendAndConfirmEvidence,Be as buildSendStepAcceptance,et as countMarkerOccurrencesInChatContentBlocks,Ye as countMarkerOccurrencesInOcrBlocks,Oe as nextSmokeDrainWaitMs,xe as parseWeChatChannelActionSmokeArgs,ke as resolveWeChatSmokeObserveSessionMode,Ae as runWeChatChannelActionSmoke,De as stepsForMode};
package/dist/src/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{Command as M}from"commander";import u from"chalk";import G from"node:os";import R from"node:fs";import{loadConfig as I,saveConfig as J,getConfigPath as j,getShennianDir as H,resolveShennianPath as N}from"./config/index.js";import{CliRelayClient as K}from"./relay/client.js";import{registerPairCommand as B,runSmartStart as W}from"./commands/pair.js";import{clearDaemonPidIfOwner as O,createDaemonInstanceId as Y,clearDaemonLauncher as T,findRunningDaemonProcessIds as q,isRemoteAccessDisabled as z,registerDaemonCommand as Q,writeDaemonPid as _,writeDaemonLauncher as P}from"./commands/daemon.js";import{registerAgentCommand as X}from"./commands/agent.js";import{registerManagerCommand as Z}from"./commands/manager.js";import{registerExternalCommand as ee}from"./commands/external.js";import{registerWeChatCommand as ne}from"./commands/wechat.js";import{registerRuntimeCommand as te}from"./commands/runtime.js";import{registerUpgradeCommand as oe}from"./commands/upgrade.js";import{registerToolsCommand as re}from"./commands/tools.js";import{SessionManager as se}from"./session/manager.js";import{SERVERS as k,regionToUrl as ae,urlToRegion as ie}from"./region.js";import{getCurrentVersion as L,handleStartupCrashCheck as ce,checkForUpdate as le,isUpgradeVersionInCooldown as me,recordUpgradeFailure as pe}from"./upgrade/engine.js";import{detectAgents as de}from"./agents/detect.js";import{augmentProcessPath as b}from"./env-path.js";b();const x=L(),ge=3e4,ue=5*6e4;import{getCachedAgentInfos as fe,resolveAgentInfos as he}from"./agents/model-registry.js";import{initCliLogReporter as ve,reportLog as v}from"./log-reporter.js";import{isNativeFusionEnabled as Se}from"./native-fusion/config.js";import{NativeSessionFusionService as we}from"./native-fusion/service.js";import{startDaemonLogRetention as Ie}from"./daemon-log.js";const ye=H(),De=N("daemon.pid");function $e(){try{const n=R.readFileSync(De,"utf-8").trim();if(n.startsWith("{")){const o=JSON.parse(n),r=Number(o.pid);return Number.isInteger(r)&&r>0?r:null}const t=parseInt(n,10);return Number.isInteger(t)&&t>0?t:null}catch{return null}}function Re(n){return n.replace(/^https:\/\//,"wss://").replace(/^http:\/\//,"ws://")}function ke(n){const t=[`trigger=${n.trigger??"unknown"}`,`phase=${n.phase}`,`code=${n.code??"unknown"}`,`attempt=${n.reconnectAttempt}`];return n.reason&&t.push(`reason=${n.reason}`),n.error&&t.push(`error=${n.error}`),t.join(" ")}async function F(n,t=5e3){const o=Date.now();for(;Date.now()-o<t;){try{process.kill(n,0)}catch{return!0}await new Promise(r=>setTimeout(r,100))}try{return process.kill(n,0),!1}catch{return!0}}const a=new M;a.name("shennian").description("Shennian \u2014 AI Agent Control Plane").version(x),a.option("--api <url>","Server URL override").option("--name <name>","Machine name",G.hostname()).action(async n=>{const t=I(),o=n.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??t.serverUrl??void 0;await W(o,n.name)}),a.command("run-service",{hidden:!0}).description("(internal) Connect to relay server, called by the background service").option("--api <url>","Server URL override").action(async n=>{const t=N("env.json");try{const e=JSON.parse(R.readFileSync(t,"utf-8"));for(const[g,m]of Object.entries(e))process.env[g]||(process.env[g]=m);b()}catch{}const o=Ie();z()&&(console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`),clearInterval(o),process.exit(0));const r=!!(process.env.INVOCATION_ID||process.env.JOURNAL_STREAM||process.env.SHENNIAN_DESKTOP_SERVER_URL),f=async(e,g)=>{console.log(`[${new Date().toISOString()}] ${g} (PID ${e})`),process.kill(e,"SIGTERM"),await F(e)||(process.kill(e,"SIGKILL"),await F(e,2e3))};try{const e=$e();if(e&&e!==process.pid)try{process.kill(e,0),r?await f(e,"managed start taking over from existing daemon"):(console.log(`[${new Date().toISOString()}] daemon already running (PID ${e}), skipping duplicate start`),process.exit(0))}catch{}}catch{}const p=q(process.pid);if(p.length>0)if(r)for(const e of p)try{await f(e,"managed start taking over from orphan daemon")}catch{}else console.log(`[${new Date().toISOString()}] daemon already running (PID ${p[0]}), skipping duplicate start`),process.exit(0);const i=Y();_(process.pid,i,{version:x}),P(process.pid,void 0,i),process.on("exit",()=>{O(process.pid,i),T(i)}),await ce()&&(console.log(`[${new Date().toISOString()}] Rolled back to previous version, restarting...`),process.exit(0));const s=I();s.machineToken||(console.error(u.red("\u2717 Not paired yet. Run: shennian")),process.exit(1));const c=n.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??s.serverUrl??k.cn.url,S=`${Re(c)}/relay/machine`,d=L(),D=de(),h=D.map(e=>e.type),$=fe(D);s.machineId&&ve(c,s.machineId),console.log(`[${new Date().toISOString()}] Connecting to ${S}... (v${d}) agents: ${h.join(",")}`),v({level:"info",wsEvent:"daemon.start",metadata:{version:d,agents:h}});let w=null;const l=new K({serverUrl:S,machineToken:s.machineToken,cliVersion:d,agentList:h,onConnected:()=>{console.log(`[${new Date().toISOString()}] \u2713 Connected`),v({level:"info",wsEvent:"daemon.connected"}),$.some(e=>e.models.length>0)&&l.sendEvent({type:"event",event:"machine.agents",payload:{agentList:h,agents:$}}),he(D,{serverUrl:s.serverUrl??c,authToken:s.machineToken??s.accessToken}).then(e=>{JSON.stringify(e)!==JSON.stringify($)&&l.sendEvent({type:"event",event:"machine.agents",payload:{agentList:h,agents:e}})}).catch(()=>{}),import("./upgrade/engine.js").then(({readUpgradeAttempt:e,clearUpgradeAttempt:g})=>{const m=e();g(),m&&(console.log(`[${new Date().toISOString()}] [upgrade] Reporting success: ${m.from} \u2192 ${m.to}`),l.sendEvent({type:"event",event:"upgrade",payload:{state:"success",machineId:"self",from:m.from,to:m.to}}))}).catch(()=>{}),Ee(l,s.autoUpgrade??"patch",d),w?.handleConnected()},onDisconnected:e=>{console.log(`[${new Date().toISOString()}] \u26A0 Disconnected, reconnecting... ${ke(e)}`),v({level:"warn",wsEvent:"daemon.disconnected",metadata:{code:e.code,reason:e.reason,error:e.error,phase:e.phase,trigger:e.trigger,reconnectAttempt:e.reconnectAttempt}})},onReq:e=>{console.log(`[${new Date().toISOString()}] [req] ${e.method}`),v({level:"info",type:"ws",wsEvent:e.method,wsDirection:"in",traceId:e.traceId}),C.handleReq(e)}});w=Se()?new we(l):null;const C=new se(l,w,d);R.mkdirSync(ye,{recursive:!0}),_(process.pid,i,{version:d}),P(process.pid,void 0,i),l.connect(),process.stdin.resume();let U=!1;const A=async()=>{if(!U){U=!0,console.log(u.gray(`
2
- Disconnecting...`)),v({level:"info",wsEvent:"daemon.stop"}),clearInterval(o);try{await C.cleanup(),w?.stop(),l.disconnect(),O(process.pid,i),T(i)}finally{process.exit(0)}}};process.on("SIGINT",()=>{A()}),process.on("SIGTERM",()=>{A()})});const V=a.command("config").description("View or modify configuration");V.command("show",{isDefault:!0}).description("Show current configuration").action(()=>{console.log(`Config file: ${j()}`);const t={...I()};if(t.machineToken&&(t.machineToken=t.machineToken.slice(0,12)+"..."),t.serverUrl){const o=ie(t.serverUrl);console.log(`Region: ${o} (${k[o].label})`)}console.log(JSON.stringify(t,null,2))}),V.command("set").description("Update a config value").argument("<key>",'Config key (e.g. "server")').argument("<value>",'Config value (e.g. "cn" or "global")').action((n,t)=>{const o=I();if(n==="server"){t!=="cn"&&t!=="global"&&(console.error(u.red('\u2717 Value must be "cn" or "global"')),process.exit(1));const r=t;o.serverUrl=ae(r),J(o),console.log(u.green(`\u2713 Server set to ${k[r].label}`)),console.log(u.yellow(" Restart the background service for this to take effect: shennian stop && shennian start"));return}console.error(u.red(`\u2717 Unknown config key: ${n}. Supported: server`)),process.exit(1)}),B(a),Q(a),X(a),Z(a),ee(a),ne(a),te(a),oe(a),re(a),a.parse();async function Ee(n,t,o){if(t==="none")return;let r=!1;const f=async()=>{if(r)return;let p;try{p=await le(o)}catch{return}if(!p.hasUpdate)return;const{changeType:i,current:E,latest:s}=p;if(!(t==="patch"&&i!=="patch")&&!(t==="minor"&&i==="major")&&!me(s)){console.log(`[${new Date().toISOString()}] [upgrade] ${E} \u2192 ${s} (${i}), auto-upgrading...`),r=!0;try{const{handleUpgradeStart:c}=await import("./commands/upgrade.js");await c(n,"auto-upgrade",s,{currentVersion:o})}catch(c){const y=c instanceof Error?c.message:String(c),S=pe(s,y);console.log(`[${new Date().toISOString()}] [upgrade] ${s} failed, retry after ${new Date(S.nextRetryAt).toISOString()}: ${y}`)}finally{r=!1}}};setTimeout(()=>{f()},ge),setInterval(()=>{f()},ue)}
1
+ import{Command as M}from"commander";import u from"chalk";import G from"node:os";import R from"node:fs";import{loadConfig as I,saveConfig as J,getConfigPath as j,getShennianDir as H,resolveShennianPath as N}from"./config/index.js";import{CliRelayClient as K}from"./relay/client.js";import{registerPairCommand as B,runSmartStart as W}from"./commands/pair.js";import{clearDaemonPidIfOwner as O,createDaemonInstanceId as Y,clearDaemonLauncher as T,findRunningDaemonProcessIds as q,isRemoteAccessDisabled as z,registerDaemonCommand as Q,writeDaemonPid as _,writeDaemonLauncher as P}from"./commands/daemon.js";import{registerAgentCommand as X}from"./commands/agent.js";import{registerManagerCommand as Z}from"./commands/manager.js";import{registerExternalCommand as ee}from"./commands/external.js";import{registerWeChatCommand as ne}from"./commands/wechat.js";import{registerRuntimeCommand as te}from"./commands/runtime.js";import{registerUpgradeCommand as oe}from"./commands/upgrade.js";import{registerToolsCommand as re}from"./commands/tools.js";import{SessionManager as se}from"./session/manager.js";import{SERVERS as k,regionToUrl as ae,urlToRegion as ie}from"./region.js";import{getCurrentVersion as L,handleStartupCrashCheck as ce,checkForUpdate as le,isUpgradeVersionInCooldown as me,recordUpgradeFailure as de}from"./upgrade/engine.js";import{detectAgents as pe}from"./agents/detect.js";import{augmentProcessPath as b}from"./env-path.js";b();const x=L(),ge=3e4,ue=5*6e4;import{getCachedAgentInfos as fe,resolveAgentInfos as he}from"./agents/model-registry.js";import{initCliLogReporter as ve,reportLog as v}from"./log-reporter.js";import{isNativeFusionEnabled as Se}from"./native-fusion/config.js";import{NativeSessionFusionService as we}from"./native-fusion/service.js";import{startDaemonLogRetention as Ie}from"./daemon-log.js";const ye=H(),De=N("daemon.pid");function $e(){try{const n=R.readFileSync(De,"utf-8").trim();if(n.startsWith("{")){const o=JSON.parse(n),r=Number(o.pid);return Number.isInteger(r)&&r>0?r:null}const t=parseInt(n,10);return Number.isInteger(t)&&t>0?t:null}catch{return null}}function Re(n){return n.replace(/^https:\/\//,"wss://").replace(/^http:\/\//,"ws://")}function ke(n){const t=[`trigger=${n.trigger??"unknown"}`,`phase=${n.phase}`,`code=${n.code??"unknown"}`,`attempt=${n.reconnectAttempt}`];return n.reason&&t.push(`reason=${n.reason}`),n.error&&t.push(`error=${n.error}`),t.join(" ")}async function F(n,t=5e3){const o=Date.now();for(;Date.now()-o<t;){try{process.kill(n,0)}catch{return!0}await new Promise(r=>setTimeout(r,100))}try{return process.kill(n,0),!1}catch{return!0}}const a=new M;a.name("shennian").description("Shennian \u2014 AI Agent Control Plane").version(x),a.option("--api <url>","Server URL override").option("--name <name>","Machine name",G.hostname()).action(async n=>{const t=I(),o=n.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??t.serverUrl??void 0;await W(o,n.name)}),a.command("run-service",{hidden:!0}).description("(internal) Connect to relay server, called by the background service").option("--api <url>","Server URL override").action(async n=>{const t=N("env.json");try{const e=JSON.parse(R.readFileSync(t,"utf-8"));for(const[g,m]of Object.entries(e))process.env[g]||(process.env[g]=m);b()}catch{}const o=Ie();z()&&(console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`),clearInterval(o),process.exit(0));const r=!!(process.env.INVOCATION_ID||process.env.JOURNAL_STREAM||process.env.SHENNIAN_DESKTOP_SERVER_URL),f=async(e,g)=>{console.log(`[${new Date().toISOString()}] ${g} (PID ${e})`),process.kill(e,"SIGTERM"),await F(e)||(process.kill(e,"SIGKILL"),await F(e,2e3))};try{const e=$e();if(e&&e!==process.pid)try{process.kill(e,0),r?await f(e,"managed start taking over from existing daemon"):(console.log(`[${new Date().toISOString()}] daemon already running (PID ${e}), skipping duplicate start`),process.exit(0))}catch{}}catch{}const d=q(process.pid);if(d.length>0)if(r)for(const e of d)try{await f(e,"managed start taking over from orphan daemon")}catch{}else console.log(`[${new Date().toISOString()}] daemon already running (PID ${d[0]}), skipping duplicate start`),process.exit(0);const i=Y();_(process.pid,i,{version:x}),P(process.pid,void 0,i),process.on("exit",()=>{O(process.pid,i),T(i)}),await ce()&&(console.log(`[${new Date().toISOString()}] Rolled back to previous version, restarting...`),process.exit(0));const s=I();s.machineToken||(console.error(u.red("\u2717 Not paired yet. Run: shennian")),process.exit(1));const c=n.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??s.serverUrl??k.cn.url,S=`${Re(c)}/relay/machine`,p=L(),D=pe(),h=D.map(e=>e.type),$=fe(D);s.machineId&&ve(c,s.machineId),console.log(`[${new Date().toISOString()}] Connecting to ${S}... (v${p}) agents: ${h.join(",")}`),v({level:"info",wsEvent:"daemon.start",metadata:{version:p,agents:h}});let w=null;const l=new K({serverUrl:S,machineToken:s.machineToken,cliVersion:p,agentList:h,onConnected:()=>{console.log(`[${new Date().toISOString()}] \u2713 Connected`),v({level:"info",wsEvent:"daemon.connected"}),$.some(e=>e.models.length>0)&&l.sendEvent({type:"event",event:"machine.agents",payload:{agentList:h,agents:$}}),he(D,{serverUrl:s.serverUrl??c,authToken:s.machineToken??s.accessToken}).then(e=>{JSON.stringify(e)!==JSON.stringify($)&&l.sendEvent({type:"event",event:"machine.agents",payload:{agentList:h,agents:e}})}).catch(()=>{}),import("./upgrade/engine.js").then(({readUpgradeAttempt:e,clearUpgradeAttempt:g})=>{const m=e();g(),m&&(console.log(`[${new Date().toISOString()}] [upgrade] Reporting success: ${m.from} \u2192 ${m.to}`),l.sendEvent({type:"event",event:"upgrade",payload:{state:"success",machineId:"self",from:m.from,to:m.to}}))}).catch(()=>{}),Ee(l,s.autoUpgrade??"none",p),w?.handleConnected()},onDisconnected:e=>{console.log(`[${new Date().toISOString()}] \u26A0 Disconnected, reconnecting... ${ke(e)}`),v({level:"warn",wsEvent:"daemon.disconnected",metadata:{code:e.code,reason:e.reason,error:e.error,phase:e.phase,trigger:e.trigger,reconnectAttempt:e.reconnectAttempt}})},onReq:e=>{console.log(`[${new Date().toISOString()}] [req] ${e.method}`),v({level:"info",type:"ws",wsEvent:e.method,wsDirection:"in",traceId:e.traceId}),C.handleReq(e)}});w=Se()?new we(l):null;const C=new se(l,w,p);R.mkdirSync(ye,{recursive:!0}),_(process.pid,i,{version:p}),P(process.pid,void 0,i),l.connect(),process.stdin.resume();let U=!1;const A=async()=>{if(!U){U=!0,console.log(u.gray(`
2
+ Disconnecting...`)),v({level:"info",wsEvent:"daemon.stop"}),clearInterval(o);try{await C.cleanup(),w?.stop(),l.disconnect(),O(process.pid,i),T(i)}finally{process.exit(0)}}};process.on("SIGINT",()=>{A()}),process.on("SIGTERM",()=>{A()})});const V=a.command("config").description("View or modify configuration");V.command("show",{isDefault:!0}).description("Show current configuration").action(()=>{console.log(`Config file: ${j()}`);const t={...I()};if(t.machineToken&&(t.machineToken=t.machineToken.slice(0,12)+"..."),t.serverUrl){const o=ie(t.serverUrl);console.log(`Region: ${o} (${k[o].label})`)}console.log(JSON.stringify(t,null,2))}),V.command("set").description("Update a config value").argument("<key>",'Config key (e.g. "server")').argument("<value>",'Config value (e.g. "cn" or "global")').action((n,t)=>{const o=I();if(n==="server"){t!=="cn"&&t!=="global"&&(console.error(u.red('\u2717 Value must be "cn" or "global"')),process.exit(1));const r=t;o.serverUrl=ae(r),J(o),console.log(u.green(`\u2713 Server set to ${k[r].label}`)),console.log(u.yellow(" Restart the background service for this to take effect: shennian stop && shennian start"));return}console.error(u.red(`\u2717 Unknown config key: ${n}. Supported: server`)),process.exit(1)}),B(a),Q(a),X(a),Z(a),ee(a),ne(a),te(a),oe(a),re(a),a.parse();async function Ee(n,t,o){if(t==="none")return;let r=!1;const f=async()=>{if(r)return;let d;try{d=await le(o)}catch{return}if(!d.hasUpdate)return;const{changeType:i,current:E,latest:s}=d;if(!(t==="patch"&&i!=="patch")&&!(t==="minor"&&i==="major")&&!me(s)){console.log(`[${new Date().toISOString()}] [upgrade] ${E} \u2192 ${s} (${i}), auto-upgrading...`),r=!0;try{const{handleUpgradeStart:c}=await import("./commands/upgrade.js");await c(n,"auto-upgrade",s,{currentVersion:o})}catch(c){const y=c instanceof Error?c.message:String(c),S=de(s,y);console.log(`[${new Date().toISOString()}] [upgrade] ${s} failed, retry after ${new Date(S.nextRetryAt).toISOString()}: ${y}`)}finally{r=!1}}};setTimeout(()=>{f()},ge),setInterval(()=>{f()},ue)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.2.115",
3
+ "version": "0.2.117",
4
4
  "description": "Shennian — AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {