diff --git a/.gitignore b/.gitignore index a41c740..79cc375 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ dist pack-dist apps +assistant-app \ No newline at end of file diff --git a/assistant/bun.config.mjs b/assistant/bun.config.mjs index 1dc6da3..09a4239 100644 --- a/assistant/bun.config.mjs +++ b/assistant/bun.config.mjs @@ -1,17 +1,26 @@ // @ts-check // https://bun.sh/docs/bundler -// @ts-ignore +import path from 'node:path'; import pkg from './package.json'; +import fs from 'node:fs'; // bun run src/index.ts -- +import { fileURLToPath } from 'node:url'; +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +/** + * + * @param {string} p + * @returns + */ +export const w = (p) => path.join(__dirname, p); await Bun.build({ target: 'node', format: 'esm', - entrypoints: ['./src/index.ts'], - outdir: './dist', + entrypoints: [w('./src/index.ts')], + outdir: w('./dist'), naming: { entry: 'assistant.mjs', }, - + external: ['pm2'], define: { ENVISION_VERSION: JSON.stringify(pkg.version), }, @@ -21,13 +30,33 @@ await Bun.build({ await Bun.build({ target: 'node', format: 'esm', - entrypoints: ['./src/server.ts'], - outdir: './dist', + entrypoints: [w('./src/server.ts')], + outdir: w('./dist'), naming: { - entry: 'assistan-server.mjs', - }, - define: { - ENVISION_VERSION: JSON.stringify(pkg.version), + entry: 'assistant-server.mjs', }, + external: ['pm2'], env: 'ENVISION_*', }); + +export const copyFileToEnvision = async () => { + const src = ['dist', 'bin'].map((dir) => { + return { absolute: path.join(__dirname, dir), name: dir }; + }); + const dest = path.join(__dirname, '..'); + for (const dir of src) { + const files = fs.readdirSync(dir.absolute); + for (const file of files) { + const srcFile = path.join(dir.absolute, file); + const destFile = path.join(dest, dir.name, file); + try { + fs.copyFileSync(srcFile, destFile); + } catch (err) { + console.error('Error copying files: origin: ', srcFile, 'dest: ', destFile); + console.error('Error copying files:', err); + continue; + } + } + } +}; +await copyFileToEnvision(); diff --git a/assistant/package.json b/assistant/package.json index 671308c..194aa5b 100644 --- a/assistant/package.json +++ b/assistant/package.json @@ -19,7 +19,7 @@ ], "scripts": { "dev": "bun run src/run.ts ", - "dev:server": "cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 bun --watch src/server.ts", + "dev:server": "cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 bun --watch src/run-server.ts", "build": "rimraf dist && bun run bun.config.mjs" }, "bin": { @@ -27,6 +27,7 @@ "ev-asst": "bin/assistant.js" }, "devDependencies": { + "@kevisual/ai-center": "^0.0.3", "@kevisual/load": "^0.0.6", "@kevisual/local-app-manager": "^0.1.16", "@kevisual/query": "0.0.17", @@ -41,6 +42,8 @@ "chalk": "^5.4.1", "commander": "^13.1.0", "cross-env": "^7.0.3", + "dotenv": "^16.5.0", + "get-port": "^7.1.0", "inquirer": "^12.6.0", "lodash-es": "^4.17.21", "nanoid": "^5.1.5", @@ -49,6 +52,7 @@ "send": "^1.2.0", "supports-color": "^10.0.0", "ws": "npm:@kevisual/ws", + "dayjs": "^1.11.13", "zustand": "^5.0.3" }, "engines": { @@ -58,9 +62,11 @@ "access": "public" }, "dependencies": { - "dayjs": "^1.11.13" + "pm2": "^6.0.5" }, "overrides": { - "ws": "npm:@kevisual/ws" + "ws": "npm:@kevisual/ws", + "@kevisual/query": "0.0.17", + "@kevisual/router": "0.0.13" } } \ No newline at end of file diff --git a/assistant/pem/https-cert.pem b/assistant/pem/https-cert.pem deleted file mode 100644 index cdd8681..0000000 --- a/assistant/pem/https-cert.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICXTCCAcagAwIBAgIJUmN5oWFZdxK8MA0GCSqGSIb3DQEBBQUAMF8xCjAIBgNV -BAMTASoxCzAJBgNVBAYTAkNOMREwDwYDVQQIEwhaaGVKaWFuZzERMA8GA1UEBxMI -SGFuZ3pob3UxETAPBgNVBAoTCEVudmlzaW9uMQswCQYDVQQLEwJJVDAeFw0yNTA0 -MjQxODExMjZaFw0yNjA0MjQxODExMjZaMF8xCjAIBgNVBAMTASoxCzAJBgNVBAYT -AkNOMREwDwYDVQQIEwhaaGVKaWFuZzERMA8GA1UEBxMISGFuZ3pob3UxETAPBgNV -BAoTCEVudmlzaW9uMQswCQYDVQQLEwJJVDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw -gYkCgYEAirpqS9Lwh5JNY7N303wphXCR/HZDgfw1HnP6b62WVJTHtU97hLKjrTXx -zUYPEyySXLzFGjptKSjT3ZgulV1I9YBXg2gdDibxxxZUZHoJ8j0oh+MSxRv1fTzw -+HEBErUJQJ4lHnf9nbi7Tf48XiNWqh9Lce3XvyDFQoRDASX5yeUCAwEAAaMhMB8w -HQYDVR0RBBYwFIIBKoIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBBQUAA4GB -AGCYapPzhY0zUVZxo6CsijdDQpuHe2G3cDs4bzpF2YHRGN3t8/cPwROt7FWCkzBt -b7g/Tar+200fGspmLS95QisjiKo0fAKfaEE8CHXr2jlt8+omOz0tPg9LCZi2GtgI -8EC+Vvvcd9UjzHmoPBZQF4qAvJ2IyOwBh6Vwyh8las+e ------END CERTIFICATE----- diff --git a/assistant/pem/https-private-key.pem b/assistant/pem/https-private-key.pem deleted file mode 100644 index 2c99f5b..0000000 --- a/assistant/pem/https-private-key.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQCKumpL0vCHkk1js3fTfCmFcJH8dkOB/DUec/pvrZZUlMe1T3uE -sqOtNfHNRg8TLJJcvMUaOm0pKNPdmC6VXUj1gFeDaB0OJvHHFlRkegnyPSiH4xLF -G/V9PPD4cQEStQlAniUed/2duLtN/jxeI1aqH0tx7de/IMVChEMBJfnJ5QIDAQAB -AoGAGmBUKoN6OQSPk0fBniOqz1S2ZP5lWncF8HrToF0sSnuZNvdcQEAoz5uElGdg -IWClmV1IynJWY+9/zM+M99grMT6it3VHHVM3MQoTf1Am4Vy0qgKR6Y1TzE0XLrVW -3e3ezDph3gG0EQsRxVbn/goCEfstuhJaFyxHvsQRtPY+Z1ECQQC8ffbjV8hb911o -iUw67FquOL9AYrFfQfohkQZ1TrDv0VTCAYpB7e5ml4dBhUL1dQbFV7avZIufD5fl -pxCKkAPNAkEAvGnQPByrKj6ggf2l1CzgjXzZ24wm3AkJutWkFjAcf5EFy0+MIBOi -ejyrGcGi9eovXCLGLrgzaBeAHa4XNkX2eQJAEZE73VxlFA0t63xAWo2EthAb4whP -t60SfuZhT7WR0AgWei5ikFp4iZ89v+GHqBDMHMBcCmS4jo6JfaHgbMmXUQJAAIDL -1I1DC77VEOPLgJCKHPabYlGyfN3tT7loUcLZIKITgOJ6fk9vHKJy1oPE2qFAdR+G -pfNJ99owNmQTncp8CQJAI3fp5VABViB3uha4cHmpRUvoGNWmmh9Ob6LypDsGtd8z -8ah+4Ek1DvsQC4XDuwgwnQsCmEYfa2P1T/GIdqPadw== ------END RSA PRIVATE KEY----- diff --git a/assistant/src/command/init/index.ts b/assistant/src/command/config-manager/index.ts similarity index 87% rename from assistant/src/command/init/index.ts rename to assistant/src/command/config-manager/index.ts index ee0deef..31eba5c 100644 --- a/assistant/src/command/init/index.ts +++ b/assistant/src/command/config-manager/index.ts @@ -15,8 +15,10 @@ const Init = new Command('init') } else if (opts.path) { opts.path = path.resolve(opts.path); } + const configDir = AssistantInit.detectConfigDir(opts.path); + console.log('configDir', configDir); const assistantInit = new AssistantInit({ - path: opts.path, + path: configDir, }); assistantInit.init(); }); diff --git a/assistant/src/index.ts b/assistant/src/index.ts index 55de4e8..8216991 100644 --- a/assistant/src/index.ts +++ b/assistant/src/index.ts @@ -1,5 +1,5 @@ import { program, runProgram } from '@/program.ts'; -import './command/init/index.ts'; +import './command/config-manager/index.ts'; import './command/app-manager/index.ts'; /** diff --git a/assistant/src/module/assistant/config/index.ts b/assistant/src/module/assistant/config/index.ts index af07f14..92b935d 100644 --- a/assistant/src/module/assistant/config/index.ts +++ b/assistant/src/module/assistant/config/index.ts @@ -37,7 +37,7 @@ export const initConfig = (configRootPath: string) => { */ appsDir, /** - * 服务配置文件路径 assistant-service-config.json + * 服务配置文件路径 assistant-apps-config.json */ appsConfigPath, /** @@ -65,6 +65,15 @@ type AssistantConfigData = { proxy?: ProxyInfo[]; apiProxyList?: ProxyInfo[]; description?: string; + /** + * 首页 + */ + home?: string; + ai?: { + provider?: string | 'DeepSeek' | 'SiliconFlow'; + apiKey?: string; + model?: string; + }; }; let assistantConfig: AssistantConfigData; type AssistantConfigOptions = { @@ -142,7 +151,7 @@ export class AssistantConfig { fs.writeFileSync(pageConfigPath, JSON.stringify(_saveConfig, null, 2)); return _saveConfig; } - assAppConfig(app: any) { + addAppConfig(app: any) { const config = this.getPageConfig(); const assistantConfig = this.getCacheAssistantConfig(); const _apps = config.list; diff --git a/assistant/src/run-server.ts b/assistant/src/run-server.ts new file mode 100644 index 0000000..aeeed2f --- /dev/null +++ b/assistant/src/run-server.ts @@ -0,0 +1,3 @@ +import { runServer } from "./server.ts"; + +runServer(); \ No newline at end of file diff --git a/assistant/src/server.ts b/assistant/src/server.ts index c17d2a7..05deb1f 100644 --- a/assistant/src/server.ts +++ b/assistant/src/server.ts @@ -1,10 +1,71 @@ import { app } from './app.ts'; import { proxyRoute, proxyWs } from './services/proxy/proxy-page-index.ts'; +import getPort, { portNumbers } from 'get-port'; +import { program } from 'commander'; +import { spawnSync } from 'child_process'; +export const runServer = async (port?: number) => { + let _port: number | undefined; + if (port) { + _port = await getPort({ port }); + if (_port !== port) { + console.log(`Port ${port} is not available`); + _port = undefined; + } + } + if (!_port) { + // 检车端口可用性 + const isPortAvailable = await getPort({ port: portNumbers(51015, 52000) }); + if (!isPortAvailable) { + console.log(`Port ${isPortAvailable} is not available`); + process.exit(1); + } + _port = isPortAvailable; + } + app.listen(_port, () => { + console.log(`Server is running on https://localhost:${_port}`); + }); + app.server.on(proxyRoute); + proxyWs(); + return { + app, + port: _port, + }; +}; +program + .description('启动服务') + .option('-d, --daemon', '是否以守护进程方式运行') + .option('-n, --name ', '服务名称', 'assistant-server') + .option('-p, --port ', '服务端口') + .option('-s, --start', '是否启动服务') + .action(async (options) => { + // console.log('当前执行路径:', execPath, inte); + if (options.daemon) { + const [_interpreter, execPath] = process.argv; + const name = options.name; + const port = options.port; + let pm2Command = `pm2 start ${execPath} --name ${name} -- -s `; + if (port) { + pm2Command += ` -p ${port}`; + } + const result = spawnSync(pm2Command, { + shell: true, + stdio: 'inherit', + }); + if (result.error) { + console.error('Error starting server:', result.error); + process.exit(1); + } + console.log('以守护进程方式运行'); + } else if (options.start) { + console.log('启动服务'); + const server = await runServer(options.port); + } + }); -app.listen(51015, () => { - console.log('Server is running on http://localhost:51015'); -}); - -app.server.on(proxyRoute); - -proxyWs(); +export const runParser = async (argv: string[]) => { + try { + program.parse(argv); + } catch (error) { + console.error('执行错误:', error.message); + } +}; diff --git a/assistant/src/services/init/index.ts b/assistant/src/services/init/index.ts index e741fa2..660ffd0 100644 --- a/assistant/src/services/init/index.ts +++ b/assistant/src/services/init/index.ts @@ -4,6 +4,7 @@ import { checkFileExists, AssistantConfig } from '@/module/assistant/index.ts'; import { chalk } from '@/module/chalk.ts'; export type AssistantInitOptions = { path?: string; + init?: boolean; }; /** * 助手初始化类 @@ -14,6 +15,7 @@ export class AssistantInit extends AssistantConfig { const configDir = opts?.path || process.cwd(); super({ configDir, + init: opts?.init ?? false, }); } @@ -30,21 +32,30 @@ export class AssistantInit extends AssistantConfig { } } checkConfigPath() { - const assistantPath = path.join(this.configDir, 'assistant-config.json'); + const assistantPath = path.join(this.configDir, 'assistant-app', 'assistant-config.json'); return checkFileExists(assistantPath); } createAssistantConfig() { const assistantPath = this.configPath?.configPath; + // 创建助手配置文件 assistant-config.json if (!checkFileExists(assistantPath, true)) { this.setConfig({ description: '助手配置文件', }); - console.log(chalk.green('助手配置文件创建成功')); + console.log(chalk.green('助手配置文件assistant-config.json创建成功')); } const env = this.configPath?.envConfigPath; + // 创建助手环境配置文件 env if (!checkFileExists(env, true)) { fs.writeFileSync(env, '# 环境配置文件\n'); - console.log(chalk.green('助手环境配置文件创建成功')); + console.log(chalk.green('助手环境配置.env文件创建成功')); + } + + 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创建成功')); } } } diff --git a/assistant/src/services/proxy/proxy-page-index.ts b/assistant/src/services/proxy/proxy-page-index.ts index 136d0e8..ff9d966 100644 --- a/assistant/src/services/proxy/proxy-page-index.ts +++ b/assistant/src/services/proxy/proxy-page-index.ts @@ -11,6 +11,10 @@ export const proxyRoute = async (req: http.IncomingMessage, res: http.ServerResp const appDir = assistantConfig.configPath?.pageDir; const url = new URL(req.url, 'http://localhost'); const pathname = url.pathname; + if (pathname === '/' && _assistantConfig?.home) { + res.writeHead(302, { Location: `${_assistantConfig?.home}/` }); + return res.end(); + } if (pathname.startsWith('/favicon.ico')) { res.statusCode = 404; res.end('Not Found Favicon'); diff --git a/assistant/src/test/chat.ts b/assistant/src/test/chat.ts new file mode 100644 index 0000000..cfbfdb4 --- /dev/null +++ b/assistant/src/test/chat.ts @@ -0,0 +1,53 @@ +// import { AssistantConfig } from '@/module/assistant/index.ts'; +import { assistantConfig } from '../config.ts'; + +import { ProviderManager, SiliconFlowProvider } from '@kevisual/ai-center'; + +const config = assistantConfig.getConfig(); +console.log('aiConfig', config.ai); +const providerManager = new ProviderManager({ + provider: config.ai.provider, + apiKey: config.ai.apiKey!, + model: config.ai.model!, +}); + +const chatTest = async (text: string) => { + const result = await providerManager.provider.chat([ + { + role: 'user', + content: text, + }, + ]); + console.log('result', result); + return result.choices[0].message.content; +}; + +chatTest('你好').then((res) => { +console.log('chatTest', res); +}); + +// providerManager.provider.test().then((res) => { +// console.log('test', res); +// }); +// const siliconflow = providerManager.provider as any; +const siliconflow = new SiliconFlowProvider({ + apiKey: config.ai.apiKey!, + model: config.ai.model!, +}); +const main = async () => { + const usage = await siliconflow.getUsageInfo(); + console.log(usage); +}; + +// main(); +const test = async () => { + const result = await siliconflow.chat([ + { + role: 'user', + content: '你好', + }, + ]); + console.log('result', result, 'result.choices[0].message.content', result.choices[0].message.content); + return result.choices[0].message.content; +}; +// test(); diff --git a/assistant/src/test/provider/model-scope.ts b/assistant/src/test/provider/model-scope.ts new file mode 100644 index 0000000..fecaa96 --- /dev/null +++ b/assistant/src/test/provider/model-scope.ts @@ -0,0 +1,22 @@ +import { ProviderManager, SiliconFlowProvider, ModelScopeProvider } from '@kevisual/ai-center'; + +import { config } from 'dotenv'; +config(); +const providerTest = async () => { + const providerConfig = { provider: 'ModelScope', model: 'Qwen/Qwen2.5-Coder-32B-Instruct', apiKey: process.env.MODEL_SCOPE_API_KEY }; + const provider = await ProviderManager.createProvider(providerConfig); + const result = await provider.chat([{ role: 'user', content: '你好' }]); + console.log(result); +}; + +providerTest(); + +const modelScopeTest = async () => { + const provider = new ModelScopeProvider({ + apiKey: process.env.MODEL_SCOPE_API_KEY, + model: 'Qwen/Qwen2.5-Coder-32B-Instruct', + }); + const result = await provider.chat([{ role: 'user', content: '你好' }]); + console.log(result); +}; +// modelScopeTest(); \ No newline at end of file diff --git a/assistant/task-command/.gitignore b/assistant/task-command/.gitignore new file mode 100644 index 0000000..4edcc19 --- /dev/null +++ b/assistant/task-command/.gitignore @@ -0,0 +1,9 @@ +node_modules +.DS_Store + +dist + +pack-dist + +.env* +!.env*example \ No newline at end of file diff --git a/assistant/task-command/.npmrc b/assistant/task-command/.npmrc new file mode 100644 index 0000000..8d5f68f --- /dev/null +++ b/assistant/task-command/.npmrc @@ -0,0 +1,4 @@ + +//npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN} +//registry.npmjs.org/:_authToken=${NPM_TOKEN} +ignore-workspace-root-check=true \ No newline at end of file diff --git a/assistant/task-command/mod.d.ts b/assistant/task-command/mod.d.ts new file mode 100644 index 0000000..7d1302c --- /dev/null +++ b/assistant/task-command/mod.d.ts @@ -0,0 +1,67 @@ +declare const TaskCommandType: readonly ["npm-install"]; +type TaskCommand = { + key?: string; + /** + * 任务描述 + */ + description?: string; + /** + * 命令, 执行的任务 + */ + command: string; + type?: (typeof TaskCommandType)[number] | string; + /** + * 任务执行完成后,执行判断的命令 + */ + after?: string; + /** + * 任务执行前,执行判断的命令 + */ + before?: string; + /** + * 任务执行完成后, 检测输出的文本内容,如果有这个文本,表示任务执行成功 + * 如果没有这个文本,表示任务执行失败 + */ + afterCheck?: string; + /** + * 任务执行前, 检测输出的文本内容,如果有这个文本,表示任务已经安装 + * 如果没有这个文本,表示任务没有安装 + */ + beforeCheck?: string; +}; +declare class TasksCommand { + tasks: Map; + constructor(); + addTask(task: TaskCommand, run?: boolean): this; + getTask(name: string): TaskCommand; + runTask(name: string): { + task: TaskCommand; + code: number; + } | { + code: number; + message: string; + }; + /** + * 检测是否需要继续执行。 + * 1. res.code === 500 代表执行失败, 需要继续执行 + * 2. res.code === 200 代表执行成功,但是需要检测输出内容 + * 2.1 如果有 check 的内容,代表不需要继续执行 + * 2.2 如果没有 check 的内容,代表需要继续执行 + * @param res + * @param check + * @returns + */ + private checkForContainue; + runCommand(command: string): { + code: number; + data: string; + message?: undefined; + } | { + code: number; + data: string; + message: any; + }; +} + +export { TaskCommandType, TasksCommand }; +export type { TaskCommand }; diff --git a/assistant/task-command/mod.ts b/assistant/task-command/mod.ts new file mode 100644 index 0000000..9e96501 --- /dev/null +++ b/assistant/task-command/mod.ts @@ -0,0 +1,142 @@ +import { execSync } from 'node:child_process'; + +export const TaskCommandType = ['npm-install'] as const; +export type TaskCommand = { + key?: string; + /** + * 任务描述 + */ + description?: string; + /** + * 命令, 执行的任务 + */ + command: string; + type?: (typeof TaskCommandType)[number] | string; + /** + * 任务执行完成后,执行判断的命令 + */ + after?: string; + /** + * 任务执行前,执行判断的命令 + */ + before?: string; + /** + * 任务执行完成后, 检测输出的文本内容,如果有这个文本,表示任务执行成功 + * 如果没有这个文本,表示任务执行失败 + */ + afterCheck?: string; + /** + * 任务执行前, 检测输出的文本内容,如果有这个文本,表示任务已经安装 + * 如果没有这个文本,表示任务没有安装 + */ + beforeCheck?: string; +}; +export class TasksCommand { + tasks: Map = new Map(); + constructor() {} + addTask(task: TaskCommand, run?: boolean) { + const key = task?.key || task?.description; + if (!key) { + throw new Error('当前的任务没有key'); + } + this.tasks.set(key, task); + if (run) { + this.runTask(key); + } + return this; + } + getTask(name: string) { + return this.tasks.get(name); + } + runTask(name: string) { + const task = this.getTask(name); + const end = (data?: { code: number; [key: string]: any }) => { + return { + ...data, + task, + }; + }; + if (!task) { + return { + code: 500, + message: `没有找到 ${name} 这个任务`, + }; + } + let { command, before, after, afterCheck, beforeCheck, type } = task; + if (type === 'npm-install' && !afterCheck) { + afterCheck = 'added'; + } + if (before) { + const res = this.runCommand(before); + console.log('before', res, beforeCheck, this.checkForContainue(res, beforeCheck)); + if (!this.checkForContainue(res, beforeCheck)) { + return end({ + code: 200, + message: `当前任务不需要执行, ${command}`, + }); + } + } + const res = this.runCommand(command); + console.log('runCommand', res); + if (res.code !== 200) { + return end(res); + } + let checkText = res.data || ''; + if (after) { + const res = this.runCommand(after); + if (res.code !== 200) { + return end(res); + } + checkText = res.data || ''; + } + if (afterCheck) { + const isSuccess = checkText?.includes?.(afterCheck); + return end({ + code: isSuccess ? 200 : 500, + output: res.data, + check: afterCheck, + message: isSuccess ? `当前任务执行成功, ${command}` : `当前任务执行失败, ${command}`, + }); + } + return end(res); + } + /** + * 检测是否需要继续执行。 + * 1. res.code === 500 代表执行失败, 需要继续执行 + * 2. res.code === 200 代表执行成功,但是需要检测输出内容 + * 2.1 如果有 check 的内容,代表不需要继续执行 + * 2.2 如果没有 check 的内容,代表需要继续执行 + * @param res + * @param check + * @returns + */ + private checkForContainue(res: { data: string; code: number; [key: string]: any }, check?: string, isBefore = true) { + if (res.code !== 200) { + return true; + } + if (!check) { + return true; + } + const hasIncludes = res.data?.includes?.(check); + if (isBefore) { + // 代表已经安装, 不需要继续执行 + return !hasIncludes; + } + return hasIncludes; + } + runCommand(command: string) { + try { + const res = execSync(command, { encoding: 'utf-8' }); + return { + code: 200, + data: res.toString(), + }; + } catch (error) { + return { + code: 500, + data: '', + message: error.toString(), + }; + } + } +} diff --git a/assistant/task-command/package.json b/assistant/task-command/package.json new file mode 100644 index 0000000..a534b3a --- /dev/null +++ b/assistant/task-command/package.json @@ -0,0 +1,26 @@ +{ + "name": "@kevisual/task-command", + "version": "0.0.1", + "description": "", + "types": "mod.d.ts", + "scripts": { + "dts": "dts -i mod.ts -o mod.d.ts -d ." + }, + "keywords": [], + "publishConfig": { + "registry": "https://registry.npmjs.org/", + "access": "public" + }, + "files": [ + "mod.ts", + "mod.d.ts" + ], + "author": "abearxiong (https://www.xiongxiao.me)", + "license": "MIT", + "packageManager": "pnpm@10.7.0", + "type": "module", + "exports": { + ".": "./mod.ts", + "./mod.ts": "./mod.ts" + } +} \ No newline at end of file diff --git a/assistant/task-command/readme.md b/assistant/task-command/readme.md new file mode 100644 index 0000000..5a560bb --- /dev/null +++ b/assistant/task-command/readme.md @@ -0,0 +1,3 @@ +# task-command + +command line task runner \ No newline at end of file diff --git a/assistant/tasks/silkyai/deno.json b/assistant/tasks/silkyai/deno.json new file mode 100644 index 0000000..5721a7d --- /dev/null +++ b/assistant/tasks/silkyai/deno.json @@ -0,0 +1,34 @@ +{ + "tasks": { + "dev": { + "command": "deno run -A talkshow.ts", + "desc": "Run the server in development mode" + }, + "build": { + "command": "deno run --allow-all --unstable src/build.ts", + "desc": "Build the project" + }, + "build:dts": { + "command": "deno run -A talkshow.ts --dts", + "desc": "Build the project with dts" + } + }, + "lint": { + "files": [ + "src/**/*.ts", + "src/**/*.tsx", + "src/**/*.js", + "src/**/*.jsx" + ], + "options": { + "rules": { + "ban-untagged-todo": false, + "no-explicit-any": false, + "no-unused-vars": false + } + } + }, + "imports": { + "https://esm.xiongxiao.me/@kevisual/task-command/mod.ts": "../../task-command/mod.ts" + } +} \ No newline at end of file diff --git a/assistant/tasks/silkyai/deno.lock b/assistant/tasks/silkyai/deno.lock new file mode 100644 index 0000000..4fbc1a4 --- /dev/null +++ b/assistant/tasks/silkyai/deno.lock @@ -0,0 +1,17 @@ +{ + "version": "4", + "specifiers": { + "npm:@types/node@*": "22.12.0" + }, + "npm": { + "@types/node@22.12.0": { + "integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==", + "dependencies": [ + "undici-types" + ] + }, + "undici-types@6.20.0": { + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" + } + } +} diff --git a/assistant/tasks/silkyai/talkshow.ts b/assistant/tasks/silkyai/talkshow.ts index 8d8d30c..2574085 100644 --- a/assistant/tasks/silkyai/talkshow.ts +++ b/assistant/tasks/silkyai/talkshow.ts @@ -1,3 +1,40 @@ +import { TasksCommand } from 'https://esm.xiongxiao.me/@kevisual/task-command/mod.ts'; +// import { TasksCommand } from '../../task-command/mod.ts'; +const init = { + description: '安装依赖', + command: 'npm install -g @kevisual/cli --registry=https://registry.npmmirror.com', + afterCheck: 'added', +}; +const init1 = { + description: '安装 pm2', + type: 'npm-install', + command: 'npm install -g pm2 --registry=https://registry.npmmirror.com', + before: 'pm2 -v', +}; +const init2 = { + description: '安装 deno', + command: 'npm install -g deno --registry=https://registry.npmmirror.com', + type: 'npm-install', + before: 'deno -v', + beforeCheck: 'deno', +}; +const init3 = { + description: '安装 bun', + type: 'npm-install', + command: 'npm install -g bun --registry=https://registry.npmmirror.com', + beforeCheck: 'bun -v', +}; + +// =========================== +// 安装talkshow的程序到本地 +const talk = { + description: '设置默认的 base registry 地址 为 https://kevisual.silkyai.cn', + command: 'ev base -s https://kevisual.silkyai.cn', +}; +const talkInit = { + description: '初始化一个助手客户端,生成配置文件。', + command: 'asst init', +}; const task1 = { description: '下载前端应用 root/center 应用', command: 'ev app download -i root/center -o assistant-app/page', @@ -12,3 +49,26 @@ const task3 = { description: '安装后端应用 root/talkshow-code-center 应用', command: 'ev app download -i root/talkshow-code-center -t app -o assistant-app/apps/talkshow-code-center', }; + +// =========================== + +const runTask1 = async () => { + const tasksCommand = new TasksCommand(); + tasksCommand.addTask(init2); + const res = tasksCommand.runTask(init2.description); + console.log(res); +}; +// runTask1(); +const runTestTask = async () => { + const tasksCommand = new TasksCommand(); + const task = { + description: 'test', + command: 'npm i -g rollup --registry=https://registry.npmmirror.com', + type: 'npm-install', + }; + tasksCommand.addTask(task); + const res = tasksCommand.runTask(task.description); + console.log(res); + return res; +}; +runTestTask(); diff --git a/bin/assistant-server.js b/bin/assistant-server.js new file mode 100755 index 0000000..5668f57 --- /dev/null +++ b/bin/assistant-server.js @@ -0,0 +1,4 @@ +#!/usr/bin/env node +import { runParser } from '../dist/assistant-server.mjs'; + +runParser(process.argv); diff --git a/bin/assistant.js b/bin/assistant.js old mode 100644 new mode 100755 diff --git a/package.json b/package.json index 8dd50a9..becae0b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kevisual/envision-cli", - "version": "0.0.41", + "version": "0.0.42", "description": "envision command tools", "main": "dist/app.mjs", "type": "module", @@ -15,7 +15,9 @@ "envision": "bin/envision.js", "ev": "bin/envision.js", "assistant": "bin/assistant.js", - "asst": "bin/assistant.js" + "assistant-server": "bin/assistant-server.js", + "asst": "bin/assistant.js", + "asst-server": "bin/assistant-server.js" }, "files": [ "dist", @@ -32,6 +34,11 @@ "cli" ], "author": "abearxiong", + "dependencies": { + "pino": "^9.6.0", + "pino-pretty": "^13.0.0", + "pm2": "^6.0.5" + }, "devDependencies": { "@kevisual/load": "^0.0.6", "@kevisual/query": "0.0.17", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 14be2ab..4d5eafd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,16 @@ settings: importers: .: + dependencies: + pino: + specifier: ^9.6.0 + version: 9.6.0 + pino-pretty: + specifier: ^13.0.0 + version: 13.0.0 + pm2: + specifier: ^6.0.5 + version: 6.0.5(supports-color@10.0.0) devDependencies: '@kevisual/load': specifier: ^0.0.6 @@ -71,16 +81,19 @@ importers: assistant: dependencies: - dayjs: - specifier: ^1.11.13 - version: 1.11.13 + pm2: + specifier: ^6.0.5 + version: 6.0.5(supports-color@10.0.0) devDependencies: + '@kevisual/ai-center': + specifier: ^0.0.3 + version: 0.0.3 '@kevisual/load': specifier: ^0.0.6 version: 0.0.6 '@kevisual/local-app-manager': specifier: ^0.1.16 - version: 0.1.16(@kevisual/router@0.0.13)(@kevisual/types@0.0.1)(@kevisual/use-config@1.0.11(dotenv@16.5.0))(pm2@5.4.3(supports-color@10.0.0)) + version: 0.1.16(@kevisual/router@0.0.13)(@kevisual/types@0.0.1)(@kevisual/use-config@1.0.11(dotenv@16.5.0))(pm2@6.0.5(supports-color@10.0.0)) '@kevisual/query': specifier: 0.0.17 version: 0.0.17(@kevisual/ws@8.0.0)(encoding@0.1.13) @@ -117,6 +130,15 @@ importers: cross-env: specifier: ^7.0.3 version: 7.0.3 + dayjs: + specifier: ^1.11.13 + version: 1.11.13 + dotenv: + specifier: ^16.5.0 + version: 16.5.0 + get-port: + specifier: ^7.1.0 + version: 7.1.0 inquirer: specifier: ^12.6.0 version: 12.6.0(@types/node@22.15.2) @@ -498,6 +520,9 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@kevisual/ai-center@0.0.3': + resolution: {integrity: sha512-GYY8PyOxh8G9VYkm5rBCmOabrdIdN5b5kyx15OaX0fZEi1rG5bzDTL4BTqx5KhurG01HHbXiq32BbCv4ZaSMVA==} + '@kevisual/cache@0.0.2': resolution: {integrity: sha512-2Cl5KF2Gi27uLfhO6CdTMFnRzx9vYnqevAo7d9ab3rOaqTgF8tLeAXglXyRbaWW3WUbHU2XaOb4r98uUsqIQQw==} @@ -551,11 +576,11 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@pm2/agent@2.0.4': - resolution: {integrity: sha512-n7WYvvTJhHLS2oBb1PjOtgLpMhgImOq8sXkPBw6smeg9LJBWZjiEgPKOpR8mn9UJZsB5P3W4V/MyvNnp31LKeA==} + '@pm2/agent@2.1.1': + resolution: {integrity: sha512-0V9ckHWd/HSC8BgAbZSoq8KXUG81X97nSkAxmhKDhmF8vanyaoc1YXwc2KVkbWz82Rg4gjd2n9qiT3i7bdvGrQ==} - '@pm2/io@6.0.1': - resolution: {integrity: sha512-KiA+shC6sULQAr9mGZ1pg+6KVW9MF8NpG99x26Lf/082/Qy8qsTCtnJy+HQReW1A9Rdf0C/404cz0RZGZro+IA==} + '@pm2/io@6.1.0': + resolution: {integrity: sha512-IxHuYURa3+FQ6BKePlgChZkqABUKFYH6Bwbw7V/pWU1pP6iR1sCI26l7P9ThUEB385ruZn/tZS3CXDUF5IA1NQ==} engines: {node: '>=6.0'} '@pm2/js-api@0.8.0': @@ -1210,9 +1235,6 @@ packages: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} - eventemitter2@0.4.14: - resolution: {integrity: sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==} - eventemitter2@5.0.1: resolution: {integrity: sha512-5EM1GHXycJBS6mauYAbVKT1cVs7POKWb2NXD4Vyt8dDqeZa7LaDK1/sjtL+Zb0lzTpSNil4596Dyu97hz37QLg==} @@ -1316,6 +1338,10 @@ packages: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} + get-port@7.1.0: + resolution: {integrity: sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==} + engines: {node: '>=16'} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -1490,10 +1516,6 @@ packages: jws@3.2.2: resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} - lazy@1.0.11: - resolution: {integrity: sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA==} - engines: {node: '>=0.2.0'} - lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -1661,10 +1683,6 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - nssocket@0.6.0: - resolution: {integrity: sha512-a9GSOIql5IqgWJR3F/JXG4KpJTA3Z53Cj0MeMvGpglytB1nxE4PdFNC0jINe27CS7cGivoynwc054EzCcT3M3w==} - engines: {node: '>= 0.10.x'} - object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -1780,9 +1798,9 @@ packages: pm2-sysmonit@1.2.8: resolution: {integrity: sha512-ACOhlONEXdCTVwKieBIQLSi2tQZ8eKinhcr9JpZSUAL8Qy0ajIgRtsLxG/lwPOW3JEKqPyw/UaHmTWhUzpP4kA==} - pm2@5.4.3: - resolution: {integrity: sha512-4/I1htIHzZk1Y67UgOCo4F1cJtas1kSds31N8zN0PybO230id1nigyjGuGFzUnGmUFPmrJ0On22fO1ChFlp7VQ==} - engines: {node: '>=12.0.0'} + pm2@6.0.5: + resolution: {integrity: sha512-+O43WPaEiwYbm6/XSpAOO1Rtya/Uof0n7x8hJZGfwIuepesNTIVArpZh4KqFfze0cvvqZMr0maTW3ifhvmyeMQ==} + engines: {node: '>=16.0.0'} hasBin: true postcss-load-config@6.0.1: @@ -1813,8 +1831,8 @@ packages: promptly@2.2.0: resolution: {integrity: sha512-aC9j+BZsRSSzEsXBNBwDnAxujdx19HycZoKgRgzWnS8eOHg1asuf9heuLprfbe739zY3IdUQx+Egv6Jn135WHA==} - proxy-agent@6.3.1: - resolution: {integrity: sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==} + proxy-agent@6.4.0: + resolution: {integrity: sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==} engines: {node: '>= 14'} proxy-from-env@1.1.0: @@ -2578,6 +2596,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@kevisual/ai-center@0.0.3': {} + '@kevisual/cache@0.0.2(rollup@4.40.0)(tslib@2.8.1)(typescript@5.8.2)': dependencies: '@rollup/plugin-commonjs': 28.0.3(rollup@4.40.0) @@ -2594,12 +2614,12 @@ snapshots: dependencies: eventemitter3: 5.0.1 - '@kevisual/local-app-manager@0.1.16(@kevisual/router@0.0.13)(@kevisual/types@0.0.1)(@kevisual/use-config@1.0.11(dotenv@16.5.0))(pm2@5.4.3(supports-color@10.0.0))': + '@kevisual/local-app-manager@0.1.16(@kevisual/router@0.0.13)(@kevisual/types@0.0.1)(@kevisual/use-config@1.0.11(dotenv@16.5.0))(pm2@6.0.5(supports-color@10.0.0))': dependencies: '@kevisual/router': 0.0.13 '@kevisual/types': 0.0.1 '@kevisual/use-config': 1.0.11(dotenv@16.5.0) - pm2: 5.4.3(supports-color@10.0.0) + pm2: 6.0.5(supports-color@10.0.0) '@kevisual/query-login@0.0.5(@kevisual/query@0.0.17(@kevisual/ws@8.0.0)(encoding@0.1.13))(rollup@4.40.0)(typescript@5.8.2)': dependencies: @@ -2666,7 +2686,7 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@pm2/agent@2.0.4(supports-color@10.0.0)': + '@pm2/agent@2.1.1(supports-color@10.0.0)': dependencies: async: 3.2.6 chalk: 3.0.0 @@ -2675,10 +2695,9 @@ snapshots: eventemitter2: 5.0.1 fast-json-patch: 3.1.1 fclone: 1.0.11 - nssocket: 0.6.0 pm2-axon: 4.0.1(supports-color@10.0.0) pm2-axon-rpc: 0.7.1(supports-color@10.0.0) - proxy-agent: 6.3.1(supports-color@10.0.0) + proxy-agent: 6.4.0(supports-color@10.0.0) semver: 7.5.4 ws: 7.5.10 transitivePeerDependencies: @@ -2686,7 +2705,7 @@ snapshots: - supports-color - utf-8-validate - '@pm2/io@6.0.1(supports-color@10.0.0)': + '@pm2/io@6.1.0(supports-color@10.0.0)': dependencies: async: 2.6.4 debug: 4.3.7(supports-color@10.0.0) @@ -3241,8 +3260,6 @@ snapshots: event-target-shim@5.0.1: {} - eventemitter2@0.4.14: {} - eventemitter2@5.0.1: {} eventemitter2@6.4.9: {} @@ -3340,6 +3357,8 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 + get-port@7.1.0: {} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -3537,8 +3556,6 @@ snapshots: jwa: 1.4.1 safe-buffer: 5.2.1 - lazy@1.0.11: {} - lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} @@ -3660,11 +3677,6 @@ snapshots: normalize-path@3.0.0: {} - nssocket@0.6.0: - dependencies: - eventemitter2: 0.4.14 - lazy: 1.0.11 - object-assign@4.1.1: {} on-exit-leak-free@2.1.2: {} @@ -3828,10 +3840,10 @@ snapshots: - supports-color optional: true - pm2@5.4.3(supports-color@10.0.0): + pm2@6.0.5(supports-color@10.0.0): dependencies: - '@pm2/agent': 2.0.4(supports-color@10.0.0) - '@pm2/io': 6.0.1(supports-color@10.0.0) + '@pm2/agent': 2.1.1(supports-color@10.0.0) + '@pm2/io': 6.1.0(supports-color@10.0.0) '@pm2/js-api': 0.8.0(supports-color@10.0.0) '@pm2/pm2-version-check': 1.0.4(supports-color@10.0.0) async: 3.2.6 @@ -3885,7 +3897,7 @@ snapshots: dependencies: read: 1.0.7 - proxy-agent@6.3.1(supports-color@10.0.0): + proxy-agent@6.4.0(supports-color@10.0.0): dependencies: agent-base: 7.1.3 debug: 4.4.0(supports-color@10.0.0)