import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import { createRequire } from "node:module"; import { pathToFileURL } from "node:url"; const root="/home/mes123456/FreeCADWasmDev/working/FreeCAD"; const build=path.resolve(process.argv[2]||path.join(root,"freecad-source/build-web/configure/bin")); const b=JSON.parse(fs.readFileSync(path.join(root,"docs/current/module-batch-manifest.json"),"utf8")); if(b.status!=="ready"||b.selected?.module!=="PartDesign"||b.selected?.tier!=="tier-2-pure"||b.selected?.family!=="geometry-value"||b.records.length<2||b.records.length>32) throw Error("unexpected PartDesign tier-2 geometry-value batch"); const rows=b.records.map(([apiId,name,disposition,sourcePath])=>({apiId,name,family:b.selected.family,sourcePath,disposition})); globalThis.__dirname=`${build}${path.sep}`; globalThis.require=createRequire(import.meta.url); const out=path.join(root,"/tmp-partdesign-batch-ts"); fs.mkdirSync(out,{recursive:true}); const {execFileSync}=await import("node:child_process"); execFileSync(path.join(root,"web/node_modules/.bin/tsc"),["--target","ES2022","--module","ESNext","--moduleResolution","Bundler","--strict","--skipLibCheck","--outDir",out,"--declaration","false","--noEmit","false",path.join(root,"web/src/facade-envelope.ts"),path.join(root,"web/src/partdesign-python-family-facade.ts")],{cwd:root,stdio:"inherit"}); const f=await import(pathToFileURL(path.join(out,"partdesign-python-family-facade.js"))); const e=await import(pathToFileURL(path.join(out,"facade-envelope.js"))); const workerJs=path.join(build,"FreeCADWebPartDesignRuntimeProbe.worker.js"), workerCjs=path.join(build,"FreeCADWebPartDesignRuntimeProbe.worker.cjs"); if(!fs.existsSync(workerCjs)) fs.copyFileSync(workerJs,workerCjs); const l=await import(pathToFileURL(path.join(build,"FreeCADWebPartDesignRuntimeProbe.js"))); const k=await l.default({wasmBinary:fs.readFileSync(path.join(build,"FreeCADWebPartDesignRuntimeProbe.wasm")),locateFile:(file)=>file.endsWith("worker.js")?workerCjs:path.join(build,file),print:()=>{},printErr:()=>{}}); const q=new e.FacadeSerialQueue(); const req=f.createPartDesignPythonFamilyRequest("pd-tier2-pure-function",rows,"tier-2-pure"); const success=await f.dispatchPartDesignPythonFamily(q,req,k); const invoke=v=>JSON.parse(String(k.ccall("fc_web_dispatch_json","string",["string"],[JSON.stringify(v)]))); const repeat={kind:"result",result:invoke({cmd:"partdesign.pythonFamilyBatch",args:req.payload})}; const cross={kind:"result",result:invoke({cmd:"partdesign.pythonFamilyBatch",args:{...req.payload,records:[{...rows[0],apiId:"py:BIM:class:Binding"}]}})}; if(success.kind!=="result"||repeat.kind!=="result"||cross.kind!=="result") throw Error(JSON.stringify({success,repeat,cross})); const result=success.result; const terminal=["exposed","restricted","nonportable","not_implemented"]; const counts=Object.fromEntries(terminal.map(s=>[s,result.records.filter(r=>r.status===s).length])); if(result.count!==rows.length||result.records.some(r=>!terminal.includes(r.status)||r.native!==true||r.resourcesReleased!==true)||JSON.stringify(result)!==JSON.stringify(repeat.result)) throw Error("invalid native batch result"); const hash=v=>crypto.createHash("sha256").update(JSON.stringify(v)).digest("hex"); const evidence=`docs/p6/partdesign-module-batch-${b.batchId}-runtime.json`; const manifestPath=path.join(root,"docs/p6/python-api-manifest.json"); const m=JSON.parse(fs.readFileSync(manifestPath,"utf8")); const by=new Map(result.records.map(r=>[r.apiId,r])); for(const r of m.records){const n=by.get(r.id);if(n){r.disposition=n.status;r.dispositionEvidence=[evidence];r.dispositionReason=n.message;}} fs.writeFileSync(manifestPath,JSON.stringify(m,null,2)+"\n"); const runtime=path.join(root,"web/public/kernel/FreeCADWebPartDesignRuntimeProbe.js"),wasm=path.join(root,"web/public/kernel/FreeCADWebPartDesignRuntimeProbe.wasm"); const artifacts={module:"PartDesign",worker:"partdesign-python.worker.ts",revision:result.records[0]?.sourceRevision,runtimeUrl:"/kernel/FreeCADWebPartDesignRuntimeProbe.js",wasmUrl:"/kernel/FreeCADWebPartDesignRuntimeProbe.wasm",dataUrl:null,assetBaseUrl:"/kernel/",buildProfile:"fast-dev",runtimeSha256:crypto.createHash("sha256").update(fs.readFileSync(runtime)).digest("hex"),wasmSha256:crypto.createHash("sha256").update(fs.readFileSync(wasm)).digest("hex")}; const report={schema:"freecad-web-p6-partdesign-geometry-value-module-batch-runtime/v1",taskId:"FW-P6-FPA-Y",batchId:b.batchId,module:"PartDesign",tier:b.selected.tier,family:b.selected.family,status:"pass_with_boundaries",route:{command:"partdesign.pythonFamilyBatch",native:"freecad-source/src/WebAssembly/FreeCADCoreProbe/PartDesignRuntimeProbe.cpp:fc_web_dispatch_json",facade:"web/src/partdesign-python-family-facade.ts",worker:"web/src/partdesign-python.worker.ts"},input:req,result,resultSha256:hash(result),replay:{equal:true,resultSha256:hash(repeat.result)},crossModule:{result:cross},dispositionCounts:counts,records:result.records.map(r=>({...r,evidenceSha256:hash(r)})),resources:{resourcesReleased:true,documentMutation:false},artifacts,boundaries:["Values and statuses are returned by compiled FreeCAD through fc_web_dispatch_json; Python-only records remain source-bounded."]}; fs.writeFileSync(path.join(root,evidence),JSON.stringify(report,null,2)+"\n"); fs.writeFileSync(path.join(root,`docs/freecad-p6-partdesign-geometry-value-module-batch-${b.batchId}.log`),JSON.stringify({status:report.status,batchId:b.batchId,count:rows.length,dispositionCounts:counts,resultSha256:report.resultSha256,artifacts})+"\n"); console.log(JSON.stringify({status:report.status,batchId:b.batchId,count:rows.length,dispositionCounts:counts,resultSha256:report.resultSha256})); process.exit(0);