publishport-opencli 1.0.25 → 1.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/clis/_shared/watch.js +3 -3
- package/dist/src/execution.js +2 -2
- package/package.json +1 -1
package/clis/_shared/watch.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{existsSync as
|
|
2
|
-
`)}function u(e,t,r={}){
|
|
1
|
+
import{existsSync as ee,mkdirSync as te,readFileSync as re,writeFileSync as ne}from"node:fs";import{homedir as ae}from"node:os";import{dirname as ie,join as G}from"node:path";import{cli as se,Strategy as oe}from"@jackwener/opencli/registry";import{AuthRequiredError as J,CommandExecutionError as ce}from"@jackwener/opencli/errors";const P=1000,B=300,j=60,D=30,z=2000,le=20;function ue(){return G(ae(),".ppcli","watch")}function H(e,t){const r=String(process.env.PPCLI_ACTIVE_PROFILE??"").trim();return G(ue(),`${e}${r?`@${r}`:""}.${t}.seen.json`)}function de(e,t){const r=H(e,t);try{if(!ee(r))return{ids:[],set:new Set,lastTs:0,firstRun:!0};const i=JSON.parse(re(r,"utf-8")),o=Array.isArray(i?.ids)?i.ids.map(String):[],c=Number.isFinite(i?.lastTs)?Number(i.lastTs):0;return{ids:o,set:new Set(o),lastTs:c,firstRun:c<=0}}catch{return{ids:[],set:new Set,lastTs:0,firstRun:!0}}}function E(e,t,r){const i=H(e,t);try{te(ie(i),{recursive:!0});ne(i,JSON.stringify({ids:r.ids.slice(-z),lastTs:r.lastTs||0}),"utf-8")}catch{}}function fe(e,t){if(e.set.has(t))return!1;e.set.add(t);e.ids.push(t);while(e.ids.length>z){const r=e.ids.shift();e.set.delete(r)}return!0}function R(e){process.stdout.write(`${JSON.stringify(e)}
|
|
2
|
+
`)}function u(e,t,r={}){R({type:"status",site:e,state:t,ts:Date.now(),...r})}function K(e,t){if(!t||typeof t!=="object")return null;const r=t.id==null?"":String(t.id);if(!r)return null;const i=t.sender&&typeof t.sender==="object"?{id:t.sender.id==null?"":String(t.sender.id),name:String(t.sender.name??"")}:{id:"",name:String(t.sender??"")};return{type:"event",site:e,event:String(t.event??"message"),id:r,ts:Number.isFinite(t.ts)?Number(t.ts):Date.now(),conversation_id:t.conversation_id==null?"":String(t.conversation_id),sender:i,text:String(t.text??""),url:t.url==null?"":String(t.url),raw:t.raw??null}}function V(e){if(!e)return[];return Array.isArray(e)?e.filter(Boolean):[e]}function Q(e){try{return new URL(e).origin}catch{return""}}function pe(e){return`(function(){
|
|
3
3
|
if (window.__pp_stream_hooked) return;
|
|
4
4
|
window.__pp_stream_hooked = true;
|
|
5
5
|
var PATTERNS = ${JSON.stringify(String(e||"").split("|").map((r)=>r.trim()).filter(Boolean))};
|
|
@@ -56,4 +56,4 @@ import{existsSync as Q,mkdirSync as X,readFileSync as Y,writeFileSync as Z}from"
|
|
|
56
56
|
WrappedES.prototype = NativeES.prototype;
|
|
57
57
|
window.EventSource = WrappedES;
|
|
58
58
|
}
|
|
59
|
-
})()`}async function
|
|
59
|
+
})()`}async function me(e){let t;try{t=await e.evaluate("(function(){ var o = window.__pp_stream || []; window.__pp_stream = []; return JSON.stringify(o); })()")}catch{return[]}let r;try{r=JSON.parse(typeof t==="string"?t:"[]")}catch{return[]}if(!Array.isArray(r))return[];return r.map((i)=>({kind:"page-hook",channel:i.channel,direction:i.direction,url:i.url,method:i.channel==="websocket"?"WS":"SSE",eventName:i.eventName||void 0,responseStatus:200,responseContentType:i.binary?"application/octet-stream":"text/plain",responsePreview:i.binary?"":String(i.data??""),timestamp:i.ts||Date.now()}))}export function registerWatch(e){if(!e?.site||!e?.domain||!e?.watchUrl||typeof e.parse!=="function")throw Error("registerWatch 需要 site、domain、watchUrl 和 parse");const t=e.name??"watch",r=e.site,i=Q(e.watchUrl);se({site:r,name:t,access:"read",description:e.description??`长驻监听${r}的新消息,旁听页面自身的实时通道并按 NDJSON 逐条输出(不对平台发轮询请求)`,domain:e.domain,strategy:oe.COOKIE,browser:!0,navigateBefore:!1,sessionKey:"watch",siteSession:"persistent",defaultWindowMode:"background",args:[{name:"interval",type:"int",required:!1,default:P,help:`本机取帧间隔毫秒(默认 ${P})。纯本机 IPC,不发平台请求`},{name:"reconcile-interval",type:"int",required:!1,default:0,help:`对账间隔秒(0 = 用该平台的默认值:可旁听实时通道的平台 ${B} 秒兜底,只能靠拉取的平台 ${j} 秒一轮);-1 = 彻底关闭对账`},{name:"heartbeat",type:"int",required:!1,default:D,help:`心跳间隔秒(默认 ${D}),无事件时输出一行 status 表示还活着`},{name:"events",type:"str",required:!1,help:"只输出这些事件类型,逗号分隔(如 dm,comment);默认全部"},{name:"once",type:"bool",required:!1,default:!1,help:"只跑一轮对账后退出,不长驻。用于验证解析器和补历史"},{name:"replay-seen",type:"bool",required:!1,default:!1,help:"忽略去重表,把解析到的事件全部重新输出(调试用,会导致重复触发)"},{name:"backfill",type:"bool",required:!1,default:!1,help:"首次运行时把已存在的历史消息也当成新事件输出(默认只静默登记,不触发)"},{name:"dump-frames",type:"bool",required:!1,default:!1,help:"侦察模式:把收到的每一条原始帧(url / 通道 / 内容片段)也打出来,用来给新平台摸清事件通道"},{name:"include-own",type:"bool",required:!1,default:!1,help:"连自己发出去的消息也当成事件(默认不算——否则自动回复会追着自己的回复自我触发)。调试解析用"}],columns:["event","id","sender","text","ts"],func:async(o,c)=>{const X=Math.max(200,Number(c.interval??P)),k=e.mode==="reconcile"?"reconcile":"stream",_=Number(c["reconcile-interval"]??0),b=_<0?0:_>0?_:k==="reconcile"?j:B,U=Math.max(0,Number(c.heartbeat??D)),x=c.once===!0||c.once==="true",S=c["replay-seen"]===!0||c["replay-seen"]==="true",T=c.backfill===!0||c.backfill==="true",Y=c["dump-frames"]===!0||c["dump-frames"]==="true",h=String(c.events??"").split(",").map((l)=>l.trim()).filter(Boolean);if(typeof o.startNetworkCapture!=="function"||typeof o.readNetworkCapture!=="function")throw new ce("当前浏览器通道不支持网络捕获,watch 无法工作(需要 CDP 或扩展路径)");const d=de(r,t),C={site:r,page:o,state:{},includeOwn:c["include-own"]===!0||c["include-own"]==="true"};let p=0,W=0,y=!1;const g=[];let m=d.firstRun&&!T&&!S,O=!1;const w=d.lastTs,F=(l)=>{const a=K(r,l);if(!a)return!1;if(h.length&&!h.includes(a.event))return!1;if(!S&&!fe(d,`${a.event}:${a.id}`))return!1;if(a.ts>d.lastTs)d.lastTs=a.ts;if(m){W++;return!1}if(!T&&!S&&w>0&&a.ts>0&&a.ts<=w){W++;return!1}if(!x)R(a);g.push(a);p++;return!0},Z=(l)=>{let a=0;for(const n of l){const s=K(r,n);if(!s)continue;if(h.length&&!h.includes(s.event))continue;if(d.set.has(`${s.event}:${s.id}`))continue;if(w>0&&s.ts>0&&s.ts<=w)continue;a++}return a},v=async(l,a=!1)=>{if(typeof e.reconcile!=="function")return;try{const n=V(await e.reconcile(o,C));if(a&&!m&&!T&&!S&&Z(n)>le){m=!0;O=!0}let s=0;for(const f of n)if(F(f))s++;u(r,"reconciled",{reason:l,scanned:n.length,new:s})}catch(n){if(n instanceof J)throw n;u(r,"reconcile_failed",{reason:l,error:n?.message??String(n)})}},I=async(l)=>{let a=!1;try{a=await o.startNetworkCapture(e.pattern??"")!==!1}catch{a=!1}const n=pe(e.pattern??"");y=!1;let s=!1;if(typeof o.cdp==="function")try{await o.cdp("Page.enable",{});await o.cdp("Page.addScriptToEvaluateOnNewDocument",{source:n});s=!0;y=!0}catch{}await o.goto(e.watchUrl,{waitUntil:s?"load":"none"});if(!s)try{await o.evaluate(n);y=!0;u(r,"page_hook_late",{note:"浏览器扩展版本较旧,旁听脚本只能在导航后注入;页面在此之前已建立的连接要等它重连才能被看到"})}catch(f){u(r,"page_hook_unavailable",{error:f?.message??String(f)})}if(!a){await o.startNetworkCapture(e.pattern??"");await o.goto(e.watchUrl,{waitUntil:"load"})}if(typeof e.onAttach==="function")await e.onAttach(o,C);u(r,"watching",{reason:l,mode:k,url:e.watchUrl,pattern:e.pattern??"",reconcile_seconds:b})};await I("start");await v("startup",!0);if(m){E(r,t,d);u(r,"seeded",{seeded:W,desynced:O,note:O?"去重表和收件箱对不上(上次没跑完 / 换了账号 / 表被裁剪),本轮把当前收件箱重新登记为「已见过」,不触发任何事件。从现在起只有新消息才会上报":"首次运行:已把当前收件箱登记为「已见过」,不触发任何事件。从现在起只有新消息才会上报(要补历史请加 --backfill)"});m=!1}if(x){E(r,t,d);return g}let A=!1;const N=()=>{A=!0};process.on("SIGINT",N);process.on("SIGTERM",N);let M=Date.now(),L=Date.now(),q=p;try{while(!A){await new Promise((n)=>setTimeout(n,X));if(A)break;let l=[];try{l=await o.readNetworkCapture()??[];if(y)l=l.concat(await me(o))}catch(n){u(r,"reattaching",{error:n?.message??String(n)});try{await I("capture_lost");await v("reattach")}catch(s){if(s instanceof J)throw s;u(r,"reattach_failed",{error:s?.message??String(s)})}continue}for(const n of l){if(Y)R({type:"frame",site:r,via:n?.kind==="page-hook"?"page-hook":"cdp",channel:n?.channel??"http",direction:n?.direction??"",method:n?.method??"",url:String(n?.url??"").slice(0,200),size:n?.responseBodyFullSize??String(n?.responsePreview??"").length,preview:String(n?.responsePreview??"").slice(0,600)});if(n?.direction==="sent")continue;let s;try{s=await e.parse(n,C)}catch(f){u(r,"parse_failed",{url:n?.url??"",error:f?.message??String(f)});continue}for(const f of V(s))F(f)}if(p!==q){E(r,t,d);q=p;L=Date.now()}if(i&&typeof o.getCurrentUrl==="function")try{const n=await o.getCurrentUrl();if(n&&Q(n)!==i){u(r,"page_drifted",{url:n});await I("drift");await v("drift")}}catch{}const a=Date.now();if(b&&a-M>=b*1000){M=a;await v("interval")}if(U&&a-L>=U*1000){L=a;u(r,"alive",{emitted:p})}}}finally{process.off("SIGINT",N);process.off("SIGTERM",N);E(r,t,d);u(r,"stopped",{emitted:p})}return g}})}export function frameJson(e){const t=e?.responsePreview;if(typeof t!=="string"||!t)return null;if(t.startsWith("base64:"))return null;try{return JSON.parse(t)}catch{return null}}
|
package/dist/src/execution.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{getRegistry as oe,fullName as g}from"./registry.js";import{pathToFileURL as ie}from"node:url";import*as se from"node:crypto";import*as M from"node:fs";import*as j from"node:os";import*as N from"node:path";import{executePipeline as K}from"./pipeline/index.js";import{adapterLoadError as ae,ArgumentError as d,CommandExecutionError as
|
|
2
|
-
`);try{n?.(o)}catch(s){X.warn(`[trace] Trace export callback failed: ${s instanceof Error?s.message:String(s)}`)}return o}catch(o){X.warn(`[trace] Failed to export trace artifact: ${o instanceof Error?o.message:String(o)}`);return}}export function resolveFileBackedArg(e,r){const t=e.args.find((l)=>l.fromFile);if(!t)return;const n=typeof t.fromFile==="string"?t.fromFile:"file",o=t.positional?`<${t.name}>`:`--${t.name}`,s=r[n]==null?"":String(r[n]).trim(),u=r[t.name]==null?"":String(r[t.name]);if(s){if(u.trim())throw new d(`${o} 和 --${n} 只能二选一,不能同时给`);const l=N.resolve(s.startsWith("~/")?N.join(j.homedir(),s.slice(2)):s);let m;try{m=M.readFileSync(l,"utf-8")}catch(w){throw new d(`--${n} 指向的文件读不到: ${l}(${D(w)})`)}const i=m.trim();if(!i)throw new d(`--${n} 指向的文件内容为空: ${l}`);r[t.name]=i;$e(N.dirname(l));return}if(!u.trim()&&t.requiredUnlessFile)throw new d(`缺少 ${t.name}:${o} 或 --${n} 给其一`)}export function prepareCommandArgs(e,r){const t=coerceAndValidateArgs(e.args,r);resolveFileBackedArg(e,t);e.validateArgs?.(t);return t}const Z=30;function
|
|
1
|
+
import{getRegistry as oe,fullName as g}from"./registry.js";import{pathToFileURL as ie}from"node:url";import*as se from"node:crypto";import*as M from"node:fs";import*as j from"node:os";import*as N from"node:path";import{executePipeline as K}from"./pipeline/index.js";import{adapterLoadError as ae,ArgumentError as d,CommandExecutionError as A,SessionBusyError as ce,attachTraceReceipt as ue,getErrorMessage as D}from"./errors.js";import{shouldUseBrowserSession as le}from"./capabilityRouting.js";import{getBrowserFactory as fe,browserSession as me,runWithTimeout as V,DEFAULT_BROWSER_COMMAND_TIMEOUT as de}from"./runtime.js";import{withBrowserSessionLockIf as pe}from"./browser-session-lock.js";import{resolveProfile as he}from"./browser/profile.js";import{ensureManagedChrome as we}from"./browser/managed-chrome.js";import{generateFingerprintJs as ge}from"./browser/fingerprint.js";import{CDPBridge as ye}from"./browser/index.js";import{clearDaemonRunContext as ve,generateRunId as Se,isUnknownOutcomeError as G,releaseSiteSessionLease as J,setDaemonCommandTimeoutSeconds as be,setDaemonRunContext as Q}from"./browser/daemon-client.js";import{emitHook as _}from"./hooks.js";import{setContentBaseDir as $e}from"./utils.js";import{log as X}from"./logger.js";import{isElectronApp as Ee}from"./electron-apps.js";import{probeCDP as Pe,resolveElectronEndpoint as Ae}from"./launcher.js";import{ObservationSession as Ce,exportObservationSession as xe}from"./observation/index.js";import{resolveAdapterSourcePath as Ie}from"./adapter-source.js";const S=new Map,k=new Map,Re=`${j.homedir()}/.ppcli/clis/`;function Te(e){if(e===void 0||e===null||e===""||e==="off")return"off";if(e==="on"||e==="retain-on-failure")return e;throw new d(`--trace must be one of: off, on, retain-on-failure. Received: "${String(e)}"`)}export function coerceAndValidateArgs(e,r){const t={...r};for(const n of e){const o=t[n.name];if(n.required&&(o===void 0||o===null||o===""))throw new d(`Argument "${n.name}" is required.`,n.help??`Provide a value for --${n.name}`);if(o!==void 0&&o!==null){if(n.type==="int"||n.type==="number"){const u=Number(o);if(!Number.isFinite(u))throw new d(`Argument "${n.name}" must be a valid number. Received: "${o}"`);if(n.type==="int"&&!Number.isInteger(u))throw new d(`Argument "${n.name}" must be a valid integer. Received: "${o}"`);t[n.name]=u}else if(n.type==="boolean"||n.type==="bool")if(typeof o==="string"){const u=o.toLowerCase();if(u==="true"||u==="1")t[n.name]=!0;else if(u==="false"||u==="0")t[n.name]=!1;else throw new d(`Argument "${n.name}" must be a boolean (true/false). Received: "${o}"`)}else t[n.name]=Boolean(o);const s=t[n.name];if(n.choices&&n.choices.length>0){if(!n.choices.map(String).includes(String(s)))throw new d(`Argument "${n.name}" must be one of: ${n.choices.join(", ")}. Received: "${s}"`)}}else if(n.default!==void 0)t[n.name]=n.default}return t}async function B(e,r,t,n){const o=e;if(o._lazy&&o._modulePath){const s=o._modulePath;if(s.startsWith(Re)&&S.has(s))try{const m=M.statSync(s),i=k.get(s);if(i!==void 0&&m.mtimeMs!==i)S.delete(s)}catch{}if(!S.has(s)){const m=ie(s).href,w=import(k.has(s)?`${m}?t=${Date.now()}`:m).then(()=>{try{k.set(s,M.statSync(s).mtimeMs)}catch{}},(p)=>{S.delete(s);throw ae(`Failed to load adapter module ${s}: ${D(p)}`,"Check that the adapter file exists and has no syntax errors.")});S.set(s,w)}await S.get(s);const l=oe().get(g(e));if(l?.func)return Y(l,r,t,n);if(l?.pipeline)return K(r,l.pipeline,{args:t,debug:n})}if(e.func)return Y(e,r,t,n);if(e.pipeline)return K(r,e.pipeline,{args:t,debug:n});throw new A(`Command ${g(e)} has no func or pipeline`,"This is likely a bug in the adapter definition. Please report this issue.")}function Y(e,r,t,n){if(e.browser===!1)return e.func(t,n);if(!r)throw new A(`Command ${g(e)} requires a browser session but none was provided`);return e.func(r,t,n)}function Me(e){if(e.navigateBefore===!1)return null;if(typeof e.navigateBefore==="string")return e.navigateBefore;return null}function Ne(e,r){if(!e||!r)return!1;try{const t=new URL(e).hostname;return t===r||t.endsWith(`.${r}`)}catch{return!1}}function De(e,r){if(!r)return!1;try{const t=new URL(e),n=t.hostname===r||t.hostname.endsWith(`.${r}`),o=t.pathname===""||t.pathname==="/";return n&&o&&t.search===""&&t.hash===""}catch{return!1}}async function _e(e,r,t,n){if(t!=="persistent"||!e.domain)return!0;if(!De(n,e.domain))return!0;const o=await r.getCurrentUrl?.().catch(()=>null);return!Ne(o,e.domain)}export async function executeCommand(e,r,t=!1,n={}){let o;try{o=n.prepared?r:prepareCommandArgs(e,r)}catch(i){if(i instanceof d)throw i;throw new d(D(i))}const s=qe(e,o);be(s);const u=Te(n.trace),l={command:g(e),args:o,startedAt:Date.now()};await _("onBeforeExecute",l);let m;try{if(le(e)){const i=Ee(e.site),w=he(n.profile),p=!i&&w.kind==="managed"?w:null;process.env.PPCLI_ACTIVE_PROFILE=p?p.name:"";let P;const C=We(e.defaultWindowMode??"background",n.windowMode);let F,L;if(p){P=await we(p.name,p.entry,{windowMode:C});const c=p.entry.fingerprint;if(c?.enabled)F=ge(c);const a=p.entry.proxy;if(a?.username)L={username:a.username,password:a.password??""}}else if(i){const c=process.env.OPENCLI_CDP_ENDPOINT;if(c){const a=Number(new URL(c).port);if(!await Pe(a))throw new A(`CDP not reachable at ${c}`,"Check that the app is running with --remote-debugging-port and the endpoint is correct.");P=c}else P=await Ae(e.site)}const re=p?ye:fe(e.site),W=!p&&w.kind==="extension"?w.contextId:void 0,ne=e,b=Ue(e,n.siteSession),x=Oe(e,b),q=Le(b,n.keepTab),y=b==="persistent"&&e.access==="write"?{runId:Se(),session:x}:null;if(y)Q({runId:y.runId,command:g(e),access:"write"});let z,H=!1,I=null;try{m=await pe(C!=="foreground",()=>me(re,async(c)=>{const a=u==="off"?null:new Ce({scope:{contextId:W??p?.name,session:x,target:c.getActivePage?.(),site:e.site,command:g(e),adapterSourcePath:Ie(ne)}});if(a){a.record({stream:"action",name:"command",phase:"start",data:{args:o}});await c.startNetworkCapture?.().catch(()=>!1)}const h=Me(e);if(h&&await _e(e,c,b,h)){a?.record({stream:"action",name:"pre_navigate",phase:"start",data:{url:h}});try{await c.goto(h);a?.record({stream:"action",name:"pre_navigate",phase:"end",data:{url:h}})}catch(f){if(f instanceof ce)throw f;a?.record({stream:"action",name:"pre_navigate",phase:"error",data:{url:h,error:f instanceof Error?f.message:String(f)}});const v=new A(`Pre-navigation to ${h} failed: ${f instanceof Error?f.message:f}`,"Check that the site is reachable and the browser extension is running.");v.cause=f;if(a&&(u==="on"||u==="retain-on-failure")){a.record({stream:"error",message:v.message,stack:v.stack,code:v.code,hint:v.hint});await U(a,c).catch(()=>{});O(a,"failure",v,n.onTraceExport)}throw v}}const E=s!==null?s+Z:de,R=B(e,c,o,t);I=R;let T=!1;R.then(()=>{T=!0},()=>{T=!0});try{const f=await V(R,{timeout:E,label:g(e),hint:te(e,s)});a?.record({stream:"action",name:"command",phase:"end"});if(a&&u==="on"){await U(a,c).catch(()=>{});O(a,"success",void 0,n.onTraceExport)}if(!q)await c.closeWindow?.().catch(()=>{});return f}catch(f){if(!T)H=!0;if(a){a.record({stream:"action",name:"command",phase:"error",data:{error:f instanceof Error?f.message:String(f)}});a.record({stream:"error",message:f instanceof Error?f.message:String(f),stack:f instanceof Error?f.stack:void 0});if(u==="on"||u==="retain-on-failure"){await U(a,c).catch(()=>{});O(a,"failure",f,n.onTraceExport)}}if(!q)await c.closeWindow?.().catch(()=>{});throw f}},{session:x,cdpEndpoint:P,contextId:W,windowMode:C,surface:"adapter",siteSession:b,initScript:F,proxyAuth:L}),p?.name)}catch(c){z=c;throw c}finally{if(y)if(H&&I){const{runId:c,session:a}=y,h=(E)=>{ve(c);if(!G(E))J({runId:c,session:a,surface:"adapter"})};I.then(()=>h(),(E)=>h(E))}else{Q(null);if(!G(z))await J({runId:y.runId,session:y.session,surface:"adapter"})}}}else if(s!==null){const i=s+Z;m=await V(B(e,null,o,t),{timeout:i,label:g(e),hint:te(e,s)})}else m=await B(e,null,o,t)}catch(i){l.error=i;l.finishedAt=Date.now();await _("onAfterExecute",l);throw i}l.finishedAt=Date.now();await _("onAfterExecute",l,m);return m}async function U(e,r){const t=r.getActivePage?.()??e.scope.target,[n,o,s,u,l]=await Promise.all([r.getCurrentUrl?.().catch(()=>null)??Promise.resolve(null),r.snapshot().catch(()=>{return}),r.readNetworkCapture?.().catch(()=>[])??Promise.resolve([]),r.consoleMessages("all").catch(()=>[]),r.screenshot({format:"png"}).catch(()=>{return})]);if(o!==void 0||n!==void 0)e.record({stream:"state",url:n,target:t,snapshot:o,label:"final"});for(const m of Array.isArray(s)?s:[]){const i=m;e.record({stream:"network",url:String(i.url??""),method:typeof i.method==="string"?i.method:void 0,status:typeof i.responseStatus==="number"?i.responseStatus:void 0,contentType:typeof i.responseContentType==="string"?i.responseContentType:void 0,size:typeof i.responseBodyFullSize==="number"?i.responseBodyFullSize:void 0,requestHeaders:i.requestHeaders,responseHeaders:i.responseHeaders,requestBody:i.requestBodyPreview,responseBody:i.responsePreview,ts:typeof i.timestamp==="number"?i.timestamp:void 0})}for(const m of Array.isArray(u)?u:[])if(m&&typeof m==="object"){const i=m;e.record({stream:"console",level:String(i.type??i.level??"log"),text:String(i.text??i.message??""),ts:typeof i.timestamp==="number"?i.timestamp:void 0})}else e.record({stream:"console",level:"log",text:String(m)});if(typeof l==="string"&&l)e.record({stream:"screenshot",format:"png",data:l,label:"final"})}function O(e,r,t,n){try{const o=xe(e,{error:t,status:r});if(r==="failure"&&t!==void 0)ue(t,o.receipt);else process.stderr.write(`ppcli trace artifact: ${o.dir}
|
|
2
|
+
`);try{n?.(o)}catch(s){X.warn(`[trace] Trace export callback failed: ${s instanceof Error?s.message:String(s)}`)}return o}catch(o){X.warn(`[trace] Failed to export trace artifact: ${o instanceof Error?o.message:String(o)}`);return}}export function resolveFileBackedArg(e,r){const t=e.args.find((l)=>l.fromFile);if(!t)return;const n=typeof t.fromFile==="string"?t.fromFile:"file",o=t.positional?`<${t.name}>`:`--${t.name}`,s=r[n]==null?"":String(r[n]).trim(),u=r[t.name]==null?"":String(r[t.name]);if(s){if(u.trim())throw new d(`${o} 和 --${n} 只能二选一,不能同时给`);const l=N.resolve(s.startsWith("~/")?N.join(j.homedir(),s.slice(2)):s);let m;try{m=M.readFileSync(l,"utf-8")}catch(w){throw new d(`--${n} 指向的文件读不到: ${l}(${D(w)})`)}const i=m.trim();if(!i)throw new d(`--${n} 指向的文件内容为空: ${l}`);r[t.name]=i;$e(N.dirname(l));return}if(!u.trim()&&t.requiredUnlessFile)throw new d(`缺少 ${t.name}:${o} 或 --${n} 给其一`)}export function prepareCommandArgs(e,r){const t=coerceAndValidateArgs(e.args,r);resolveFileBackedArg(e,t);e.validateArgs?.(t);return t}const Z=30;function ke(e){if(e===void 0||e===null||e==="")return null;if(e==="ephemeral"||e==="persistent")return e;throw new d(`--site-session must be one of: ephemeral, persistent. Received: "${String(e)}"`)}function Be(){const e=process.env.PUBLISHPORT_SITE_SESSION;if(e==="persistent"||e==="ephemeral")return e;return null}function Ue(e,r){return ke(r)??Be()??e.siteSession??"persistent"}function Oe(e,r){const t=typeof e.sessionKey==="string"&&e.sessionKey.trim()?`:${e.sessionKey.trim()}`:"";if(r==="persistent")return`site:${e.site}${t}`;return`site:${e.site}${t}:${se.randomUUID()}`}function Fe(e,r){if(r===void 0||r==="")return null;if(r==="true")return!0;if(r==="false")return!1;throw new d(`${e} must be one of: true, false. Received: "${String(r)}"`)}function Le(e,r){if(e==="persistent")return!0;return Fe("--keep-tab",r)??!1}function ee(e,r){if(r===void 0||r==="")return null;if(r==="foreground"||r==="background")return r;throw new d(`${e} must be one of: foreground, background. Received: "${String(r)}"`)}function We(e="background",r){return ee("--window",r)??ee("OPENCLI_WINDOW",process.env.OPENCLI_WINDOW)??e}function te(e,r){const t=e.access==="write"?"⚠️ 这是写操作,超时不代表没写成功——请求可能已经到达平台。禁止直接重试:"+"先用该平台的列表/统计命令(stats / lists / articles 等)按标题回查,确认没写进去再重发。 ":"";if(r!==null)return`${t}Pass a higher --timeout value (currently ${r}s)`;if(e.args.some((n)=>n.name==="timeout"))return`${t}Try again, or pass a higher --timeout <seconds>`;return t+"This command has no --timeout option. Retry once; if it keeps timing out, "+"the page or browser bridge is likely stuck — have the user reopen the PublishPort client. "+"The global default can be raised with OPENCLI_BROWSER_COMMAND_TIMEOUT."}function qe(e,r){if(!e.args.some((o)=>o.name==="timeout"))return null;const t=r.timeout;if(t===void 0||t===null||t==="")throw new d(`Argument "timeout" must be a positive integer. Received: "${String(t)}"`);const n=Number(t);if(!Number.isInteger(n)||n<=0)throw new d(`Argument "timeout" must be a positive integer. Received: "${String(t)}"`);return n}
|