feat: 助手配置与服务命令扩展及依赖更新

This commit is contained in:
熊潇 2025-04-27 03:26:50 +08:00
parent f2abfbf17c
commit 75d181ef43
25 changed files with 296 additions and 64 deletions

2
assistant/.npmrc Normal file
View File

@ -0,0 +1,2 @@
//npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN}
//registry.npmjs.org/:_authToken=${NPM_TOKEN}

View File

@ -35,6 +35,9 @@ await Bun.build({
naming: {
entry: 'assistant-server.mjs',
},
define: {
ENVISION_VERSION: JSON.stringify(pkg.version),
},
external: ['pm2'],
env: 'ENVISION_*',
});

View File

@ -33,6 +33,8 @@
"@kevisual/query": "0.0.17",
"@kevisual/query-login": "0.0.5",
"@kevisual/router": "^0.0.13",
"@kevisual/task-command": "^0.0.2",
"@kevisual/types": "^0.0.7",
"@kevisual/use-config": "^1.0.11",
"@types/bun": "^1.2.10",
"@types/lodash-es": "^4.17.12",
@ -42,6 +44,7 @@
"chalk": "^5.4.1",
"commander": "^13.1.0",
"cross-env": "^7.0.3",
"dayjs": "^1.11.13",
"dotenv": "^16.5.0",
"get-port": "^7.1.0",
"inquirer": "^12.6.0",
@ -52,7 +55,6 @@
"send": "^1.2.0",
"supports-color": "^10.0.0",
"ws": "npm:@kevisual/ws",
"dayjs": "^1.11.13",
"zustand": "^5.0.3"
},
"engines": {
@ -63,10 +65,5 @@
},
"dependencies": {
"pm2": "^6.0.5"
},
"overrides": {
"ws": "npm:@kevisual/ws",
"@kevisual/query": "0.0.17",
"@kevisual/router": "0.0.13"
}
}

View File

@ -1,7 +1,13 @@
import { App } from '@kevisual/router';
import { HttpsPem } from '@/module/assistant/https/sign.ts';
import { assistantConfig } from '@/config.ts';
export { assistantConfig };
// import { AssistantConfig } from '@/module/assistant/index.ts';
import { AssistantInit } from '@/services/init/index.ts';
export const configDir = AssistantInit.detectConfigDir();
export const assistantConfig = new AssistantInit({
path: configDir,
init: true,
});
const httpsPem = new HttpsPem(assistantConfig);
export const app = new App({
serverOptions: {

View File

@ -0,0 +1,31 @@
import { program, Command } from '@/program.ts';
import { spawnSync } from 'node:child_process';
const command = new Command('server')
.description('启动服务')
.option('-d, --daemon', '是否以守护进程方式运行')
.option('-n, --name <name>', '服务名称')
.option('-p, --port <port>', '服务端口')
.option('-s, --start', '是否启动服务')
.action((options) => {
const { port } = options;
const shellCommands = [];
if (options.daemon) {
shellCommands.push('-d');
}
if (options.name) {
shellCommands.push(`-n ${options.name}`);
}
if (options.start) {
shellCommands.push('-s');
}
if (port) {
shellCommands.push(`-p ${port}`);
}
console.log(`Assistant server shell command: asst-server ${shellCommands.join(' ')}`);
const child = spawnSync('asst-server', shellCommands, {
stdio: 'inherit',
shell: true,
});
});
program.addCommand(command);

View File

@ -1,6 +1,9 @@
import { program, Command } from '@/program.ts';
import { AssistantInit } from '@/services/init/index.ts';
import path from 'node:path';
import fs from 'node:fs';
import inquirer from 'inquirer';
import chalk from 'chalk';
type InitCommandOptions = {
path?: string;
@ -24,3 +27,39 @@ const Init = new Command('init')
});
program.addCommand(Init);
const removeCommand = new Command('remove')
.description('删除助手配置文件') // TODO
.option('-p --path <path>', '助手路径,默认为执行命令的目录,如果助手路径不存在则创建。')
.action((opts) => {
if (opts.path && !opts.path.startsWith('/')) {
opts.path = path.join(process.cwd(), opts.path);
} else if (opts.path) {
opts.path = path.resolve(opts.path);
}
const configDir = AssistantInit.detectConfigDir(opts.path);
const assistantDir = path.join(configDir, 'assistant-app');
if (fs.existsSync(assistantDir)) {
inquirer
.prompt([
{
type: 'confirm',
name: 'confirm',
message: `确定要删除助手配置文件吗?\n助手配置文件路径${assistantDir}`,
default: false,
},
])
.then((answers) => {
if (answers.confirm) {
fs.rmSync(assistantDir, { recursive: true, force: true });
console.log(chalk.green('助手配置文件已删除'));
} else {
console.log(chalk.blue('助手配置文件未删除'));
}
});
} else {
console.log(chalk.blue('助手配置文件不存在'));
}
});
program.addCommand(removeCommand);

View File

@ -3,5 +3,5 @@ import { AssistantConfig } from '@/module/assistant/index.ts';
export const configDir = AssistantConfig.detectConfigDir();
export const assistantConfig = new AssistantConfig({
configDir,
init: true,
init: false,
});

View File

@ -1,6 +1,7 @@
import { program, runProgram } from '@/program.ts';
import './command/config-manager/index.ts';
import './command/app-manager/index.ts';
import './command/asst-server/index.ts';
/**
*

View File

@ -20,7 +20,7 @@ export const initConfig = (configRootPath: string) => {
const pageConfigPath = path.join(configDir, 'assistant-page-config.json');
const pageDir = createDir(path.join(configDir, 'page'));
const appsDir = createDir(path.join(configDir, 'apps'));
const appsConfigPath = path.join(appsDir, 'assistant-apps-config.json');
const appsConfigPath = path.join(configDir, 'assistant-apps-config.json');
const appPidPath = path.join(configDir, 'assistant-app.pid');
const envConfigPath = path.join(configDir, '.env');
return {
@ -82,17 +82,34 @@ type AssistantConfigOptions = {
};
export class AssistantConfig {
config: AssistantConfigData;
configPath: ReturnInitConfigType;
#configPath: ReturnInitConfigType;
configDir: string;
isMountedConfig?: boolean;
constructor(opts?: AssistantConfigOptions) {
this.configDir = opts?.configDir || configDir;
if (opts?.init) {
this.init();
}
}
set configPath(configPath: ReturnInitConfigType) {
this.#configPath = configPath;
}
get configPath() {
if (!this.#configPath) {
initConfig(this.configDir);
}
return this.#configPath;
}
init() {
this.configPath = initConfig(this.configDir);
this.isMountedConfig = true;
}
checkMounted() {
if (!this.isMountedConfig) {
this.init();
}
}
getConfigPath() {}
getConfig() {
try {
if (!checkFileExists(this.configPath.configPath)) {

View File

@ -6,7 +6,8 @@ export class AssistantApp extends Manager {
config: AssistantConfig;
constructor(config: AssistantConfig) {
const appsPath = config.configPath?.appsDir || path.join(process.cwd(), 'apps');
config.checkMounted();
const appsPath = config?.configPath?.appsDir || path.join(process.cwd(), 'apps');
const appsConfigPath = config.configPath?.appsConfigPath;
const configFimename = path.basename(appsConfigPath || '');
super({

View File

@ -8,7 +8,7 @@ try {
if (ENVISION_VERSION) version = ENVISION_VERSION;
} catch (e) {}
// @ts-ignore
program.name('app').description('A CLI tool with envison').version(version);
program.name('asst').description('A CLI tool with envison').version(version, '-v, --version', 'output the current version');
const ls = new Command('ls').description('List files in the current directory').action(() => {
console.log('List files');

View File

@ -0,0 +1,27 @@
import { app, assistantConfig } from '@/app.ts';
// import { getCacheAssistantConfig, setConfig } from '@/modules/config/index.ts';
// import { reload } from '@/modules/parent-msg.ts';
app
.route({
path: 'config',
description: '获取配置',
})
.define(async (ctx) => {
ctx.body = assistantConfig.getCacheAssistantConfig();
})
.addTo(app);
app
.route({
path: 'config',
key: 'set',
description: '设置配置',
})
.define(async (ctx) => {
const { data } = ctx.query;
// reload();
ctx.body = assistantConfig.setConfig(data);
})
.addTo(app);

View File

@ -0,0 +1,2 @@
import './config/index.ts'
import './shop-install/index.ts'

View File

@ -0,0 +1,61 @@
import { app } from '@/app.ts';
// import { getInstallList, installApp, uninstallApp } from '@/modules/install.ts';
const getInstallList = async () => {
return [];
};
const installApp = async (pkg: string) => {
return {
code: 200,
message: 'success',
data: {
pkg,
},
};
};
const uninstallApp = async (pkg: string) => {
return {
code: 200,
message: 'success',
};
};
app
.route({
path: 'shop',
key: 'list-installed',
})
.define(async (ctx) => {
// https://localhost:51015/client/router?path=shop&key=list-installed
const list = await getInstallList();
ctx.body = list;
})
.addTo(app);
app
.route({
path: 'shop',
key: 'install',
})
.define(async (ctx) => {
// https://localhost:51015/client/router?path=shop&key=install
const { pkg } = ctx.query.data;
const res = await installApp(pkg);
if (res.code !== 200) {
ctx.throw(res.code, res.message);
}
ctx.body = res;
})
.addTo(app);
app
.route({
path: 'shop',
key: 'uninstall',
})
.define(async (ctx) => {
// https://localhost:51015/client/router?path=shop&key=uninstall
const { pkg } = ctx.query.data;
const res = await uninstallApp(pkg);
ctx.body = res;
})
.addTo(app);

View File

@ -1,5 +1,7 @@
import { app } from './app.ts';
import { proxyRoute, proxyWs } from './services/proxy/proxy-page-index.ts';
import './routes/index.ts';
import getPort, { portNumbers } from 'get-port';
import { program } from 'commander';
import { spawnSync } from 'child_process';

View File

@ -0,0 +1 @@
// app downlaod

View File

@ -2,6 +2,7 @@ import fs from 'node:fs';
import path from 'node:path';
import { checkFileExists, AssistantConfig } from '@/module/assistant/index.ts';
import { chalk } from '@/module/chalk.ts';
import { HttpsPem } from '@/module/assistant/https/sign.ts';
export type AssistantInitOptions = {
path?: string;
init?: boolean;
@ -15,8 +16,11 @@ export class AssistantInit extends AssistantConfig {
const configDir = opts?.path || process.cwd();
super({
configDir,
init: opts?.init ?? false,
init: false,
});
if (opts?.init) {
this.init();
}
}
async init() {
@ -24,38 +28,51 @@ export class AssistantInit extends AssistantConfig {
if (!this.checkConfigPath()) {
console.log(chalk.blue('助手路径不存在,正在创建...'));
super.init();
this.createAssistantConfig();
} else {
super.init();
console.log(chalk.yellow('助手路径已存在'));
return;
}
this.createAssistantConfig();
this.createEnvConfig();
this.createOtherConfig();
}
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');
if (!checkFileExists(pemDir)) {
new HttpsPem(this);
console.log(chalk.green('助手证书目录创建成功'));
}
}
createAssistantConfig() {
const assistantPath = this.configPath?.configPath;
// 创建助手配置文件 assistant-config.json
if (!checkFileExists(assistantPath, true)) {
this.setConfig({
description: '助手配置文件',
home: '/root/center',
proxy: [],
apiProxyList: [],
});
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('助手环境配置.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创建成功'));
}
}
}

View File

@ -7,3 +7,5 @@ pack-dist
.env*
!.env*example
mod.mjs

View File

@ -0,0 +1,28 @@
// @ts-check
// https://bun.sh/docs/bundler
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: [w('./mod.ts')],
outdir: w('.'),
naming: {
entry: 'mod.mjs',
},
external: ['pm2'],
define: {
ENVISION_VERSION: JSON.stringify(pkg.version),
},
env: 'ENVISION_*',
});

View File

@ -1,10 +1,11 @@
{
"name": "@kevisual/task-command",
"version": "0.0.1",
"version": "0.0.2",
"description": "",
"types": "mod.d.ts",
"scripts": {
"dts": "dts -i mod.ts -o mod.d.ts -d ."
"dts": "dts -i mod.ts -o mod.d.ts -d .",
"build": "bun run bun.config.mjs"
},
"keywords": [],
"publishConfig": {
@ -13,14 +14,15 @@
},
"files": [
"mod.ts",
"mod.d.ts"
"mod.d.ts",
"mod.mjs"
],
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
"license": "MIT",
"packageManager": "pnpm@10.7.0",
"type": "module",
"exports": {
".": "./mod.ts",
".": "./mod.mjs",
"./mod.ts": "./mod.ts"
}
}

View File

@ -1,32 +1,14 @@
{
"extends": "@kevisual/types/json/backend.json",
"compilerOptions": {
"module": "nodenext",
"target": "esnext",
"noImplicitAny": false,
"outDir": "./dist",
"sourceMap": false,
"newLine": "LF",
"baseUrl": "./",
"typeRoots": [
"node_modules/@types",
],
"declaration": true,
"noEmit": false,
"allowImportingTsExtensions": true,
"emitDeclarationOnly": true,
"moduleResolution": "NodeNext",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"baseUrl": ".",
"paths": {
"@/*": [
"src/*"
],
}
]
},
},
"include": [
"src/**/*.ts",
"src/**/*",
],
"exclude": [],
}

0
bin/assistant-server.js Executable file → Normal file
View File

0
bin/assistant.js Executable file → Normal file
View File

23
pnpm-lock.yaml generated
View File

@ -93,7 +93,7 @@ importers:
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@6.0.5(supports-color@10.0.0))
version: 0.1.16(@kevisual/router@0.0.13)(@kevisual/types@0.0.7)(@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)
@ -103,6 +103,12 @@ importers:
'@kevisual/router':
specifier: ^0.0.13
version: 0.0.13
'@kevisual/task-command':
specifier: ^0.0.2
version: 0.0.2
'@kevisual/types':
specifier: ^0.0.7
version: 0.0.7
'@kevisual/use-config':
specifier: ^1.0.11
version: 1.0.11(dotenv@16.5.0)
@ -548,8 +554,11 @@ packages:
'@kevisual/router@0.0.13':
resolution: {integrity: sha512-raji8aKXr0jigmJVOKBXb5gpstiAuyoIDy9m6SyPf4lRjCU3pspVI1bpscOUCBlaPICo6TLzPQxXhyTvvvtdWw==}
'@kevisual/types@0.0.1':
resolution: {integrity: sha512-3Wn6WjpfbOGTqIVS7YQ/0CIQEEbZEp+uCTbIWqTZyuytiA/Xoglr5kG3AbTuLFQ81AvfxjEjp5dAnFub+2IhhQ==}
'@kevisual/task-command@0.0.2':
resolution: {integrity: sha512-GVGcm2edTdIkiRaO8PoR8MhkHEyqq2xG3knMI6Ba+0YknzRECAzR0tgkHLGRPyIClG0J6gDzo2qaglf2s3ci5w==}
'@kevisual/types@0.0.7':
resolution: {integrity: sha512-qU/vg7WilTmxbWQZ4PbYNaTDQO83KaCqoT10FbGg8FCwGG2luuEKTvCYcXfvpl7qA+AHGKcSm0JJc61s4oLCww==}
'@kevisual/use-config@1.0.11':
resolution: {integrity: sha512-ccilQTRZTpO075L67ZBXhr8Lp3i73/W5cCMT5enMjVrnJT5K0i5JH5IbzBhF6WY5Rj8dmVsAyyjJe24ClyM7Eg==}
@ -2614,10 +2623,10 @@ 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@6.0.5(supports-color@10.0.0))':
'@kevisual/local-app-manager@0.1.16(@kevisual/router@0.0.13)(@kevisual/types@0.0.7)(@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/types': 0.0.7
'@kevisual/use-config': 1.0.11(dotenv@16.5.0)
pm2: 6.0.5(supports-color@10.0.0)
@ -2662,7 +2671,9 @@ snapshots:
path-to-regexp: 8.2.0
selfsigned: 2.4.1
'@kevisual/types@0.0.1': {}
'@kevisual/task-command@0.0.2': {}
'@kevisual/types@0.0.7': {}
'@kevisual/use-config@1.0.11(dotenv@16.5.0)':
dependencies:

View File

@ -7,7 +7,7 @@ try {
if (ENVISION_VERSION) version = ENVISION_VERSION;
} catch (e) {}
// @ts-ignore
program.name('app').description('A CLI tool with envison').version(version);
program.name('app').description('A CLI tool with envison').version(version, '-v, --version');
const ls = new Command('ls').description('List files in the current directory').action(() => {
console.log('List files');