// Import the captured official-page snapshots through the existing secure Skill. // Collection was performed by Codex; the workshop Agent imports archived real sources. import fs from 'node:fs'; import path from 'node:path'; import crypto from 'node:crypto'; import {fileURLToPath} from 'node:url'; import {spawnSync} from 'node:child_process'; export const TASK_KEY='KSF-真实资料-20261102-01'; const check=(ok,code='LIVE_IMPORT_MISMATCH')=>{if(!ok)throw Object.assign(Error(code),{code});}; const safe=e=>/^[A-Z][A-Z0-9_]+$/.test(e?.code||'')?e.code:'LIVE_IMPORT_FAILED'; const canonical=v=>v&&typeof v==='object'?Array.isArray(v)?'['+v.map(canonical).join(',')+']':'{'+Object.keys(v).sort().map(k=>JSON.stringify(k)+':'+canonical(v[k])).join(',')+'}':JSON.stringify(v); export function validateLiveContext(c){ check(c&&Object.keys(c).length===3&&Object.keys(c).every(k=>['version','taskKey','agentProfileKey'].includes(k)),'INVALID_LIVE_CONTEXT'); check(c.version==='ksf.first-live-import.v1'&&c.taskKey===TASK_KEY&&/^agent-account:[a-f0-9]{64}$/.test(c.agentProfileKey||''),'INVALID_LIVE_CONTEXT');return c; } export async function runFirstLiveImport({context,bundle,invoke,checkpoint=()=>{}}){ validateLiveContext(context); check(bundle?.version==='ksf.first-live-source-batch.v1'&&bundle.taskKey===TASK_KEY&&bundle.batches?.length===2&&bundle.facts?.length===9,'INVALID_LIVE_BUNDLE'); const ids=[],results=[]; const run=async(command,input,suffix)=>{ const requestId=TASK_KEY+':'+suffix; checkpoint({status:'in-flight',command,requestId,imports:structuredClone(ids)}); const r=await invoke(command,input,requestId); checkpoint({status:'received',command,requestId,result:r,imports:structuredClone(ids)});return r; }; const contract=await run('workshop-contract',{},'contract'); check(contract.deduplication?.schema==='ksf.ingest-dedup.v1','DEDUP_CAPABILITY_UNAVAILABLE'); // Validate the entire delivery before issuing any import. for(const batch of bundle.batches){ const {task,capture}=batch; check(task?.source?.dataMode==='live'&&task.source.sourceKind==='web'&&task.source.sourceUrl===capture.url&&task.source.collectedAt===capture.collectedAt,'INVALID_LIVE_BUNDLE'); check(['https://www.uni-president.com.cn/products-jiangbanmian.asp','https://www.uni-president.com.cn/products-qiaomianguan.asp'].includes(capture.url),'INVALID_LIVE_BUNDLE'); check(crypto.createHash('sha256').update(task.source.rawText).digest('hex')===capture.rawTextSha256,'LIVE_SOURCE_HASH_MISMATCH'); for(const row of task.records){ check(['KfCategory','KfProduct','KfEvidence'].includes(row.className)&&row.data.dataMode==='live','INVALID_LIVE_BUNDLE'); if(row.className==='KfEvidence')check(task.source.rawText.includes(row.data.quote)&&row.data.locator.url===capture.url&&row.data.productRef?.$item,'LIVE_QUOTE_MISMATCH'); } } for(const batch of bundle.batches){ const {task,key}=batch; const preflight=await run('workshop-dedup',task,key+':preflight'); check(preflight.readOnly===true&&preflight.schema==='ksf.ingest-dedup.v1','DEDUP_RECEIPT_MISMATCH'); const result=await run('workshop-import',task,key+':import'); ids.push({key,sourceId:result.sourceId,items:result.items}); checkpoint({status:'import-recorded',imports:structuredClone(ids)}); check(result.status==='succeeded'&&result.dataMode==='live'&&result.formalReportPublished===false&&result.sourceId&&result.items?.length===task.records.length,'LIVE_IMPORT_RECEIPT_MISMATCH'); const map=new Map(result.items.map(x=>[x.itemKey,x]));check(map.size===task.records.length,'LIVE_IMPORT_RECEIPT_MISMATCH'); const source=await run('workshop-read',{className:'KfSource',objectId:result.sourceId},key+':read-source'); for(const field of ['rawText','sourceUrl','sourceKind','dataMode'])check(source.record?.[field]===task.source[field],'LIVE_SOURCE_READBACK_MISMATCH'); for(const row of task.records){ const saved=map.get(row.itemKey);check(saved?.className===row.className&&saved.status==='succeeded'&&saved.objectId&&['created','unchanged'].includes(saved.operation),'LIVE_IMPORT_RECEIPT_MISMATCH'); const {record}=await run('workshop-read',{className:row.className,objectId:saved.objectId},key+':read-'+row.itemKey); check(record?.objectId===saved.objectId&&record.dataMode==='live','LIVE_ENTITY_READBACK_MISMATCH'); for(const [field,value]of Object.entries(row.data)){ if(value?.$item)check(record[field]?.objectId===map.get(value.$item)?.objectId,'LIVE_REFERENCE_MISMATCH'); else if(contract.allowedClasses?.find(c=>c.className===row.className)?.fields?.find(f=>f.name===field)?.type==='Date')check(Date.parse(record[field]?.iso||record[field])===Date.parse(value),'LIVE_ENTITY_READBACK_MISMATCH'); else check(canonical(record[field])===canonical(value),'LIVE_ENTITY_READBACK_MISMATCH'); } if(row.className!=='KfCategory')check(record.sourceRef?.objectId===result.sourceId,'LIVE_SOURCE_REFERENCE_MISMATCH'); } results.push({key,sourceId:result.sourceId,sourceOperation:result.sourceOperation,counts:result.counts,items:result.items}); } const categoryIds=results.map(r=>r.items.find(i=>i.className==='KfCategory')?.objectId); check(categoryIds[0]&&categoryIds[0]===categoryIds[1],'LIVE_CATEGORY_REUSE_MISMATCH'); const receipt={ok:true,operation:'first-live-official-sources-imported',taskKey:TASK_KEY,dataMode:'live',sourcePageCount:2,productEntryCount:9,evidenceCount:9,categoryId:categoryIds[0],imports:results,sourceAndEntityReadbackVerified:true,collectionPerformedBy:'Codex',importExecutedBy:'current workshop Agent via secure entry',ecommerceOrSocialCollected:false,formalReportPublished:false,pendingQuestions:bundle.pendingQuestions}; checkpoint({status:'complete',receipt});return receipt; } if(process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url)){ try{ const args=process.argv.slice(2);check(args.length===5&&args[0]==='--input'&&args[2]==='--state-dir'&&args[4]==='--execute','USAGE'); check(process.platform==='linux'&&process.geteuid()===10000,'HERMES_UID_REQUIRED'); const input=args[1],state=args[3],parent=path.dirname(state); check(path.isAbsolute(input)&&path.isAbsolute(state),'ABSOLUTE_PATH_REQUIRED'); for(const p of [input,parent])check(fs.realpathSync(p)===p,'UNSAFE_LIVE_PATH'); for(const [p,mode]of [[input,0o600],[parent,0o700]]){const s=fs.statSync(p);check(s.uid===process.geteuid()&&(s.mode&0o777)===mode,'PRIVATE_LIVE_PATH_REQUIRED');} const context=validateLiveContext(JSON.parse(fs.readFileSync(input,'utf8'))); const bundlePath=path.join(path.dirname(fileURLToPath(import.meta.url)),'first-live-batch.json'); const bytes=fs.readFileSync(bundlePath); const expected='0118c861ae9a7da5e4d361497050200a2e4e595c7a2d76c733a22970cd179326'; check(crypto.createHash('sha256').update(bytes).digest('hex')===expected,'LIVE_BUNDLE_HASH_MISMATCH'); const bundle=JSON.parse(bytes),worker='/opt/data/skills/ksf-workshop-runtime/scripts/ksf-secure.mjs'; check(fs.statSync(worker).isFile(),'SECURE_ENTRY_UNAVAILABLE'); check(!fs.existsSync(state),'LIVE_STATE_EXISTS');fs.mkdirSync(state,{mode:0o700}); const journal={version:'ksf.first-live-journal.v1',at:new Date().toISOString(),taskKey:TASK_KEY,status:'running',steps:[]}; const persist=()=>fs.writeFileSync(path.join(state,'journal.json'),JSON.stringify(journal,null,2),{mode:0o600});persist(); let count=0; const invoke=async(command,task,requestId)=>{ check(['workshop-contract','workshop-dedup','workshop-import','workshop-read'].includes(command),'COMMAND_NOT_ALLOWED'); const name=String(++count).padStart(2,'0')+'-'+command,file=path.join(state,name+'.input.json'); fs.writeFileSync(file,JSON.stringify(task,null,2),{mode:0o600,flag:'wx'}); const p=spawnSync(process.execPath,[worker,command,...(command==='workshop-import'?['--agent-profile',context.agentProfileKey]:[]),'--input',file,'--request-id',requestId],{encoding:'utf8',timeout:660000,maxBuffer:4*1024*1024,windowsHide:true}); fs.writeFileSync(path.join(state,name+'.transport.json'),JSON.stringify({exitCode:p.status,signal:p.signal,spawnFailed:!!p.error,stdout:p.stdout||'',stderr:p.stderr||''}),{mode:0o600,flag:'wx'}); check(!p.error&&!p.signal,'LIVE_REQUEST_UNCERTAIN');let receipt; try{receipt=JSON.parse(p.stdout?.trim()?p.stdout:p.stderr);}catch{check(false,'LIVE_RECEIPT_INVALID');} fs.writeFileSync(path.join(state,name+'.receipt.json'),JSON.stringify(receipt,null,2),{mode:0o600,flag:'wx'}); if(!(p.status===0&&receipt?.ok===true&&receipt.entryResult?.ok===true)){const code=receipt?.entryResult?.error?.code||receipt?.error?.code;check(false,/^[A-Z][A-Z0-9_]+$/.test(code||'')?code:'LIVE_COMMAND_FAILED');} check(receipt.command===command&&receipt.requestId===requestId&&receipt.entryResult.command===command&&receipt.entryResult.requestId===requestId,'LIVE_RECEIPT_BINDING_MISMATCH'); return receipt.entryResult.result; }; try{ const receipt=await runFirstLiveImport({context,bundle,invoke,checkpoint:e=>{journal.status=e.status;journal.steps.push(e);persist();}}); fs.writeFileSync(path.join(state,'summary.json'),JSON.stringify(receipt,null,2),{mode:0o600,flag:'wx'});console.log(JSON.stringify(receipt,null,2)); }catch(e){journal.status='stopped';journal.error={code:safe(e),message:'保留原键及现场,错误不代表零写入;不重试不删目录不换键。'};persist();throw e;} }catch(e){console.error(JSON.stringify({ok:false,error:{code:safe(e),message:'真实资料导入停止;保留编号与回执,不输出原始异常或凭据。'}}));process.exitCode=1;} }