feat: add silky cli tools

This commit is contained in:
2025-04-27 22:16:09 +08:00
parent 75d181ef43
commit 6867de838e
42 changed files with 3867 additions and 251 deletions

View File

@@ -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}`);
}
}
}

View File

@@ -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;
}
}