| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- // 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;}
- }
|