@helixlife-ai/xiantao 0.1.21 → 0.1.22

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.
@@ -1,5 +1,9 @@
1
- import{readFile as X}from"node:fs/promises";import{Args as D,Flags as f}from"@oclif/core";import{XtzCommand as O}from"../../base-command.js";import{getAuthContext as $}from"../../lib/auth.js";import{XIANTAO_HISTORY_UUID as N}from"../../lib/constants.js";import{downloadToPath as R}from"../../lib/download.js";import{XtzChoiceRequiredError as E,XtzError as u}from"../../lib/errors.js";import{globalFlags as j,toolCloudFlags as B}from"../../lib/flags.js";import{fetchXiantaoHistoryDownloadButtons as K,getXiantaoHistoryRecordStatus as J,waitForLatestXiantaoHistoryRecord as L,waitForXiantaoHistoryRecordCompletion as V}from"../../lib/history.js";import{deepMerge as y,isJsonObject as F}from"../../lib/json.js";import{confirmPlotArgsMain as q,promptPlotArgsMain as Q,promptPlotCloudRecordSelection as G,promptPlotFilePath as T,promptPlotInputSource as Y,promptPlotMenuSelection as W,promptPlotResultSelection as Z}from"../../lib/plot-interactive.js";import{uploadFile as oo}from"../../lib/plot.js";import{parseSetOverrides as eo,parseSpecificOverrides as to,plotOverrideFlags as io}from"../../lib/plot-options.js";import{buildArgsMainFromSchema as P,buildArgsSpecificFromSchema as H}from"../../lib/plot-schema.js";import{loadPlotArgsMainConfig as ro,resolveXiantaoToolProductUuid as no}from"../../lib/storage.js";import{findDefaultXiantaoCloudInput as x,findDefaultXiantaoRecord as M,listXiantaoUploadFields as C}from"../../lib/tool-inputs.js";import{fetchXiantaoCloudData as A}from"../../lib/xiantao-cloud.js";import{buildSubmitArgsData as lo,resolveXiantaoDownload as z,submitXiantaoPlot as uo,verifyXiantaoPlotUpload as ao}from"../../lib/xiantao-plot.js";import{fetchAllPlotArgs as so,fetchToolMenu as co,fetchToolMenus as mo,resolveToolMenuByCode as fo,updatePlotArgs as ho}from"../../lib/xiantao.js";class wo extends O{resolveToolFileInputs(o,e){if(o&&e&&e.length>0)throw new u("FILE \u4E0E `--file` \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528\u3002");return o?[o]:e??[]}async prepareToolRun(o,e,t){this.validateInputSourceFlags(e,t);const i=await this.getProfile(t.profile),d=await $(i,t.token),r=await this.resolveModule(o,t,d),{moduleId:l,route:n,toolProductUuid:a,uuid:s}=r,c=await so(d,{moduleId:l,uuid:s}),h=await this.resolveInputMode(c,{cloudRequested:!!(t.cloudDataId?.trim()||t.cloudFilter?.trim()||typeof t.cloudIndex=="number"||t.cloudKey?.trim()||t.cloudRecordFile||t.cloudRecordJson),demo:t.demo,fileInputs:e,interactive:t.interactive}),p=await ro(l,t.config),b=y(p,eo(t.set)),S=to(t.specific);let w=c.args_main??[],_=c.args_specific??[],g=y(P(w),b),v=y(H(_),S),m=h.mode==="cloud"?await this.resolveCloudInput(c,t,l,d,s):h.mode==="demo"?this.resolveDemoInput(c,l):h.mode==="record"?this.resolveRecordInput(c,l):await this.uploadAndVerify(i,h.fileInputs??[],{argsMain:g,argsData:c.args_data??[],moduleId:l,uuid:s},d);if(m.schema.length&&(w=m.schema,g=y(P(w),b)),m.input.kind==="cloud"){const k=await ho(d,{argsData:lo(m.duid,m.input),argsKey:m.input.cloud.key,argsMain:g,argsSpecific:v,moduleId:l,uuid:s}),I=x(k.args_data??[]);I&&(m={...m,input:{kind:"cloud",cloud:{key:I.key,label:I.label,record:this.normalizeCloudRecord(I.record)}}}),w=k.args_main??w,_=k.args_specific??_,g=y(P(w),b),v=y(H(_),S)}return{agent:i,argsMain:g,argsSpecific:v,argsSpecificSchema:_,auth:d,duid:m.duid,input:m.input,inputMode:h.mode,inputSummary:this.summarizePreparedInput(m.input),moduleId:l,notice:c.notice??"",route:n,schema:w,toolProductUuid:a,uuid:s}}async executeToolRun(o,e,t){const i=await this.prepareToolRun(o,e,t);let d=i.argsMain;const r=i.argsSpecific;t.interactive&&(d=await Q(i.schema??[],d),await q(d));const l=Date.now(),n=await uo(i.auth,{argsMain:d,argsSpecific:r,duid:i.duid,input:i.input,moduleId:i.moduleId,route:i.route,uuid:i.uuid});if(n.asyncSubmission)return this.resolveAsyncToolRun(i,d,r,t,l,n.message);const a=t.download?await this.downloadResult(i.auth,{downloadPath:t.download,downloads:n.downloads,file:n.file,moduleId:i.moduleId,uuid:i.uuid}):await this.downloadInteractiveResults(i.auth,{choice:t.interactive?await Z({downloads:n.downloads,hasFile:!!n.file}):{downloadFile:!1,downloads:[]},file:n.file,moduleId:i.moduleId,uuid:i.uuid}),s=a[0];return{data:{agent:i.agent,args_main:d,args_specific:r,body:n.body,download_path:s,download_paths:a,downloads:n.downloads,duid:i.duid,file:n.file??null,history:null,history_hint:null,...i.inputSummary,mode:i.inputMode,module_id:i.moduleId,notice:i.notice,result_source:"direct",route:i.route,submission_message:n.message,tool_product_uuid:i.toolProductUuid,uuid:i.uuid},text:this.formatResultText(n,a,t.interactive&&!t.download)}}async resolveAsyncToolRun(o,e,t,i,d,r){const l=await L(o.auth,{intervalMs:3e3,moduleId:o.moduleId,submittedAtMs:d,timeoutMs:i.download?6e4:12e3}),n=l?this.toHistorySummary(l,o.moduleId):null;if(!i.download)return{data:{agent:o.agent,args_main:e,args_specific:t,body:"",download_path:void 0,download_paths:[],downloads:[],duid:o.duid,file:null,history:n,history_hint:this.buildHistoryHint(n),...o.inputSummary,mode:o.inputMode,module_id:o.moduleId,notice:o.notice,result_source:"history",route:o.route,submission_message:r,tool_product_uuid:o.toolProductUuid,uuid:o.uuid},text:this.formatAsyncHistoryText(n,r)};if(!l?.fuid?.trim())return{data:{agent:o.agent,args_main:e,args_specific:t,body:"",download_path:void 0,download_paths:[],downloads:[],duid:o.duid,file:null,history:n,history_hint:this.buildHistoryHint(n),...o.inputSummary,mode:o.inputMode,module_id:o.moduleId,notice:o.notice,result_source:"history",route:o.route,submission_message:r,tool_product_uuid:o.toolProductUuid,uuid:o.uuid},text:this.formatAsyncHistoryText(n,`${r}\uFF0C\u4F46\u6682\u672A\u5B9A\u4F4D\u5230\u5386\u53F2\u8BB0\u5F55\u3002`)};const a=await V(o.auth,{fuid:l.fuid.trim(),intervalMs:3e3,timeoutMs:6e4}),s=a?this.toHistorySummary(a,o.moduleId):n;if(!a?.fuid?.trim())return{data:{agent:o.agent,args_main:e,args_specific:t,body:"",download_path:void 0,download_paths:[],downloads:[],duid:o.duid,file:null,history:s,history_hint:this.buildHistoryHint(s),...o.inputSummary,mode:o.inputMode,module_id:o.moduleId,notice:o.notice,result_source:"history",route:o.route,submission_message:`${r}\uFF0C\u4F46\u7B49\u5F85\u5386\u53F2\u8BB0\u5F55\u5B8C\u6210\u8D85\u65F6\u3002`,tool_product_uuid:o.toolProductUuid,uuid:o.uuid},text:this.formatAsyncHistoryText(s,`${r}\uFF0C\u4F46\u7B49\u5F85\u5386\u53F2\u8BB0\u5F55\u5B8C\u6210\u8D85\u65F6\u3002`)};const{body:c,downloads:h,paths:p}=await this.downloadAsyncHistoryResult(o.auth,{downloadPath:i.download,fuid:a.fuid.trim(),moduleId:o.moduleId});return{data:{agent:o.agent,args_main:e,args_specific:t,body:c,download_path:p[0],download_paths:p,downloads:h,duid:o.duid,file:null,history:s,history_hint:this.buildHistoryHint(s),...o.inputSummary,mode:o.inputMode,module_id:o.moduleId,notice:o.notice,result_source:"history",route:o.route,submission_message:r,tool_product_uuid:o.toolProductUuid,uuid:o.uuid},text:this.formatAsyncHistoryDownloadText(s,p)}}async downloadAsyncHistoryResult(o,e){let t;for(let i=0;i<4;i+=1){const d=await K(o,{fuid:e.fuid});try{const r=await this.downloadResult(o,{downloadPath:e.downloadPath,downloads:d.downloads,moduleId:e.moduleId,uuid:N});return{body:d.body,downloads:d.downloads,paths:r}}catch(r){if(!(r instanceof u)||!this.isRetryableAsyncDownloadError(r)||i===3)throw r;t=r,await this.sleep(3e3)}}throw t??new u("\u4E0B\u8F7D\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")}formatResultText(o,e,t){const i=[];if(o.file&&i.push(o.file),!o.file&&(o.downloads.length>0||o.body)&&i.push("\u5206\u6790\u5B8C\u6210"),!o.file&&!o.body&&o.downloads.length===0)return"\u63D0\u4EA4\u5B8C\u6210";if(o.downloads.length>0&&!t)for(const d of o.downloads)i.push(`${d.label} (${d.device})`);for(const d of e)i.push(d);return i.join(`
2
- `)}formatAsyncHistoryText(o,e){const t=[e];return o&&t.push(`\u5386\u53F2\u8BB0\u5F55: ${o.fuid} (${o.status})`),t.push(this.buildHistoryHint(o)),t.join(`
3
- `)}formatAsyncHistoryDownloadText(o,e){const t=[];o&&t.push(`\u5386\u53F2\u8BB0\u5F55: ${o.fuid} (${o.status})`);for(const i of e)t.push(i);return t.join(`
4
- `)}async downloadResult(o,e){if(e.downloads.length>0){const t=this.pickDownloadItem(e.downloads,e.downloadPath);if(!t)throw new u("\u5F53\u524D\u6A21\u5757\u8FD4\u56DE\u591A\u4E2A\u53EF\u4E0B\u8F7D\u7ED3\u679C\uFF0C\u8BF7\u5C06 `--download` \u8DEF\u5F84\u6539\u4E3A\u5E26\u76EE\u6807\u6269\u5C55\u540D\u7684\u6587\u4EF6\u540D\uFF0C\u6216\u4F7F\u7528 `--interactive` \u9009\u62E9\u3002");const i=await z(o,{item:t,moduleId:e.moduleId,uuid:e.uuid});return[await R(i.url,e.downloadPath)]}if(e.file)return[await R(e.file,e.downloadPath)];throw new u("\u5F53\u524D\u6A21\u5757\u672A\u8FD4\u56DE\u53EF\u4E0B\u8F7D\u6587\u4EF6\u3002")}pickDownloadItem(o,e){const t=this.inferDownloadDevice(e);if(t){const d=o.filter(r=>this.normalizeDevice(r.device)===t);if(d.length===1)return d[0]}const i=o.filter(d=>d.endpoint==="public.output.download-result");if(i.length===1)return i[0];if(o.length===1)return o[0]}inferDownloadDevice(o){if(!o)return;const e=o.trim().split(".").pop()?.toLowerCase();if(e)return this.normalizeDevice(e)}normalizeDevice(o){const e=o.trim().toLowerCase();return e==="tif"?"tiff":e==="jpg"?"jpeg":e}toHistorySummary(o,e){const t=o.fuid?.trim();return t?{fuid:t,id:typeof o.id=="number"?o.id:null,module_id:o.module_id?.trim()||e,module_name:o.module_name?.trim()||"",name:o.name?.trim()||"",status:J(o),time:o.time?.trim()||"",type:o.type?.trim()||""}:null}buildHistoryHint(o){return o?`\u53EF\u4F7F\u7528 \`xt history download ${o.fuid} --device pdf\` \u6216 \`xt history list\` \u67E5\u770B\u7ED3\u679C`:"\u53EF\u4F7F\u7528 `xt history list` \u67E5\u770B\u4EFB\u52A1\u8FDB\u5EA6"}async downloadSelectedResults(o,e){const t=[];for(const i of e.downloads){const d=await z(o,{item:i,moduleId:e.moduleId,uuid:e.uuid});t.push(await R(d.url,d.fileName))}return t}async downloadInteractiveResults(o,e){const t=[];return e.choice.downloadFile&&e.file&&t.push(await R(e.file)),e.choice.downloads.length>0&&t.push(...await this.downloadSelectedResults(o,{downloads:e.choice.downloads,moduleId:e.moduleId,uuid:e.uuid})),t}isRetryableAsyncDownloadError(o){return o.message.includes("\u4E0B\u8F7D\u5931\u8D25")||o.message.includes("\u672A\u83B7\u53D6\u5230\u4E0B\u8F7D\u94FE\u63A5")}async sleep(o){await new Promise(e=>setTimeout(e,o))}async resolveInputMode(o,e){if(e.demo)return{mode:"demo"};if(e.fileInputs.length>0)return{fileInputs:e.fileInputs,mode:"upload"};if(e.cloudRequested)return{mode:"cloud"};if(this.hasRecordInput(o))return{mode:"record"};if(this.hasCloudInput(o))return{mode:"cloud"};if(!e.interactive)return{mode:"upload"};if(!this.hasDemoInput(o))return{fileInputs:[await T()],mode:"upload"};const t=await Y();return t==="demo"?{mode:t}:{fileInputs:[await T()],mode:t}}resolveDemoInput(o,e){const t=o.id?.duid?.trim();if(!t)throw new u(`\u6A21\u5757 ${e} \u672A\u8FD4\u56DE demo duid\uFF0C\u65E0\u6CD5\u4F7F\u7528 \`--demo\`\u3002`);const i=C(o.args_data??[]);if(!i.length||i.some(d=>!d.defaultUpload))throw new u(`\u6A21\u5757 ${e} \u672A\u8FD4\u56DE\u53EF\u7528\u7684 demo \u6587\u4EF6\u4FE1\u606F\uFF0C\u65E0\u6CD5\u4F7F\u7528 \`--demo\`\u3002`);return{duid:t,input:{kind:"upload",uploads:i.map(d=>({key:d.key,label:d.label,upload:{fileName:d.defaultUpload.fileName,fileOss:d.defaultUpload.fileOss,fileSize:d.defaultUpload.fileSize}}))},schema:[]}}hasDemoInput(o){if(!o.id?.duid?.trim())return!1;const t=C(o.args_data??[]);return t.length>0&&t.every(i=>!!i.defaultUpload)}async resolveCloudInput(o,e,t,i,d){const r=x(o.args_data??[]),l=e.cloudKey?.trim()||r?.key||"";if(!l)throw new u(`\u6A21\u5757 ${t} \u672A\u8FD4\u56DE\u53EF\u7528\u7684\u4E91\u7AEF\u6570\u636E\u53C2\u6570\uFF0C\u8BF7\u663E\u5F0F\u4F20\u5165 \`--cloudKey\`.`);const n=await this.resolveCloudRecord(i,e,{argsKey:l,defaultRecord:r?.record,moduleId:t,uuid:d});if(!n)throw new u(`\u6A21\u5757 ${t} \u672A\u8FD4\u56DE\u9ED8\u8BA4\u4E91\u7AEF\u6570\u636E\uFF0C\u8BF7\u4F20\u5165 \`--cloudRecordJson\` \u6216 \`--cloudRecordFile\`.`);return{duid:o.id?.duid?.trim()||"cloud",input:{kind:"cloud",cloud:{key:l,label:r?.label??"",record:this.normalizeCloudRecord(n)}},schema:[]}}resolveRecordInput(o,e){const t=o.id?.duid?.trim();if(!t)throw new u(`\u6A21\u5757 ${e} \u672A\u8FD4\u56DE record duid\uFF0C\u65E0\u6CD5\u4F7F\u7528\u5386\u53F2\u8BB0\u5F55\u8F93\u5165\u3002`);const i=M(o.args_data??[]);if(!i)throw new u(`\u6A21\u5757 ${e} \u672A\u8FD4\u56DE\u53EF\u7528\u7684\u6570\u636E\u8BB0\u5F55\uFF0C\u65E0\u6CD5\u76F4\u63A5\u8FD0\u884C\u3002`);return{duid:t,input:{kind:"record",record:{key:i.key,label:i.label,moduleId:i.moduleId,moduleName:i.moduleName,recordId:i.recordId,recordName:i.recordName,time:i.time}},schema:[]}}hasRecordInput(o){return!!(o.id?.duid?.trim()&&M(o.args_data??[]))}hasCloudInput(o){return!!x(o.args_data??[])}async uploadAndVerify(o,e,t,i){const d=await this.uploadFiles(o,e,t.argsData??[],t.moduleId),r=await ao(i,{argsMain:t.argsMain,moduleId:t.moduleId,uploads:d,uuid:t.uuid});return{duid:r.duid,input:{kind:"upload",uploads:d},schema:r.schema}}summarizePreparedInput(o){if(o.kind==="cloud")return{file_name:null,file_oss:null,file_size:null,input_cloud:this.summarizeCloudInput(o.cloud),input_record:null,input_uploads:null};if(o.kind==="record")return{file_name:null,file_oss:null,file_size:null,input_cloud:null,input_record:{label:o.record.label,module_id:o.record.moduleId,module_name:o.record.moduleName,record_id:o.record.recordId,record_name:o.record.recordName,time:o.record.time},input_uploads:null};const e=o.uploads.map(i=>({file_name:i.upload.fileName,file_oss:i.upload.fileOss,file_size:i.upload.fileSize,key:i.key,label:i.label})),t=e.length===1?e[0]:null;return{file_name:t?.file_name??null,file_oss:t?.file_oss??null,file_size:t?.file_size??null,input_cloud:null,input_record:null,input_uploads:e}}summarizeCloudInput(o){return{data_filter:this.readCloudOptionValue(o.record.data_filter),data_id:typeof o.record.data_id=="string"?o.record.data_id.trim():"",data_process:this.readCloudOptionValue(o.record.data_process),key:o.key,label:o.label,record:structuredClone(o.record),record_label:typeof o.record.label=="string"?o.record.label.trim():""}}readCloudOptionValue(o){return F(o)&&(typeof o.value=="string"?o.value.trim():"")||null}async resolveCloudRecord(o,e,t){return e.cloudRecordJson?this.parseCloudRecord(e.cloudRecordJson,"--cloudRecordJson"):e.cloudRecordFile?this.parseCloudRecord(await X(e.cloudRecordFile,"utf8"),"--cloudRecordFile"):e.cloudFilter?.trim()||e.cloudDataId?.trim()||typeof e.cloudIndex=="number"?this.resolveCloudRecordByQuery(o,e,t):t.defaultRecord}parseCloudRecord(o,e){let t;try{t=JSON.parse(o)}catch{throw new u(`${e} \u4E0D\u662F\u5408\u6CD5 JSON\u3002`)}if(!F(t))throw new u(`${e} \u5FC5\u987B\u662F JSON \u5BF9\u8C61\u3002`);return t}normalizeCloudRecord(o){const e={};for(const[t,i]of Object.entries(o))i!==void 0&&(e[t]=structuredClone(i));return(typeof e.type!="string"||!e.type.trim())&&(e.type="cloud"),e}validateInputSourceFlags(o,e){const t=!!(e.cloudRecordJson||e.cloudRecordFile),i=!!(e.cloudDataId?.trim()||e.cloudFilter?.trim()||typeof e.cloudIndex=="number"),d=t||i;if(e.cloudRecordJson&&e.cloudRecordFile)throw new u("`--cloudRecordJson` \u4E0E `--cloudRecordFile` \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528\u3002");if(t&&i)throw new u("\u663E\u5F0F\u4E91\u7AEF\u8BB0\u5F55\u53C2\u6570\u4E0D\u80FD\u4E0E `--cloudFilter` / `--cloudDataId` / `--cloudIndex` \u540C\u65F6\u4F7F\u7528\u3002");if(e.demo&&d)throw new u("`--demo` \u4E0D\u80FD\u4E0E\u4E91\u7AEF\u6570\u636E\u8BB0\u5F55\u53C2\u6570\u540C\u65F6\u4F7F\u7528\u3002");if(o.length>0&&d)throw new u("`--file` \u4E0D\u80FD\u4E0E\u4E91\u7AEF\u6570\u636E\u8BB0\u5F55\u53C2\u6570\u540C\u65F6\u4F7F\u7528\u3002")}async resolveCloudRecordByQuery(o,e,t){const i=await this.fetchCloudRecords(o,{argsKey:t.argsKey,filter:e.cloudFilter?.trim(),moduleId:t.moduleId,selectedRecord:t.defaultRecord,uuid:t.uuid});if(i.length===0){const r=e.cloudFilter?.trim();throw r?new u(`\u672A\u627E\u5230\u5339\u914D\u4E91\u7AEF\u6570\u636E: ${r}`):new u("\u5F53\u524D\u6A21\u5757\u6CA1\u6709\u53EF\u9009\u7684\u4E91\u7AEF\u6570\u636E\u8BB0\u5F55\u3002")}const d=e.cloudDataId?.trim();if(d){const r=i.find(l=>(typeof l.data_id=="string"?l.data_id.trim():"")===d);if(!r)throw new u(`\u672A\u627E\u5230 data_id=${d} \u5BF9\u5E94\u7684\u4E91\u7AEF\u6570\u636E\u3002`);return r}if(typeof e.cloudIndex=="number"){const r=i[e.cloudIndex];if(!r)throw new u(`\u4E91\u7AEF\u6570\u636E\u7D22\u5F15\u8D85\u51FA\u8303\u56F4: ${e.cloudIndex}\uFF0C\u5F53\u524D\u5171\u6709 ${i.length} \u6761\u3002`);return r}if(i.length===1)return i[0];if(e.interactive)return this.normalizeCloudRecord(await G(i));throw new E(this.buildCloudSelectionHint(i,e.cloudFilter?.trim()),this.buildCloudSelectionData(i,e.cloudFilter?.trim()))}async fetchCloudRecords(o,e){const t=await A(o,{argsKey:e.argsKey,currentPage:1,filter:e.filter,moduleId:e.moduleId,selectedRecord:e.selectedRecord,uuid:e.uuid}),i=t.records.map(d=>this.normalizeCloudRecord(d));for(let d=t.currentPage+1;d<=t.lastPage;d+=1){const r=await A(o,{argsKey:e.argsKey,currentPage:d,filter:e.filter,moduleId:e.moduleId,selectedRecord:e.selectedRecord,uuid:e.uuid});i.push(...r.records.map(l=>this.normalizeCloudRecord(l)))}return i}buildCloudSelectionHint(o,e){const t=[e?`\u5339\u914D\u5230\u591A\u4E2A\u4E91\u7AEF\u6570\u636E: ${e}`:"\u5339\u914D\u5230\u591A\u4E2A\u4E91\u7AEF\u6570\u636E","\u8BF7\u4F7F\u7528 `--cloudIndex` \u6216 `--cloudDataId` \u6307\u5B9A\u5176\u4E2D\u4E00\u6761\uFF1A"];return o.forEach((i,d)=>{const r=typeof i.data_id=="string"?i.data_id.trim():"",l=typeof i.label=="string"?i.label.trim():"";t.push(` [${d}] ${l||r}`)}),t.join(`
5
- `)}buildCloudSelectionData(o,e){return{choices:o.map((t,i)=>{const d=typeof t.data_id=="string"?t.data_id.trim():"",r=typeof t.label=="string"?t.label.trim():"";return{data_id:d,index:i,label:r||d}}),filter:e??"",selection_type:"cloud_record"}}async uploadFiles(o,e,t,i){const d=C(t??[]),r=this.resolveUploadInputs(e,d,i),l=await $(o),n=[];for(const a of r){const s=await oo(l,a.filePath);n.push({key:a.key,label:a.label,upload:s})}return n}resolveUploadInputs(o,e,t){if(!e.length)throw new u(`\u6A21\u5757 ${t} \u672A\u68C0\u6D4B\u5230\u53EF\u4E0A\u4F20\u8F93\u5165\uFF0C\u4E0D\u80FD\u4F7F\u7528 \`--file\`\u3002`);if(!o.length)throw e.length===1?new u("\u901A\u7528\u6A21\u5F0F\u8BF7\u4F20\u5165 FILE / `--file <xlsx>`\uFF0C\u6216\u6539\u7528 `--demo`\u3002"):new u(`\u6A21\u5757 ${t} \u9700\u8981\u591A\u4E2A\u4E0A\u4F20\u5B57\u6BB5\uFF0C\u8BF7\u4F7F\u7528 \`--file key=path\`\u3002\u53EF\u7528\u5B57\u6BB5: ${e.map(n=>n.key).join(", ")}`);const[i]=e;if(e.length===1&&o.length===1){const n=this.parseUploadFileInput(o[0]);if(n.key&&n.key!==i.key)throw new u(`\u6A21\u5757 ${t} \u4EC5\u652F\u6301\u4E0A\u4F20\u5B57\u6BB5 ${i.key}\uFF0C\u6536\u5230 ${n.key}\u3002`);return[{filePath:n.path,key:i.key,label:i.label}]}const d=new Map(e.map(n=>[n.key,n])),r=new Map;for(const n of o){const a=this.parseUploadFileInput(n);if(!a.key){if(e.length===1){if(r.has(i.key))throw new u(`\u6A21\u5757 ${t} \u4EC5\u9700\u8981 1 \u4E2A\u4E0A\u4F20\u6587\u4EF6\uFF0C\u6536\u5230\u91CD\u590D\u8F93\u5165\u3002`);r.set(i.key,a.path);continue}throw new u(`\u6A21\u5757 ${t} \u9700\u8981\u591A\u4E2A\u4E0A\u4F20\u5B57\u6BB5\uFF0C\u8BF7\u4F7F\u7528 \`--file key=path\`\u3002\u53EF\u7528\u5B57\u6BB5: ${e.map(c=>c.key).join(", ")}`)}const s=d.get(a.key);if(!s)throw new u(`\u6A21\u5757 ${t} \u4E0D\u5B58\u5728\u4E0A\u4F20\u5B57\u6BB5 ${a.key}\u3002\u53EF\u7528\u5B57\u6BB5: ${e.map(c=>c.key).join(", ")}`);if(r.has(s.key))throw new u(`\u4E0A\u4F20\u5B57\u6BB5 ${s.key} \u91CD\u590D\u4F20\u5165\u3002`);r.set(s.key,a.path)}const l=e.filter(n=>n.required&&!r.has(n.key));if(l.length>0)throw new u(`\u6A21\u5757 ${t} \u7F3A\u5C11\u5FC5\u586B\u4E0A\u4F20\u5B57\u6BB5: ${l.map(n=>n.key).join(", ")}`);return e.flatMap(n=>{const a=r.get(n.key);return a?[{filePath:a,key:n.key,label:n.label}]:[]})}parseUploadFileInput(o){const e=o.trim();if(!e)throw new u("`--file` \u4E0D\u80FD\u4E3A\u7A7A\u3002");const t=e.indexOf("=");if(t<=0)return{path:e};const i=e.slice(0,t).trim(),d=e.slice(t+1).trim();if(!i||!d)throw new u("\u591A\u4E0A\u4F20\u6A21\u5757\u8BF7\u4F7F\u7528 `--file key=path`\u3002");return{key:i,path:d}}async resolveModule(o,e,t){const i=o?.trim(),d=e.route?.trim(),r=e.uuid?.trim(),l=await no(e.toolProductUuid);if(!i){if(!e.interactive)throw new u("\u8BF7\u4F20\u5165 `module_id`\uFF0C\u6216\u4F7F\u7528 `--interactive --file <xlsx>` \u5148\u4ECE\u83DC\u5355\u9009\u62E9\u5DE5\u5177\u3002");const a=await W(this.sortTopLevelMenus(await mo(t,l)));return{moduleId:a.code,route:d??a.route,toolProductUuid:l,uuid:r??a.uuid}}if(d&&r)return{moduleId:i,route:d,toolProductUuid:l,uuid:r};const n=e.menuUuid?.trim();if(n&&l){const a=await co(t,n,l),s=d??this.requireMenuRoute(a),c=a.code?.trim();if(c&&c!==i)throw new u(`\u83DC\u5355\u6A21\u5757 code \u4E3A ${c}\uFF0C\u4E0E\u4F20\u5165\u7684 module_id ${i} \u4E0D\u4E00\u81F4\u3002`);return{moduleId:i,route:s,toolProductUuid:l,uuid:r??n}}if(l){const a=await fo(t,l,i);return{moduleId:i,route:d??a.route,toolProductUuid:l,uuid:r??a.uuid}}if(!r)throw new u("\u901A\u7528\u6A21\u5F0F\u9700\u8981\u4F20\u5165 `--uuid`\uFF0C\u6216\u4F7F\u7528\u9ED8\u8BA4/\u663E\u5F0F `toolProductUuid` \u81EA\u52A8\u89E3\u6790\u3002");if(!d)throw new u("\u901A\u7528\u6A21\u5F0F\u9700\u8981\u4F20\u5165 `--route`\uFF0C\u6216\u4F7F\u7528\u9ED8\u8BA4/\u663E\u5F0F `toolProductUuid` \u81EA\u52A8\u89E3\u6790\u3002");return{moduleId:i,route:d,toolProductUuid:l,uuid:r}}sortTopLevelMenus(o){const e=["\u57FA\u7840\u7ED8\u56FE","\u8868\u8FBE\u5DEE\u5F02","\u529F\u80FD\u805A\u7C7B","\u4EA4\u4E92\u7F51\u7EDC","\u4E34\u5E8A\u610F\u4E49","\u5176\u4ED6"],t=new Map(e.map((i,d)=>[i,d]));return[...o].sort((i,d)=>{const r=t.get(i.title?.trim()??"")??Number.MAX_SAFE_INTEGER,l=t.get(d.title?.trim()??"")??Number.MAX_SAFE_INTEGER;return r-l})}requireMenuRoute(o){const e=o.route;if(typeof e!="string"||!e.trim())throw new u("\u83DC\u5355\u672A\u8FD4\u56DE\u53EF\u7528 route\uFF0C\u8BF7\u6539\u7528 `--route` \u663E\u5F0F\u6307\u5B9A\u3002");return e.trim()}}class U extends wo{static description="Run a Xiantao bioinformatics tool";static args={tool:D.string({description:"Tool id; optional with --interactive to choose from menus"}),file:D.string({description:"Path to the local xlsx file; optional with --demo or --interactive"})};static flags={...j,...B,...io,demo:f.boolean({default:!1,description:"Use the module demo data returned by fetch-all instead of uploading a local file"}),file:f.string({description:"Path to the local xlsx file; repeat or use KEY=PATH for named upload fields",multiple:!0}),download:f.string({description:"Download the generated file or preferred analysis result to this local path after submission"}),interactive:f.boolean({default:!1,description:"Prompt for dynamic args before submitting the module"}),menuUuid:f.string({description:"Tool menu UUID from /products/apply/:toolProductUuid/analyse/:uuid"}),route:f.string({description:"Tool route like app1.violin_flat in generic mode"}),token:f.string({description:"Bearer token for agent.helixlife.cn xiantao APIs; falls back to the stored agent token"}),toolProductUuid:f.string({description:"tool_product_uuid used to auto-resolve module UUID and route in generic mode; defaults to the main Xiantao product UUID"}),uuid:f.string({description:"Tool UUID used in generic mode for fetch-all and verify-upload; optional when --toolProductUuid is provided"})};async run(){this.warnIfLegacyPlotCommand();const{args:o,flags:e}=await this.parse(U);if(e.interactive&&e.json)throw new u("`--interactive` \u4E0D\u80FD\u4E0E `--json` \u540C\u65F6\u4F7F\u7528\u3002");const t=this.resolveToolFileInputs(o.file,e.file),i=await this.executeToolRun(o.tool,t,e);this.print(e,i.data,i.text,{profile:i.data.agent})}}export{wo as ToolRunCommandBase,U as default};
1
+ import{readFile as L}from"node:fs/promises";import{Args as S,Flags as h}from"@oclif/core";import{XtzCommand as X}from"../../base-command.js";import{getAuthContext as M}from"../../lib/auth.js";import{XIANTAO_HISTORY_UUID as N}from"../../lib/constants.js";import{downloadToPath as g}from"../../lib/download.js";import{XtzChoiceRequiredError as O,XtzError as a}from"../../lib/errors.js";import{globalFlags as B,toolCloudFlags as E}from"../../lib/flags.js";import{fetchXiantaoHistoryDownloadButtons as j,getXiantaoHistoryRecordStatus as K,waitForLatestXiantaoHistoryRecord as J,waitForXiantaoHistoryRecordCompletion as V}from"../../lib/history.js";import{deepMerge as p,isJsonObject as U}from"../../lib/json.js";import{confirmPlotArgsMain as q,promptPlotArgsMain as Q,promptPlotCloudRecordSelection as G,promptPlotFilePath as F,promptPlotInputSource as Y,promptPlotMenuSelection as W,promptPlotResultSelection as Z}from"../../lib/plot-interactive.js";import{uploadFile as ee}from"../../lib/plot.js";import{parseSetOverrides as oe,parseSpecificOverrides as te,plotOverrideFlags as ie}from"../../lib/plot-options.js";import{buildArgsMainFromSchema as P,buildArgsSpecificFromSchema as T}from"../../lib/plot-schema.js";import{loadPlotArgsMainConfig as de,resolveXiantaoToolProductUuid as ne}from"../../lib/storage.js";import{findDefaultXiantaoCloudInput as D,findDefaultXiantaoRecord as H,listXiantaoUploadFields as $}from"../../lib/tool-inputs.js";import{fetchXiantaoCloudData as z}from"../../lib/xiantao-cloud.js";import{buildSubmitArgsData as re,resolveXiantaoDownload as A,submitXiantaoPlot as le,verifyXiantaoPlotUpload as ae}from"../../lib/xiantao-plot.js";import{fetchAllPlotArgs as ue,fetchToolMenu as se,fetchToolMenus as ce,resolveToolMenuByCode as me,updatePlotArgs as he}from"../../lib/xiantao.js";class fe extends X{resolveToolFileInputs(e,o){if(e&&o&&o.length>0)throw new a("FILE \u4E0E `--file` \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528\u3002");return e?[e]:o??[]}async prepareToolRun(e,o,t){this.validateInputSourceFlags(o,t);const i=await this.getProfile(t.profile),d=await M(i,t.token),n=await this.resolveModule(e,t,d),{moduleId:l,route:r,toolProductUuid:u,uuid:s}=n,c=await ue(d,{moduleId:l,uuid:s}),f=await this.resolveInputMode(c,{cloudRequested:!!(t.cloudDataId?.trim()||t.cloudFilter?.trim()||typeof t.cloudIndex=="number"||t.cloudKey?.trim()||t.cloudRecordFile||t.cloudRecordJson),demo:t.demo,fileInputs:o,interactive:t.interactive}),y=await de(l,t.config),R=p(y,oe(t.set)),x=te(t.specific);let w=c.args_main??[],_=c.args_specific??[],I=p(P(w),R),v=p(T(_),x),m=f.mode==="cloud"?await this.resolveCloudInput(c,t,l,d,s):f.mode==="demo"?this.resolveDemoInput(c,l):f.mode==="record"?this.resolveRecordInput(c,l):await this.uploadAndVerify(i,f.fileInputs??[],{argsMain:I,argsData:c.args_data??[],moduleId:l,uuid:s},d);if(m.schema.length&&(w=m.schema,I=p(P(w),R)),m.input.kind==="cloud"){const k=await he(d,{argsData:re(m.duid,m.input),argsKey:m.input.cloud.key,argsMain:I,argsSpecific:v,moduleId:l,uuid:s}),b=D(k.args_data??[]);b&&(m={...m,input:{kind:"cloud",cloud:{key:b.key,label:b.label,record:this.normalizeCloudRecord(b.record)}}}),w=k.args_main??w,_=k.args_specific??_,I=p(P(w),R),v=p(T(_),x)}return{agent:i,argsMain:I,argsSpecific:v,argsSpecificSchema:_,auth:d,duid:m.duid,input:m.input,inputMode:f.mode,inputSummary:this.summarizePreparedInput(m.input),moduleId:l,notice:c.notice??"",route:r,schema:w,toolProductUuid:u,uuid:s}}async executeToolRun(e,o,t){this.validateDownloadFlags(t);const i=await this.prepareToolRun(e,o,t);let d=i.argsMain;const n=i.argsSpecific;t.interactive&&(d=await Q(i.schema??[],d),await q(d));const l=Date.now(),r=await le(i.auth,{argsMain:d,argsSpecific:n,duid:i.duid,input:i.input,moduleId:i.moduleId,route:i.route,uuid:i.uuid});if(r.asyncSubmission)return this.resolveAsyncToolRun(i,d,n,t,l,r.message);const u=t.download?await this.downloadResult(i.auth,{downloadPath:t.download,downloadItem:t.downloadItem,downloadLabel:t.downloadLabel,downloads:r.downloads,file:r.file,moduleId:i.moduleId,uuid:i.uuid}):await this.downloadInteractiveResults(i.auth,{choice:t.interactive?await Z({downloads:r.downloads,hasFile:!!r.file}):{downloadFile:!1,downloads:[]},file:r.file,moduleId:i.moduleId,uuid:i.uuid}),s=u[0];return{data:{agent:i.agent,args_main:d,args_specific:n,body:r.body,download_path:s,download_paths:u,downloads:r.downloads,duid:i.duid,file:r.file??null,history:null,history_hint:null,...i.inputSummary,mode:i.inputMode,module_id:i.moduleId,notice:i.notice,result_source:"direct",route:i.route,submission_message:r.message,tool_product_uuid:i.toolProductUuid,uuid:i.uuid},text:this.formatResultText(r,u,t.interactive&&!t.download)}}async resolveAsyncToolRun(e,o,t,i,d,n){const l=await J(e.auth,{intervalMs:3e3,moduleId:e.moduleId,submittedAtMs:d,timeoutMs:i.download?6e4:12e3}),r=l?this.toHistorySummary(l,e.moduleId):null;if(!i.download)return{data:{agent:e.agent,args_main:o,args_specific:t,body:"",download_path:void 0,download_paths:[],downloads:[],duid:e.duid,file:null,history:r,history_hint:this.buildHistoryHint(r),...e.inputSummary,mode:e.inputMode,module_id:e.moduleId,notice:e.notice,result_source:"history",route:e.route,submission_message:n,tool_product_uuid:e.toolProductUuid,uuid:e.uuid},text:this.formatAsyncHistoryText(r,n)};if(!l?.fuid?.trim())return{data:{agent:e.agent,args_main:o,args_specific:t,body:"",download_path:void 0,download_paths:[],downloads:[],duid:e.duid,file:null,history:r,history_hint:this.buildHistoryHint(r),...e.inputSummary,mode:e.inputMode,module_id:e.moduleId,notice:e.notice,result_source:"history",route:e.route,submission_message:n,tool_product_uuid:e.toolProductUuid,uuid:e.uuid},text:this.formatAsyncHistoryText(r,`${n}\uFF0C\u4F46\u6682\u672A\u5B9A\u4F4D\u5230\u5386\u53F2\u8BB0\u5F55\u3002`)};const u=await V(e.auth,{fuid:l.fuid.trim(),intervalMs:3e3,timeoutMs:6e4}),s=u?this.toHistorySummary(u,e.moduleId):r;if(!u?.fuid?.trim())return{data:{agent:e.agent,args_main:o,args_specific:t,body:"",download_path:void 0,download_paths:[],downloads:[],duid:e.duid,file:null,history:s,history_hint:this.buildHistoryHint(s),...e.inputSummary,mode:e.inputMode,module_id:e.moduleId,notice:e.notice,result_source:"history",route:e.route,submission_message:`${n}\uFF0C\u4F46\u7B49\u5F85\u5386\u53F2\u8BB0\u5F55\u5B8C\u6210\u8D85\u65F6\u3002`,tool_product_uuid:e.toolProductUuid,uuid:e.uuid},text:this.formatAsyncHistoryText(s,`${n}\uFF0C\u4F46\u7B49\u5F85\u5386\u53F2\u8BB0\u5F55\u5B8C\u6210\u8D85\u65F6\u3002`)};const{body:c,downloads:f,paths:y}=await this.downloadAsyncHistoryResult(e.auth,{downloadPath:i.download,downloadItem:i.downloadItem,downloadLabel:i.downloadLabel,fuid:u.fuid.trim(),moduleId:e.moduleId});return{data:{agent:e.agent,args_main:o,args_specific:t,body:c,download_path:y[0],download_paths:y,downloads:f,duid:e.duid,file:null,history:s,history_hint:this.buildHistoryHint(s),...e.inputSummary,mode:e.inputMode,module_id:e.moduleId,notice:e.notice,result_source:"history",route:e.route,submission_message:n,tool_product_uuid:e.toolProductUuid,uuid:e.uuid},text:this.formatAsyncHistoryDownloadText(s,y)}}async downloadAsyncHistoryResult(e,o){let t;for(let i=0;i<4;i+=1){const d=await j(e,{fuid:o.fuid});try{const n=await this.downloadResult(e,{downloadPath:o.downloadPath,downloadItem:o.downloadItem,downloadLabel:o.downloadLabel,downloads:d.downloads,moduleId:o.moduleId,uuid:N});return{body:d.body,downloads:d.downloads,paths:n}}catch(n){if(!(n instanceof a)||!this.isRetryableAsyncDownloadError(n)||i===3)throw n;t=n,await this.sleep(3e3)}}throw t??new a("\u4E0B\u8F7D\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")}formatResultText(e,o,t){const i=[];if(e.file&&i.push(e.file),!e.file&&(e.downloads.length>0||e.body)&&i.push("\u5206\u6790\u5B8C\u6210"),!e.file&&!e.body&&e.downloads.length===0)return"\u63D0\u4EA4\u5B8C\u6210";if(e.downloads.length>0&&!t)for(const d of e.downloads)i.push(`${d.label} (${d.device})`);for(const d of o)i.push(d);return i.join(`
2
+ `)}formatAsyncHistoryText(e,o){const t=[o];return e&&t.push(`\u5386\u53F2\u8BB0\u5F55: ${e.fuid} (${e.status})`),t.push(this.buildHistoryHint(e)),t.join(`
3
+ `)}formatAsyncHistoryDownloadText(e,o){const t=[];e&&t.push(`\u5386\u53F2\u8BB0\u5F55: ${e.fuid} (${e.status})`);for(const i of o)t.push(i);return t.join(`
4
+ `)}async downloadResult(e,o){if(o.downloads.length>0){const t=this.pickDownloadItem(o.downloads,{item:o.downloadItem,label:o.downloadLabel,outputPath:o.downloadPath});if(!t)throw new a(this.buildMultipleDownloadsMessage(o.downloads));const i=await A(e,{item:t,moduleId:o.moduleId,uuid:o.uuid});return[await g(i.url,o.downloadPath)]}if(o.file)return[await g(o.file,o.downloadPath)];throw new a("\u5F53\u524D\u6A21\u5757\u672A\u8FD4\u56DE\u53EF\u4E0B\u8F7D\u6587\u4EF6\u3002")}pickDownloadItem(e,o){if(o.item!==void 0)return this.pickDownloadItemByIndex(e,o.item);if(o.label)return this.pickDownloadItemByLabel(e,o.label);const t=this.inferDownloadDevice(o.outputPath);if(t){const d=e.filter(n=>this.normalizeDevice(n.device)===t);if(d.length===1)return d[0];if(d.length>1)throw new a(`\u4E0B\u8F7D\u683C\u5F0F ${t} \u5339\u914D\u5230\u591A\u4E2A\u7ED3\u679C\uFF0C\u8BF7\u6539\u7528 \`--downloadItem\` \u6216 \`--downloadLabel\` \u7CBE\u786E\u9009\u62E9\u3002
5
+ ${this.buildMultipleDownloadsMessage(e)}`)}const i=e.filter(d=>d.endpoint==="public.output.download-result");if(i.length===1)return i[0];if(e.length===1)return e[0]}pickDownloadItemByIndex(e,o){if(!Number.isInteger(o)||o<1||o>e.length)throw new a(`\u4E0B\u8F7D\u9879\u5E8F\u53F7 ${o} \u65E0\u6548\uFF0C\u53EF\u9009\u8303\u56F4\u4E3A 1-${e.length}\u3002
6
+ ${this.buildMultipleDownloadsMessage(e)}`);return e[o-1]}pickDownloadItemByLabel(e,o){const t=o.trim().toLowerCase();if(!t)return;const i=e.filter(d=>d.label.trim().toLowerCase()===t);if(i.length===1)return i[0];if(i.length>1)throw new a(`\u4E0B\u8F7D\u9879\u540D\u79F0 ${o} \u5339\u914D\u5230\u591A\u4E2A\u7ED3\u679C\uFF0C\u8BF7\u6539\u7528 \`--downloadItem\` \u7CBE\u786E\u9009\u62E9\u3002
7
+ ${this.buildMultipleDownloadsMessage(e)}`)}inferDownloadDevice(e){if(!e)return;const o=e.trim().split(".").pop()?.toLowerCase();if(o)return this.normalizeDevice(o)}normalizeDevice(e){const o=e.trim().toLowerCase();return o==="tif"?"tiff":o==="jpg"?"jpeg":o}buildMultipleDownloadsMessage(e){const o=["\u5F53\u524D\u6A21\u5757\u8FD4\u56DE\u591A\u4E2A\u53EF\u4E0B\u8F7D\u6587\u4EF6\uFF0C\u8BF7\u4F7F\u7528 `--downloadItem`\u3001`--downloadLabel` \u6216\u5E26\u76EE\u6807\u6269\u5C55\u540D\u7684 `--download` \u8DEF\u5F84\u660E\u786E\u9009\u62E9\u3002","\u53EF\u9009\u4E0B\u8F7D\u9879\uFF1A"];return e.forEach((t,i)=>{o.push(`${i+1}. ${t.label} (device=${t.device}, endpoint=${t.endpoint})`)}),o.join(`
8
+ `)}validateDownloadFlags(e){if(e.downloadItem!==void 0&&e.downloadLabel)throw new a("`--downloadItem` \u4E0E `--downloadLabel` \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528\u3002");if((e.downloadItem!==void 0||e.downloadLabel)&&!e.download)throw new a("`--downloadItem` \u548C `--downloadLabel` \u4EC5\u53EF\u4E0E `--download` \u4E00\u8D77\u4F7F\u7528\u3002")}toHistorySummary(e,o){const t=e.fuid?.trim();return t?{fuid:t,id:typeof e.id=="number"?e.id:null,module_id:e.module_id?.trim()||o,module_name:e.module_name?.trim()||"",name:e.name?.trim()||"",status:K(e),time:e.time?.trim()||"",type:e.type?.trim()||""}:null}buildHistoryHint(e){return e?`\u53EF\u4F7F\u7528 \`xt history download ${e.fuid} --device pdf\` \u6216 \`xt history list\` \u67E5\u770B\u7ED3\u679C`:"\u53EF\u4F7F\u7528 `xt history list` \u67E5\u770B\u4EFB\u52A1\u8FDB\u5EA6"}async downloadSelectedResults(e,o){const t=[];for(const i of o.downloads){const d=await A(e,{item:i,moduleId:o.moduleId,uuid:o.uuid});t.push(await g(d.url,d.fileName))}return t}async downloadInteractiveResults(e,o){const t=[];return o.choice.downloadFile&&o.file&&t.push(await g(o.file)),o.choice.downloads.length>0&&t.push(...await this.downloadSelectedResults(e,{downloads:o.choice.downloads,moduleId:o.moduleId,uuid:o.uuid})),t}isRetryableAsyncDownloadError(e){return e.message.includes("\u4E0B\u8F7D\u5931\u8D25")||e.message.includes("\u672A\u83B7\u53D6\u5230\u4E0B\u8F7D\u94FE\u63A5")}async sleep(e){await new Promise(o=>setTimeout(o,e))}async resolveInputMode(e,o){if(o.demo)return this.hasDemoInput(e)?{mode:"demo"}:this.hasRecordInput(e)?{mode:"record"}:this.hasCloudInput(e)?{mode:"cloud"}:{mode:"demo"};if(o.fileInputs.length>0)return{fileInputs:o.fileInputs,mode:"upload"};if(o.cloudRequested)return{mode:"cloud"};if(this.hasRecordInput(e))return{mode:"record"};if(this.hasCloudInput(e))return{mode:"cloud"};if(!o.interactive)return{mode:"upload"};if(!this.hasDemoInput(e))return{fileInputs:[await F()],mode:"upload"};const t=await Y();return t==="demo"?{mode:t}:{fileInputs:[await F()],mode:t}}resolveDemoInput(e,o){const t=e.id?.duid?.trim();if(!t)throw new a(`\u6A21\u5757 ${o} \u672A\u8FD4\u56DE demo duid\uFF0C\u65E0\u6CD5\u4F7F\u7528 \`--demo\`\u3002`);const i=$(e.args_data??[]);if(!i.length||i.some(d=>!d.defaultUpload))throw new a(`\u6A21\u5757 ${o} \u672A\u8FD4\u56DE\u53EF\u7528\u7684 demo \u6587\u4EF6\u4FE1\u606F\uFF0C\u65E0\u6CD5\u4F7F\u7528 \`--demo\`\u3002`);return{duid:t,input:{kind:"upload",uploads:i.map(d=>({key:d.key,label:d.label,upload:{fileName:d.defaultUpload.fileName,fileOss:d.defaultUpload.fileOss,fileSize:d.defaultUpload.fileSize}}))},schema:[]}}hasDemoInput(e){if(!e.id?.duid?.trim())return!1;const t=$(e.args_data??[]);return t.length>0&&t.every(i=>!!i.defaultUpload)}async resolveCloudInput(e,o,t,i,d){const n=D(e.args_data??[]),l=o.cloudKey?.trim()||n?.key||"";if(!l)throw new a(`\u6A21\u5757 ${t} \u672A\u8FD4\u56DE\u53EF\u7528\u7684\u4E91\u7AEF\u6570\u636E\u53C2\u6570\uFF0C\u8BF7\u663E\u5F0F\u4F20\u5165 \`--cloudKey\`.`);const r=await this.resolveCloudRecord(i,o,{argsKey:l,defaultRecord:n?.record,moduleId:t,uuid:d});if(!r)throw new a(`\u6A21\u5757 ${t} \u672A\u8FD4\u56DE\u9ED8\u8BA4\u4E91\u7AEF\u6570\u636E\uFF0C\u8BF7\u4F20\u5165 \`--cloudRecordJson\` \u6216 \`--cloudRecordFile\`.`);return{duid:e.id?.duid?.trim()||"cloud",input:{kind:"cloud",cloud:{key:l,label:n?.label??"",record:this.normalizeCloudRecord(r)}},schema:[]}}resolveRecordInput(e,o){const t=e.id?.duid?.trim();if(!t)throw new a(`\u6A21\u5757 ${o} \u672A\u8FD4\u56DE record duid\uFF0C\u65E0\u6CD5\u4F7F\u7528\u5386\u53F2\u8BB0\u5F55\u8F93\u5165\u3002`);const i=H(e.args_data??[]);if(!i)throw new a(`\u6A21\u5757 ${o} \u672A\u8FD4\u56DE\u53EF\u7528\u7684\u6570\u636E\u8BB0\u5F55\uFF0C\u65E0\u6CD5\u76F4\u63A5\u8FD0\u884C\u3002`);return{duid:t,input:{kind:"record",record:{key:i.key,label:i.label,moduleId:i.moduleId,moduleName:i.moduleName,recordId:i.recordId,recordName:i.recordName,time:i.time}},schema:[]}}hasRecordInput(e){return!!(e.id?.duid?.trim()&&H(e.args_data??[]))}hasCloudInput(e){return!!D(e.args_data??[])}async uploadAndVerify(e,o,t,i){const d=await this.uploadFiles(e,o,t.argsData??[],t.moduleId),n=await ae(i,{argsMain:t.argsMain,moduleId:t.moduleId,uploads:d,uuid:t.uuid});return{duid:n.duid,input:{kind:"upload",uploads:d},schema:n.schema}}summarizePreparedInput(e){if(e.kind==="cloud")return{file_name:null,file_oss:null,file_size:null,input_cloud:this.summarizeCloudInput(e.cloud),input_record:null,input_uploads:null};if(e.kind==="record")return{file_name:null,file_oss:null,file_size:null,input_cloud:null,input_record:{label:e.record.label,module_id:e.record.moduleId,module_name:e.record.moduleName,record_id:e.record.recordId,record_name:e.record.recordName,time:e.record.time},input_uploads:null};const o=e.uploads.map(i=>({file_name:i.upload.fileName,file_oss:i.upload.fileOss,file_size:i.upload.fileSize,key:i.key,label:i.label})),t=o.length===1?o[0]:null;return{file_name:t?.file_name??null,file_oss:t?.file_oss??null,file_size:t?.file_size??null,input_cloud:null,input_record:null,input_uploads:o}}summarizeCloudInput(e){return{data_filter:this.readCloudOptionValue(e.record.data_filter),data_id:typeof e.record.data_id=="string"?e.record.data_id.trim():"",data_process:this.readCloudOptionValue(e.record.data_process),key:e.key,label:e.label,record:structuredClone(e.record),record_label:typeof e.record.label=="string"?e.record.label.trim():""}}readCloudOptionValue(e){return U(e)&&(typeof e.value=="string"?e.value.trim():"")||null}async resolveCloudRecord(e,o,t){return o.cloudRecordJson?this.parseCloudRecord(o.cloudRecordJson,"--cloudRecordJson"):o.cloudRecordFile?this.parseCloudRecord(await L(o.cloudRecordFile,"utf8"),"--cloudRecordFile"):o.cloudFilter?.trim()||o.cloudDataId?.trim()||typeof o.cloudIndex=="number"?this.resolveCloudRecordByQuery(e,o,t):t.defaultRecord}parseCloudRecord(e,o){let t;try{t=JSON.parse(e)}catch{throw new a(`${o} \u4E0D\u662F\u5408\u6CD5 JSON\u3002`)}if(!U(t))throw new a(`${o} \u5FC5\u987B\u662F JSON \u5BF9\u8C61\u3002`);return t}normalizeCloudRecord(e){const o={};for(const[t,i]of Object.entries(e))i!==void 0&&(o[t]=structuredClone(i));return(typeof o.type!="string"||!o.type.trim())&&(o.type="cloud"),o}validateInputSourceFlags(e,o){const t=!!(o.cloudRecordJson||o.cloudRecordFile),i=!!(o.cloudDataId?.trim()||o.cloudFilter?.trim()||typeof o.cloudIndex=="number"),d=t||i;if(o.cloudRecordJson&&o.cloudRecordFile)throw new a("`--cloudRecordJson` \u4E0E `--cloudRecordFile` \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528\u3002");if(t&&i)throw new a("\u663E\u5F0F\u4E91\u7AEF\u8BB0\u5F55\u53C2\u6570\u4E0D\u80FD\u4E0E `--cloudFilter` / `--cloudDataId` / `--cloudIndex` \u540C\u65F6\u4F7F\u7528\u3002");if(o.demo&&d)throw new a("`--demo` \u4E0D\u80FD\u4E0E\u4E91\u7AEF\u6570\u636E\u8BB0\u5F55\u53C2\u6570\u540C\u65F6\u4F7F\u7528\u3002");if(e.length>0&&d)throw new a("`--file` \u4E0D\u80FD\u4E0E\u4E91\u7AEF\u6570\u636E\u8BB0\u5F55\u53C2\u6570\u540C\u65F6\u4F7F\u7528\u3002")}async resolveCloudRecordByQuery(e,o,t){const i=await this.fetchCloudRecords(e,{argsKey:t.argsKey,filter:o.cloudFilter?.trim(),moduleId:t.moduleId,selectedRecord:t.defaultRecord,uuid:t.uuid});if(i.length===0){const n=o.cloudFilter?.trim();throw n?new a(`\u672A\u627E\u5230\u5339\u914D\u4E91\u7AEF\u6570\u636E: ${n}`):new a("\u5F53\u524D\u6A21\u5757\u6CA1\u6709\u53EF\u9009\u7684\u4E91\u7AEF\u6570\u636E\u8BB0\u5F55\u3002")}const d=o.cloudDataId?.trim();if(d){const n=i.find(l=>(typeof l.data_id=="string"?l.data_id.trim():"")===d);if(!n)throw new a(`\u672A\u627E\u5230 data_id=${d} \u5BF9\u5E94\u7684\u4E91\u7AEF\u6570\u636E\u3002`);return n}if(typeof o.cloudIndex=="number"){const n=i[o.cloudIndex];if(!n)throw new a(`\u4E91\u7AEF\u6570\u636E\u7D22\u5F15\u8D85\u51FA\u8303\u56F4: ${o.cloudIndex}\uFF0C\u5F53\u524D\u5171\u6709 ${i.length} \u6761\u3002`);return n}if(i.length===1)return i[0];if(o.interactive)return this.normalizeCloudRecord(await G(i));throw new O(this.buildCloudSelectionHint(i,o.cloudFilter?.trim()),this.buildCloudSelectionData(i,o.cloudFilter?.trim()))}async fetchCloudRecords(e,o){const t=await z(e,{argsKey:o.argsKey,currentPage:1,filter:o.filter,moduleId:o.moduleId,selectedRecord:o.selectedRecord,uuid:o.uuid}),i=t.records.map(d=>this.normalizeCloudRecord(d));for(let d=t.currentPage+1;d<=t.lastPage;d+=1){const n=await z(e,{argsKey:o.argsKey,currentPage:d,filter:o.filter,moduleId:o.moduleId,selectedRecord:o.selectedRecord,uuid:o.uuid});i.push(...n.records.map(l=>this.normalizeCloudRecord(l)))}return i}buildCloudSelectionHint(e,o){const t=[o?`\u5339\u914D\u5230\u591A\u4E2A\u4E91\u7AEF\u6570\u636E: ${o}`:"\u5339\u914D\u5230\u591A\u4E2A\u4E91\u7AEF\u6570\u636E","\u8BF7\u4F7F\u7528 `--cloudIndex` \u6216 `--cloudDataId` \u6307\u5B9A\u5176\u4E2D\u4E00\u6761\uFF1A"];return e.forEach((i,d)=>{const n=typeof i.data_id=="string"?i.data_id.trim():"",l=typeof i.label=="string"?i.label.trim():"";t.push(` [${d}] ${l||n}`)}),t.join(`
9
+ `)}buildCloudSelectionData(e,o){return{choices:e.map((t,i)=>{const d=typeof t.data_id=="string"?t.data_id.trim():"",n=typeof t.label=="string"?t.label.trim():"";return{data_id:d,index:i,label:n||d}}),filter:o??"",selection_type:"cloud_record"}}async uploadFiles(e,o,t,i){const d=$(t??[]),n=this.resolveUploadInputs(o,d,i),l=await M(e),r=[];for(const u of n){const s=await ee(l,u.filePath);r.push({key:u.key,label:u.label,upload:s})}return r}resolveUploadInputs(e,o,t){if(!o.length)throw new a(`\u6A21\u5757 ${t} \u672A\u68C0\u6D4B\u5230\u53EF\u4E0A\u4F20\u8F93\u5165\uFF0C\u4E0D\u80FD\u4F7F\u7528 \`--file\`\u3002`);if(!e.length)throw o.length===1?new a("\u901A\u7528\u6A21\u5F0F\u8BF7\u4F20\u5165 FILE / `--file <xlsx>`\uFF0C\u6216\u6539\u7528 `--demo`\u3002"):new a(`\u6A21\u5757 ${t} \u9700\u8981\u591A\u4E2A\u4E0A\u4F20\u5B57\u6BB5\uFF0C\u8BF7\u4F7F\u7528 \`--file key=path\`\u3002\u53EF\u7528\u5B57\u6BB5: ${o.map(r=>r.key).join(", ")}`);const[i]=o;if(o.length===1&&e.length===1){const r=this.parseUploadFileInput(e[0]);if(r.key&&r.key!==i.key)throw new a(`\u6A21\u5757 ${t} \u4EC5\u652F\u6301\u4E0A\u4F20\u5B57\u6BB5 ${i.key}\uFF0C\u6536\u5230 ${r.key}\u3002`);return[{filePath:r.path,key:i.key,label:i.label}]}const d=new Map(o.map(r=>[r.key,r])),n=new Map;for(const r of e){const u=this.parseUploadFileInput(r);if(!u.key){if(o.length===1){if(n.has(i.key))throw new a(`\u6A21\u5757 ${t} \u4EC5\u9700\u8981 1 \u4E2A\u4E0A\u4F20\u6587\u4EF6\uFF0C\u6536\u5230\u91CD\u590D\u8F93\u5165\u3002`);n.set(i.key,u.path);continue}throw new a(`\u6A21\u5757 ${t} \u9700\u8981\u591A\u4E2A\u4E0A\u4F20\u5B57\u6BB5\uFF0C\u8BF7\u4F7F\u7528 \`--file key=path\`\u3002\u53EF\u7528\u5B57\u6BB5: ${o.map(c=>c.key).join(", ")}`)}const s=d.get(u.key);if(!s)throw new a(`\u6A21\u5757 ${t} \u4E0D\u5B58\u5728\u4E0A\u4F20\u5B57\u6BB5 ${u.key}\u3002\u53EF\u7528\u5B57\u6BB5: ${o.map(c=>c.key).join(", ")}`);if(n.has(s.key))throw new a(`\u4E0A\u4F20\u5B57\u6BB5 ${s.key} \u91CD\u590D\u4F20\u5165\u3002`);n.set(s.key,u.path)}const l=o.filter(r=>r.required&&!n.has(r.key));if(l.length>0)throw new a(`\u6A21\u5757 ${t} \u7F3A\u5C11\u5FC5\u586B\u4E0A\u4F20\u5B57\u6BB5: ${l.map(r=>r.key).join(", ")}`);return o.flatMap(r=>{const u=n.get(r.key);return u?[{filePath:u,key:r.key,label:r.label}]:[]})}parseUploadFileInput(e){const o=e.trim();if(!o)throw new a("`--file` \u4E0D\u80FD\u4E3A\u7A7A\u3002");const t=o.indexOf("=");if(t<=0)return{path:o};const i=o.slice(0,t).trim(),d=o.slice(t+1).trim();if(!i||!d)throw new a("\u591A\u4E0A\u4F20\u6A21\u5757\u8BF7\u4F7F\u7528 `--file key=path`\u3002");return{key:i,path:d}}async resolveModule(e,o,t){const i=e?.trim(),d=o.route?.trim(),n=o.uuid?.trim(),l=await ne(o.toolProductUuid);if(!i){if(!o.interactive)throw new a("\u8BF7\u4F20\u5165 `module_id`\uFF0C\u6216\u4F7F\u7528 `--interactive --file <xlsx>` \u5148\u4ECE\u83DC\u5355\u9009\u62E9\u5DE5\u5177\u3002");const u=await W(this.sortTopLevelMenus(await ce(t,l)));return{moduleId:u.code,route:d??u.route,toolProductUuid:l,uuid:n??u.uuid}}if(d&&n)return{moduleId:i,route:d,toolProductUuid:l,uuid:n};const r=o.menuUuid?.trim();if(r&&l){const u=await se(t,r,l),s=d??this.requireMenuRoute(u),c=u.code?.trim();if(c&&c!==i)throw new a(`\u83DC\u5355\u6A21\u5757 code \u4E3A ${c}\uFF0C\u4E0E\u4F20\u5165\u7684 module_id ${i} \u4E0D\u4E00\u81F4\u3002`);return{moduleId:i,route:s,toolProductUuid:l,uuid:n??r}}if(l){const u=await me(t,l,i);return{moduleId:i,route:d??u.route,toolProductUuid:l,uuid:n??u.uuid}}if(!n)throw new a("\u901A\u7528\u6A21\u5F0F\u9700\u8981\u4F20\u5165 `--uuid`\uFF0C\u6216\u4F7F\u7528\u9ED8\u8BA4/\u663E\u5F0F `toolProductUuid` \u81EA\u52A8\u89E3\u6790\u3002");if(!d)throw new a("\u901A\u7528\u6A21\u5F0F\u9700\u8981\u4F20\u5165 `--route`\uFF0C\u6216\u4F7F\u7528\u9ED8\u8BA4/\u663E\u5F0F `toolProductUuid` \u81EA\u52A8\u89E3\u6790\u3002");return{moduleId:i,route:d,toolProductUuid:l,uuid:n}}sortTopLevelMenus(e){const o=["\u57FA\u7840\u7ED8\u56FE","\u8868\u8FBE\u5DEE\u5F02","\u529F\u80FD\u805A\u7C7B","\u4EA4\u4E92\u7F51\u7EDC","\u4E34\u5E8A\u610F\u4E49","\u5176\u4ED6"],t=new Map(o.map((i,d)=>[i,d]));return[...e].sort((i,d)=>{const n=t.get(i.title?.trim()??"")??Number.MAX_SAFE_INTEGER,l=t.get(d.title?.trim()??"")??Number.MAX_SAFE_INTEGER;return n-l})}requireMenuRoute(e){const o=e.route;if(typeof o!="string"||!o.trim())throw new a("\u83DC\u5355\u672A\u8FD4\u56DE\u53EF\u7528 route\uFF0C\u8BF7\u6539\u7528 `--route` \u663E\u5F0F\u6307\u5B9A\u3002");return o.trim()}}class C extends fe{static description="Run a Xiantao bioinformatics tool";static args={tool:S.string({description:"Tool id; optional with --interactive to choose from menus"}),file:S.string({description:"Path to the local xlsx file; optional with --demo or --interactive"})};static flags={...B,...E,...ie,demo:h.boolean({default:!1,description:"Prefer the module default remote input returned by fetch-all instead of uploading a local file"}),file:h.string({description:"Path to the local xlsx file; repeat or use KEY=PATH for named upload fields",multiple:!0}),download:h.string({description:"Download the generated file or preferred analysis result to this local path after submission"}),downloadItem:h.integer({description:"Select a download item by its 1-based index when --download matches multiple results"}),downloadLabel:h.string({description:"Select a download item by its label when --download matches multiple results"}),interactive:h.boolean({default:!1,description:"Prompt for dynamic args before submitting the module"}),menuUuid:h.string({description:"Tool menu UUID from /products/apply/:toolProductUuid/analyse/:uuid"}),route:h.string({description:"Tool route like app1.violin_flat in generic mode"}),token:h.string({description:"Bearer token for agent.helixlife.cn xiantao APIs; falls back to the stored agent token"}),toolProductUuid:h.string({description:"tool_product_uuid used to auto-resolve module UUID and route in generic mode; defaults to the main Xiantao product UUID"}),uuid:h.string({description:"Tool UUID used in generic mode for fetch-all and verify-upload; optional when --toolProductUuid is provided"})};async run(){this.warnIfLegacyPlotCommand();const{args:e,flags:o}=await this.parse(C);if(o.interactive&&o.json)throw new a("`--interactive` \u4E0D\u80FD\u4E0E `--json` \u540C\u65F6\u4F7F\u7528\u3002");const t=this.resolveToolFileInputs(e.file,o.file),i=await this.executeToolRun(e.tool,t,o);this.print(o,i.data,i.text,{profile:i.data.agent})}}export{fe as ToolRunCommandBase,C as default};
@@ -1 +1 @@
1
- import{Args as a,Flags as o}from"@oclif/core";import{createErrorEnvelope as d,createSuccessEnvelope as u}from"../../lib/envelope.js";import{XtzError as i}from"../../lib/errors.js";import{globalFlags as f,toolCloudFlags as c}from"../../lib/flags.js";import{plotOverrideFlags as g}from"../../lib/plot-options.js";import{ToolRunCommandBase as p}from"../plot/run.js";class r extends p{static description="Execute a Xiantao bioinformatics tool in agent mode";static usage="tool exec <tool> [--file <value> ... | --demo] --json [--download <path>]";static args={tool:a.string({description:"Tool id, e.g. violin_flat",required:!0}),file:a.string({hidden:!0})};static flags={...f,...c,...g,demo:o.boolean({default:!1,description:"Use the module demo data returned by fetch-all instead of uploading a local file"}),download:o.string({description:"Download the generated file or preferred analysis result to this local path after submission"}),file:o.string({description:"Path to the local xlsx file; repeat or use KEY=PATH for named upload fields",multiple:!0}),interactive:o.boolean({default:!1,hidden:!0}),menuUuid:o.string({description:"Tool menu UUID from /products/apply/:toolProductUuid/analyse/:uuid"}),route:o.string({description:"Tool route like app1.violin_flat in generic mode"}),token:o.string({description:"Bearer token for agent.helixlife.cn xiantao APIs; falls back to the stored agent token"}),toolProductUuid:o.string({description:"tool_product_uuid used to auto-resolve module UUID and route in generic mode; defaults to the main Xiantao product UUID"}),uuid:o.string({description:"Tool UUID used in generic mode for fetch-all and verify-upload; optional when --toolProductUuid is provided"})};async catch(t){const e=await this.getProfile(this.readProfileFlag());this.log(JSON.stringify(d(e,"tool exec",this.normalizeError(t)),null,2)),this.exit(1)}async run(){const{args:t,flags:e}=await this.parse(r);if(!e.json)throw new i("`xt tool exec` \u4EC5\u652F\u6301 `--json` \u8F93\u51FA\u3002");const l=this.resolveToolFileInputs(t.file,e.file);if(e.demo&&l.length>0)throw new i("`--demo` \u4E0E `--file` \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528\u3002");const n=await this.executeToolRun(t.tool,l,{...e,interactive:!1}),s=await this.getProfile(e.profile);this.log(JSON.stringify(u(s,"tool exec",n.data),null,2))}readProfileFlag(){for(let t=0;t<this.argv.length;t+=1){const e=this.argv[t];if((e==="--profile"||e==="--agent")&&this.argv[t+1])return this.argv[t+1];if(e.startsWith("--profile="))return e.slice(10);if(e.startsWith("--agent="))return e.slice(8)}}normalizeError(t){return t.message.replace(/\u001B\[[0-?]*[ -/]*[@-~]/g,"").includes("required arg")?new i("`xt tool exec` \u9700\u8981\u4F20\u5165 TOOL\u3002"):t}}export{r as default};
1
+ import{Args as a,Flags as o}from"@oclif/core";import{createErrorEnvelope as d,createSuccessEnvelope as u}from"../../lib/envelope.js";import{XtzError as i}from"../../lib/errors.js";import{globalFlags as c,toolCloudFlags as f}from"../../lib/flags.js";import{plotOverrideFlags as g}from"../../lib/plot-options.js";import{ToolRunCommandBase as p}from"../plot/run.js";class l extends p{static description="Execute a Xiantao bioinformatics tool in agent mode";static usage="tool exec <tool> [--file <value> ... | --demo] --json [--download <path> [--downloadItem <n> | --downloadLabel <value>]]";static args={tool:a.string({description:"Tool id, e.g. violin_flat",required:!0}),file:a.string({hidden:!0})};static flags={...c,...f,...g,demo:o.boolean({default:!1,description:"Prefer the module default remote input returned by fetch-all instead of uploading a local file"}),download:o.string({description:"Download the generated file or preferred analysis result to this local path after submission"}),downloadItem:o.integer({description:"Select a download item by its 1-based index when --download matches multiple results"}),downloadLabel:o.string({description:"Select a download item by its label when --download matches multiple results"}),file:o.string({description:"Path to the local xlsx file; repeat or use KEY=PATH for named upload fields",multiple:!0}),interactive:o.boolean({default:!1,hidden:!0}),menuUuid:o.string({description:"Tool menu UUID from /products/apply/:toolProductUuid/analyse/:uuid"}),route:o.string({description:"Tool route like app1.violin_flat in generic mode"}),token:o.string({description:"Bearer token for agent.helixlife.cn xiantao APIs; falls back to the stored agent token"}),toolProductUuid:o.string({description:"tool_product_uuid used to auto-resolve module UUID and route in generic mode; defaults to the main Xiantao product UUID"}),uuid:o.string({description:"Tool UUID used in generic mode for fetch-all and verify-upload; optional when --toolProductUuid is provided"})};async catch(t){const e=await this.getProfile(this.readProfileFlag());this.log(JSON.stringify(d(e,"tool exec",this.normalizeError(t)),null,2)),this.exit(1)}async run(){const{args:t,flags:e}=await this.parse(l);if(!e.json)throw new i("`xt tool exec` \u4EC5\u652F\u6301 `--json` \u8F93\u51FA\u3002");const r=this.resolveToolFileInputs(t.file,e.file);if(e.demo&&r.length>0)throw new i("`--demo` \u4E0E `--file` \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528\u3002");const n=await this.executeToolRun(t.tool,r,{...e,interactive:!1}),s=await this.getProfile(e.profile);this.log(JSON.stringify(u(s,"tool exec",n.data),null,2))}readProfileFlag(){for(let t=0;t<this.argv.length;t+=1){const e=this.argv[t];if((e==="--profile"||e==="--agent")&&this.argv[t+1])return this.argv[t+1];if(e.startsWith("--profile="))return e.slice(10);if(e.startsWith("--agent="))return e.slice(8)}}normalizeError(t){return t.message.replace(/\u001B\[[0-?]*[ -/]*[@-~]/g,"").includes("required arg")?new i("`xt tool exec` \u9700\u8981\u4F20\u5165 TOOL\u3002"):t}}export{l as default};
@@ -1 +1 @@
1
- import{Args as n,Flags as o}from"@oclif/core";import{createErrorEnvelope as u,createSuccessEnvelope as d}from"../../lib/envelope.js";import{XtzError as r}from"../../lib/errors.js";import{globalFlags as p,toolCloudFlags as c}from"../../lib/flags.js";import{plotOverrideFlags as f}from"../../lib/plot-options.js";import{buildArgsMainFromSchema as m,buildArgsSpecificFromSchema as g}from"../../lib/plot-schema.js";import{ToolRunCommandBase as h}from"../plot/run.js";class a extends h{static description="Prepare a Xiantao bioinformatics tool in agent mode and return the final dynamic schema";static usage="tool prepare <tool> [--file <value> ... | --demo] --json";static args={tool:n.string({description:"Tool id, e.g. violin_flat",required:!0}),file:n.string({hidden:!0})};static flags={...p,...c,...f,demo:o.boolean({default:!1,description:"Use the module demo data returned by fetch-all instead of uploading a local file"}),file:o.string({description:"Path to the local xlsx file; repeat or use KEY=PATH for named upload fields",multiple:!0}),interactive:o.boolean({default:!1,hidden:!0}),menuUuid:o.string({description:"Tool menu UUID from /products/apply/:toolProductUuid/analyse/:uuid"}),route:o.string({description:"Tool route like app1.violin_flat in generic mode"}),token:o.string({description:"Bearer token for agent.helixlife.cn xiantao APIs; falls back to the stored agent token"}),toolProductUuid:o.string({description:"tool_product_uuid used to auto-resolve module UUID and route in generic mode; defaults to the main Xiantao product UUID"}),uuid:o.string({description:"Tool UUID used in generic mode for fetch-all and verify-upload; optional when --toolProductUuid is provided"})};async catch(t){const i=await this.getProfile(this.readProfileFlag());this.log(JSON.stringify(u(i,"tool prepare",this.normalizeError(t)),null,2)),this.exit(1)}async run(){const{args:t,flags:i}=await this.parse(a);if(!i.json)throw new r("`xt tool prepare` \u4EC5\u652F\u6301 `--json` \u8F93\u51FA\u3002");const l=this.resolveToolFileInputs(t.file,i.file);if(i.demo&&l.length>0)throw new r("`--demo` \u4E0E `--file` \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528\u3002");const e=await this.prepareToolRun(t.tool,l,{...i,interactive:!1}),s=await this.getProfile(i.profile);this.log(JSON.stringify(d(s,"tool prepare",{agent:e.agent,args_main:e.schema??[],args_main_defaults:m(e.schema),args_main_prepared:e.argsMain,args_specific:e.argsSpecificSchema,args_specific_defaults:g(e.argsSpecificSchema),args_specific_prepared:e.argsSpecific,duid:e.duid,file_name:e.inputSummary.file_name,file_oss:e.inputSummary.file_oss,file_size:e.inputSummary.file_size,input_cloud:e.inputSummary.input_cloud,input_record:e.inputSummary.input_record,input_uploads:e.inputSummary.input_uploads,mode:e.inputMode,module_id:e.moduleId,notice:e.notice,route:e.route,tool_product_uuid:e.toolProductUuid,uuid:e.uuid}),null,2))}readProfileFlag(){for(let t=0;t<this.argv.length;t+=1){const i=this.argv[t];if((i==="--profile"||i==="--agent")&&this.argv[t+1])return this.argv[t+1];if(i.startsWith("--profile="))return i.slice(10);if(i.startsWith("--agent="))return i.slice(8)}}normalizeError(t){return t.message.replace(/\u001B\[[0-?]*[ -/]*[@-~]/g,"").includes("required arg")?new r("`xt tool prepare` \u9700\u8981\u4F20\u5165 TOOL\u3002"):t}}export{a as default};
1
+ import{Args as n,Flags as o}from"@oclif/core";import{createErrorEnvelope as u,createSuccessEnvelope as d}from"../../lib/envelope.js";import{XtzError as r}from"../../lib/errors.js";import{globalFlags as p,toolCloudFlags as c}from"../../lib/flags.js";import{plotOverrideFlags as f}from"../../lib/plot-options.js";import{buildArgsMainFromSchema as m,buildArgsSpecificFromSchema as g}from"../../lib/plot-schema.js";import{ToolRunCommandBase as h}from"../plot/run.js";class a extends h{static description="Prepare a Xiantao bioinformatics tool in agent mode and return the final dynamic schema";static usage="tool prepare <tool> [--file <value> ... | --demo] --json";static args={tool:n.string({description:"Tool id, e.g. violin_flat",required:!0}),file:n.string({hidden:!0})};static flags={...p,...c,...f,demo:o.boolean({default:!1,description:"Prefer the module default remote input returned by fetch-all instead of uploading a local file"}),file:o.string({description:"Path to the local xlsx file; repeat or use KEY=PATH for named upload fields",multiple:!0}),interactive:o.boolean({default:!1,hidden:!0}),menuUuid:o.string({description:"Tool menu UUID from /products/apply/:toolProductUuid/analyse/:uuid"}),route:o.string({description:"Tool route like app1.violin_flat in generic mode"}),token:o.string({description:"Bearer token for agent.helixlife.cn xiantao APIs; falls back to the stored agent token"}),toolProductUuid:o.string({description:"tool_product_uuid used to auto-resolve module UUID and route in generic mode; defaults to the main Xiantao product UUID"}),uuid:o.string({description:"Tool UUID used in generic mode for fetch-all and verify-upload; optional when --toolProductUuid is provided"})};async catch(t){const i=await this.getProfile(this.readProfileFlag());this.log(JSON.stringify(u(i,"tool prepare",this.normalizeError(t)),null,2)),this.exit(1)}async run(){const{args:t,flags:i}=await this.parse(a);if(!i.json)throw new r("`xt tool prepare` \u4EC5\u652F\u6301 `--json` \u8F93\u51FA\u3002");const l=this.resolveToolFileInputs(t.file,i.file);if(i.demo&&l.length>0)throw new r("`--demo` \u4E0E `--file` \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528\u3002");const e=await this.prepareToolRun(t.tool,l,{...i,interactive:!1}),s=await this.getProfile(i.profile);this.log(JSON.stringify(d(s,"tool prepare",{agent:e.agent,args_main:e.schema??[],args_main_defaults:m(e.schema),args_main_prepared:e.argsMain,args_specific:e.argsSpecificSchema,args_specific_defaults:g(e.argsSpecificSchema),args_specific_prepared:e.argsSpecific,duid:e.duid,file_name:e.inputSummary.file_name,file_oss:e.inputSummary.file_oss,file_size:e.inputSummary.file_size,input_cloud:e.inputSummary.input_cloud,input_record:e.inputSummary.input_record,input_uploads:e.inputSummary.input_uploads,mode:e.inputMode,module_id:e.moduleId,notice:e.notice,route:e.route,tool_product_uuid:e.toolProductUuid,uuid:e.uuid}),null,2))}readProfileFlag(){for(let t=0;t<this.argv.length;t+=1){const i=this.argv[t];if((i==="--profile"||i==="--agent")&&this.argv[t+1])return this.argv[t+1];if(i.startsWith("--profile="))return i.slice(10);if(i.startsWith("--agent="))return i.slice(8)}}normalizeError(t){return t.message.replace(/\u001B\[[0-?]*[ -/]*[@-~]/g,"").includes("required arg")?new r("`xt tool prepare` \u9700\u8981\u4F20\u5165 TOOL\u3002"):t}}export{a as default};
@@ -1,4 +1,4 @@
1
- import m from"node:http";import{AUTH_BIND_ENDPOINT as p,PASSPORT_JUMP_ENDPOINT as w}from"./constants.js";import{openUrl as d}from"./open-url.js";import{XtzError as c}from"./errors.js";import{requestJson as E}from"./http.js";import{getXiantaoTokenPath as F,loadXiantaoToken as f,requireXiantaoToken as D,saveXiantaoToken as k}from"./storage.js";async function y(t,e){const a=e?.trim()||process.env.XIANTAO_TOKEN?.trim()||await D(t);return{agent:t,token:a}}async function h(t){const e=await f(t);return e?{agent:t,token:e}:void 0}async function C(t){const e=await g(),a=e.callbackUrl.toString(),u=new URL(w);u.searchParams.set("cb_url",a);const o=await d(u.toString()),i=await e.waitForToken(),l=await k(t,i);return{browserOpened:o,callbackUrl:a,jumpUrl:u.toString(),reused:!1,token:i,tokenPath:l}}async function T(t,e){const a=await h(t);if(a){try{await E(p,{body:JSON.stringify({auth_key:e}),headers:{Authorization:`Bearer ${a.token}`,"Content-Type":"application/json",origin:"https://www.helixlife.net",platform:"pc",referer:"https://www.helixlife.net/",source:"PC"},method:"POST"},{agent:t,tokenKind:"xiantao"})}catch(u){if(u instanceof c&&u.message.includes("\u4ED9\u6843\u7F51\u9875\u6388\u6743\u5DF2\u8FC7\u671F\u6216\u65E0\u6548"))return;throw u}return{browserOpened:!1,reused:!0,token:a.token,tokenPath:F(t)}}}async function g(){let t,e;const a=new Promise((r,n)=>{t=r,e=n}),u=m.createServer((r,n)=>{const s=new URL(r.url??"/","http://127.0.0.1").searchParams.get("t")?.trim();if(n.statusCode=s?200:400,n.setHeader("Content-Type","text/html; charset=utf-8"),n.end(s?B:P),u.close(),s){t(s);return}e(new c("\u672A\u4ECE\u6D4F\u89C8\u5668\u56DE\u8C03\u4E2D\u83B7\u53D6\u5230\u4ED9\u6843\u7F51\u9875 token"))});await new Promise((r,n)=>{u.listen(0,"127.0.0.1",()=>r()),u.once("error",n)});const o=u.address();if(!o||typeof o=="string")throw u.close(),new c("\u65E0\u6CD5\u542F\u52A8\u672C\u5730\u767B\u5F55\u56DE\u8C03\u670D\u52A1");const i=new URL(`http://127.0.0.1:${o.port}/callback`),l=setTimeout(()=>{u.close(),e(new c("\u7B49\u5F85\u4ED9\u6843\u7F51\u9875\u767B\u5F55\u56DE\u8C03\u8D85\u65F6"))},300*1e3);return{callbackUrl:i,waitForToken:async()=>{try{return await a}finally{clearTimeout(l)}}}}const B=`<!doctype html>
1
+ import m from"node:http";import{AUTH_BIND_ENDPOINT as p,PASSPORT_JUMP_ENDPOINT as w}from"./constants.js";import{openUrl as d}from"./open-url.js";import{XtzError as c}from"./errors.js";import{requestJson as E}from"./http.js";import{getXiantaoTokenPath as F,loadXiantaoToken as f,requireXiantaoToken as D,saveXiantaoToken as k}from"./storage.js";async function y(t,e){const a=e?.trim()||process.env.XIANTAO_TOKEN?.trim()||await D(t);return{agent:t,token:a}}async function h(t){const e=await f(t);return e?{agent:t,token:e}:void 0}async function C(t){const e=await g(),a=e.callbackUrl.toString(),u=new URL(w);u.searchParams.set("cb_url",a);const n=await d(u.toString()),i=await e.waitForToken(),l=await k(t,i);return{browserOpened:n,callbackUrl:a,jumpUrl:u.toString(),reused:!1,token:i,tokenPath:l}}async function T(t,e){const a=await h(t);if(a){try{await E(p,{body:JSON.stringify({auth_key:e}),headers:{Authorization:`Bearer ${a.token}`,"Content-Type":"application/json",origin:"https://www.helixlife.net",platform:"pc",referer:"https://www.helixlife.net/",source:"PC"},method:"POST"},{agent:t,tokenKind:"xiantao"})}catch(u){if(u instanceof c&&u.message.includes("\u4ED9\u6843\u7F51\u9875\u6388\u6743\u5DF2\u8FC7\u671F\u6216\u65E0\u6548"))return;throw u}return{browserOpened:!1,reused:!0,token:a.token,tokenPath:F(t)}}}async function g(){let t,e;const a=new Promise((r,o)=>{t=r,e=o}),u=m.createServer((r,o)=>{const s=new URL(r.url??"/","http://127.0.0.1").searchParams.get("t")?.trim();if(o.statusCode=s?200:400,o.setHeader("Content-Type","text/html; charset=utf-8"),o.end(s?B:P),u.close(),s){t(s);return}e(new c("\u672A\u4ECE\u6D4F\u89C8\u5668\u56DE\u8C03\u4E2D\u83B7\u53D6\u5230\u4ED9\u6843\u7F51\u9875 token"))});await new Promise((r,o)=>{u.listen(0,"127.0.0.1",()=>r()),u.once("error",o)});const n=u.address();if(!n||typeof n=="string")throw u.close(),new c("\u65E0\u6CD5\u542F\u52A8\u672C\u5730\u767B\u5F55\u56DE\u8C03\u670D\u52A1");const i=new URL(`http://127.0.0.1:${n.port}/callback`),l=setTimeout(()=>{u.close(),e(new c("\u7B49\u5F85\u4ED9\u6843\u7F51\u9875\u767B\u5F55\u56DE\u8C03\u8D85\u65F6"))},300*1e3);return{callbackUrl:i,waitForToken:async()=>{try{return await a}finally{clearTimeout(l)}}}}const B=`<!doctype html>
2
2
  <html lang="zh-CN">
3
3
  <head><meta charset="utf-8"><title>\u767B\u5F55\u6210\u529F</title></head>
4
4
  <body><p>\u4ED9\u6843\u7F51\u9875\u767B\u5F55\u6210\u529F\uFF0C\u73B0\u5728\u53EF\u4EE5\u5173\u95ED\u6B64\u9875\u9762\u5E76\u56DE\u5230\u7EC8\u7AEF\u3002</p></body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helixlife-ai/xiantao",
3
- "version": "0.1.21",
3
+ "version": "0.1.22",
4
4
  "description": "CLI for Xiantao bioinformatics tools",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",