nuwax-file-server 1.5.0 → 1.5.1
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.
package/dist/cli.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{Command as ee}from"commander";import{createRequire as te}from"module";import f from"path";import U from"os";import c from"fs-extra";import{spawn as E}from"cross-spawn";import V from"tree-kill";import{fileURLToPath as q}from"url";import{execFileSync as R}from"child_process";import M from"http";import{createRequire as G}from"module";var I=f.dirname(q(import.meta.url)),H=G(import.meta.url),n={name:"nuwax-file-server",pidDir:f.join(U.tmpdir(),"nuwax-file-server"),pidFileName:"server.pid",lockFileName:"start.lock",defaultStopTimeout:3e4,defaultStartTimeout:3e4,staleLockTimeout:12e4,checkInterval:500};function $(){return f.join(n.pidDir,n.pidFileName)}function F(){return f.join(n.pidDir,n.lockFileName)}function J(){let e=[f.join(I,"..","server.js"),f.join(I,"server.js")];for(let t of e)if(c.existsSync(t))return t;return e[0]}function W(){let e=["../../package.json","../package.json"];for(let t of e)try{let o=H(t);if(o?.version)return o.version}catch{}return"unknown"}function x(){try{let e=$();if(!c.existsSync(e))return null;let t=c.readFileSync(e,"utf8"),o=JSON.parse(t);return!o||typeof o.pid!="number"?null:o}catch(e){return e.code!=="ENOENT"&&console.error(`Read PID file failed: ${e.message}`),null}}function B(e){try{let t=$();c.ensureDirSync(n.pidDir),c.writeFileSync(t,JSON.stringify(e,null,2)),console.debug(`PID file written: ${t}`)}catch(t){throw console.error(`Write PID file failed: ${t.message}`),t}}function v(){try{let e=$();c.existsSync(e)&&(c.removeSync(e),console.debug(`PID file deleted: ${e}`))}catch(e){console.error(`Delete PID file failed: ${e.message}`)}}function g(e){try{return process.kill(e,0),!0}catch(t){return t.code!=="ESRCH"}}function K(e){try{return k()?R("powershell",["-NoProfile","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId = ${e}").CommandLine`],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim():R("ps",["-p",String(e),"-o","command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim()}catch{return""}}function X(e){if(!g(e))return!1;let t=K(e);if(!t)return!1;let o=t.toLowerCase(),s=f.basename(f.join(I,"..","server.js")).toLowerCase(),i=n.name.toLowerCase();return o.includes(s)||o.includes(i)}function z(){c.ensureDirSync(n.pidDir);let e=F(),t=`${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2,10)}`,o=JSON.stringify({pid:process.pid,token:t,createdAt:new Date().toISOString()},null,2);try{let s=c.openSync(e,"wx");return c.writeSync(s,o),{fd:s,token:t}}catch(s){if(s.code!=="EEXIST")throw s;try{let i=c.readFileSync(e,"utf8"),r=JSON.parse(i),a=Number(r?.pid),u=r?.createdAt?new Date(r.createdAt).getTime():0,l=Date.now()-u,C=Number.isFinite(a)&&a>0&&g(a),p=!u||Number.isNaN(l)||l>n.staleLockTimeout;if(!C||p){c.removeSync(e);let S=c.openSync(e,"wx");return c.writeSync(S,o),console.warn("Detected stale start lock, auto cleaned"),{fd:S,token:t}}}catch{c.removeSync(e);let r=c.openSync(e,"wx");return c.writeSync(r,o),console.warn("Detected invalid start lock, auto cleaned"),{fd:r,token:t}}throw s}}function Q(e){let t=e?.fd,o=e?.token;try{t!=null&&c.closeSync(t)}catch{}try{let s=F();if(c.existsSync(s)){let i=!1;if(!o)i=!0;else try{let r=c.readFileSync(s,"utf8");i=JSON.parse(r)?.token===o}catch{i=!0}i&&c.removeSync(s)}}catch{}}function k(){return process.platform==="win32"}async function Y(e=n.defaultStopTimeout){let t=x();return t?X(t.pid)?(console.log(`Existing service process detected (PID: ${t.pid}), stopping before start...`),await h(t.pid,!1)&&await D(t.pid,e)?(v(),{success:!0,message:`Existing process ${t.pid} stopped gracefully`}):(console.warn(`Graceful stop timeout or failed for PID ${t.pid}, force stop...`),await h(t.pid,!0)?await D(t.pid,e)?(v(),{success:!0,message:`Existing process ${t.pid} stopped forcibly`}):{success:!1,message:`Existing process ${t.pid} did not exit after force stop`}:{success:!1,message:`Failed to stop existing process ${t.pid}`})):(console.log(`Found stale PID file (PID: ${t.pid}), clean it...`),v(),{success:!0,message:"Stale PID file cleaned"}):{success:!0,message:"No existing service process"}}async function h(e,t=!1){return new Promise(o=>{if(!g(e)){console.debug(`Process ${e} does not exist, already stopped`),o(!0);return}let s=t?"SIGKILL":"SIGTERM",i=k()?"taskkill":"tree-kill";if(console.debug(`Use ${i} to stop process ${e} (signal: ${s})`),k()){let r=t?["/F","/PID",String(e)]:["/PID",String(e)],a=E("taskkill",r,{stdio:["ignore","pipe","pipe"],windowsHide:!0}),u="";a.stdout.on("data",l=>{u+=l.toString()}),a.stderr.on("data",l=>{u+=l.toString()}),a.on("error",l=>{console.error(`Stop process failed: ${l.message}`),o(!1)}),a.on("close",l=>{l===0?(console.debug(`Process ${e} stopped`),o(!0)):(console.warn(`taskkill exit code: ${l}, output: ${u}`),t?o(!1):h(e,!0).then(o))})}else V(e,s,r=>{r?r.code==="ESRCH"?(console.debug(`Process ${e} does not exist`),o(!0)):(console.error(`Stop process failed: ${r.message}`),o(!1)):(console.debug(`Process ${e} stopped`),o(!0))})})}async function D(e,t=n.defaultStopTimeout){let o=Date.now();for(;g(e);){if(Date.now()-o>t)return console.warn(`Wait for process ${e} to stop timeout (${t}ms)`),!1;await new Promise(i=>setTimeout(i,n.checkInterval))}let s=Date.now()-o;return console.debug(`Process ${e} stopped after ${s}ms`),!0}async function Z(e,t=n.defaultStartTimeout){let o=Number(e);if(!Number.isFinite(o)||o<=0)return!1;let s=Date.now();for(;Date.now()-s<=t;){if(await new Promise(r=>{let a=M.get({host:"127.0.0.1",port:o,path:"/health",timeout:Math.min(2e3,n.checkInterval*4)},u=>{r(u.statusCode>=200&&u.statusCode<300),u.resume()});a.on("timeout",()=>{a.destroy(),r(!1)}),a.on("error",()=>r(!1))}))return!0;await new Promise(r=>setTimeout(r,n.checkInterval))}return!1}async function N(e={}){let{env:t,port:o,config:s}=e,i=null;console.log(`Start service ${n.name}...`);try{i=z()}catch(r){return r.code==="EEXIST"?{success:!1,pid:null,message:"Another start operation is in progress, please retry later"}:{success:!1,pid:null,message:`Acquire start lock failed: ${r.message}`}}try{let r=Number(e.timeout)||n.defaultStopTimeout,a=await Y(r);if(!a.success)return{success:!1,pid:null,message:`Service start blocked: ${a.message}`};let u={...process.env};t&&(u.NODE_ENV=t,console.log(`Environment: ${t}`)),o&&(u.PORT=o,console.log(`Port: ${o}`)),s&&(u.CONFIG_FILE=s,console.log(`Configuration file: ${s}`));let l=J(),p=E("node",[l,...[]],{env:u,stdio:["pipe","pipe","pipe"],detached:!0,cwd:process.cwd()});if(p.stdout.on("data",m=>{process.stdout.write(m)}),p.stderr.on("data",m=>{process.stderr.write(m)}),p.on("error",m=>{console.error(`Start service failed: ${m.message}`)}),await new Promise(m=>setTimeout(m,2e3)),!g(p.pid))return{success:!1,pid:null,message:"Service start failed"};let S={pid:p.pid,startedAt:new Date().toISOString(),env:t||process.env.NODE_ENV||"production",port:o||process.env.PORT||"60000",version:W(),platform:process.platform};B(S);let P=Number(e.startTimeout)||n.defaultStartTimeout;return await Z(S.port,P)?(p.unref(),console.log(`Service started (PID: ${p.pid})`),console.log(`Service address: http://localhost:${S.port}`),{success:!0,pid:p.pid,message:"Service started successfully"}):(console.error(`Service health check timeout (${P}ms), stop failed instance...`),await h(p.pid,!0),v(),{success:!1,pid:null,message:`Service health check timeout (${P}ms)`})}finally{Q(i)}}async function T(e={}){let{force:t=!1,timeout:o=n.defaultStopTimeout}=e;console.log(`Stop service ${n.name}...`);let s=x();if(!s)return{success:!1,message:"Service not found"};if(!g(s.pid))return console.log("Service process has stopped, clean PID file..."),v(),{success:!0,message:"Service has stopped (process has exited)"};if(!await h(s.pid,t))return{success:!1,message:"Stop service failed"};let r=await D(s.pid,o);return v(),r?{success:!0,message:"Service has stopped"}:{success:!1,message:"Service stop timeout"}}async function O(e={}){console.log(`Restart service ${n.name}...`);let t=await T(e);!t.success&&t.message!=="Service not found"&&console.warn(`Stop service failed: ${t.message}`),await new Promise(s=>setTimeout(s,2e3));let o=await N(e);return o.success?{success:!0,pid:o.pid,message:"Service has restarted"}:{success:!1,pid:null,message:`Restart failed: ${o.message}`}}function _(){let e=x();return e?g(e.pid)?{running:!0,pidInfo:e,message:"Service running"}:{running:!1,pidInfo:e,message:"Service process does not exist"}:{running:!1,pidInfo:null,message:"Service not running"}}function L(e){try{let t=new Date(e),o=new Date;if(isNaN(t.getTime()))return"unknown";let s=Math.floor((o-t)/1e3),i=Math.floor(s/3600),r=Math.floor(s%3600/60),a=s%60;return i>0?`${i} hours ${r} minutes ${a} seconds`:r>0?`${r} minutes ${a} seconds`:`${a} seconds`}catch{return"unknown"}}var Pe=te(import.meta.url),A="1.5.0",d=new ee,w={reset:"\x1B[0m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",cyan:"\x1B[36m"};function j(e){console.error(`${w.red}ERROR: ${e}${w.reset}`)}function b(e){console.log(`${w.green}${e}${w.reset}`)}function oe(e){console.log(`${w.blue}${e}${w.reset}`)}function y(e){return async(...t)=>{try{let o=await e(...t);o&&o.success===!1?(j(o.message||"Command failed"),process.exitCode=1):process.exitCode=0}catch(o){j(o?.message||"Command failed with unexpected error"),process.exitCode=1}}}async function se(e){let t=await N({env:e.env,port:e.port,config:e.config,timeout:Number(e.timeout),startTimeout:Number(e.startTimeout)});return t.success&&b(`Service started (PID: ${t.pid})`),t}async function re(e){let t=await T({force:e.force,timeout:Number(e.timeout)});return t.success&&b(t.message||"Service stopped"),t}async function ne(e){let t=await O({env:e.env,port:e.port,config:e.config,timeout:Number(e.timeout),startTimeout:Number(e.startTimeout)});return t.success&&b(t.message||"Service restarted"),t}function ie(){let e=_();return oe(`${n.name} service status:`),console.log(""),console.log(` Service name: ${n.name}`),console.log(` Running status: ${e.running?"Running":"Stopped"}`),console.log(` Message: ${e.message}`),console.log(` PID file: ${$()}`),e.pidInfo&&(console.log(` Process ID: ${e.pidInfo.pid}`),console.log(` Environment: ${e.pidInfo.env||"Unknown"}`),console.log(` Port: ${e.pidInfo.port||"Unknown"}`),console.log(` Version: ${e.pidInfo.version||A}`),console.log(` Platform: ${e.pidInfo.platform||process.platform}`),console.log(` Started at: ${e.pidInfo.startedAt||"Unknown"}`),console.log(` Uptime: ${L(e.pidInfo.startedAt)}`)),console.log(""),{success:e.running,message:e.message}}function ce(){d.name("nuwax-file-server").description("Cross-platform file service deployment tool, supporting start/stop/restart/status").version(A,"-v, --version","Display version number").helpOption("-h, --help","Display help information"),d.command("start").allowUnknownOption().description("Start service").option("--env <environment>","\u73AF\u5883: development|production|test","production").option("--port <port>","Service port").option("--config <path>","Custom configuration file path").option("--timeout <ms>","\u505C\u6B62\u65E7\u8FDB\u7A0B\u7B49\u5F85\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09",`${n.defaultStopTimeout}`).option("--start-timeout <ms>","\u542F\u52A8\u5065\u5EB7\u68C0\u67E5\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09",`${n.defaultStartTimeout}`).action(y(se)),d.command("stop").description("Stop service").option("--force","Force stop").option("--timeout <ms>","\u505C\u6B62\u670D\u52A1\u7B49\u5F85\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09",`${n.defaultStopTimeout}`).action(y(re)),d.command("restart").allowUnknownOption().description("Restart service").option("--env <environment>","\u73AF\u5883: development|production|test","production").option("--port <port>","Service port").option("--config <path>","Custom configuration file path").option("--timeout <ms>","\u505C\u6B62\u65E7\u8FDB\u7A0B\u7B49\u5F85\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09",`${n.defaultStopTimeout}`).option("--start-timeout <ms>","\u542F\u52A8\u5065\u5EB7\u68C0\u67E5\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09",`${n.defaultStartTimeout}`).action(y(ne)),d.command("status").description("View service status").action(y(ie)),d.command("help").description("Display help information").action(()=>{d.outputHelp()}),d.parse(process.argv),process.argv.slice(2).length||(d.outputHelp(),process.exitCode=0)}ce();
|
|
2
|
+
import{Command as ee}from"commander";import{createRequire as te}from"module";import f from"path";import U from"os";import c from"fs-extra";import{spawn as E}from"cross-spawn";import V from"tree-kill";import{fileURLToPath as q}from"url";import{execFileSync as R}from"child_process";import M from"http";import{createRequire as G}from"module";var I=f.dirname(q(import.meta.url)),H=G(import.meta.url),n={name:"nuwax-file-server",pidDir:f.join(U.tmpdir(),"nuwax-file-server"),pidFileName:"server.pid",lockFileName:"start.lock",defaultStopTimeout:3e4,defaultStartTimeout:3e4,staleLockTimeout:12e4,checkInterval:500};function $(){return f.join(n.pidDir,n.pidFileName)}function F(){return f.join(n.pidDir,n.lockFileName)}function J(){let e=[f.join(I,"..","server.js"),f.join(I,"server.js")];for(let t of e)if(c.existsSync(t))return t;return e[0]}function W(){let e=["../../package.json","../package.json"];for(let t of e)try{let o=H(t);if(o?.version)return o.version}catch{}return"unknown"}function x(){try{let e=$();if(!c.existsSync(e))return null;let t=c.readFileSync(e,"utf8"),o=JSON.parse(t);return!o||typeof o.pid!="number"?null:o}catch(e){return e.code!=="ENOENT"&&console.error(`Read PID file failed: ${e.message}`),null}}function B(e){try{let t=$();c.ensureDirSync(n.pidDir),c.writeFileSync(t,JSON.stringify(e,null,2)),console.debug(`PID file written: ${t}`)}catch(t){throw console.error(`Write PID file failed: ${t.message}`),t}}function v(){try{let e=$();c.existsSync(e)&&(c.removeSync(e),console.debug(`PID file deleted: ${e}`))}catch(e){console.error(`Delete PID file failed: ${e.message}`)}}function g(e){try{return process.kill(e,0),!0}catch(t){return t.code!=="ESRCH"}}function K(e){try{return k()?R("powershell",["-NoProfile","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId = ${e}").CommandLine`],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim():R("ps",["-p",String(e),"-o","command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim()}catch{return""}}function X(e){if(!g(e))return!1;let t=K(e);if(!t)return!1;let o=t.toLowerCase(),s=f.basename(f.join(I,"..","server.js")).toLowerCase(),i=n.name.toLowerCase();return o.includes(s)||o.includes(i)}function z(){c.ensureDirSync(n.pidDir);let e=F(),t=`${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2,10)}`,o=JSON.stringify({pid:process.pid,token:t,createdAt:new Date().toISOString()},null,2);try{let s=c.openSync(e,"wx");return c.writeSync(s,o),{fd:s,token:t}}catch(s){if(s.code!=="EEXIST")throw s;try{let i=c.readFileSync(e,"utf8"),r=JSON.parse(i),a=Number(r?.pid),u=r?.createdAt?new Date(r.createdAt).getTime():0,l=Date.now()-u,C=Number.isFinite(a)&&a>0&&g(a),p=!u||Number.isNaN(l)||l>n.staleLockTimeout;if(!C||p){c.removeSync(e);let S=c.openSync(e,"wx");return c.writeSync(S,o),console.warn("Detected stale start lock, auto cleaned"),{fd:S,token:t}}}catch{c.removeSync(e);let r=c.openSync(e,"wx");return c.writeSync(r,o),console.warn("Detected invalid start lock, auto cleaned"),{fd:r,token:t}}throw s}}function Q(e){let t=e?.fd,o=e?.token;try{t!=null&&c.closeSync(t)}catch{}try{let s=F();if(c.existsSync(s)){let i=!1;if(!o)i=!0;else try{let r=c.readFileSync(s,"utf8");i=JSON.parse(r)?.token===o}catch{i=!0}i&&c.removeSync(s)}}catch{}}function k(){return process.platform==="win32"}async function Y(e=n.defaultStopTimeout){let t=x();return t?X(t.pid)?(console.log(`Existing service process detected (PID: ${t.pid}), stopping before start...`),await h(t.pid,!1)&&await D(t.pid,e)?(v(),{success:!0,message:`Existing process ${t.pid} stopped gracefully`}):(console.warn(`Graceful stop timeout or failed for PID ${t.pid}, force stop...`),await h(t.pid,!0)?await D(t.pid,e)?(v(),{success:!0,message:`Existing process ${t.pid} stopped forcibly`}):{success:!1,message:`Existing process ${t.pid} did not exit after force stop`}:{success:!1,message:`Failed to stop existing process ${t.pid}`})):(console.log(`Found stale PID file (PID: ${t.pid}), clean it...`),v(),{success:!0,message:"Stale PID file cleaned"}):{success:!0,message:"No existing service process"}}async function h(e,t=!1){return new Promise(o=>{if(!g(e)){console.debug(`Process ${e} does not exist, already stopped`),o(!0);return}let s=t?"SIGKILL":"SIGTERM",i=k()?"taskkill":"tree-kill";if(console.debug(`Use ${i} to stop process ${e} (signal: ${s})`),k()){let r=t?["/F","/PID",String(e)]:["/PID",String(e)],a=E("taskkill",r,{stdio:["ignore","pipe","pipe"],windowsHide:!0}),u="";a.stdout.on("data",l=>{u+=l.toString()}),a.stderr.on("data",l=>{u+=l.toString()}),a.on("error",l=>{console.error(`Stop process failed: ${l.message}`),o(!1)}),a.on("close",l=>{l===0?(console.debug(`Process ${e} stopped`),o(!0)):(console.warn(`taskkill exit code: ${l}, output: ${u}`),t?o(!1):h(e,!0).then(o))})}else V(e,s,r=>{r?r.code==="ESRCH"?(console.debug(`Process ${e} does not exist`),o(!0)):(console.error(`Stop process failed: ${r.message}`),o(!1)):(console.debug(`Process ${e} stopped`),o(!0))})})}async function D(e,t=n.defaultStopTimeout){let o=Date.now();for(;g(e);){if(Date.now()-o>t)return console.warn(`Wait for process ${e} to stop timeout (${t}ms)`),!1;await new Promise(i=>setTimeout(i,n.checkInterval))}let s=Date.now()-o;return console.debug(`Process ${e} stopped after ${s}ms`),!0}async function Z(e,t=n.defaultStartTimeout){let o=Number(e);if(!Number.isFinite(o)||o<=0)return!1;let s=Date.now();for(;Date.now()-s<=t;){if(await new Promise(r=>{let a=M.get({host:"127.0.0.1",port:o,path:"/health",timeout:Math.min(2e3,n.checkInterval*4)},u=>{r(u.statusCode>=200&&u.statusCode<300),u.resume()});a.on("timeout",()=>{a.destroy(),r(!1)}),a.on("error",()=>r(!1))}))return!0;await new Promise(r=>setTimeout(r,n.checkInterval))}return!1}async function N(e={}){let{env:t,port:o,config:s}=e,i=null;console.log(`Start service ${n.name}...`);try{i=z()}catch(r){return r.code==="EEXIST"?{success:!1,pid:null,message:"Another start operation is in progress, please retry later"}:{success:!1,pid:null,message:`Acquire start lock failed: ${r.message}`}}try{let r=Number(e.timeout)||n.defaultStopTimeout,a=await Y(r);if(!a.success)return{success:!1,pid:null,message:`Service start blocked: ${a.message}`};let u={...process.env};t&&(u.NODE_ENV=t,console.log(`Environment: ${t}`)),o&&(u.PORT=o,console.log(`Port: ${o}`)),s&&(u.CONFIG_FILE=s,console.log(`Configuration file: ${s}`));let l=J(),p=E("node",[l,...[]],{env:u,stdio:["pipe","pipe","pipe"],detached:!0,cwd:process.cwd()});if(p.stdout.on("data",m=>{process.stdout.write(m)}),p.stderr.on("data",m=>{process.stderr.write(m)}),p.on("error",m=>{console.error(`Start service failed: ${m.message}`)}),await new Promise(m=>setTimeout(m,2e3)),!g(p.pid))return{success:!1,pid:null,message:"Service start failed"};let S={pid:p.pid,startedAt:new Date().toISOString(),env:t||process.env.NODE_ENV||"production",port:o||process.env.PORT||"60000",version:W(),platform:process.platform};B(S);let P=Number(e.startTimeout)||n.defaultStartTimeout;return await Z(S.port,P)?(p.unref(),console.log(`Service started (PID: ${p.pid})`),console.log(`Service address: http://localhost:${S.port}`),{success:!0,pid:p.pid,message:"Service started successfully"}):(console.error(`Service health check timeout (${P}ms), stop failed instance...`),await h(p.pid,!0),v(),{success:!1,pid:null,message:`Service health check timeout (${P}ms)`})}finally{Q(i)}}async function T(e={}){let{force:t=!1,timeout:o=n.defaultStopTimeout}=e;console.log(`Stop service ${n.name}...`);let s=x();if(!s)return{success:!1,message:"Service not found"};if(!g(s.pid))return console.log("Service process has stopped, clean PID file..."),v(),{success:!0,message:"Service has stopped (process has exited)"};if(!await h(s.pid,t))return{success:!1,message:"Stop service failed"};let r=await D(s.pid,o);return v(),r?{success:!0,message:"Service has stopped"}:{success:!1,message:"Service stop timeout"}}async function O(e={}){console.log(`Restart service ${n.name}...`);let t=await T(e);!t.success&&t.message!=="Service not found"&&console.warn(`Stop service failed: ${t.message}`),await new Promise(s=>setTimeout(s,2e3));let o=await N(e);return o.success?{success:!0,pid:o.pid,message:"Service has restarted"}:{success:!1,pid:null,message:`Restart failed: ${o.message}`}}function _(){let e=x();return e?g(e.pid)?{running:!0,pidInfo:e,message:"Service running"}:{running:!1,pidInfo:e,message:"Service process does not exist"}:{running:!1,pidInfo:null,message:"Service not running"}}function L(e){try{let t=new Date(e),o=new Date;if(isNaN(t.getTime()))return"unknown";let s=Math.floor((o-t)/1e3),i=Math.floor(s/3600),r=Math.floor(s%3600/60),a=s%60;return i>0?`${i} hours ${r} minutes ${a} seconds`:r>0?`${r} minutes ${a} seconds`:`${a} seconds`}catch{return"unknown"}}var Pe=te(import.meta.url),A="1.5.1",d=new ee,w={reset:"\x1B[0m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",cyan:"\x1B[36m"};function j(e){console.error(`${w.red}ERROR: ${e}${w.reset}`)}function b(e){console.log(`${w.green}${e}${w.reset}`)}function oe(e){console.log(`${w.blue}${e}${w.reset}`)}function y(e){return async(...t)=>{try{let o=await e(...t);o&&o.success===!1?(j(o.message||"Command failed"),process.exitCode=1):process.exitCode=0}catch(o){j(o?.message||"Command failed with unexpected error"),process.exitCode=1}}}async function se(e){let t=await N({env:e.env,port:e.port,config:e.config,timeout:Number(e.timeout),startTimeout:Number(e.startTimeout)});return t.success&&b(`Service started (PID: ${t.pid})`),t}async function re(e){let t=await T({force:e.force,timeout:Number(e.timeout)});return t.success&&b(t.message||"Service stopped"),t}async function ne(e){let t=await O({env:e.env,port:e.port,config:e.config,timeout:Number(e.timeout),startTimeout:Number(e.startTimeout)});return t.success&&b(t.message||"Service restarted"),t}function ie(){let e=_();return oe(`${n.name} service status:`),console.log(""),console.log(` Service name: ${n.name}`),console.log(` Running status: ${e.running?"Running":"Stopped"}`),console.log(` Message: ${e.message}`),console.log(` PID file: ${$()}`),e.pidInfo&&(console.log(` Process ID: ${e.pidInfo.pid}`),console.log(` Environment: ${e.pidInfo.env||"Unknown"}`),console.log(` Port: ${e.pidInfo.port||"Unknown"}`),console.log(` Version: ${e.pidInfo.version||A}`),console.log(` Platform: ${e.pidInfo.platform||process.platform}`),console.log(` Started at: ${e.pidInfo.startedAt||"Unknown"}`),console.log(` Uptime: ${L(e.pidInfo.startedAt)}`)),console.log(""),{success:e.running,message:e.message}}function ce(){d.name("nuwax-file-server").description("Cross-platform file service deployment tool, supporting start/stop/restart/status").version(A,"-v, --version","Display version number").helpOption("-h, --help","Display help information"),d.command("start").allowUnknownOption().description("Start service").option("--env <environment>","\u73AF\u5883: development|production|test","production").option("--port <port>","Service port").option("--config <path>","Custom configuration file path").option("--timeout <ms>","\u505C\u6B62\u65E7\u8FDB\u7A0B\u7B49\u5F85\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09",`${n.defaultStopTimeout}`).option("--start-timeout <ms>","\u542F\u52A8\u5065\u5EB7\u68C0\u67E5\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09",`${n.defaultStartTimeout}`).action(y(se)),d.command("stop").description("Stop service").option("--force","Force stop").option("--timeout <ms>","\u505C\u6B62\u670D\u52A1\u7B49\u5F85\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09",`${n.defaultStopTimeout}`).action(y(re)),d.command("restart").allowUnknownOption().description("Restart service").option("--env <environment>","\u73AF\u5883: development|production|test","production").option("--port <port>","Service port").option("--config <path>","Custom configuration file path").option("--timeout <ms>","\u505C\u6B62\u65E7\u8FDB\u7A0B\u7B49\u5F85\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09",`${n.defaultStopTimeout}`).option("--start-timeout <ms>","\u542F\u52A8\u5065\u5EB7\u68C0\u67E5\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09",`${n.defaultStartTimeout}`).action(y(ne)),d.command("status").description("View service status").action(y(ie)),d.command("help").description("Display help information").action(()=>{d.outputHelp()}),d.parse(process.argv),process.argv.slice(2).length||(d.outputHelp(),process.exitCode=0)}ce();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import v from"express";import b from"multer";import g from"fs";import j from"path";import{ValidationError as P,asyncHandler as c}from"../utils/error/errorHandler.js";import{log as u}from"../utils/log/logUtils.js";import z from"../appConfig/index.js";import{createWorkspace as T,pushSkillsToWorkspace as O,initProjectTemplate as R,installProjectDependencies as M,executeCommand as _,deleteWorkspace as B,zipWorkspace as H,buildAgentPackage as L,cleanupBuildArtifacts as W}from"../utils/computer/computerUtils.js";import{getFileList as J,getFileMeta as K,resolveExistingFile as V,searchFiles as G,updateFiles as Z,uploadFile as X,uploadFiles as Y,generateFile as Q,downloadAllFiles as q,getLatestLogs as ee,importProject as te}from"../utils/computer/computerFileUtils.js";import{resolveServiceContext as d}from"../utils/computer/workspaceContext.js";import{listFsRoots as se,listFsChildren as ae}from"../utils/computer/fsBrowserUtils.js";const A=v.Router(),I=b({storage:b.diskStorage({destination:(e,n,s)=>{try{const t=typeof e.headers["x-workspace-type"]=="string"?e.headers["x-workspace-type"].trim().toLowerCase():"",a=typeof e.headers["x-app-id"]=="string"?e.headers["x-app-id"].trim():"";let o;if(t==="userapp"&&a){const i=z.USERAPP_WORKSPACE_DIR;if(!i)return s(new Error("USERAPP_WORKSPACE_DIR is not configured, cannot determine upload temporary directory"));o=j.join(i,String(a),".tmp")}else{const i=z.COMPUTER_WORKSPACE_DIR;if(!i)return s(new Error("COMPUTER_WORKSPACE_DIR is not configured, cannot determine upload temporary directory"));const r=e.body?.userId||"unknown",l=e.body?.cId||"unknown";o=j.join(i,String(r),String(l),".tmp")}g.existsSync(o)||g.mkdirSync(o,{recursive:!0}),s(null,o)}catch(t){s(t)}},filename:(e,n,s)=>{const t=j.extname(n.originalname)||".zip",a=j.basename(n.originalname,t),o=`${Date.now()}_${Math.round(Math.random()*1e6)}`;s(null,`${a}_${o}${t}`)}}),limits:{fileSize:z.UPLOAD_MAX_FILE_SIZE_BYTES}});function oe(e,n,s,t){if(e&&e.name==="MulterError"||e&&(e.name==="ValidationError"||e instanceof P))return t(e);t(e)}const ne=[{path:"/create-workspace",method:"post",middleware:I.single("file"),handler:c(async(e,n)=>{const{userId:s,cId:t}=e.body||{},a=e.file||null,o=d(e),i=`computer:${s}:${t}`;u(i,"INFO","Create workspace request",{userId:s,cId:t,workspaceType:o.workspaceType,appId:o.appId,hasFile:!!a,fileName:a?.originalname,fileSize:a?.size});const r=await T(s,t,a,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,o);n.status(200).json({success:!0,...r})})},{path:"/create-workspace-v2",method:"post",middleware:I.single("file"),handler:c(async(e,n)=>{const{userId:s,cId:t,agentId:a,skillUrls:o,skillUrlMap:i,skillNames:r,updateSkillNames:l,mcpServersConfig:p,hooksConfig:f,permissionsConfig:m,hookScripts:h}=e.body||{},k=e.file||null,C=d(e),D=`computer:${s}:${t}`;let N=o;if(typeof o=="string")try{N=JSON.parse(o)}catch{N=[o]}let w=i;if(typeof i=="string")try{w=JSON.parse(i)}catch{w=null}let F=r;if(typeof r=="string")try{const y=JSON.parse(r);F=Array.isArray(y)?y:[r]}catch{F=r.split(",").map(y=>y.trim()).filter(Boolean)}let S=l;if(typeof l=="string")try{const y=JSON.parse(l);S=Array.isArray(y)?y:[l]}catch{S=l.split(",").map(y=>y.trim()).filter(Boolean)}let $=h;if(typeof h=="string")try{$=JSON.parse(h)}catch{$=null}const x=Array.isArray(N)?N.length:0,E=w&&typeof w=="object"&&!Array.isArray(w)?Object.keys(w).length:0;u(D,"INFO","Create workspace v2 request",{userId:s,cId:t,agentId:a,workspaceType:C.workspaceType,appId:C.appId,hasFile:!!k,fileName:k?.originalname,fileSize:k?.size,skillUrlsCount:x,skillUrlMapCount:E,skillNamesCount:Array.isArray(F)?F.length:0,updateSkillNamesCount:Array.isArray(S)?S.length:0,hasMcpServersConfig:!!p,hasHooksConfig:!!f,hasPermissionsConfig:!!m,hookScriptsCount:Array.isArray($)?$.length:0});const U=await T(s,t,k,N,p,m,f,$,a,F,S,w,C);n.status(200).json({success:!0,...U})})},{path:"/push-skills-to-workspace",method:"post",middleware:I.single("file"),handler:c(async(e,n)=>{const{userId:s,cId:t}=e.body||{},a=e.file||null,o=d(e),i=`computer:${s}:${t}`;u(i,"INFO","\u63A8\u9001\u6280\u80FD\u5230\u5DE5\u4F5C\u7A7A\u95F4\u8BF7\u6C42",{userId:s,cId:t,workspaceType:o.workspaceType,appId:o.appId,hasFile:!!a,fileName:a?.originalname,fileSize:a?.size});const r=await O(s,t,a,void 0,void 0,o);n.status(200).json({success:!0,...r})})},{path:"/push-skills-to-workspace-v2",method:"post",middleware:I.single("file"),handler:c(async(e,n)=>{const{userId:s,cId:t,agentId:a,skillUrls:o}=e.body||{},i=e.file||null,r=d(e),l=`computer:${s}:${t}`;let p=o;if(typeof o=="string")try{const m=JSON.parse(o);p=Array.isArray(m)?m:[o]}catch{p=[o]}u(l,"INFO","\u63A8\u9001\u6280\u80FD\u5230\u5DE5\u4F5C\u7A7A\u95F4\u8BF7\u6C42(v2)",{userId:s,cId:t,agentId:a,workspaceType:r.workspaceType,appId:r.appId,hasFile:!!i,fileName:i?.originalname,fileSize:i?.size,skillUrlsCount:Array.isArray(p)?p.length:0});const f=await O(s,t,i,p,a,r);n.status(200).json({success:!0,...f})})},{path:"/fs/roots",method:"get",handler:c(async(e,n)=>{const s=await se();n.status(200).json({success:!0,...s})})},{path:"/fs/children",method:"get",handler:c(async(e,n)=>{const{path:s}=e.query,t=await ae(s);n.status(200).json({success:!0,...t})})},{path:"/get-file-list",method:"get",handler:c(async(e,n)=>{const{userId:s,cId:t,proxyPath:a,customTargetDir:o,relativePath:i,recursive:r}=e.query,l=await J(s,t,a,o,i,r,d(e));n.status(200).json({success:!0,...l})})},{path:"/resolve-file",method:"get",handler:c(async(e,n)=>{const{userId:s,cId:t,proxyPath:a,customTargetDir:o,filePath:i}=e.query,r=await V(s,t,i,a,o,d(e));n.status(200).json({success:!0,...r})})},{path:"/get-file-meta",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t,customTargetDir:a,filePaths:o,fileMetaMaxBatch:i}=e.body||{},r=await K(s,t,o,a,d(e),i);n.status(200).json({success:!0,...r})})},{path:"/search-files",method:"get",handler:c(async(e,n)=>{const{userId:s,cId:t,proxyPath:a,customTargetDir:o,relativePath:i,kw:r,limit:l,maxVisit:p,timeoutMs:f}=e.query,m=await G(s,t,a,r,o,i,l,p,f,d(e));n.status(200).json({success:!0,...m})})},{path:"/files-update",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t,files:a,customTargetDir:o}=e.body||{},i=`computer:${s}:${t}`;u(i,"INFO","Files update",{userId:s,cId:t,filesCount:a?a.length:0}),a&&Array.isArray(a)&&a.forEach(l=>{if(l&&typeof l.contents=="string"&&l.contents)try{l.contents=decodeURIComponent(l.contents)}catch(p){u(i,"WARN","Decode file content failed",{fileName:l.name,error:p.message})}});const r=await Z(s,t,a,o,d(e));n.status(200).json(r)})},{path:"/upload-file",method:"post",middleware:I.single("file"),handler:c(async(e,n)=>{const{userId:s,cId:t,filePath:a,customTargetDir:o}=e.body||{},i=e.file,r=`computer:${s}:${t}`;u(r,"INFO","Upload single file",{userId:s,cId:t,filePath:a});const p={buffer:await g.promises.readFile(i.path),originalname:i.originalname,mimetype:i.mimetype,size:i.size};try{const f=await X(s,t,p,a,o,d(e));n.status(200).json(f)}finally{g.existsSync(i.path)&&await g.promises.unlink(i.path)}})},{path:"/generate-file",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t,fileName:a,content:o,customTargetDir:i}=e.body||{},r=`computer:${s}:${t}`;u(r,"INFO","Generate file request",{userId:s,cId:t,fileName:a,contentLength:typeof o=="string"?o.length:0});const l=await Q(s,t,a,o,i,d(e));n.status(200).json(l)})},{path:"/import-project",method:"post",middleware:I.single("file"),handler:c(async(e,n)=>{const{userId:s,cId:t,customTargetDir:a}=e.body||{},o=e.file,i=`computer:${s}:${t}`;if(u(i,"INFO","Import project request",{userId:s,cId:t,fileName:o?.originalname,fileSize:o?.size}),!o)throw new P("file is required",{field:"file"});const r=await te(s,t,o,a,d(e));n.status(200).json(r)})},{path:"/upload-files",method:"post",middleware:I.array("files"),handler:c(async(e,n)=>{const{userId:s,cId:t,filePaths:a,customTargetDir:o}=e.body||{},i=e.files||[],r=`computer:${s}:${t}`,l=Array.isArray(a)?a:typeof a=="string"?[a]:a;u(r,"INFO","Batch upload files request",{userId:s,cId:t,filesCount:i.length,filePathsCount:Array.isArray(l)?l.length:0});const p=[],f=[];try{for(const h of i){f.push(h.path);const k=await g.promises.readFile(h.path);p.push({buffer:k,originalname:h.originalname,mimetype:h.mimetype,size:h.size})}const m=await Y(s,t,p,l,o,d(e));n.status(200).json(m)}finally{for(const m of f)if(g.existsSync(m))try{await g.promises.unlink(m)}catch(h){u(r,"WARN","Clean temporary file failed",{tempPath:m,error:h.message})}}})},{path:"/install-project",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t,programmingLanguage:a}=e.body||{},o=`computer:${s}:${t}`;u(o,"INFO","Install project request",{userId:s,cId:t,programmingLanguage:a});const i=await M(s,t,a,d(e));n.status(200).json({success:!0,...i})})},{path:"/init-project-template",method:"post",middleware:I.single("file"),handler:c(async(e,n)=>{const{userId:s,cId:t,enableGit:a}=e.body||{},o=e.file||null,i=`computer:${s}:${t}`;u(i,"INFO","Init project template request",{userId:s,cId:t,hasFile:!!o,fileName:o?.originalname,fileSize:o?.size,enableGit:a});const r=await R(s,t,o,a,d(e));n.status(200).json({success:!0,...r})})},{path:"/download-all-files",method:"get",handler:c(async(e,n)=>{const{userId:s,cId:t,customTargetDir:a}=e.query||{},o=`computer:${s}:${t}`;u(o,"INFO","Download all files request",{userId:s,cId:t});const{archive:i,zipFileName:r}=await q(s,t,a,d(e));n.setHeader("Content-Type","application/zip");const l=encodeURIComponent(r);n.setHeader("Content-Disposition",`attachment; filename="${l}"; filename*=UTF-8''${l}`),i.on("error",p=>{n.destroy(p)}),i.pipe(n),i.finalize()})},{path:"/execute-command",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t,command:a}=e.body||{},o=`computer:${s}:${t}`;u(o,"INFO","Execute command request",{userId:s,cId:t,command:a});const i=await _(s,t,a,d(e));n.status(200).json({success:!0,...i})})},{path:"/delete-workspace",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t}=e.body||{},a=`computer:${s}:${t}`;u(a,"INFO","Delete workspace request",{userId:s,cId:t});const o=await B(s,t,d(e));n.status(200).json({success:!0,...o})})},{path:"/get-logs",method:"get",handler:c(async(e,n)=>{const{userId:s,cId:t,tailLines:a}=e.query,o=a?parseInt(a,10):200,i=Number.isFinite(o)&&o>0?o:200,r=await ee(s,t,i,d(e));n.status(200).json(r)})},{path:"/zip-workspace",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t,excludeDirs:a}=e.body||{},o=`computer:${s}:${t}`;u(o,"INFO","Zip workspace request",{userId:s,cId:t,hasExcludeDirs:!!a});const{archive:i,zipFileName:r}=await H(s,t,a||null,d(e));n.setHeader("Content-Type","application/zip");const l=encodeURIComponent(r);n.setHeader("Content-Disposition",`attachment; filename="${l}"; filename*=UTF-8''${l}`),i.on("error",p=>{n.destroy(p)}),i.pipe(n),i.finalize()})},{path:"/build-agent-package",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t,agentId:a,version:o}=e.body||{},i=`computer:${s}:${t}`;u(i,"INFO","Build agent package request",{userId:s,cId:t,agentId:a,version:o});const r=await L(s,t,a,o,d(e));n.status(200).json({success:!0,...r})})},{path:"/cleanup-build-artifacts",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t}=e.body||{},a=`computer:${s}:${t}`;u(a,"INFO","Cleanup build artifacts request",{userId:s,cId:t});const o=await W(s,t,d(e));n.status(200).json({success:!0,...o})})}];ne.forEach(e=>{if(e.middleware)A[e.method](e.path,e.middleware,e.handler);else if(e.customHandler){const n=[];e.handler&&n.push(e.handler),e.decodeMiddleware&&n.push(e.decodeMiddleware),n.push(oe),n.push(e.customHandler),A[e.method](e.path,...n)}else A[e.method](e.path,e.handler)});export default A;
|
|
1
|
+
import v from"express";import z from"multer";import g from"fs";import j from"path";import{ValidationError as P,asyncHandler as c}from"../utils/error/errorHandler.js";import{log as u}from"../utils/log/logUtils.js";import b from"../appConfig/index.js";import{createWorkspace as D,pushSkillsToWorkspace as T,initProjectTemplate as R,installProjectDependencies as M,executeCommand as _,deleteWorkspace as B,zipWorkspace as H,buildAgentPackage as L,cleanupBuildArtifacts as W}from"../utils/computer/computerUtils.js";import{getFileList as J,getFileMeta as K,resolveExistingFile as V,searchFiles as G,updateFiles as Z,uploadFile as X,uploadFiles as Y,generateFile as Q,downloadAllFiles as q,getLatestLogs as ee,importProject as te}from"../utils/computer/computerFileUtils.js";import{resolveServiceContext as d}from"../utils/computer/workspaceContext.js";import{listFsRoots as se,listFsChildren as ae,createFsDirectory as oe,renameFsDirectory as ne}from"../utils/computer/fsBrowserUtils.js";const A=v.Router(),I=z({storage:z.diskStorage({destination:(e,n,s)=>{try{const t=typeof e.headers["x-workspace-type"]=="string"?e.headers["x-workspace-type"].trim().toLowerCase():"",a=typeof e.headers["x-app-id"]=="string"?e.headers["x-app-id"].trim():"";let o;if(t==="userapp"&&a){const r=b.USERAPP_WORKSPACE_DIR;if(!r)return s(new Error("USERAPP_WORKSPACE_DIR is not configured, cannot determine upload temporary directory"));o=j.join(r,String(a),".tmp")}else{const r=b.COMPUTER_WORKSPACE_DIR;if(!r)return s(new Error("COMPUTER_WORKSPACE_DIR is not configured, cannot determine upload temporary directory"));const i=e.body?.userId||"unknown",l=e.body?.cId||"unknown";o=j.join(r,String(i),String(l),".tmp")}g.existsSync(o)||g.mkdirSync(o,{recursive:!0}),s(null,o)}catch(t){s(t)}},filename:(e,n,s)=>{const t=j.extname(n.originalname)||".zip",a=j.basename(n.originalname,t),o=`${Date.now()}_${Math.round(Math.random()*1e6)}`;s(null,`${a}_${o}${t}`)}}),limits:{fileSize:b.UPLOAD_MAX_FILE_SIZE_BYTES}});function re(e,n,s,t){if(e&&e.name==="MulterError"||e&&(e.name==="ValidationError"||e instanceof P))return t(e);t(e)}const ie=[{path:"/create-workspace",method:"post",middleware:I.single("file"),handler:c(async(e,n)=>{const{userId:s,cId:t}=e.body||{},a=e.file||null,o=d(e),r=`computer:${s}:${t}`;u(r,"INFO","Create workspace request",{userId:s,cId:t,workspaceType:o.workspaceType,appId:o.appId,hasFile:!!a,fileName:a?.originalname,fileSize:a?.size});const i=await D(s,t,a,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,o);n.status(200).json({success:!0,...i})})},{path:"/create-workspace-v2",method:"post",middleware:I.single("file"),handler:c(async(e,n)=>{const{userId:s,cId:t,agentId:a,skillUrls:o,skillUrlMap:r,skillNames:i,updateSkillNames:l,mcpServersConfig:p,hooksConfig:f,permissionsConfig:m,hookScripts:h}=e.body||{},k=e.file||null,C=d(e),O=`computer:${s}:${t}`;let N=o;if(typeof o=="string")try{N=JSON.parse(o)}catch{N=[o]}let w=r;if(typeof r=="string")try{w=JSON.parse(r)}catch{w=null}let F=i;if(typeof i=="string")try{const y=JSON.parse(i);F=Array.isArray(y)?y:[i]}catch{F=i.split(",").map(y=>y.trim()).filter(Boolean)}let S=l;if(typeof l=="string")try{const y=JSON.parse(l);S=Array.isArray(y)?y:[l]}catch{S=l.split(",").map(y=>y.trim()).filter(Boolean)}let $=h;if(typeof h=="string")try{$=JSON.parse(h)}catch{$=null}const x=Array.isArray(N)?N.length:0,E=w&&typeof w=="object"&&!Array.isArray(w)?Object.keys(w).length:0;u(O,"INFO","Create workspace v2 request",{userId:s,cId:t,agentId:a,workspaceType:C.workspaceType,appId:C.appId,hasFile:!!k,fileName:k?.originalname,fileSize:k?.size,skillUrlsCount:x,skillUrlMapCount:E,skillNamesCount:Array.isArray(F)?F.length:0,updateSkillNamesCount:Array.isArray(S)?S.length:0,hasMcpServersConfig:!!p,hasHooksConfig:!!f,hasPermissionsConfig:!!m,hookScriptsCount:Array.isArray($)?$.length:0});const U=await D(s,t,k,N,p,m,f,$,a,F,S,w,C);n.status(200).json({success:!0,...U})})},{path:"/push-skills-to-workspace",method:"post",middleware:I.single("file"),handler:c(async(e,n)=>{const{userId:s,cId:t}=e.body||{},a=e.file||null,o=d(e),r=`computer:${s}:${t}`;u(r,"INFO","\u63A8\u9001\u6280\u80FD\u5230\u5DE5\u4F5C\u7A7A\u95F4\u8BF7\u6C42",{userId:s,cId:t,workspaceType:o.workspaceType,appId:o.appId,hasFile:!!a,fileName:a?.originalname,fileSize:a?.size});const i=await T(s,t,a,void 0,void 0,o);n.status(200).json({success:!0,...i})})},{path:"/push-skills-to-workspace-v2",method:"post",middleware:I.single("file"),handler:c(async(e,n)=>{const{userId:s,cId:t,agentId:a,skillUrls:o}=e.body||{},r=e.file||null,i=d(e),l=`computer:${s}:${t}`;let p=o;if(typeof o=="string")try{const m=JSON.parse(o);p=Array.isArray(m)?m:[o]}catch{p=[o]}u(l,"INFO","\u63A8\u9001\u6280\u80FD\u5230\u5DE5\u4F5C\u7A7A\u95F4\u8BF7\u6C42(v2)",{userId:s,cId:t,agentId:a,workspaceType:i.workspaceType,appId:i.appId,hasFile:!!r,fileName:r?.originalname,fileSize:r?.size,skillUrlsCount:Array.isArray(p)?p.length:0});const f=await T(s,t,r,p,a,i);n.status(200).json({success:!0,...f})})},{path:"/fs/roots",method:"get",handler:c(async(e,n)=>{const s=await se();n.status(200).json({success:!0,...s})})},{path:"/fs/children",method:"get",handler:c(async(e,n)=>{const{path:s}=e.query,t=await ae(s);n.status(200).json({success:!0,...t})})},{path:"/fs/mkdir",method:"post",handler:c(async(e,n)=>{const{parentPath:s,dirName:t}=e.body||{},a=await oe(s,t);n.status(200).json({success:!0,...a})})},{path:"/fs/rename",method:"post",handler:c(async(e,n)=>{const{path:s,newName:t}=e.body||{},a=await ne(s,t);n.status(200).json({success:!0,...a})})},{path:"/get-file-list",method:"get",handler:c(async(e,n)=>{const{userId:s,cId:t,proxyPath:a,customTargetDir:o,relativePath:r,recursive:i}=e.query,l=await J(s,t,a,o,r,i,d(e));n.status(200).json({success:!0,...l})})},{path:"/resolve-file",method:"get",handler:c(async(e,n)=>{const{userId:s,cId:t,proxyPath:a,customTargetDir:o,filePath:r}=e.query,i=await V(s,t,r,a,o,d(e));n.status(200).json({success:!0,...i})})},{path:"/get-file-meta",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t,customTargetDir:a,filePaths:o,fileMetaMaxBatch:r}=e.body||{},i=await K(s,t,o,a,d(e),r);n.status(200).json({success:!0,...i})})},{path:"/search-files",method:"get",handler:c(async(e,n)=>{const{userId:s,cId:t,proxyPath:a,customTargetDir:o,relativePath:r,kw:i,limit:l,maxVisit:p,timeoutMs:f}=e.query,m=await G(s,t,a,i,o,r,l,p,f,d(e));n.status(200).json({success:!0,...m})})},{path:"/files-update",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t,files:a,customTargetDir:o}=e.body||{},r=`computer:${s}:${t}`;u(r,"INFO","Files update",{userId:s,cId:t,filesCount:a?a.length:0}),a&&Array.isArray(a)&&a.forEach(l=>{if(l&&typeof l.contents=="string"&&l.contents)try{l.contents=decodeURIComponent(l.contents)}catch(p){u(r,"WARN","Decode file content failed",{fileName:l.name,error:p.message})}});const i=await Z(s,t,a,o,d(e));n.status(200).json(i)})},{path:"/upload-file",method:"post",middleware:I.single("file"),handler:c(async(e,n)=>{const{userId:s,cId:t,filePath:a,customTargetDir:o}=e.body||{},r=e.file,i=`computer:${s}:${t}`;u(i,"INFO","Upload single file",{userId:s,cId:t,filePath:a});const p={buffer:await g.promises.readFile(r.path),originalname:r.originalname,mimetype:r.mimetype,size:r.size};try{const f=await X(s,t,p,a,o,d(e));n.status(200).json(f)}finally{g.existsSync(r.path)&&await g.promises.unlink(r.path)}})},{path:"/generate-file",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t,fileName:a,content:o,customTargetDir:r}=e.body||{},i=`computer:${s}:${t}`;u(i,"INFO","Generate file request",{userId:s,cId:t,fileName:a,contentLength:typeof o=="string"?o.length:0});const l=await Q(s,t,a,o,r,d(e));n.status(200).json(l)})},{path:"/import-project",method:"post",middleware:I.single("file"),handler:c(async(e,n)=>{const{userId:s,cId:t,customTargetDir:a}=e.body||{},o=e.file,r=`computer:${s}:${t}`;if(u(r,"INFO","Import project request",{userId:s,cId:t,fileName:o?.originalname,fileSize:o?.size}),!o)throw new P("file is required",{field:"file"});const i=await te(s,t,o,a,d(e));n.status(200).json(i)})},{path:"/upload-files",method:"post",middleware:I.array("files"),handler:c(async(e,n)=>{const{userId:s,cId:t,filePaths:a,customTargetDir:o}=e.body||{},r=e.files||[],i=`computer:${s}:${t}`,l=Array.isArray(a)?a:typeof a=="string"?[a]:a;u(i,"INFO","Batch upload files request",{userId:s,cId:t,filesCount:r.length,filePathsCount:Array.isArray(l)?l.length:0});const p=[],f=[];try{for(const h of r){f.push(h.path);const k=await g.promises.readFile(h.path);p.push({buffer:k,originalname:h.originalname,mimetype:h.mimetype,size:h.size})}const m=await Y(s,t,p,l,o,d(e));n.status(200).json(m)}finally{for(const m of f)if(g.existsSync(m))try{await g.promises.unlink(m)}catch(h){u(i,"WARN","Clean temporary file failed",{tempPath:m,error:h.message})}}})},{path:"/install-project",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t,programmingLanguage:a}=e.body||{},o=`computer:${s}:${t}`;u(o,"INFO","Install project request",{userId:s,cId:t,programmingLanguage:a});const r=await M(s,t,a,d(e));n.status(200).json({success:!0,...r})})},{path:"/init-project-template",method:"post",middleware:I.single("file"),handler:c(async(e,n)=>{const{userId:s,cId:t,enableGit:a}=e.body||{},o=e.file||null,r=`computer:${s}:${t}`;u(r,"INFO","Init project template request",{userId:s,cId:t,hasFile:!!o,fileName:o?.originalname,fileSize:o?.size,enableGit:a});const i=await R(s,t,o,a,d(e));n.status(200).json({success:!0,...i})})},{path:"/download-all-files",method:"get",handler:c(async(e,n)=>{const{userId:s,cId:t,customTargetDir:a}=e.query||{},o=`computer:${s}:${t}`;u(o,"INFO","Download all files request",{userId:s,cId:t});const{archive:r,zipFileName:i}=await q(s,t,a,d(e));n.setHeader("Content-Type","application/zip");const l=encodeURIComponent(i);n.setHeader("Content-Disposition",`attachment; filename="${l}"; filename*=UTF-8''${l}`),r.on("error",p=>{n.destroy(p)}),r.pipe(n),r.finalize()})},{path:"/execute-command",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t,command:a}=e.body||{},o=`computer:${s}:${t}`;u(o,"INFO","Execute command request",{userId:s,cId:t,command:a});const r=await _(s,t,a,d(e));n.status(200).json({success:!0,...r})})},{path:"/delete-workspace",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t}=e.body||{},a=`computer:${s}:${t}`;u(a,"INFO","Delete workspace request",{userId:s,cId:t});const o=await B(s,t,d(e));n.status(200).json({success:!0,...o})})},{path:"/get-logs",method:"get",handler:c(async(e,n)=>{const{userId:s,cId:t,tailLines:a}=e.query,o=a?parseInt(a,10):200,r=Number.isFinite(o)&&o>0?o:200,i=await ee(s,t,r,d(e));n.status(200).json(i)})},{path:"/zip-workspace",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t,excludeDirs:a}=e.body||{},o=`computer:${s}:${t}`;u(o,"INFO","Zip workspace request",{userId:s,cId:t,hasExcludeDirs:!!a});const{archive:r,zipFileName:i}=await H(s,t,a||null,d(e));n.setHeader("Content-Type","application/zip");const l=encodeURIComponent(i);n.setHeader("Content-Disposition",`attachment; filename="${l}"; filename*=UTF-8''${l}`),r.on("error",p=>{n.destroy(p)}),r.pipe(n),r.finalize()})},{path:"/build-agent-package",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t,agentId:a,version:o}=e.body||{},r=`computer:${s}:${t}`;u(r,"INFO","Build agent package request",{userId:s,cId:t,agentId:a,version:o});const i=await L(s,t,a,o,d(e));n.status(200).json({success:!0,...i})})},{path:"/cleanup-build-artifacts",method:"post",handler:c(async(e,n)=>{const{userId:s,cId:t}=e.body||{},a=`computer:${s}:${t}`;u(a,"INFO","Cleanup build artifacts request",{userId:s,cId:t});const o=await W(s,t,d(e));n.status(200).json({success:!0,...o})})}];ie.forEach(e=>{if(e.middleware)A[e.method](e.path,e.middleware,e.handler);else if(e.customHandler){const n=[];e.handler&&n.push(e.handler),e.decodeMiddleware&&n.push(e.decodeMiddleware),n.push(re),n.push(e.customHandler),A[e.method](e.path,...n)}else A[e.method](e.path,e.handler)});export default A;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import m from"fs";import w from"os";import h from"path";import{ValidationError as o}from"../error/errorHandler.js";function a(t){const r=t.startsWith("\\\\")||t.startsWith("//");let e=String(t).replace(/\\/g,"/").replace(/\/{2,}/g,"/");return r&&(e="/"+e),e}export async function listFsRoots(){const t=a(w.homedir()),r=[];if(process.platform==="win32")for(let e=65;e<=90;e++){const n=String.fromCharCode(e)+":/";try{await m.promises.stat(n),r.push({name:n,path:n,isDir:!0})}catch{}}else r.push({name:"/",path:"/",isDir:!0});return{roots:r,home:t}}function p(t,r="path"){if(!t||typeof t!="string"||t.includes("\0"))throw new o(`${r} is required`,{field:r});if(!h.isAbsolute(t))throw new o(`${r} must be absolute`,{field:r})}function u(t,r){const e=String(t??"").trim();if(!e||e.includes("\0"))throw new o(`${r} is required`,{field:r});if(e.includes("/")||e.includes("\\"))throw new o(`${r} must not contain path separators`,{field:r});if(e==="."||e==="..")throw new o(`${r} must not be a relative segment`,{field:r});if(e.length>255)throw new o(`${r} exceeds 255 characters`,{field:r});return e}export async function listFsChildren(t){p(t);let r;try{r=await m.promises.readdir(t,{withFileTypes:!0})}catch(n){throw new o(`cannot read directory (${n.code||n.message})`,{field:"path"})}const e=[];for(const n of r){let i=n.isDirectory();const c=n.isSymbolicLink();if(c)try{i=(await m.promises.stat(h.join(t,n.name))).isDirectory()}catch{}e.push({name:n.name,path:a(h.join(t,n.name)),isDir:i,isSymlink:c})}return e.sort((n,i)=>Number(i.isDir)-Number(n.isDir)||n.name.localeCompare(i.name,void 0,{sensitivity:"base",numeric:!0})),{path:a(t),entries:e}}export async function createFsDirectory(t,r){p(t,"parentPath");const e=u(r,"dirName"),n=h.join(t,e);try{await m.promises.mkdir(n)}catch(i){throw i.code==="EEXIST"?new o(`directory already exists: ${e}`,{field:"dirName"}):i.code==="ENOENT"?new o("parent directory does not exist",{field:"parentPath"}):new o(`cannot create directory (${i.code||i.message})`,{field:"dirName"})}return{path:a(n),name:e,parentPath:a(t),isDir:!0,isSymlink:!1}}export async function renameFsDirectory(t,r){p(t);const e=u(r,"newName"),n=h.dirname(t);if(n===t)throw new o("cannot rename the root directory",{field:"path"});const i=h.join(n,e);let c;try{await m.promises.stat(i),c=!0}catch(s){if(s.code!=="ENOENT")throw new o(`cannot rename (${s.code||s.message})`,{field:"path"});c=!1}if(c)throw new o(`name already exists: ${e}`,{field:"newName"});try{await m.promises.rename(t,i)}catch(s){throw s.code==="ENOENT"?new o("directory does not exist",{field:"path"}):new o(`cannot rename directory (${s.code||s.message})`,{field:"newName"})}return{path:a(i),name:e,parentPath:a(n),isDir:!0,isSymlink:!1}}
|
package/package.json
CHANGED