feat: add silky cli tools
This commit is contained in:
		| @@ -1 +1,124 @@ | ||||
| // app downlaod | ||||
| import { checkFileExists, AssistantConfig } from '@/module/assistant/index.ts'; | ||||
| import path from 'path'; | ||||
| import fs from 'fs'; | ||||
| import inquirer from 'inquirer'; | ||||
|  | ||||
| import { spawnSync } from 'child_process'; | ||||
| export const runCommand = (command: string, args: string[]) => { | ||||
|   const result = spawnSync(command, args, { | ||||
|     stdio: 'inherit', | ||||
|     shell: true, | ||||
|   }); | ||||
|   if (result.error) { | ||||
|     console.error('Error executing command:', result.error); | ||||
|     throw result.error; | ||||
|   } | ||||
|   if (result.status !== 0) { | ||||
|     console.error('Command failed with status:', result.status); | ||||
|     throw new Error(`Command failed with status: ${result.status}`); | ||||
|   } | ||||
|   return result; | ||||
| }; | ||||
| export type appType = 'web' | 'app'; | ||||
|  | ||||
| type DownloadAppOptions = { | ||||
|   /** | ||||
|    * 应用名称 | ||||
|    * @type {string} | ||||
|    * @example user/app | ||||
|    * @description 应用名称 | ||||
|    */ | ||||
|   id: string; | ||||
|   type?: appType; | ||||
|   registry?: string; | ||||
|   /** | ||||
|    * 应用名称,默认为 user/app的 app | ||||
|    */ | ||||
|   appName?: string; | ||||
| }; | ||||
| type DeleteAppOptions = { | ||||
|   /** | ||||
|    * 应用名称 | ||||
|    * @type {string} | ||||
|    * @example user/app | ||||
|    * @description 应用名称 | ||||
|    */ | ||||
|   id: string; | ||||
|   type?: appType; | ||||
|   appName?: string; | ||||
| }; | ||||
| export class AppDownload { | ||||
|   config: AssistantConfig; | ||||
|   constructor(config: AssistantConfig) { | ||||
|     this.config = config; | ||||
|   } | ||||
|   async downloadApp(opts: DownloadAppOptions) { | ||||
|     const { id, type = 'web' } = opts; | ||||
|     const configDir = this.config.configDir; | ||||
|     this.config?.checkMounted(); | ||||
|     const appsDir = this.config.configPath?.appsDir; | ||||
|     const pageDir = this.config.configPath?.pageDir; | ||||
|     if (!id) { | ||||
|       throw new Error('应用名称不能为空'); | ||||
|     } | ||||
|     const command = 'ev'; | ||||
|     const args = ['app', 'download']; | ||||
|     args.push('-i', id); | ||||
|     if (type) { | ||||
|       args.push('-t', type); | ||||
|     } | ||||
|     const appName = opts?.appName || id.split('/').pop(); | ||||
|     if (type === 'web') { | ||||
|       args.push('-o', pageDir); | ||||
|     } else if (type === 'app') { | ||||
|       args.push('-o', path.join(appsDir, appName)); | ||||
|     } else { | ||||
|       throw new Error('应用类型错误,只能是 web 或 app'); | ||||
|     } | ||||
|     if (opts.registry) { | ||||
|       args.push('-r', opts.registry); | ||||
|     } | ||||
|     return runCommand(command, args); | ||||
|   } | ||||
|   async confirm(message?: string) { | ||||
|     const { confirm } = await inquirer.prompt([ | ||||
|       { | ||||
|         type: 'confirm', | ||||
|         name: 'confirm', | ||||
|         message: message || '是否继续删除应用?', | ||||
|         default: false, | ||||
|       }, | ||||
|     ]); | ||||
|     return confirm; | ||||
|   } | ||||
|   async deleteApp(opts: DeleteAppOptions) { | ||||
|     const { id, type = 'web' } = opts; | ||||
|     const appName = opts?.appName || id.split('/').pop(); | ||||
|     this.config?.checkMounted(); | ||||
|     const appsDir = this.config.configPath?.appsDir; | ||||
|     const pageDir = this.config.configPath?.pageDir; | ||||
|     if (!id) { | ||||
|       throw new Error('应用名称不能为空'); | ||||
|     } | ||||
|     let deletePath = ''; | ||||
|     let isDelete = false; | ||||
|     if (type === 'web') { | ||||
|       // 直接删除路径就行 | ||||
|       const pagePath = path.join(pageDir, id); | ||||
|       deletePath = pagePath; | ||||
|     } else if (type === 'app') { | ||||
|       const appPath = path.join(appsDir, appName); | ||||
|       deletePath = appPath; | ||||
|     } | ||||
|     if (deletePath && checkFileExists(deletePath)) { | ||||
|       const confirm = await this.confirm(`是否删除 ${deletePath} 应用?`); | ||||
|       if (!confirm) { | ||||
|         console.log('取消删除应用'); | ||||
|         return; | ||||
|       } | ||||
|       fs.rmSync(deletePath, { recursive: true }); | ||||
|       isDelete = true; | ||||
|       console.log(`删除应用成功: ${deletePath}`); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import fs from 'node:fs'; | ||||
| import path from 'node:path'; | ||||
| import { checkFileExists, AssistantConfig } from '@/module/assistant/index.ts'; | ||||
| import { checkFileExists, AssistantConfig, AssistantConfigData } from '@/module/assistant/index.ts'; | ||||
| import { chalk } from '@/module/chalk.ts'; | ||||
| import { HttpsPem } from '@/module/assistant/https/sign.ts'; | ||||
| export type AssistantInitOptions = { | ||||
| @@ -66,13 +66,16 @@ export class AssistantInit extends AssistantConfig { | ||||
|     const assistantPath = this.configPath?.configPath; | ||||
|     // 创建助手配置文件 assistant-config.json | ||||
|     if (!checkFileExists(assistantPath, true)) { | ||||
|       this.setConfig({ | ||||
|         description: '助手配置文件', | ||||
|         home: '/root/center', | ||||
|         proxy: [], | ||||
|         apiProxyList: [], | ||||
|       }); | ||||
|       this.setConfig(this.getDefaultInitAssistantConfig()); | ||||
|       console.log(chalk.green('助手配置文件assistant-config.json创建成功')); | ||||
|     } | ||||
|   } | ||||
|   protected getDefaultInitAssistantConfig() { | ||||
|     return { | ||||
|       description: '助手配置文件', | ||||
|       home: '/root/center', | ||||
|       proxy: [], | ||||
|       apiProxyList: [], | ||||
|     } as AssistantConfigData; | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user