"feat: 增加助手应用配置管理功能与服务器守护进程支持"

This commit is contained in:
2025-04-27 00:35:44 +08:00
parent bcc12209e0
commit f2abfbf17c
27 changed files with 658 additions and 102 deletions

9
assistant/task-command/.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
node_modules
.DS_Store
dist
pack-dist
.env*
!.env*example

View File

@@ -0,0 +1,4 @@
//npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN}
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
ignore-workspace-root-check=true

67
assistant/task-command/mod.d.ts vendored Normal file
View File

@@ -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<string, TaskCommand>;
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 };

View File

@@ -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<string, TaskCommand> = 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(),
};
}
}
}

View File

@@ -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 <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
"license": "MIT",
"packageManager": "pnpm@10.7.0",
"type": "module",
"exports": {
".": "./mod.ts",
"./mod.ts": "./mod.ts"
}
}

View File

@@ -0,0 +1,3 @@
# task-command
command line task runner