#!/usr/bin/env node import { execFileSync } from 'node:child_process'; const DEFAULT_CDP = '/Users/inmanx/.agents/skills/chrome-cdp/scripts/cdp.mjs'; const DEFAULT_PLATFORM_TARGET = 'DA600CC0'; const EXTENSION_ID = 'kafggjjlhebccdgkechmbgflkaifkccf'; function parseArgs(argv) { const args = { expectedRunId: '', identifier: '', tid: '', ddid: '', departureDate: '', expectedNote: '', expectedPayloadSha256: '', platformTarget: DEFAULT_PLATFORM_TARGET, cdp: process.env.CDP_CLI || DEFAULT_CDP, timeoutMs: 45_000 }; for (let index = 0; index < argv.length; index += 1) { const value = argv[index]; if (value === '--expected-run-id') args.expectedRunId = argv[++index] || ''; else if (value === '--identifier') args.identifier = argv[++index] || ''; else if (value === '--tid') args.tid = argv[++index] || ''; else if (value === '--ddid') args.ddid = argv[++index] || ''; else if (value === '--departure-date') args.departureDate = argv[++index] || ''; else if (value === '--expected-note') args.expectedNote = argv[++index] || ''; else if (value === '--expected-payload-sha256') args.expectedPayloadSha256 = argv[++index] || ''; else if (value === '--platform-target') args.platformTarget = argv[++index] || ''; else if (value === '--cdp') args.cdp = argv[++index] || ''; else if (value === '--timeout-ms') args.timeoutMs = Number(argv[++index]); else throw new Error(`unknown argument: ${value}`); } const errors = []; if (!args.expectedRunId || !args.expectedNote.includes(args.expectedRunId)) errors.push('run_id_mismatch'); if (!args.identifier.includes('TEST-202609') || !args.expectedNote.includes('TEST-202609')) errors.push('marker_mismatch'); if (!/^\d+$/.test(args.tid) || !/^\d+$/.test(args.ddid)) errors.push('numeric_ref_missing'); if (!/^2026-09-\d{2}$/.test(args.departureDate)) errors.push('date_outside_2026_09'); if (!/^[a-f0-9]{64}$/.test(args.expectedPayloadSha256)) errors.push('payload_hash_invalid'); if (!Number.isFinite(args.timeoutMs) || args.timeoutMs < 10_000) errors.push('timeout_invalid'); if (errors.length) throw new Error(`native baseline safety check failed: ${errors.join(',')}`); return args; } function cdp(args, command, target, ...rest) { return execFileSync(process.execPath, [args.cdp, command, target, ...rest], { encoding: 'utf8', maxBuffer: 32 * 1024 * 1024 }).trim(); } function parseJson(value, label) { try { return JSON.parse(String(value || '').trim()); } catch { throw new Error(`${label} returned non-JSON output: ${String(value || '').slice(0, 500)}`); } } function wait(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } const args = parseArgs(process.argv.slice(2)); parseJson(cdp(args, 'eval', args.platformTarget, `(async()=>JSON.stringify(await sendToExtension('PING',{},3000)))()`), 'extension ping'); const targetList = parseJson(cdp(args, 'evalraw', args.platformTarget, 'Target.getTargets', '{}'), 'target list'); const worker = targetList.targetInfos?.find((target) => ( target.type === 'service_worker' && target.url === `chrome-extension://${EXTENSION_ID}/background.js` )); if (!worker?.targetId) throw new Error('extension_service_worker_missing'); const attached = parseJson(cdp(args, 'evalraw', args.platformTarget, 'Target.attachToTarget', JSON.stringify({ targetId: worker.targetId, flatten: false })), 'service worker attach'); if (!attached.sessionId) throw new Error('extension_service_worker_attach_failed'); const taskKey = `NATIVE-UPDATE-BASELINE-${args.expectedRunId}-${Date.now()}`; const operation = { runId: args.expectedRunId, identifier: args.identifier, tid: args.tid, ddid: args.ddid, departureDate: args.departureDate, expectedNote: args.expectedNote, expectedPayloadSha256: args.expectedPayloadSha256 }; const expression = `(async()=>{ const operation=${JSON.stringify(operation)}; const tabs=await chrome.tabs.query({url:"https://lwlt.hisy.cc/*"}); const tab=tabs.find((candidate)=>/\\/System\\/Mainlt\\.asp/i.test(candidate.url||""))||tabs[0]; if(!tab?.id)throw new Error("erp_tab_missing"); const candidates=await chrome.scripting.executeScript({ target:{tabId:tab.id,allFrames:true},world:"MAIN", func:(operation)=>{ const form=document.querySelector('#ListForm,form[name="ListForm"]'); const ddid=String(form?.querySelector('[name="ddid"]')?.value||""); const tid=String(form?.querySelector('[name="tdid"]')?.value||""); const note=String(form?.querySelector('[name="xiadanbeizhu"]')?.value||""); return { pathname:String(location.pathname||""),title:document.title, matched:/\\/system\\/business\\/orders_add\\.asp$/i.test(location.pathname||"") &&ddid===operation.ddid&&tid===operation.tid&¬e===operation.expectedNote, ddid_matched:ddid===operation.ddid,tid_matched:tid===operation.tid, note_matched:note===operation.expectedNote,marker_matched:note.includes("TEST-202609") }; },args:[operation] }); const exact=candidates.filter((item)=>item.result?.matched===true); if(exact.length!==1)throw new Error("exact_business_frame_count_"+exact.length); const frameId=exact[0].frameId; const injected=await chrome.scripting.executeScript({ target:{tabId:tab.id,frameIds:[frameId]},world:"MAIN", func:async(operation)=>{ const sha256=async(value)=>{ const digest=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(value)); return [...new Uint8Array(digest)].map((byte)=>byte.toString(16).padStart(2,"0")).join(""); }; const dateYyyyMD=(value)=>String(value||"").split("-").map((part,index)=>index?String(Number(part)):part).join("-"); const listUrl=new URL("/System/DAT/orders.asp",location.origin); listUrl.searchParams.set("Act","JH_OrderList"); const listParams=new URLSearchParams({ Tpage:"1",P_Size:"50",riqi:"chufari",S_chufariqi:dateYyyyMD(operation.departureDate), S_chufarizhi:dateYyyyMD(operation.departureDate),S_fabudanwei:"老挝联泰", S_tuanxuhao:operation.identifier,S_zhuangtai:"" }); const listResponse=await fetch(listUrl.href,{ method:"POST",credentials:"same-origin", headers:{"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"},body:listParams.toString() }); const listText=await listResponse.text(); const listDocument=new DOMParser().parseFromString(""+listText+"
","text/html"); const rows=[...listDocument.querySelectorAll("tr")].filter((row)=>{ const controls=[...row.querySelectorAll("input,a,button")] .map((element)=>[element.value||"",element.getAttribute("href")||"",element.getAttribute("onclick")||""].join(" ")).join(" "); const evidence=((row.innerText||row.textContent||"")+" "+controls).replace(/\\s+/g," "); const native=/^tr[_-]\\d+$/i.test(row.id||"")||Boolean(row.querySelector("input[name=xuanzeid],input#xuanzeid")); return native&&evidence.includes(operation.identifier); }); const row=rows.length===1?rows[0]:null; const actions=row?[...row.querySelectorAll("[onclick],a[href]")] .map((element)=>((element.getAttribute("onclick")||"")+" "+(element.getAttribute("href")||"")).trim()):[]; const joined=actions.join(" "); const rowTid=(row?.id||"").match(/^tr[_-](\\d+)$/i)?.[1] ||joined.match(/[?&]tid=(\\d+)/i)?.[1]||""; const rowDdid=joined.match(/OPEN_update\\(\\s*["']?(\\d+)["']?\\s*,\\s*["']?0["']?\\s*,/i)?.[1] ||joined.match(/[?&]ddid=(\\d+)/i)?.[1]||""; const evidence=row?((row.innerText||row.textContent||"")+" "+joined).replace(/\\s+/g," "):""; const ownership={ http_status:listResponse.status,candidate_count:rows.length,tid_matched:rowTid===operation.tid, ddid_matched:rowDdid===operation.ddid,identifier_matched:evidence.includes(operation.identifier), marker_matched:evidence.includes("TEST-202609"),account_matched:evidence.includes("测试ai员工账号"), login_timeout:/登录|登陆|login|验证码/i.test(listText),permission_error:/权限|permission|无权/i.test(listText) }; ownership.matched=listResponse.ok&&ownership.candidate_count===1&&ownership.tid_matched&&ownership.ddid_matched &&ownership.identifier_matched&&ownership.marker_matched&&ownership.account_matched &&!ownership.login_timeout&&!ownership.permission_error; if(!ownership.matched)return {status:"blocked",stage:"ownership_preflight",ownership,write_attempted:false,no_erp_write:true}; const form=document.querySelector('#ListForm,form[name="ListForm"]'); const jq=window.jQuery||window.$; const note=form?.querySelector('[name="xiadanbeizhu"]'); const ddid=String(form?.querySelector('[name="ddid"]')?.value||""); const tid=String(form?.querySelector('[name="tdid"]')?.value||""); if(!form||!jq||typeof window.SubmitInfoForm!=="function"||ddid!==operation.ddid||tid!==operation.tid ||String(note?.value||"")!==operation.expectedNote||!String(note?.value||"").includes("TEST-202609")){ return {status:"blocked",stage:"form_preflight",ownership,write_attempted:false,no_erp_write:true}; } const requestBody="Act=DoInfoJH&"+jq(form).serialize(); const requestHash=await sha256(requestBody); if(requestHash!==operation.expectedPayloadSha256){ return {status:"blocked",stage:"payload_preflight",ownership,request_sha256:requestHash,write_attempted:false,no_erp_write:true}; } const originalAjax=jq.ajax; const originalGlobalEval=jq.globalEval; const originalAlert=window.alert; const originalDialogAlert=jq.dialog?.alert; const alerts=[]; const records=[]; let responseScript=""; window.alert=(message)=>{alerts.push(String(message||""))}; if(jq.dialog&&typeof originalDialogAlert==="function")jq.dialog.alert=(message)=>{alerts.push(String(message||""))}; if(typeof originalGlobalEval==="function")jq.globalEval=(code)=>{responseScript+=String(code||"")}; jq.ajax=function(optionsArg,...rest){ const config=typeof optionsArg==="string"?{url:optionsArg}:{...(optionsArg||{})}; const data=String(config.data||""); const exactRequest=/\\/System\\/DAT\\/orders\\.asp/i.test(String(config.url||""))&&data===requestBody; const record={exact_request:exactRequest,data_type:String(config.dataType||""),method:String(config.type||config.method||""),completed:false,ok:false}; records.push(record); if(!exactRequest){record.completed=true;record.blocked=true;return {readyState:4,status:0,abort(){}}} const originalSuccess=config.success; const originalError=config.error; const originalComplete=config.complete; config.success=function(responseText,textStatus){ record.ok=true;record.text_status=String(textStatus||"");record.response_text=String(responseText||""); return originalSuccess?originalSuccess.apply(this,arguments):undefined; }; config.error=function(jqXHR,textStatus){record.ok=false;record.text_status=String(textStatus||"");return originalError?originalError.apply(this,arguments):undefined}; config.complete=function(jqXHR,textStatus){ record.completed=true;record.http_status=Number(jqXHR?.status||0);record.response_text=record.response_text||String(jqXHR?.responseText||""); record.text_status=record.text_status||String(textStatus||""); return originalComplete?originalComplete.apply(this,arguments):undefined; }; return originalAjax.call(this,config,...rest); }; let thrown=""; try{window.SubmitInfoForm()}catch(error){thrown=String(error?.message||error)} const started=Date.now(); while(Date.now()-started<30000&&!records.some((record)=>record.completed))await new Promise((resolve)=>setTimeout(resolve,250)); jq.ajax=originalAjax; if(typeof originalGlobalEval==="function")jq.globalEval=originalGlobalEval; window.alert=originalAlert; if(jq.dialog&&typeof originalDialogAlert==="function")jq.dialog.alert=originalDialogAlert; const detailUrl=new URL(location.href); detailUrl.searchParams.set("_",String(Date.now())); const detailResponse=await fetch(detailUrl.href,{credentials:"same-origin",cache:"no-store"}); const detailText=await detailResponse.text(); const detailDocument=new DOMParser().parseFromString(detailText,"text/html"); const persistedNote=String(detailDocument.querySelector('[name="xiadanbeizhu"]')?.value||""); const record=records[0]||{}; const responseText=String(record.response_text||responseScript||""); const responseMessage=responseText.replace(/<[^>]+>/g," ").replace(/\\s+/g," ").trim().slice(0,500); const requery={ http_status:detailResponse.status,matched:detailResponse.ok&&persistedNote===operation.expectedNote, note_length:persistedNote.length,marker_present:persistedNote.includes("TEST-202609"), login_timeout:/登录|登陆|login|验证码/i.test(detailText),permission_error:/权限|permission|无权/i.test(detailText) }; const serverResponse={ http_status:Number(record.http_status||0),completed:record.completed===true,ok:record.ok===true, response_bytes:new Blob([responseText]).size,response_sha256:await sha256(responseText), response_message:responseMessage,success_hint:/成功|保存|完成|success|ok/i.test(responseMessage), error_hint:/失败|错误|异常|error/i.test(responseMessage)&&!/成功|success|ok/i.test(responseMessage) }; const completed=records.length===1&&record.exact_request===true&&!record.blocked&&!thrown &&serverResponse.completed&&serverResponse.ok&&serverResponse.success_hint&&requery.matched; return { status:completed?"completed":"uncertain",stage:"native_independent_update_baseline", resolved_refs:{identifier:operation.identifier,tid:operation.tid,ddid:operation.ddid,departure_date:operation.departureDate}, ownership,native_request:{action:"DoInfoJH",endpoint:"/System/DAT/orders.asp",method:"POST",data_type:record.data_type,request_sha256:requestHash}, server_response:serverResponse,requery,write_attempted:true,no_erp_write:false, side_effects:["no_procurement","no_payment","no_notification","no_external_send"],manual_review_required:!completed }; },args:[operation] }); const report=injected[0]?.result||{status:"blocked",stage:"injection_result_missing",write_attempted:false,no_erp_write:true}; const saved=await chrome.storage.local.get("businessTaskResults"); const resultMap=saved.businessTaskResults||{}; resultMap[${JSON.stringify(taskKey)}]={...report,message:"native independent update baseline completed"}; await chrome.storage.local.set({businessTaskResults:resultMap}); return true; })()`; const message = JSON.stringify({ id: 1, method: 'Runtime.evaluate', params: { expression, awaitPromise: true, returnByValue: true } }); cdp(args, 'evalraw', args.platformTarget, 'Target.sendMessageToTarget', JSON.stringify({ sessionId: attached.sessionId, message })); const startedAt = Date.now(); let result = null; while (Date.now() - startedAt < args.timeoutMs) { try { const response = parseJson(cdp( args, 'eval', args.platformTarget, `(async()=>JSON.stringify(await sendToExtension('GET_TASK_RESULT',{task_id:${JSON.stringify(taskKey)}},3000)))()` ), 'baseline result'); result = response?.result || null; if (result && ['completed', 'uncertain', 'blocked'].includes(result.status)) break; } catch { // The bounded native baseline is still running. } await wait(500); } try { cdp(args, 'evalraw', args.platformTarget, 'Target.detachFromTarget', JSON.stringify({ sessionId: attached.sessionId })); } catch { // Detachment is cleanup only. } if (!result) throw new Error(`native update baseline timed out after ${args.timeoutMs}ms; do not retry`); console.log(JSON.stringify({ task_key: taskKey, result }, null, 2)); if (result.status !== 'completed') process.exitCode = 2;