import fs from 'node:fs'; import path from 'node:path'; import { checkFileExists, AssistantConfig, AssistantConfigData, parseHomeArg, parseHelpArg } from '@/module/assistant/index.ts'; import { chalk } from '@/module/chalk.ts'; import { HttpsPem } from '@/module/assistant/https/sign.ts'; import { Query } from '@kevisual/query/query'; import { installDeps } from '@/module/npm-install.ts' export { parseHomeArg, parseHelpArg }; export type AssistantInitOptions = { path?: string; init?: boolean; }; const randomId = () => Math.random().toString(36).substring(2, 8); /** * 助手初始化类 * @class AssistantInit */ export class AssistantInit extends AssistantConfig { #query: Query constructor(opts?: AssistantInitOptions) { const configDir = opts?.path || process.cwd(); super({ configDir, init: false, }); if (opts?.init) { this.init(); } } async init() { // 1. 检查助手路径是否存在 if (!this.checkConfigPath()) { console.log(chalk.blue('助手路径不存在,正在创建...')); super.init(); } else { super.init(); const assistantConfig = this; console.log(chalk.yellow('助手路径已存在'), chalk.green(assistantConfig.configDir)); } this.createAssistantConfig(); this.createEnvConfig(); this.createOtherConfig(); this.initPnpm(); this.initIgnore(); } get query() { if (!this.#query) { this.setQuery(); } return this.#query; } get baseURL() { return `${this.getConfig()?.app?.url || 'https://kevisual.cn'}/api/router`; } setQuery(query?: Query) { this.#query = query || new Query({ url: `${this.getConfig()?.app?.url || 'https://kevisual.cn'}/api/router`, }); } checkConfigPath() { const assistantPath = path.join(this.configDir, 'assistant-app', 'assistant-config.json'); return checkFileExists(assistantPath); } createEnvConfig() { const env = this.configPath?.envConfigPath; // 创建助手环境配置文件 env if (!checkFileExists(env, true)) { fs.writeFileSync(env, '# 环境配置文件\n'); console.log(chalk.green('助手环境配置.env文件创建成功')); } } createOtherConfig() { const appsConfig = this.configPath?.appsConfigPath; // 创建助手应用配置文件 apps if (!checkFileExists(appsConfig, true)) { fs.writeFileSync(appsConfig, JSON.stringify({ description: 'apps manager.', list: [] })); console.log(chalk.green('助手应用配置文件 apps.json 创建成功')); } // create pem dir // const pemDir = path.join(this.configPath?.configDir, 'pem'); const httpsPem = new HttpsPem(this); if (httpsPem.isHttps) { if (!checkFileExists(pemDir)) { console.log(chalk.green('助手证书目录创建成功')); } } } createAssistantConfig() { const assistantPath = this.configPath?.configPath; // 创建助手配置文件 assistant-config.json if (!checkFileExists(assistantPath, true)) { this.setConfig(this.getDefaultInitAssistantConfig()); console.log(chalk.green('助手配置文件assistant-config.json创建成功')); } else { const config = this.getConfig(); if (!config?.app?.id) { if (!config.app) { config.app = {}; } config.app.id = randomId(); this.setConfig(config); console.log(chalk.green('助手配置文件assistant-config.json更新成功')); } } } initPnpm() { const pnpmPath = path.join(this.configDir, 'assistant-app', 'pnpm-workspace.yaml'); let create = false; if (!checkFileExists(pnpmPath, true)) { create = true; fs.writeFileSync( pnpmPath, `packages: - 'apps/**/*' - 'pages/**/*' `, ); console.log(chalk.green('助手 pnpm-workspace.yaml 文件创建成功')); } const packagePath = path.join(this.configDir, 'assistant-app', 'package.json'); if (!checkFileExists(packagePath, true)) { create = true; fs.writeFileSync( packagePath, `{ "name": "assistant-app", "version": "1.0.0", "description": "assistant-app package pnpm, node pkgs projects", "type": "module", "scripts": { "start": "pm2 start apps/root/code-center/app.mjs --name root/code-center", "cnb": "ASSISTANT_CONFIG_DIR=/workspace asst server -s -p 7878" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "@kevisual/router": "latest", "@kevisual/use-config": "latest", "@kevisual/query": "latest", "ioredis": "latest", "minio": "latest", "pg": "latest", "pm2": "latest", "sequelize": "latest", "crypto-js": "latest", "better-sqlite3": "latest", "unstorage": "latest", "dayjs": "latest", "es-toolkit": "latest", "node-cron": "latest", "dotenv": "latest" }, "devDependencies": { "@types/node": "latest", "@types/crypto-js": "latest" } } `, ); console.log(chalk.green('助手 package.json 文件创建成功, 正在安装依赖...')); installDeps({ appPath: path.dirname(packagePath), isProduction: true }).then(() => { console.log(chalk.green('助手依赖安装完成')); }); } return { create, }; } initIgnore() { const gitignorePath = path.join(this.configDir, '.gitignore'); let content = ''; if (checkFileExists(gitignorePath, true)) { content = fs.readFileSync(gitignorePath, 'utf-8'); } const ignoreLines = [ 'node_modules', '.DS_Store', 'dist', 'pack-dist', 'cache-file', 'build', 'apps/**/node_modules/', 'pages/**/node_modules/', '.env', '!.env*development', '.pnpm-store', '.vite', '.astro' ]; let updated = false; ignoreLines.forEach((line) => { if (!content.includes(line)) { content += `\n${line}`; updated = true; } }); if (updated) { fs.writeFileSync(gitignorePath, content.trim() + '\n'); console.log(chalk.green('.gitignore 文件更新成功')); } } protected getDefaultInitAssistantConfig() { const id = randomId(); return { app: { url: 'https://kevisual.cn', id, }, description: '助手配置文件', docs: "https://kevisual.cn/root/cli/docs/", home: '/root/home', proxy: [], share: { enabled: false, url: 'https://kevisual.cn/ws/proxy', }, } as AssistantConfigData; } getHttps() { const https = this.getConfig()?.https || {}; return { https, protocol: https?.type === 'https' ? 'https' : 'http', }; } }