@runium/cli 0.0.2 → 0.0.4

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.
Files changed (38) hide show
  1. package/app.js +2 -2
  2. package/commands/plugin/plugin-add.js +1 -1
  3. package/commands/plugin/plugin-disable.js +1 -1
  4. package/commands/plugin/plugin-enable.js +1 -1
  5. package/commands/plugin/plugin-remove.js +1 -1
  6. package/commands/plugin/plugin.js +1 -1
  7. package/commands/project/project-add.js +1 -1
  8. package/commands/project/project-command.js +1 -1
  9. package/commands/project/project-start.js +1 -1
  10. package/commands/project/project-state-command.js +1 -1
  11. package/commands/project/project-status.js +1 -1
  12. package/commands/project/project-stop.js +1 -1
  13. package/commands/project/project-validate.js +4 -1
  14. package/commands/project/project.js +1 -1
  15. package/commands/runium-command.js +1 -1
  16. package/constants/error-code.js +1 -1
  17. package/index.js +1 -1
  18. package/macros/date.js +1 -0
  19. package/macros/index.js +1 -1
  20. package/macros/path.js +1 -1
  21. package/package.json +4 -3
  22. package/services/command.js +1 -0
  23. package/services/config.js +1 -1
  24. package/services/file.js +1 -0
  25. package/services/index.js +1 -1
  26. package/services/output.js +3 -3
  27. package/services/plugin-context.js +1 -1
  28. package/services/plugin.js +1 -1
  29. package/services/profile.js +1 -1
  30. package/services/project.js +1 -1
  31. package/services/shutdown.js +1 -1
  32. package/utils/get-version.js +1 -0
  33. package/utils/index.js +1 -1
  34. package/validation/create-validator.js +1 -0
  35. package/validation/get-config-schema.js +1 -0
  36. package/validation/get-error-messages.js +1 -0
  37. package/validation/get-plugin-schema.js +1 -0
  38. package/validation/index.js +1 -0
package/app.js CHANGED
@@ -1,6 +1,6 @@
1
- import{existsSync as u}from"node:fs";import{resolve as p}from"node:path";import{Command as v}from"commander";import{Container as o}from"typedi";import*as c from"./commands/index.js";import{ConfigService as l,ProfileService as g,PluginService as d,ShutdownService as m,OutputService as h,OutputLevel as r,PluginContextService as S}from"./services/index.js";const f=`\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
1
+ import{existsSync as c}from"node:fs";import{resolve as u}from"node:path";import{Command as v}from"commander";import{Container as o}from"typedi";import*as p from"./commands/index.js";import{CommandService as g,ConfigService as l,ProfileService as m,PluginService as h,ShutdownService as d,OutputService as S,OutputLevel as n,PluginContextService as f}from"./services/index.js";import{getVersion as P}from"./utils/index.js";const C=`\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
2
2
  \u2551 \u2554\u2550\u2557 \u2566 \u2566 \u2554\u2557\u2554 \u2566 \u2566 \u2566 \u2554\u2566\u2557 \u2551
3
3
  \u2551 \u2560\u2566\u255D \u2551 \u2551 \u2551\u2551\u2551 \u2551 \u2551 \u2551 \u2551\u2551\u2551 \u2551
4
4
  \u2551 \u2569\u255A\u2550 \u255A\u2550\u255D \u255D\u255A\u255D \u2569 \u255A\u2550\u255D \u2569 \u2569 \u2551
5
5
  \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
6
- One Tool to Run Them All!`;class F{program;configService;profileService;pluginService;shutdownService;outputService;pluginContextService;constructor(){this.program=new v("runium"),this.configService=o.get(l),this.profileService=o.get(g),this.pluginService=o.get(d),this.shutdownService=o.get(m),this.outputService=o.get(h),this.pluginContextService=o.get(S)}async start(){return await this.shutdownService.init(),await this.configService.init(),await this.profileService.init(),await this.pluginContextService.init(),this.initOutput(),this.initEnv(),await this.loadPlugins(),await this.initProgram(),this.program.parseAsync()}async loadPlugins(){const e=this.profileService.getPlugins();for(const i of e)if(i.disabled!==!0)try{const t=this.pluginService.resolvePath(i.path,i.file);await this.pluginService.loadPlugin(t)}catch(t){this.outputService.error(`Failed to load plugin "${i.name}"`);const{code:n,message:s,payload:a}=t;this.outputService.debug("Error details:",{message:s,code:n,payload:a})}}async initProgram(){const e=this.program;e.option("-D, --debug","enable debug mode"),e.option("-e, --env [paths...]","load env files"),e.version(await this.getVersion()),e.description(f),e.on("option:debug",()=>{this.setDebugMode()}),e.on("option:env",t=>{this.loadEnvFiles([t])});const i=[];Object.values(c).forEach(t=>{i.push(new t(e))})}initOutput(){(this.configService.get("output").debug||process.argv.includes("-D")||process.argv.includes("--debug"))&&this.setDebugMode()}setDebugMode(){this.outputService.getLevel()!==r.DEBUG&&(this.outputService.setLevel(r.DEBUG),this.outputService.debug("Debug mode enabled"))}initEnv(){const e=this.configService.get("env");e.path.length>0&&this.loadEnvFiles(e.path)}loadEnvFiles(e){for(const i of e)i?u(i)?process.loadEnvFile(p(i)):this.outputService.debug(`Env file "${i}" not found`):process.loadEnvFile()}async getVersion(){return(await import("./package.json",{with:{type:"json"}})).default.version}}export{F as RuniumCliApp};
6
+ One Tool to Run Them All!`;class A{program;commandService;configService;profileService;pluginService;shutdownService;outputService;pluginContextService;constructor(){this.program=new v("runium"),this.configService=o.get(l),this.profileService=o.get(m),this.pluginService=o.get(h),this.shutdownService=o.get(d),this.outputService=o.get(S),this.pluginContextService=o.get(f),this.commandService=o.get(g)}async start(){return await this.configService.init().catch(i=>{throw this.initOutput(),i}),await this.shutdownService.init(),await this.profileService.init(),await this.pluginContextService.init(),this.initOutput(),this.initEnv(),await this.loadPlugins(),await this.initProgram(),await this.initPlugins(),this.program.parseAsync()}async loadPlugins(){const i=this.profileService.getPlugins();for(const e of i)if(e.disabled!==!0)try{const t=this.pluginService.resolvePath(e.path,e.file);await this.pluginService.loadPlugin(t,e.options)}catch(t){this.outputService.error(`Failed to load plugin "${e.name}"`);const{code:r,message:s,payload:a}=t;this.outputService.debug("Error details:",{message:s,code:r,payload:a})}}async initProgram(){const i=this.program;i.option("-D, --debug","enable debug mode"),i.option("-E, --env [paths...]","load env files"),i.version(P()),i.description(C),i.on("option:debug",()=>{this.setDebugMode()}),i.on("option:env",e=>{this.loadEnvFiles([e])}),Object.values(p).forEach(e=>{this.commandService.registerCommand(e,i)})}initOutput(){(this.configService.get("output").debug||process.argv.includes("-D")||process.argv.includes("--debug"))&&this.setDebugMode()}setDebugMode(){this.outputService.getLevel()!==n.DEBUG&&(this.outputService.setLevel(n.DEBUG),this.outputService.debug("Debug mode enabled"))}initEnv(){const i=this.configService.get("env");i.path.length>0&&this.loadEnvFiles(i.path)}loadEnvFiles(i){for(const e of i){const t=u(e&&e.trim()||".env");c(t)?process.loadEnvFile(t):this.outputService.error(`Env file "${t}" not found`)}}async initPlugins(){const i=this.pluginService.getAllPlugins();for(const e of i){const t=e.app?.commands;if(t)for(const r of t)this.commandService.registerCommand(r,this.program,e.name)}await this.pluginService.runHook("app.afterInit",{profilePath:this.configService.get("profile").path})}}export{A as RuniumCliApp};
@@ -1 +1 @@
1
- import{RuniumError as a}from"@runium/core";import{ErrorCode as l}from"../../constants/index.js";import{PluginCommand as t}from"./plugin-command.js";class g extends t{config(){this.command.name("add").description("add plugin").option("-f, --file","use file path instead of plugin package name").argument("<plugin>","plugin package name or absolute file path")}async handle(e,{file:n}){const o=this.pluginService.resolvePath(e,n),i=await this.pluginService.loadPlugin(o);if(this.pluginService.getPluginByName(i))await this.profileService.addPlugin({name:i,path:n?o:e,file:n,disabled:!1,options:{}}),this.outputService.success('Plugin "%s" successfully added',i);else throw new a(`Failed to add plugin "${e}"`,l.PLUGIN_NOT_FOUND,{name:i,path:e})}}export{g as PluginAddCommand};
1
+ import{RuniumError as a}from"@runium/core";import{ErrorCode as l}from"../../constants/index.js";import{PluginCommand as s}from"./plugin-command.js";class g extends s{config(){this.command.name("add").description("add plugin").option("-f, --file","use file path instead of plugin package name").argument("<plugin>","plugin package name or absolute file path")}async handle(e,{file:n}){const o=this.pluginService.resolvePath(e,n),i=await this.pluginService.loadPlugin(o,{}),t=this.pluginService.getPluginByName(i);if(t)await this.profileService.addPlugin({name:i,path:n?o:e,file:n,disabled:!1,options:t.options??{}}),this.outputService.success('Plugin "%s" successfully added',i);else throw new a(`Failed to add plugin "${e}"`,l.PLUGIN_NOT_FOUND,{name:i,path:e})}}export{g as PluginAddCommand};
@@ -1 +1 @@
1
- import{PluginCommand as n}from"./plugin-command.js";class o extends n{config(){this.command.name("disable").description("disable plugin").option("-a, --all","disable all plugins").argument("[plugin...]","plugin names")}async handle(e,{all:l}){if(e.length===0&&!l){this.outputService.warn("No plugins specified to disable");return}l&&(e=this.profileService.getPlugins().map(i=>i.name));for(const i of e){if(this.ensureProfilePlugin(i).disabled){this.outputService.info('Plugin "%s" is already disabled',i);continue}await this.profileService.updatePlugin(i,{disabled:!0}),await this.pluginService.unloadPlugin(i),this.outputService.success('Plugin "%s" successfully disabled',i)}}}export{o as PluginDisableCommand};
1
+ import{PluginCommand as l}from"./plugin-command.js";class o extends l{config(){this.command.name("disable").description("disable plugin").option("-a, --all","disable all plugins").argument("[name...]","plugin names")}async handle(e,{all:n}){if(e.length===0&&!n){this.outputService.warn("No plugins specified to disable");return}n&&(e=this.profileService.getPlugins().map(i=>i.name));for(const i of e){if(this.ensureProfilePlugin(i).disabled){this.outputService.info('Plugin "%s" is already disabled',i);continue}await this.profileService.updatePlugin(i,{disabled:!0}),await this.pluginService.unloadPlugin(i),this.outputService.success('Plugin "%s" successfully disabled',i)}}}export{o as PluginDisableCommand};
@@ -1 +1 @@
1
- import{PluginCommand as a}from"./plugin-command.js";class u extends a{config(){this.command.name("enable").description("enable plugin").option("-a, --all","enable all plugins").argument("[plugin...]","plugin names")}async handle(i,{all:l}){if(i.length===0&&!l){this.outputService.warn("No plugins specified to enable");return}l&&(i=this.profileService.getPlugins().map(e=>e.name));for(const e of i){const n=this.ensureProfilePlugin(e);if(!n.disabled){this.outputService.info('Plugin "%s" is already enabled',e);continue}await this.profileService.updatePlugin(e,{disabled:!1});const t=this.pluginService.resolvePath(n.path,n.file);await this.pluginService.loadPlugin(t),this.outputService.success('Plugin "%s" successfully enabled',e)}}}export{u as PluginEnableCommand};
1
+ import{PluginCommand as a}from"./plugin-command.js";class u extends a{config(){this.command.name("enable").description("enable plugin").option("-a, --all","enable all plugins").argument("[name...]","plugin names")}async handle(n,{all:l}){if(n.length===0&&!l){this.outputService.warn("No plugins specified to enable");return}l&&(n=this.profileService.getPlugins().map(e=>e.name));for(const e of n){const i=this.ensureProfilePlugin(e);if(!i.disabled){this.outputService.info('Plugin "%s" is already enabled',e);continue}await this.profileService.updatePlugin(e,{disabled:!1});const t=this.pluginService.resolvePath(i.path,i.file);await this.pluginService.loadPlugin(t,i.options),this.outputService.success('Plugin "%s" successfully enabled',e)}}}export{u as PluginEnableCommand};
@@ -1 +1 @@
1
- import{PluginCommand as n}from"./plugin-command.js";class l extends n{config(){this.command.name("remove").description("remove plugin").option("-a, --all","remove all plugins").argument("[plugin...]","plugin names")}async handle(i,{all:o}){if(i.length===0&&!o){this.outputService.warn("No plugins specified to remove");return}o&&(i=this.profileService.getPlugins().map(e=>e.name));for(const e of i)this.ensureProfilePlugin(e),await this.profileService.removePlugin(e),await this.pluginService.unloadPlugin(e),this.outputService.success('Plugin "%s" successfully removed',e)}}export{l as PluginRemoveCommand};
1
+ import{PluginCommand as n}from"./plugin-command.js";class l extends n{config(){this.command.name("remove").description("remove plugin").option("-a, --all","remove all plugins").argument("[name...]","plugin names")}async handle(i,{all:o}){if(i.length===0&&!o){this.outputService.warn("No plugins specified to remove");return}o&&(i=this.profileService.getPlugins().map(e=>e.name));for(const e of i)this.ensureProfilePlugin(e),await this.profileService.removePlugin(e),await this.pluginService.unloadPlugin(e),this.outputService.success('Plugin "%s" successfully removed',e)}}export{l as PluginRemoveCommand};
@@ -1 +1 @@
1
- import{RuniumCommand as n}from"../runium-command.js";import{PluginAddCommand as i}from"./plugin-add.js";import{PluginDisableCommand as d}from"./plugin-disable.js";import{PluginEnableCommand as t}from"./plugin-enable.js";import{PluginListCommand as r}from"./plugin-list.js";import{PluginRemoveCommand as a}from"./plugin-remove.js";class f extends n{config(){this.command.name("plugin").description("manage plugins")}async handle(){this.command.help()}addSubcommands(){const o=[r,i,a,d,t];for(const m of o)this.subcommands.push(new m(this.command))}}export{f as PluginCommand};
1
+ import{RuniumCommand as m}from"../runium-command.js";import{PluginAddCommand as o}from"./plugin-add.js";import{PluginDisableCommand as n}from"./plugin-disable.js";import{PluginEnableCommand as i}from"./plugin-enable.js";import{PluginListCommand as d}from"./plugin-list.js";import{PluginRemoveCommand as a}from"./plugin-remove.js";class g extends m{subcommands=[d,o,a,n,i];config(){this.command.name("plugin").description("manage plugins")}async handle(){this.command.help()}}export{g as PluginCommand};
@@ -1 +1 @@
1
- import{RuniumError as i}from"@runium/core";import{ErrorCode as c}from"../../constants/index.js";import{ProjectCommand as d}from"./project-command.js";class m extends d{config(){this.command.name("add").description("add project").argument("<path>","project file path").argument("[name]","project name (default: project config id)")}async handle(r,o){const e=this.projectService.resolvePath(r),t=await this.projectService.initProject(e);if(t)await this.profileService.addProject({name:o??t.getConfig().id,path:e}),this.outputService.success('Project "%s" successfully added',o??t.getConfig().id);else throw new i(`Failed to add project "${e}"`,c.PROJECT_NOT_FOUND,{path:e})}}export{m as ProjectAddCommand};
1
+ import{ID_REGEX as d,RuniumError as i}from"@runium/core";import{ErrorCode as a}from"../../constants/index.js";import{ProjectCommand as s}from"./project-command.js";class h extends s{config(){this.command.name("add").description("add project").argument("<path>","project file path").argument("[name]","project name (default: project config id)")}async handle(e,c){const t=this.projectService.resolvePath(e),o=await this.projectService.initProject(t);if(o){const r=c??o.getConfig().id;this.validateProjectName(r),await this.profileService.addProject({name:r,path:t}),this.outputService.success('Project "%s" successfully added',r)}else throw new i(`Failed to add project "${t}"`,a.PROJECT_NOT_FOUND,{path:t})}validateProjectName(e){if(!d.test(e))throw new i(`Invalid project name "${e}". Only letters, digits, underscores (_), and hyphens (-) are allowed.`,a.INVALID_ARGUMENT,{name:e})}}export{h as ProjectAddCommand};
@@ -1 +1 @@
1
- import{Container as o}from"typedi";import{RuniumError as t}from"@runium/core";import{RuniumCommand as i}from"../runium-command.js";import{ErrorCode as c}from"../../constants/index.js";import{ProfileService as m,ProjectService as p}from"../../services/index.js";class S extends i{projectService;profileService;constructor(r){super(r),this.projectService=o.get(p),this.profileService=o.get(m)}ensureProfileProject(r){const e=this.profileService.getProjectByName(r);if(!e)throw new t(`Project "${r}" not found`,c.PROJECT_NOT_FOUND,{name:r});return e}}export{S as ProjectCommand};
1
+ import{Container as r}from"typedi";import{RuniumError as t}from"@runium/core";import{RuniumCommand as i}from"../runium-command.js";import{ErrorCode as c}from"../../constants/index.js";import{ProfileService as m,ProjectService as f,FileService as p}from"../../services/index.js";class a extends i{projectService;profileService;fileService;constructor(e){super(e),this.projectService=r.get(f),this.profileService=r.get(m),this.fileService=r.get(p)}ensureProfileProject(e){const o=this.profileService.getProjectByName(e);if(!o)throw new t(`Project "${e}" not found`,c.PROJECT_NOT_FOUND,{name:e});return o}}export{a as ProjectCommand};
@@ -1 +1 @@
1
- import{dirname as d}from"node:path";import{Option as j}from"commander";import{Container as m}from"typedi";import{ProjectEvent as p,RuniumError as h}from"@runium/core";import{ErrorCode as u}from"../../constants/index.js";import{ShutdownService as P}from"../../services/index.js";import{debounce as f}from"../../utils/index.js";import{ProjectStateCommand as w}from"./project-state-command.js";const S=100;class b extends w{shutdownService;constructor(t){super(t),this.shutdownService=m.get(P)}config(){this.command.name("start").description("start project").option("-f, --file","use file path instead of project name").option("-o, --output","output project state changes").addOption(new j("-w, --working-dir <choice>","set working directory").choices(["cwd","project"]).default("cwd")).argument("<name>","project name")}async handle(t,{file:a,workingDir:c,output:n}){const i=a?this.projectService.resolvePath(t):this.ensureProfileProject(t).path,r=this.getProjectDataFileName(a?i:t),s=await this.readProjectData(r);if(s&&this.isProjectProcessStarted(s.pid))throw new h(`Project "${t}" is already started`,u.PROJECT_ALREADY_STARTED,{name:t});if(c==="project"){const o=d(i);o!==process.cwd()&&process.chdir(o)}const e=await this.projectService.initProject(i);this.shutdownService.addBlocker(o=>e.stop(o)),this.addProjectListeners(e,{dataFileName:r,projectPath:i,output:n}),await e.start()}addProjectListeners(t,a){const{dataFileName:c,projectPath:n,output:i}=a,r={id:t.getConfig().id,pid:process.pid,cwd:process.cwd(),path:n,state:{project:[],tasks:{}}},s=f(()=>{this.writeProjectData(r,c)},S);s(),t.on(p.STATE_CHANGE,async e=>{r.state.project.push(e),s(),i&&this.outputService.info("Project %s",e.status)}),t.on(p.TASK_STATE_CHANGE,(e,o)=>{r.state.tasks[e]||(r.state.tasks[e]=[]),r.state.tasks[e].push(o),s(),i&&this.outputService.info("Task %s %s %s",e,o.status,o.exitCode||o.error||"")})}}export{b as ProjectStartCommand};
1
+ import{dirname as d}from"node:path";import{Option as j}from"commander";import{Container as u}from"typedi";import{ProjectEvent as h,RuniumError as m}from"@runium/core";import{ErrorCode as f}from"../../constants/index.js";import{ShutdownService as P}from"../../services/index.js";import{ProjectStateCommand as S}from"./project-state-command.js";class y extends S{shutdownService;fileWriter=null;constructor(t){super(t),this.shutdownService=u.get(P)}config(){this.command.name("start").description("start project").option("-f, --file","use file path instead of project name").option("-o, --output","output project state changes").addOption(new j("-w, --working-dir <choice>","set working directory").choices(["cwd","project"]).default("cwd")).argument("<name>","project name")}async handle(t,{file:s,workingDir:p,output:c}){const r=s?this.projectService.resolvePath(t):this.ensureProfileProject(t).path,i=this.getProjectDataFileName(s?r:t),e=this.profileService.getPath("projects",i),o=await this.readProjectData(e);if(o&&this.isProjectProcessStarted(o.pid))throw new m(`Project "${t}" is already started`,f.PROJECT_ALREADY_STARTED,{name:t});if(p==="project"){const n=d(r);n!==process.cwd()&&process.chdir(n)}const a=await this.projectService.initProject(r);this.shutdownService.addBlocker(n=>a.stop(n)),await this.fileService.ensureDirExists(d(e)),this.fileWriter=this.fileService.createAtomicWriter(e),this.addProjectListeners(a,{projectPath:r,output:c}),await this.projectService.runHook("project.beforeStart",a),await a.start()}addProjectListeners(t,s){const{projectPath:p,output:c}=s,r={id:t.getConfig().id,pid:process.pid,cwd:process.cwd(),path:p,state:{project:[],tasks:{}}},i=()=>{this.fileWriter.writeJson(r).then()};i(),t.on(h.STATE_CHANGE,async e=>{r.state.project.push(e),i(),c&&this.outputService.info("Project %s",e.status)}),t.on(h.TASK_STATE_CHANGE,(e,o)=>{r.state.tasks[e]||(r.state.tasks[e]=[]),r.state.tasks[e].push(o),i(),c&&this.outputService.info("Task %s %s %s",e,o.status,o.exitCode||o.error||"")})}}export{y as ProjectStartCommand};
@@ -1 +1 @@
1
- import{convertPathToValidFileName as r}from"../../utils/index.js";import{ProjectCommand as o}from"./project-command.js";class l extends o{getProjectDataFileName(e){let t=r(e);return t.endsWith(".json")||(t=t+".json"),t}async readProjectData(e){return this.profileService.readJsonFile("projects",e).catch(()=>null)}async writeProjectData(e,t){return this.profileService.writeJsonFile(e,"projects",t)}isProjectProcessStarted(e){try{return process.kill(Number(e),0)}catch(t){return t.code==="EPERM"}}}export{l as ProjectStateCommand};
1
+ import{convertPathToValidFileName as r}from"../../utils/index.js";import{ProjectCommand as a}from"./project-command.js";class d extends a{getProjectDataFileName(e){let t=r(e);return t.endsWith(".json")||(t=t+".json"),t}async readProjectData(e){return this.fileService.readJson(e).catch(()=>null)}isProjectProcessStarted(e){try{return process.kill(Number(e),0)}catch(t){return t.code==="EPERM"}}}export{d as ProjectStateCommand};
@@ -1 +1 @@
1
- import{formatTimestamp as p}from"../../utils/index.js";import{ProjectStateCommand as j}from"./project-state-command.js";class b extends j{config(){this.command.name("status").description("get project status").option("-f, --file","use file path instead of project name").option("-t, --tasks","show task status").option("-a, --all","show status change history").argument("<name>","project name")}async handle(a,{file:n,tasks:d,all:c}){const f=n?this.projectService.resolvePath(a):this.ensureProfileProject(a).path,l=this.getProjectDataFileName(n?f:a),i=await this.readProjectData(l);if(i){let{project:s=[]}=i.state;if(c||(s=s.length>0?[s[s.length-1]]:[]),d){const r=s.map(t=>({name:"Project",status:t.status,time:p(t.timestamp),timestamp:t.timestamp})),{tasks:o=[]}=i.state,h=[];Object.entries(o).forEach(([t,e])=>{c||(e=e.length>0?[e[e.length-1]]:[]),e.forEach(m=>{h.push({name:t,status:m.status,time:p(m.timestamp),timestamp:m.timestamp})})});const u=[...r,...h];u.sort((t,e)=>t.timestamp-e.timestamp),this.outputService.table(u,["time","name","status"])}else{const r=s.map(o=>({status:o.status,time:p(o.timestamp)}));this.outputService.table(r,["time","status"])}}else this.outputService.info(`No project status for "${a}"`)}}export{b as ProjectStatusCommand};
1
+ import{formatTimestamp as m}from"../../utils/index.js";import{ProjectStateCommand as S}from"./project-state-command.js";class D extends S{config(){this.command.name("status").description("get project status").option("-f, --file","use file path instead of project name").option("-t, --tasks","show tasks status").option("-a, --all","show status change history").argument("<name>","project name")}async handle(o,{file:p,tasks:l,all:c}){const d=p?this.projectService.resolvePath(o):this.ensureProfileProject(o).path,f=this.getProjectDataFileName(p?d:o),j=this.profileService.getPath("projects",f),r=await this.readProjectData(j);if(r){let{project:s=[]}=r.state;if(c||(s=s.length>0?[s[s.length-1]]:[]),l){const n=s.map(t=>({name:"Project",status:t.status,time:m(t.timestamp),timestamp:t.timestamp,reason:t.reason||""})),{tasks:i=[]}=r.state,h=[];Object.entries(i).forEach(([t,e])=>{c||(e=e.length>0?[e[e.length-1]]:[]),e.forEach(a=>{h.push({name:t,status:a.status,time:m(a.timestamp),timestamp:a.timestamp,reason:[a.reason,a.exitCode].filter(Boolean).join(" ")})})});const u=[...n,...h];u.sort((t,e)=>t.timestamp-e.timestamp),this.outputService.table(u,["time","name","status","reason"])}else{const n=s.map(i=>({status:i.status,time:m(i.timestamp)}));this.outputService.table(n,["time","status"])}}else this.outputService.info(`No project status for "${o}"`)}}export{D as ProjectStatusCommand};
@@ -1 +1 @@
1
- import{RuniumError as r}from"@runium/core";import{ErrorCode as i}from"../../constants/index.js";import{ProjectStateCommand as p}from"./project-state-command.js";class j extends p{config(){this.command.name("stop").description("stop project").option("-f, --file","use file path instead of project name").argument("<name>","project name")}async handle(t,{file:e}){const a=e?this.projectService.resolvePath(t):this.ensureProfileProject(t).path,s=this.getProjectDataFileName(e?a:t),o=await this.readProjectData(s);if(!o||!this.isProjectProcessStarted(o.pid))throw new r(`Project "${t}" is not started`,i.PROJECT_NOT_STARTED,{name:t});try{process.kill(o.pid,"SIGTERM")}catch(c){throw new r(`Failed to stop project "${t}"`,i.PROJECT_STOP_ERROR,{name:t,original:c})}}}export{j as ProjectStopCommand};
1
+ import{RuniumError as r}from"@runium/core";import{ErrorCode as i}from"../../constants/index.js";import{ProjectStateCommand as n}from"./project-state-command.js";class l extends n{config(){this.command.name("stop").description("stop project").option("-f, --file","use file path instead of project name").argument("<name>","project name")}async handle(t,{file:e}){const a=e?this.projectService.resolvePath(t):this.ensureProfileProject(t).path,c=this.getProjectDataFileName(e?a:t),s=this.profileService.getPath("projects",c),o=await this.readProjectData(s);if(!o||!this.isProjectProcessStarted(o.pid))throw new r(`Project "${t}" is not started`,i.PROJECT_NOT_STARTED,{name:t});try{process.kill(o.pid,"SIGTERM")}catch(p){throw new r(`Failed to stop project "${t}"`,i.PROJECT_STOP_ERROR,{name:t,original:p})}}}export{l as ProjectStopCommand};
@@ -1 +1,4 @@
1
- import{ProjectCommand as r}from"./project-command.js";class n extends r{config(){this.command.name("validate").description("validate project").option("-f, --file","use file path instead of project name").argument("<project>","project name or file path")}async handle(e,{file:t}){const i=t?this.projectService.resolvePath(e):this.ensureProfileProject(e).path,o=await this.projectService.initProject(i);try{await o.validate(),this.outputService.success('Project "%s" is valid',e)}catch(a){this.outputService.error('Project "%s" validation failed',e,a)}}}export{n as ProjectValidateCommand};
1
+ import{ProjectCommand as c}from"./project-command.js";import{getErrorMessages as n}from"../../validation/index.js";class m extends c{config(){this.command.name("validate").description("validate project").option("-f, --file","use file path instead of project name").argument("<name>","project name")}async handle(e,{file:r}){const t=r?this.projectService.resolvePath(e):this.ensureProfileProject(e).path,o=await this.projectService.initProject(t);try{await o.validate(),this.outputService.success('Project "%s" is valid',e)}catch(i){const a=n(i.payload.errors,{filter:s=>s.original?.keyword!=="oneOf"});this.outputService.error(`Project "%s" validation failed:
2
+
3
+ %s`,e,a.join(`
4
+ `))}}}export{m as ProjectValidateCommand};
@@ -1 +1 @@
1
- import{RuniumCommand as t}from"../runium-command.js";import{ProjectAddCommand as r}from"./project-add.js";import{ProjectListCommand as d}from"./project-list.js";import{ProjectRemoveCommand as e}from"./project-remove.js";import{ProjectStartCommand as n}from"./project-start.js";import{ProjectStopCommand as c}from"./project-stop.js";import{ProjectStatusCommand as a}from"./project-status.js";import{ProjectValidateCommand as i}from"./project-validate.js";class v extends t{config(){this.command.name("project").description("manage projects")}async handle(){this.command.help()}addSubcommands(){const o=[d,r,e,n,c,a,i];for(const m of o)this.subcommands.push(new m(this.command))}}export{v as ProjectCommand};
1
+ import{RuniumCommand as o}from"../runium-command.js";import{ProjectAddCommand as m}from"./project-add.js";import{ProjectListCommand as t}from"./project-list.js";import{ProjectRemoveCommand as r}from"./project-remove.js";import{ProjectStartCommand as e}from"./project-start.js";import{ProjectStopCommand as a}from"./project-stop.js";import{ProjectStatusCommand as d}from"./project-status.js";import{ProjectValidateCommand as n}from"./project-validate.js";class l extends o{subcommands=[t,m,r,e,a,d,n];config(){this.command.name("project").description("manage projects")}async handle(){this.command.help()}}export{l as ProjectCommand};
@@ -1 +1 @@
1
- import{Command as o}from"commander";import{Container as m}from"typedi";import{OutputService as d}from"../services/index.js";class i{outputService;parent;command;subcommands=[];constructor(t){this.outputService=m.get(d),this.parent=t,this.command=new o,this.config(),this.command.action(this.handle.bind(this)),this.addSubcommands(),this.parent.addCommand(this.command)}addSubcommands(){}}export{i as RuniumCommand};
1
+ import{Command as n}from"commander";import{Container as o}from"typedi";import{CommandService as r,OutputService as a}from"../services/index.js";class u{outputService;command;subcommands=[];run;constructor(t){const m=o.get(r);this.run=m.createRunCommand(this.handle,this),this.outputService=o.get(a),this.command=new n,this.config(),this.command.action(this.run.bind(this)),t.addCommand(this.command)}}export{u as RuniumCommand};
@@ -1 +1 @@
1
- var R=(_=>(_.PLUGIN_NOT_FOUND="plugin-not-found",_.PLUGIN_FILE_NOT_FOUND="plugin-file-not-found",_.PLUGIN_INCORRECT_MODULE="plugin-incorrect-module",_.PLUGIN_INCORRECT_PLUGIN="plugin-incorrect-plugin",_.PLUGIN_PATH_RESOLVE_ERROR="plugin-path-resolve-error",_.PROJECT_ALREADY_STARTED="project-already-started",_.PROJECT_NOT_STARTED="project-not-started",_.PROJECT_STOP_ERROR="project-stop-error",_.PROJECT_NOT_FOUND="project-not-found",_.PROJECT_FILE_NOT_FOUND="project-file-not-found",_.PROJECT_FILE_CAN_NOT_READ="project-file-can-not-read",_.PROJECT_JSON_PARSE_ERROR="project-json-parse-error",_.PROFILE_JSON_WRITE_ERROR="profile-json-write-error",_))(R||{});export{R as ErrorCode};
1
+ var _=(R=>(R.FILE_READ_JSON_ERROR="file-read-json-error",R.FILE_WRITE_JSON_ERROR="file-write-json-error",R.FILE_READ_ERROR="file-read-error",R.FILE_WRITE_ERROR="file-write-error",R.FILE_CREATE_DIR_ERROR="file-create-dir-error",R.PLUGIN_NOT_FOUND="plugin-not-found",R.PLUGIN_FILE_NOT_FOUND="plugin-file-not-found",R.PLUGIN_INCORRECT_MODULE="plugin-incorrect-module",R.PLUGIN_INVALID="plugin-invalid",R.PLUGIN_PATH_RESOLVE_ERROR="plugin-path-resolve-error",R.PLUGIN_LOAD_ERROR="plugin-load-error",R.PLUGIN_HOOK_ERROR="plugin-hook-error",R.PROJECT_ALREADY_STARTED="project-already-started",R.PROJECT_NOT_STARTED="project-not-started",R.PROJECT_STOP_ERROR="project-stop-error",R.PROJECT_NOT_FOUND="project-not-found",R.PROJECT_FILE_NOT_FOUND="project-file-not-found",R.PROJECT_FILE_CAN_NOT_READ="project-file-can-not-read",R.PROJECT_JSON_PARSE_ERROR="project-json-parse-error",R.INVALID_ARGUMENT="invalid-argument",R.INVALID_PATH="invalid-path",R.CONFIG_INVALID_DATA="config-invalid-data",R.COMMAND_REGISTRATION_ERROR="command-registration-error",R.COMMAND_INCORRECT="command-incorrect",R.COMMAND_NOT_FOUND="command-not-found",R.COMMAND_RUN_ERROR="command-run-error",R))(_||{});export{_ as ErrorCode};
package/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import"reflect-metadata";import{Container as e}from"typedi";import{RuniumCliApp as r}from"./app.js";import{OutputService as a}from"./services/index.js";async function i(){await new r().start()}i().catch(o=>{const t=e.get(a);t.error("Error: %s",o.message),t.debug("Error details:",{code:o.code,payload:o.payload}),process.exit(1)});
2
+ import"reflect-metadata";import{Container as e}from"typedi";import{RuniumCliApp as r}from"./app.js";import{OutputService as i,ShutdownService as n}from"./services/index.js";async function c(){await new r().start()}c().catch(t=>{const o=e.get(i);o.error("Error: %s",t.message),o.debug("Error details:",{code:t.code,payload:t.payload}),e.get(n).shutdown("error").catch(()=>{process.exit(1)})});
package/macros/date.js ADDED
@@ -0,0 +1 @@
1
+ import{formatTimestamp as t}from"../utils/format-timestamp.js";function o(){return t(Date.now())}function n(){return Date.now().toString()}export{o as dateMacro,n as timestampMacro};
package/macros/index.js CHANGED
@@ -1 +1 @@
1
- import{eqMacro as o,neMacro as r}from"./conditional.js";import{emptyMacro as m}from"./empty.js";import{envMacro as t}from"./env.js";import{pathMacro as e}from"./path.js";const M={env:t,empty:m,eq:o,ne:r,path:e};export{M as macros};
1
+ import{eqMacro as r,neMacro as o}from"./conditional.js";import{dateMacro as m,timestampMacro as t}from"./date.js";import{emptyMacro as a}from"./empty.js";import{envMacro as e}from"./env.js";import{homeDirMacro as p,pathMacro as c,tmpDirMacro as i}from"./path.js";const s={date:m,homedir:p,env:e,empty:a,eq:r,ne:o,path:c,tmpdir:i,timestamp:t};export{s as macros};
package/macros/path.js CHANGED
@@ -1 +1 @@
1
- import{resolve as t}from"node:path";function n(r){return t(r)}export{n as pathMacro};
1
+ import{resolve as t}from"node:path";import{homedir as o,tmpdir as i}from"node:os";function m(...r){return t(...r)}function p(){return i()}function c(){return o()}export{c as homeDirMacro,m as pathMacro,p as tmpDirMacro};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runium/cli",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Runium CLI",
5
5
  "author": "TheBeastApp",
6
6
  "license": "MIT",
@@ -9,11 +9,12 @@
9
9
  "runium": "./index.js"
10
10
  },
11
11
  "engines": {
12
- "node": ">=20.10.0"
12
+ "node": ">=20.12.0"
13
13
  },
14
14
  "module": "./index.js",
15
15
  "dependencies": {
16
- "@runium/core": "^0.0.4",
16
+ "@runium/core": "^0.0.8",
17
+ "@segment/ajv-human-errors": "^2.15.0",
17
18
  "commander": "^14.0.2",
18
19
  "reflect-metadata": "^0.2.2",
19
20
  "typedi": "^0.10.0"
@@ -0,0 +1 @@
1
+ var p=function(i,n,t,a){var m=arguments.length,o=m<3?n:a===null?a=Object.getOwnPropertyDescriptor(n,t):a,r;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(i,n,t,a);else for(var e=i.length-1;e>=0;e--)(r=i[e])&&(o=(m<3?r(o):m>3?r(n,t,o):r(n,t))||o);return m>3&&o&&Object.defineProperty(n,t,o),o};import{Command as C}from"commander";import{Container as R,Service as w}from"typedi";import{isRuniumError as u,RuniumError as c}from"@runium/core";import{ErrorCode as f}from"../constants/index.js";import{PluginService as P}from"./index.js";import{RuniumCommand as O}from"../commands/runium-command.js";const d="runium";let l=class{fullPathCommands=new Map;getCommandFullPath(n){const t=n.command?.name();if(t===d||!n.command.parent)return"";const a=Array.from(this.fullPathCommands.values()).find(o=>o.command===n.command.parent);if(a)return[this.getCommandFullPath(a),t].filter(Boolean).join(" ").trim();const m=n.command.parent.name();return m===d?t:[m,t].join(" ").trim()}registerCommand(n,t,a="app"){const m=(o,r)=>{try{if(!(o.prototype instanceof O))throw new c(`Command "${o.name}" for "${a}" must be a subclass of "RuniumCommand"`,f.COMMAND_INCORRECT,{context:a,CommandConstructor:o});const e=new o(r),h=this.getCommandFullPath(e);this.fullPathCommands.set(h,e),e.subcommands.length>0&&e.subcommands.forEach(s=>{m(s,e.command)})}catch(e){throw u(e)?e:new c(`Failed to register command "${o.name}" for "${a}"`,f.COMMAND_REGISTRATION_ERROR,{original:e})}};m(n,t)}createRunCommand(n,t){const a=R.get(P);return async(...m)=>{m?.length>0&&m[m.length-1]instanceof C&&m.pop();const o=this.getCommandFullPath(t);await a.runHook("app.beforeCommandRun",{command:o,args:m}),await n.call(t,...m),await a.runHook("app.afterCommandRun",{command:o,args:m})}}hasCommand(n){return this.fullPathCommands.has(n)}async runCommand(n,...t){const a=this.fullPathCommands.get(n);if(!a)throw new c(`Command "${n}" not found`,f.COMMAND_NOT_FOUND,{path:n});try{await a.run(...t)}catch(m){throw u(m)?m:new c(`Failed to run command "${n}"`,f.COMMAND_RUN_ERROR,{original:m})}}};l=p([w()],l);export{l as CommandService};
@@ -1 +1 @@
1
- var d=function(r,t,e,i){var n=arguments.length,o=n<3?t:i===null?i=Object.getOwnPropertyDescriptor(t,e):i,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(r,t,e,i);else for(var p=r.length-1;p>=0;p--)(a=r[p])&&(o=(n<3?a(o):n>3?a(t,e,o):a(t,e))||o);return n>3&&o&&Object.defineProperty(t,e,o),o};import{existsSync as f}from"node:fs";import{homedir as _}from"node:os";import{join as s,resolve as l}from"node:path";import{Service as v}from"typedi";import{readJsonFile as O}from"@runium/core";const j=".runiumrc.json",u=s(process.cwd(),j),h=".runium",E=s(_(),h),m=s(process.cwd(),h);let c=class{data={profile:{path:E},output:{debug:!1},env:{path:[]}};async init(){if(f(m)&&(this.data.profile.path=m),f(u)){const t=await O(u);if(t){const e={env:Object.assign({},this.data.env,t.env??{}),output:Object.assign({},this.data.output,t.output??{}),profile:Object.assign({},this.data.profile,t.profile??{})};e.env.path=e.env.path.map(i=>l(i)),e.profile.path=l(e.profile.path),this.data=e}}}get(t){return this.data[t]}};c=d([v()],c);export{c as ConfigService};
1
+ var d=function(i,t,e,r){var n=arguments.length,o=n<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,e):r,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(i,t,e,r);else for(var s=i.length-1;s>=0;s--)(a=i[s])&&(o=(n<3?a(o):n>3?a(t,e,o):a(t,e))||o);return n>3&&o&&Object.defineProperty(t,e,o),o};import{existsSync as l}from"node:fs";import{homedir as g}from"node:os";import{join as c,resolve as u}from"node:path";import{Service as v}from"typedi";import{readJsonFile as _,RuniumError as O}from"@runium/core";import{ErrorCode as I}from"../constants/index.js";import{createValidator as E,getConfigSchema as j,getErrorMessages as C}from"../validation/index.js";const F=".runiumrc.json",p=c(process.cwd(),F),h=".runium",b=c(g(),h),m=c(process.cwd(),h);function A(i){const t=j(),e=E(t);if(!e(i)&&e.errors){const n=C(e.errors);throw new O(`Invalid "${p}" configuration data`,I.CONFIG_INVALID_DATA,n)}}let f=class{data={profile:{path:b},plugins:{},output:{debug:!1},env:{path:[]}};async init(){if(l(m)&&(this.data.profile.path=m),l(p)){const t=await _(p);if(t){A(t);const e={env:Object.assign({},this.data.env,t.env??{}),output:Object.assign({},this.data.output,t.output??{}),profile:Object.assign({},this.data.profile,t.profile??{}),plugins:Object.assign({},this.data.plugins,t.plugins??{})};e.env.path=e.env.path.map(r=>u(r)),e.profile.path=u(e.profile.path),this.data=e}}}get(t){return this.data[t]}};f=d([v()],f);export{f as ConfigService};
@@ -0,0 +1 @@
1
+ var m=function(r,e,t,i){var a=arguments.length,n=a<3?e:i===null?i=Object.getOwnPropertyDescriptor(e,t):i,c;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")n=Reflect.decorate(r,e,t,i);else for(var l=r.length-1;l>=0;l--)(c=r[l])&&(n=(a<3?c(n):a>3?c(e,t,n):c(e,t))||n);return a>3&&n&&Object.defineProperty(e,t,n),n};import{basename as u,dirname as R,join as y}from"node:path";import{access as E,constants as x,mkdir as d,readFile as h,rename as _,writeFile as f}from"node:fs/promises";import{fileURLToPath as O}from"node:url";import{Service as F}from"typedi";import{RuniumError as o}from"@runium/core";import{ErrorCode as s}from"../constants/index.js";let w=class{async read(e,t={}){try{return await h(e,{encoding:t.encoding||"utf-8"})}catch(i){throw new o(`Can not read file ${e}`,s.FILE_READ_ERROR,{path:e,options:t,original:i})}}async write(e,t,i={}){try{await f(e,t,{encoding:i.encoding||"utf-8"})}catch(a){throw new o(`Can not write file ${e}`,s.FILE_WRITE_ERROR,{path:e,data:t,options:i,original:a})}}async readJson(e){try{const t=await h(e,{encoding:"utf-8"});return JSON.parse(t)}catch(t){throw new o(`Can not read JSON file ${e}`,s.FILE_READ_JSON_ERROR,{path:e,original:t})}}async writeJson(e,t){try{await f(e,JSON.stringify(t,null,2),{encoding:"utf-8"})}catch(i){throw new o(`Can not write JSON file ${e}`,s.FILE_WRITE_JSON_ERROR,{path:e,data:t,original:i})}}async isExists(e){try{return await E(e,x.F_OK),!0}catch{return!1}}async ensureDirExists(e){try{await d(e,{recursive:!0})}catch(t){throw new o(`Can not create directory ${e}`,s.FILE_CREATE_DIR_ERROR,{path:e,original:t})}}createAtomicWriter(e){return new p(e)}};w=m([F()],w);function g(r){const e=r instanceof URL?O(r):r.toString();return y(R(e),`.${u(e)}.tmp`)}async function D(r,e,t){for(let i=0;i<e;i++)try{return await r()}catch(a){if(i<e-1)await new Promise(n=>setTimeout(n,t));else throw a}}class p{filename;tempFilename;locked=!1;prev=null;next=null;nextPromise=null;nextData=null;constructor(e){this.filename=e,this.tempFilename=g(e)}addData(e){return this.nextData=e,this.nextPromise||=new Promise((t,i)=>{this.next=[t,i]}),new Promise((t,i)=>{this.nextPromise?.then(t).catch(i)})}async writeData(e){this.locked=!0;try{await f(this.tempFilename,e,"utf-8"),await D(async()=>{await _(this.tempFilename,this.filename)},10,100),this.prev?.[0]()}catch(t){throw t instanceof Error&&this.prev?.[1](t),t}finally{if(this.locked=!1,this.prev=this.next,this.next=this.nextPromise=null,this.nextData!==null){const t=this.nextData;this.nextData=null,await this.write(t)}}}async write(e){try{await(this.locked?this.addData(e):this.writeData(e))}catch(t){throw new o(`Can not write file ${this.filename}`,s.FILE_WRITE_ERROR,{path:this.filename,data:e,original:t})}}async writeJson(e){return this.write(JSON.stringify(e,null,2))}}export{p as AtomicWriter,w as FileService};
package/services/index.js CHANGED
@@ -1 +1 @@
1
- export*from"./config.js";export*from"./output.js";export*from"./profile.js";export*from"./plugin.js";export*from"./project.js";export*from"./shutdown.js";export*from"./plugin-context.js";
1
+ export*from"./command.js";export*from"./config.js";export*from"./file.js";export*from"./output.js";export*from"./profile.js";export*from"./plugin.js";export*from"./project.js";export*from"./shutdown.js";export*from"./plugin-context.js";
@@ -1,3 +1,3 @@
1
- var a=function(t,o,e,s){var i=arguments.length,r=i<3?o:s===null?s=Object.getOwnPropertyDescriptor(o,e):s,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(t,o,e,s);else for(var c=t.length-1;c>=0;c--)(l=t[c])&&(r=(i<3?l(r):i>3?l(o,e,r):l(o,e))||r);return i>3&&r&&Object.defineProperty(o,e,r),r};import{Console as u}from"node:console";import{Transform as h}from"node:stream";import{Service as p}from"typedi";var n;(function(t){t[t.TRACE=0]="TRACE",t[t.DEBUG=1]="DEBUG",t[t.INFO=2]="INFO",t[t.WARN=3]="WARN",t[t.ERROR=4]="ERROR",t[t.SILENT=5]="SILENT"})(n||(n={}));class R extends u{transform;constructor(){const o=new h({transform:(e,s,i)=>i(null,e)});super({stdout:o,stderr:o,colorMode:!1}),this.transform=o}getPatchedTable(o,e){this.table(o,e);const s=(this.transform.read()||"").toString(),i=s.indexOf("\u252C")+1;return s.split(`
2
- `).map(r=>r.charAt(0)+r.slice(i)).join(`
3
- `)}}const m=new R;let f=class{outputLevel=n.INFO;setLevel(o){this.outputLevel=o}getLevel(){return this.outputLevel}trace(o,...e){this.outputLevel<=n.TRACE&&console.log(o,...e)}debug(o,...e){this.outputLevel<=n.DEBUG&&console.log(o,...e)}info(o,...e){this.outputLevel<=n.INFO&&console.log(o,...e)}success(o,...e){this.outputLevel<=n.INFO&&console.log(o,...e)}warn(o,...e){this.outputLevel<=n.WARN&&console.warn(o,...e)}error(o,...e){this.outputLevel<=n.ERROR&&console.error(o,...e)}log(o,...e){this.outputLevel<n.SILENT&&console.log(o,...e)}table(o,e){if(this.outputLevel<n.SILENT){const s=o.map((r,l)=>({...r,"#":l+1})),i=m.getPatchedTable(s,e?["#",...e]:void 0);console.log(i)}}newLine(){this.outputLevel<n.SILENT&&console.log("")}clear(){this.outputLevel<n.SILENT&&console.clear()}};f=a([p()],f);export{n as OutputLevel,f as OutputService};
1
+ var a=Object.defineProperty;var c=Object.getOwnPropertyDescriptor;var u=(i,o,t,s)=>{for(var n=s>1?void 0:s?c(o,t):o,r=i.length-1,e;r>=0;r--)(e=i[r])&&(n=(s?e(o,t,n):e(n))||n);return s&&n&&a(o,t,n),n};import{Console as p}from"node:console";import{Transform as d}from"node:stream";import{inspect as v}from"node:util";import{Service as f}from"typedi";var g=(e=>(e[e.TRACE=0]="TRACE",e[e.DEBUG=1]="DEBUG",e[e.INFO=2]="INFO",e[e.WARN=3]="WARN",e[e.ERROR=4]="ERROR",e[e.SILENT=5]="SILENT",e))(g||{});class L extends p{transform;constructor(){v.defaultOptions.depth=5;const o=new d({transform:(t,s,n)=>n(null,t)});super({stdout:o,stderr:o,colorMode:!1}),this.transform=o}getPatchedTable(o,t){this.table(o,t);const s=(this.transform.read()||"").toString(),n=s.indexOf("\u252C")+1;return s.split(`
2
+ `).map(r=>r.charAt(0)+r.slice(n)).join(`
3
+ `).replace(/'([^']*)'/g,"$1 ")}}const h=new L;let l=class{outputLevel=2;setLevel(o){this.outputLevel=o}getLevel(){return this.outputLevel}trace(o,...t){this.outputLevel<=0&&console.log(o,...t)}debug(o,...t){this.outputLevel<=1&&console.log(o,...t)}info(o,...t){this.outputLevel<=2&&console.log(o,...t)}success(o,...t){this.outputLevel<=2&&console.log(o,...t)}warn(o,...t){this.outputLevel<=3&&console.warn(o,...t)}error(o,...t){this.outputLevel<=4&&console.error(o,...t)}log(o,...t){this.outputLevel<5&&console.log(o,...t)}table(o,t){if(this.outputLevel<5){const s=o.map((r,e)=>({...r,"#":e+1})),n=h.getPatchedTable(s,t?["#",...t]:void 0);console.log(n)}}newLine(){this.outputLevel<5&&console.log("")}clear(){this.outputLevel<5&&console.clear()}};l=u([f()],l);export{g as OutputLevel,l as OutputService};
@@ -1 +1 @@
1
- var v=function(i,e,t,o){var n=arguments.length,r=n<3?e:o===null?o=Object.getOwnPropertyDescriptor(e,t):o,u;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(i,e,t,o);else for(var c=i.length-1;c>=0;c--)(u=i[c])&&(r=(n<3?u(r):n>3?u(e,t,r):u(e,t))||r);return n>3&&r&&Object.defineProperty(e,t,r),r},h=function(i,e){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(i,e)},l=function(i,e){return function(t,o){e(t,o,i)}},s,f;import{Inject as d,Service as S}from"typedi";import{RuniumError as _,isRuniumError as g,RuniumTask as j,RuniumTrigger as R,readJsonFile as w,writeJsonFile as O,applyMacros as y,Task as L,TaskEvent as P,TaskStatus as T,ProjectEvent as k,ProjectStatus as B}from"@runium/core";import{RuniumCommand as E}from"../commands/runium-command.js";import{OutputLevel as m,OutputService as p,ShutdownService as b}from"./index.js";global.runium=null;let a=class{outputService;shutdownService;constructor(e,t){this.outputService=e,this.shutdownService=t}async init(){const e=this.outputService,t=this.shutdownService,o={class:{RuniumCommand:E,RuniumError:_,RuniumTask:j,RuniumTrigger:R,Task:L},enum:{OutputLevel:Object.keys(m).filter(n=>isNaN(Number(n))).reduce((n,r)=>(n[r]=m[r],n),{}),ProjectEvent:k,ProjectStatus:B,TaskEvent:P,TaskStatus:T},utils:{applyMacros:y,isRuniumError:g,readJsonFile:w,writeJsonFile:O},output:{getLevel:e.getLevel.bind(e),setLevel:e.setLevel.bind(e),trace:e.trace.bind(e),debug:e.debug.bind(e),info:e.info.bind(e),warn:e.warn.bind(e),error:e.error.bind(e),table:e.table.bind(e),log:e.log.bind(e)},shutdown:{addBlocker:t.addBlocker.bind(t),removeBlocker:t.removeBlocker.bind(t)}};global.runium=Object.freeze(o)}};a=v([S(),l(0,d()),l(1,d()),h("design:paramtypes",[typeof(s=typeof p<"u"&&p)=="function"?s:Object,typeof(f=typeof b<"u"&&b)=="function"?f:Object])],a);export{a as PluginContextService};
1
+ var P=function(a,t,e,r){var o=arguments.length,i=o<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,e):r,n;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")i=Reflect.decorate(a,t,e,r);else for(var u=a.length-1;u>=0;u--)(n=a[u])&&(i=(o<3?n(i):o>3?n(t,e,i):n(t,e))||i);return o>3&&i&&Object.defineProperty(t,e,i),i},j=function(a,t){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(a,t)},c=function(a,t){return function(e,r){t(e,r,a)}},d,p,l,m,v;import{delimiter as O}from"node:path";import{Inject as s,Service as R}from"typedi";import{RuniumError as h,isRuniumError as W,RuniumTask as E,RuniumTrigger as x,applyMacros as C,TaskEvent as L,TaskStatus as A,ProjectEvent as T,ProjectStatus as B}from"@runium/core";import{RuniumCommand as D}from"../commands/runium-command.js";import{CommandService as S,FileService as b,OutputLevel as g,OutputService as y,ProfileService as _,ShutdownService as w}from"./index.js";import{getVersion as I}from"../utils/index.js";import{ErrorCode as J}from"../constants/index.js";global.runium=null;let f=class{commandService;outputService;shutdownService;fileService;profileService;constructor(t,e,r,o,i){this.commandService=t,this.outputService=e,this.shutdownService=r,this.fileService=o,this.profileService=i}createStorageWrapper(t){return((...e)=>{const[r,...o]=e,i=this.resolveProfilePath(r),n=this.fileService[t];return n(i,...o)})}resolveProfilePath(t){const e=Array.isArray(t)?t:t.split(O);if(e.length===0||e.every(r=>r.trim()===""))throw new h("Invalid path",J.INVALID_PATH,{path:t});return this.profileService.getPath(...e)}async init(){const t=this.commandService,e=this.outputService,r=this.shutdownService,o={class:{RuniumCommand:D,RuniumError:h,RuniumTask:E,RuniumTrigger:x},enum:{OutputLevel:Object.keys(g).filter(i=>isNaN(Number(i))).reduce((i,n)=>(i[n]=g[n],i),{}),ProjectEvent:T,ProjectStatus:B,TaskEvent:L,TaskStatus:A},utils:{applyMacros:C,isRuniumError:W},output:{getLevel:e.getLevel.bind(e),setLevel:e.setLevel.bind(e),trace:e.trace.bind(e),debug:e.debug.bind(e),info:e.info.bind(e),warn:e.warn.bind(e),error:e.error.bind(e),table:e.table.bind(e),log:e.log.bind(e)},shutdown:{addBlocker:r.addBlocker.bind(r),removeBlocker:r.removeBlocker.bind(r)},command:{has:t.hasCommand.bind(t),run:t.runCommand.bind(t)},storage:{read:this.createStorageWrapper("read"),write:this.createStorageWrapper("write"),readJson:this.createStorageWrapper("readJson"),writeJson:this.createStorageWrapper("writeJson"),isExists:this.createStorageWrapper("isExists"),ensureDirExists:this.createStorageWrapper("ensureDirExists"),createAtomicWriter:this.createStorageWrapper("createAtomicWriter"),getPath:this.resolveProfilePath.bind(this)},version:I()};global.runium=Object.freeze(o)}};f=P([R(),c(0,s()),c(1,s()),c(2,s()),c(3,s()),c(4,s()),j("design:paramtypes",[typeof(d=typeof S<"u"&&S)=="function"?d:Object,typeof(p=typeof y<"u"&&y)=="function"?p:Object,typeof(l=typeof w<"u"&&w)=="function"?l:Object,typeof(m=typeof b<"u"&&b)=="function"?m:Object,typeof(v=typeof _<"u"&&_)=="function"?v:Object])],f);export{f as PluginContextService};
@@ -1 +1 @@
1
- var c=function(u,e,r,n){var t=arguments.length,o=t<3?e:n===null?n=Object.getOwnPropertyDescriptor(e,r):n,s;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(u,e,r,n);else for(var a=u.length-1;a>=0;a--)(s=u[a])&&(o=(t<3?s(o):t>3?s(e,r,o):s(e,r))||o);return t>3&&o&&Object.defineProperty(e,r,o),o};import{existsSync as m}from"node:fs";import{resolve as g}from"node:path";import{Service as P}from"typedi";import{isRuniumError as d,RuniumError as i}from"@runium/core";import{ErrorCode as l}from"../constants/index.js";let f=class{plugins=new Map;getAllPlugins(){return Array.from(this.plugins.values())}getPluginByName(e){return this.plugins.get(e)}async loadPlugin(e){if(!e||!m(e))throw new i(`Plugin file "${e}" does not exist`,l.PLUGIN_FILE_NOT_FOUND,{path:e});try{const r=await import(e),{default:n}=r;if(!n||typeof n!="function")throw new i("Plugin module must have a default function",l.PLUGIN_INCORRECT_MODULE,{path:e});const t=n();return this.validate(t),this.plugins.set(t.name,t),t.name}catch(r){throw d(r)?r:new i(`Failed to load plugin "${e}"`,l.PLUGIN_INCORRECT_PLUGIN,{path:e,original:r})}}async unloadPlugin(e){return this.plugins.delete(e)}resolvePath(e,r=!1){try{return(r?g(e):import.meta.resolve(e)).replace("file://","")}catch(n){throw new i(`Failed to resolve plugin path "${e}"`,l.PLUGIN_PATH_RESOLVE_ERROR,{path:e,original:n})}}validate(e){if(!e||!e?.name)throw new i("Incorrect plugin format",l.PLUGIN_INCORRECT_PLUGIN,{name:e.name})}};f=c([P()],f);export{f as PluginService};
1
+ var v=function(n,e,r,t){var i=arguments.length,o=i<3?e:t===null?t=Object.getOwnPropertyDescriptor(e,r):t,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(n,e,r,t);else for(var a=n.length-1;a>=0;a--)(l=n[a])&&(o=(i<3?l(o):i>3?l(e,r,o):l(e,r))||o);return i>3&&o&&Object.defineProperty(e,r,o),o},_=function(n,e){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(n,e)},P=function(n,e){return function(r,t){e(r,t,n)}},p;import{existsSync as R}from"node:fs";import{resolve as w}from"node:path";import{Inject as y,Service as O}from"typedi";import{isRuniumError as E,RuniumError as s}from"@runium/core";import{ErrorCode as u}from"../constants/index.js";import{OutputService as m}from"./index.js";import{createValidator as I,getErrorMessages as N,getPluginSchema as L}from"../validation/index.js";let d=class{outputService;plugins=new Map;validator=I(L());constructor(e){this.outputService=e}getAllPlugins(){return Array.from(this.plugins.values())}getPluginByName(e){return this.plugins.get(e)}async loadPlugin(e,r){if(!e||!R(e))throw new s(`Plugin file "${e}" does not exist`,u.PLUGIN_FILE_NOT_FOUND,{path:e});try{const t=await import(e),{default:i}=t;if(!i||typeof i!="function")throw new s("Plugin module must have a default function",u.PLUGIN_INCORRECT_MODULE,{path:e});const o=i(r);return this.validate(o),this.plugins.set(o.name,o),o.name}catch(t){throw E(t)?t:new s(`Failed to load plugin "${e}"`,u.PLUGIN_LOAD_ERROR,{path:e,original:t})}}async unloadPlugin(e){return this.plugins.delete(e)}resolvePath(e,r=!1){try{return(r?w(e):import.meta.resolve(e)).replace("file://","")}catch(t){throw new s(`Failed to resolve plugin path "${e}"`,u.PLUGIN_PATH_RESOLVE_ERROR,{path:e,original:t})}}async runHook(e,r,{mutable:t,onError:i}={}){const o=this.getAllPlugins(),[l,a]=e.split(".");for(const f of o){const g=f.hooks?.[l]?.[a];if(g)try{t?r=await g(r)??r:await g(r)}catch(h){const c=new s(`Failed to run "${f.name}.${e}" hook`,u.PLUGIN_HOOK_ERROR,{plugin:f.name,hook:e,original:h});i?i(c):(this.outputService.error("Error: %s",c.message),this.outputService.debug("Error details:",{code:c.code,payload:c.payload}))}}return t?r:void 0}validate(e){if(!this.validator(e||{})&&this.validator.errors){const t=N(this.validator.errors);throw new s("Incorrect plugin format",u.PLUGIN_INVALID,{errors:t})}}};d=v([O(),P(0,y()),_("design:paramtypes",[typeof(p=typeof m<"u"&&m)=="function"?p:Object])],d);export{d as PluginService};
@@ -1 +1 @@
1
- var d=function(s,t,i,e){var r=arguments.length,n=r<3?t:e===null?e=Object.getOwnPropertyDescriptor(t,i):e,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")n=Reflect.decorate(s,t,i,e);else for(var o=s.length-1;o>=0;o--)(a=s[o])&&(n=(r<3?a(n):r>3?a(t,i,n):a(t,i))||n);return r>3&&n&&Object.defineProperty(t,i,n),n},j=function(s,t){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(s,t)},w=function(s,t){return function(i,e){t(i,e,s)}},l;import{existsSync as u}from"node:fs";import{mkdir as f}from"node:fs/promises";import{dirname as y,join as _}from"node:path";import{Inject as v,Service as R}from"typedi";import{readJsonFile as c,RuniumError as S,writeJsonFile as h}from"@runium/core";import{ConfigService as g}from"./index.js";import{ErrorCode as E}from"../constants/index.js";const m="plugins.json",P="projects.json";let p=class{configService;path=process.cwd();plugins=[];projects=[];constructor(t){this.configService=t}async init(){this.path=this.configService.get("profile").path,u(this.path)||await f(this.path,{recursive:!0}),await this.readPlugins(),await this.readProjects()}getPlugins(){return this.plugins}getPluginByName(t){return this.plugins.find(i=>i.name===t)}async addPlugin(t){this.plugins=this.plugins.filter(i=>i.name!==t.name).concat(t),await this.writePlugins()}async removePlugin(t){this.plugins=this.plugins.filter(i=>i.name!==t),await this.writePlugins()}async updatePlugin(t,i){const e=this.plugins.findIndex(r=>r.name===t);e!==-1&&(this.plugins[e]={...this.plugins[e],...i},await this.writePlugins())}getProjects(){return this.projects}getProjectByName(t){return this.projects.find(i=>i.name===t)}async addProject(t){this.projects=this.projects.filter(i=>i.name!==t.name).concat(t),await this.writeProjects()}async removeProject(t){this.projects=this.projects.filter(i=>i.name!==t),await this.writeProjects()}async readJsonFile(...t){return c(this.getPath(...t))}async writeJsonFile(t,...i){const e=this.getPath(...i);try{const r=y(e);u(r)||await f(r,{recursive:!0}),await h(e,t)}catch(r){throw new S("Failed to write JSON file",E.PROFILE_JSON_WRITE_ERROR,{path:e,data:t,original:r})}}getPath(...t){return _(this.path,...t)}async readPlugins(){this.plugins=await c(this.getPath(m)).catch(()=>[])||this.plugins}async writePlugins(){await h(this.getPath(m),this.plugins)}async readProjects(){this.projects=await c(this.getPath(P)).catch(()=>[])||this.projects}async writeProjects(){await h(this.getPath(P),this.projects)}};p=d([R(),w(0,v()),j("design:paramtypes",[typeof(l=typeof g<"u"&&g)=="function"?l:Object])],p);export{p as ProfileService};
1
+ var j=function(s,t,i,e){var r=arguments.length,n=r<3?t:e===null?e=Object.getOwnPropertyDescriptor(t,i):e,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")n=Reflect.decorate(s,t,i,e);else for(var c=s.length-1;c>=0;c--)(a=s[c])&&(n=(r<3?a(n):r>3?a(t,i,n):a(t,i))||n);return r>3&&n&&Object.defineProperty(t,i,n),n},d=function(s,t){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(s,t)},h=function(s,t){return function(i,e){t(i,e,s)}},f,p;import{existsSync as v}from"node:fs";import{mkdir as w}from"node:fs/promises";import{join as y}from"node:path";import{Inject as l,Service as S}from"typedi";import{ConfigService as u,FileService as g}from"./index.js";const m="plugins.json",P="projects.json";let o=class{configService;fileService;path=process.cwd();plugins=[];projects=[];constructor(t,i){this.configService=t,this.fileService=i}async init(){this.path=this.configService.get("profile").path,v(this.path)||await w(this.path,{recursive:!0}),await this.readPlugins(),await this.patchPlugins(),await this.readProjects()}getPlugins(){return this.plugins}getPluginByName(t){return this.plugins.find(i=>i.name===t)}async addPlugin(t){this.plugins=this.plugins.filter(i=>i.name!==t.name).concat(t),await this.writePlugins()}async removePlugin(t){this.plugins=this.plugins.filter(i=>i.name!==t),await this.writePlugins()}async updatePlugin(t,i){const e=this.plugins.findIndex(r=>r.name===t);e!==-1&&(this.plugins[e]={...this.plugins[e],...i},await this.writePlugins())}getProjects(){return this.projects}getProjectByName(t){return this.projects.find(i=>i.name===t)}async addProject(t){this.projects=this.projects.filter(i=>i.name!==t.name).concat(t),await this.writeProjects()}async removeProject(t){this.projects=this.projects.filter(i=>i.name!==t),await this.writeProjects()}getPath(...t){return y(this.path,...t)}async readPlugins(){this.plugins=await this.fileService.readJson(this.getPath(m)).catch(()=>[])||this.plugins}async writePlugins(){await this.fileService.writeJson(this.getPath(m),this.plugins)}async patchPlugins(){const t=this.configService.get("plugins");for(const i of this.plugins){const e=t[i.name];e&&Object.assign(i,e)}}async readProjects(){this.projects=await this.fileService.readJson(this.getPath(P)).catch(()=>[])||this.projects}async writeProjects(){await this.fileService.writeJson(this.getPath(P),this.projects)}};o=j([S(),h(0,l()),h(1,l()),d("design:paramtypes",[typeof(f=typeof u<"u"&&u)=="function"?f:Object,typeof(p=typeof g<"u"&&g)=="function"?p:Object])],o);export{o as ProfileService};
@@ -1 +1 @@
1
- var d=function(n,e,t,r){var i=arguments.length,o=i<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,c;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(n,e,t,r);else for(var s=n.length-1;s>=0;s--)(c=n[s])&&(o=(i<3?c(o):i>3?c(e,t,o):c(e,t))||o);return i>3&&o&&Object.defineProperty(e,t,o),o},_=function(n,e){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(n,e)},h=function(n,e){return function(t,r){e(t,r,n)}},m;import{existsSync as j}from"node:fs";import{readFile as P}from"node:fs/promises";import{resolve as v}from"node:path";import{Inject as O,Service as R}from"typedi";import{applyMacros as E,Project as S,RuniumError as f}from"@runium/core";import{ErrorCode as u}from"../constants/index.js";import{macros as y}from"../macros/index.js";import{PluginService as g}from"./index.js";let p=class{pluginService;constructor(e){this.pluginService=e}async initProject(e){const t=await this.readFile(e),r=this.applyMacros(t),i=this.parseProjectContent(r,e),o=new S(i);return this.extendProjectWithPlugins(o)}resolvePath(e){return v(e)}async readFile(e){if(!j(e))throw new f(`Project file "${e}" does not exist`,u.PROJECT_FILE_NOT_FOUND,{path:e});try{return P(e,{encoding:"utf-8"})}catch(t){throw new f(`Failed to read project file "${e}"`,u.PROJECT_FILE_CAN_NOT_READ,{path:e,original:t})}}applyMacros(e){const r=this.pluginService.getAllPlugins().reduce((i,o)=>({...i,...o.project?.macros||{}}),{});return E(e,{...r,...y})}parseProjectContent(e,t){try{return JSON.parse(e)}catch(r){throw new f(`Failed to parse project "${t}"`,u.PROJECT_JSON_PARSE_ERROR,{path:t,original:r})}}extendProjectWithPlugins(e){return this.pluginService.getAllPlugins().forEach(r=>{const{tasks:i,actions:o,triggers:c,validationSchema:s}=r.project||{};Object.entries(o||{}).forEach(([a,l])=>{e.registerAction(a,l)}),Object.entries(i||{}).forEach(([a,l])=>{e.registerTask(a,l)}),Object.entries(c||{}).forEach(([a,l])=>{e.registerTrigger(a,l)}),s&&e.extendValidationSchema(s)}),e}};p=d([R(),h(0,O()),_("design:paramtypes",[typeof(m=typeof g<"u"&&g)=="function"?m:Object])],p);export{p as ProjectService};
1
+ var h=function(n,e,r,t){var o=arguments.length,i=o<3?e:t===null?t=Object.getOwnPropertyDescriptor(e,r):t,c;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")i=Reflect.decorate(n,e,r,t);else for(var a=n.length-1;a>=0;a--)(c=n[a])&&(i=(o<3?c(i):o>3?c(e,r,i):c(e,r))||i);return o>3&&i&&Object.defineProperty(e,r,i),i},d=function(n,e){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(n,e)},j=function(n,e){return function(r,t){e(r,t,n)}},g;import{existsSync as _}from"node:fs";import{readFile as v}from"node:fs/promises";import{resolve as P}from"node:path";import{Inject as S,Service as R}from"typedi";import{applyMacros as O,Project as y,RuniumError as u}from"@runium/core";import{ErrorCode as f}from"../constants/index.js";import{macros as E}from"../macros/index.js";import{PluginService as m}from"./index.js";let p=class{pluginService;constructor(e){this.pluginService=e}async initProject(e){await this.pluginService.runHook("project.beforeConfigRead",e);let r=await this.readFile(e);r=await this.pluginService.runHook("project.afterConfigRead",r,{mutable:!0}),r=this.applyMacros(r),r=await this.pluginService.runHook("project.afterConfigMacrosApply",r,{mutable:!0});let t=this.parseProjectContent(r,e);t=await this.pluginService.runHook("project.afterConfigParse",t,{mutable:!0});const o=new y(t);return this.extendProjectWithPlugins(o)}resolvePath(e){return P(e)}runHook(...e){return this.pluginService.runHook(...e)}async readFile(e){if(!_(e))throw new u(`Project file "${e}" does not exist`,f.PROJECT_FILE_NOT_FOUND,{path:e});try{return v(e,{encoding:"utf-8"})}catch(r){throw new u(`Failed to read project file "${e}"`,f.PROJECT_FILE_CAN_NOT_READ,{path:e,original:r})}}applyMacros(e){const t=this.pluginService.getAllPlugins().reduce((o,i)=>({...o,...i.project?.macros||{}}),{});return O(e,{...t,...E})}parseProjectContent(e,r){try{return JSON.parse(e)}catch(t){throw new u(`Failed to parse project "${r}"`,f.PROJECT_JSON_PARSE_ERROR,{path:r,original:t})}}extendProjectWithPlugins(e){return this.pluginService.getAllPlugins().forEach(t=>{const{tasks:o,actions:i,triggers:c,validationSchema:a}=t.project||{};Object.entries(i||{}).forEach(([s,l])=>{e.registerAction(s,l)}),Object.entries(o||{}).forEach(([s,l])=>{e.registerTask(s,l)}),Object.entries(c||{}).forEach(([s,l])=>{e.registerTrigger(s,l)}),a&&e.extendValidationSchema(a)}),e}};p=h([R(),j(0,S()),d("design:paramtypes",[typeof(g=typeof m<"u"&&m)=="function"?g:Object])],p);export{p as ProjectService};
@@ -1 +1 @@
1
- var d=function(i,t,e,o){var s=arguments.length,r=s<3?t:o===null?o=Object.getOwnPropertyDescriptor(t,e):o,c;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(i,t,e,o);else for(var n=i.length-1;n>=0;n--)(c=i[n])&&(r=(s<3?c(r):s>3?c(t,e,r):c(t,e))||r);return s>3&&r&&Object.defineProperty(t,e,r),r},f=function(i,t){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(i,t)},l=function(i,t){return function(e,o){t(e,o,i)}},a;import{Inject as m,Service as S}from"typedi";import{OutputService as h}from"./index.js";const p=3e4,w=250,v=["SIGHUP","SIGINT","SIGTERM","SIGQUIT"];let u=class{outputService;blockers=new Set;isShuttingDown=!1;constructor(t){this.outputService=t}async init(){v.forEach(t=>{process.on(t,()=>{this.shutdown(t).catch(e=>{this.outputService.error("Error during shutdown: %s",e.message),this.outputService.debug("Error details:",e),process.exit(1)})})}),process.on("uncaughtException",t=>{this.outputService.error("Uncaught exception: %s",t.message),this.outputService.debug("Error details:",t),this.shutdown("uncaughtException").catch(()=>{process.exit(1)})}),process.on("unhandledRejection",(t,e)=>{this.outputService.error("Unhandled rejection at:",e,"reason:",t),this.outputService.debug("Error details:",{reason:t,promise:e}),this.shutdown("unhandledRejection").catch(()=>{process.exit(1)})}),process.on("beforeExit",()=>{this.isShuttingDown||this.shutdown("exit").catch(()=>{process.exit(1)})})}addBlocker(t){this.blockers.add(t)}removeBlocker(t){return this.blockers.delete(t)}async shutdown(t){if(this.isShuttingDown||!t)return;this.isShuttingDown=!0;const e=o=>{setTimeout(()=>{process.exit(o)},w)};if(this.blockers.size===0){e(0);return}try{await this.executeBlockersWithTimeout(t),e(0)}catch{e(1)}}async executeBlockersWithTimeout(t){const e=Array.from(this.blockers).map(s=>this.executeBlocker(s,t)),o=new Promise((s,r)=>{setTimeout(()=>{r(new Error(`Shutdown timeout after ${p}ms`))},p)});await Promise.race([Promise.allSettled(e),o])}async executeBlocker(t,e){await t(e)}};u=d([S(),l(0,m()),f("design:paramtypes",[typeof(a=typeof h<"u"&&h)=="function"?a:Object])],u);export{u as ShutdownService};
1
+ var m=function(c,e,t,r){var o=arguments.length,i=o<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,s;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")i=Reflect.decorate(c,e,t,r);else for(var n=c.length-1;n>=0;n--)(s=c[n])&&(i=(o<3?s(i):o>3?s(e,t,i):s(e,t))||i);return o>3&&i&&Object.defineProperty(e,t,i),i},v=function(c,e){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(c,e)},h=function(c,e){return function(t,r){e(t,r,c)}},a,p;import{Inject as l,Service as g}from"typedi";import{OutputService as f,PluginService as d}from"./index.js";const S=3e4,w=250,b=["SIGHUP","SIGINT","SIGTERM","SIGQUIT"];let u=class{outputService;pluginService;blockers=new Set;isShuttingDown=!1;constructor(e,t){this.outputService=e,this.pluginService=t}async init(){b.forEach(e=>{process.on(e,()=>{this.shutdown(e).catch(t=>{this.outputService.error("Error during shutdown: %s",t.message),this.outputService.debug("Error details:",t),process.exit(1)})})}),process.on("uncaughtException",e=>{this.outputService.error("Uncaught exception: %s",e.message),this.outputService.debug("Error details:",e),this.shutdown("uncaughtException").catch(()=>{process.exit(1)})}),process.on("unhandledRejection",(e,t)=>{this.outputService.error("Unhandled rejection at:",t,"reason:",e),this.outputService.debug("Error details:",{reason:e,promise:t}),this.shutdown("unhandledRejection").catch(()=>{process.exit(1)})}),process.on("beforeExit",()=>{this.isShuttingDown||this.shutdown("exit").catch(()=>{process.exit(1)})})}addBlocker(e){this.blockers.add(e)}removeBlocker(e){return this.blockers.delete(e)}async shutdown(e){if(this.isShuttingDown||!e)return;const t=this.pluginService.getAllPlugins();for(const o of t){const i=o.hooks?.app?.beforeExit;i&&this.addBlocker(i.bind(o,e))}this.isShuttingDown=!0;const r=o=>{setTimeout(()=>{process.exit(o)},w)};if(this.blockers.size===0){r(0);return}try{await this.executeBlockersWithTimeout(e),r(0)}catch{r(1)}}async executeBlockersWithTimeout(e){const t=Array.from(this.blockers).map(o=>this.executeBlocker(o,e)),r=new Promise((o,i)=>{setTimeout(()=>{i(new Error(`Shutdown timeout after ${S}ms`))},S)});await Promise.race([Promise.allSettled(t),r])}async executeBlocker(e,t){await e(t)}};u=m([g(),h(0,l()),h(1,l()),v("design:paramtypes",[typeof(a=typeof f<"u"&&f)=="function"?a:Object,typeof(p=typeof d<"u"&&d)=="function"?p:Object])],u);export{u as ShutdownService};
@@ -0,0 +1 @@
1
+ import{readFileSync as r}from"node:fs";import{resolve as o}from"node:path";let n=null;function i(){if(!n){const e=o(import.meta.dirname,"..","package.json");n=JSON.parse(r(e,"utf-8")).version}return n}export{i as getVersion};
package/utils/index.js CHANGED
@@ -1 +1 @@
1
- import{convertPathToValidFileName as r}from"./convert-path-to-valid-file-name.js";import{debounce as t}from"./debounce.js";import{formatTimestamp as f}from"./format-timestamp.js";export{r as convertPathToValidFileName,t as debounce,f as formatTimestamp};
1
+ import{convertPathToValidFileName as r}from"./convert-path-to-valid-file-name.js";import{debounce as m}from"./debounce.js";import{formatTimestamp as f}from"./format-timestamp.js";import{getVersion as i}from"./get-version.js";export{r as convertPathToValidFileName,m as debounce,f as formatTimestamp,i as getVersion};
@@ -0,0 +1 @@
1
+ import a from"ajv/dist/2020.js";const r={Function};function c(e){const n=new a({allowUnionTypes:!0,allErrors:!0,verbose:!0});return n.addKeyword({keyword:"instanceof",schemaType:"string",validate:(o,t)=>t instanceof r[o]}),n.compile(e)}export{c as createValidator};
@@ -0,0 +1 @@
1
+ function e(){return{$schema:"https://json-schema.org/draft/2020-12/schema",$id:"https://runium.dev/schemas/config.json",title:"Runium Config",type:"object",properties:{env:{type:"object",properties:{path:{type:"array",items:{type:"string"}}},additionalProperties:!1},output:{type:"object",properties:{debug:{type:"boolean"}},additionalProperties:!1},profile:{type:"object",properties:{path:{type:"string"}},additionalProperties:!1},plugins:{type:"object",additionalProperties:{type:"object",properties:{disabled:{type:"boolean"},options:{type:"object"}},additionalProperties:!1}}},additionalProperties:!1}}export{e as getConfigSchema};
@@ -0,0 +1 @@
1
+ import{AggregateAjvError as i}from"@segment/ajv-human-errors";function E(o,t={filter:()=>!0}){const s=new i(o,{fieldLabels:"jsonPath",includeData:!0,includeOriginalError:!0}),n=t?.filter??(r=>!0),e=[];for(const r of s)n(r)&&e.push(r.message);return e}export{E as getErrorMessages};
@@ -0,0 +1 @@
1
+ import{ID_REGEX as e}from"@runium/core";function o(){return{$schema:"https://json-schema.org/draft/2020-12/schema",$id:"https://runium.dev/schemas/plugin.json",title:"Runium Plugin",type:"object",properties:{name:{type:"string",minLength:2,pattern:e.source},options:{type:"object",description:"Plugin configuration options"},project:{type:"object",description:"Project-level plugin definitions",properties:{macros:{type:"object",description:"Macro definitions for config file expansion",additionalProperties:{instanceof:"Function"}},tasks:{type:"object",description:"Task constructor definitions",additionalProperties:{instanceof:"Function"}},actions:{type:"object",description:"Action function definitions",additionalProperties:{instanceof:"Function"}},triggers:{type:"object",description:"Trigger constructor definitions",additionalProperties:{instanceof:"Function"}},validationSchema:{type:"object",description:"JSON Schema extension for project config validation",additionalProperties:!0}},additionalProperties:!1},app:{type:"object",description:"Application-level plugin definitions",properties:{commands:{type:"array",description:"Command constructor definitions",items:{instanceof:"Function"}}},additionalProperties:!1},hooks:{type:"object",description:"Lifecycle hooks for app and project events",properties:{app:{type:"object",description:"Application lifecycle hooks",properties:{afterInit:{instanceof:"Function",description:"Hook called after app initialization"},beforeExit:{instanceof:"Function",description:"Hook called before app exit"},beforeCommandRun:{instanceof:"Function",description:"Hook called before command execution"},afterCommandRun:{instanceof:"Function",description:"Hook called after command execution"}},additionalProperties:!1},project:{type:"object",description:"Project lifecycle hooks",properties:{beforeConfigRead:{instanceof:"Function",description:"Hook called before reading config file"},afterConfigRead:{instanceof:"Function",description:"Hook called after reading config file content"},afterConfigMacrosApply:{instanceof:"Function",description:"Hook called after applying macros to config"},afterConfigParse:{instanceof:"Function",description:"Hook called after parsing config"},beforeStart:{instanceof:"Function",description:"Hook called before project starts"}},additionalProperties:!1}},additionalProperties:!1}},required:["name"],additionalProperties:!1}}export{o as getPluginSchema};
@@ -0,0 +1 @@
1
+ import{createValidator as o}from"./create-validator.js";import{getConfigSchema as a}from"./get-config-schema.js";import{getErrorMessages as m}from"./get-error-messages.js";import{getPluginSchema as p}from"./get-plugin-schema.js";export{o as createValidator,a as getConfigSchema,m as getErrorMessages,p as getPluginSchema};