remove task

This commit is contained in:
2025-10-28 15:09:45 +08:00
parent 4dbee366c5
commit 6eb6b7ec79
30 changed files with 14 additions and 790 deletions

View File

@@ -20,7 +20,7 @@
],
"scripts": {
"dev": "bun run src/run.ts ",
"dev:server": "cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 bun --watch src/run-server.ts ",
"dev:server": "cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 bun --watch src/run-server.ts --home ",
"dev:share": "cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 bun --watch src/test/remote-app.ts ",
"build:lib": "bun run bun-lib.config.mjs",
"postbuild:lib": "dts -i src/lib.ts -o assistant-lib.d.ts -d libs -t",

View File

@@ -26,11 +26,16 @@ export const app = useContextKey('app', () => {
const init = isInit;
if (init) {
const config = assistantConfig.getConfig();
if (config?.https?.type !== 'https') {
console.log('http模式', 'http');
return new App({
serverOptions: {
path: '/client/router',
httpType: 'http',
cors: {
origin: '*',
}
},
});
}
@@ -41,6 +46,9 @@ export const app = useContextKey('app', () => {
httpType: 'https',
httpsCert: httpsPem.cert,
httpsKey: httpsPem.key,
cors: {
origin: '*',
}
},
});
});

View File

@@ -7,7 +7,7 @@ import dotenv from 'dotenv';
/**
* 助手配置文件路径, 全局配置文件目录
*/
export const configDir = createDir(path.join(homedir(), '.config/envision/assistant-app'));
export const configDir = createDir(path.join(homedir(), 'kevisual/assistant-app'));
/**
* 助手配置文件初始化

View File

@@ -84,6 +84,8 @@ program
const listenPort = options.port || config?.server?.port;
const listenPath = config?.server?.path || '127.0.0.1';
const server = await runServer(listenPort, listenPath);
} else {
console.log('请使用 -s 参数启动服务');
}
});

View File

@@ -144,7 +144,7 @@ export class AssistantInit extends AssistantConfig {
const https = this.getConfig()?.https || {};
return {
https,
protocol: https?.type === 'http' ? 'http' : 'https',
protocol: https?.type === 'https' ? 'https' : 'http',
};
}
}

View File

@@ -1,11 +0,0 @@
node_modules
.DS_Store
dist
pack-dist
.env*
!.env*example
mod.mjs

View File

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

View File

@@ -1,28 +0,0 @@
// @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,67 +0,0 @@
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

@@ -1,192 +0,0 @@
import { execSync } from 'node:child_process';
export const TaskCommandType = ['npm-install'] as const;
export type TaskCommand = {
key?: any;
/**
* 任务描述
*/
description?: string;
/**
* 命令, 执行的任务
*/
command: string;
type?: (typeof TaskCommandType)[number] | string;
/**
* 任务执行完成后,执行判断的命令
*/
after?: string;
/**
* 任务执行前,执行判断的命令
*/
before?: string;
/**
* 任务执行完成后, 检测输出的文本内容,如果有这个文本,表示任务执行成功
* 如果没有这个文本,表示任务执行失败
*/
afterCheck?: string;
/**
* 任务执行前, 检测输出的文本内容,如果有这个文本,表示任务已经安装
* 如果没有这个文本,表示任务没有安装
*/
beforeCheck?: string;
tags?: string[];
meta?: any;
};
type RunTaskResult = {
code?: number;
message?: string;
data?: any;
output?: string;
task?: TaskCommand;
};
type TaskCommandOptions = {
isDebug?: boolean;
isLog?: boolean;
};
export class TasksCommand {
tasks: Map<string | number, TaskCommand> = new Map();
isDebug: boolean = false;
isLog: boolean = false;
constructor(opts?: TaskCommandOptions) {
this.isDebug = opts?.isDebug ?? false;
this.isLog = opts?.isLog ?? false;
}
log(...args: any[]) {
if (this.isLog) {
console.log(...args);
}
}
debug(...args: any[]) {
if (this.isDebug) {
console.log(...args);
}
}
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 | number) {
return this.tasks.get(name);
}
runTask(taskName: string | number | TaskCommand): RunTaskResult {
let task: TaskCommand | undefined;
if (typeof taskName === 'string' || typeof taskName === 'number') {
task = this.getTask(taskName);
} else if (typeof taskName === 'object') {
task = taskName;
}
const end = (data?: RunTaskResult) => {
return {
...data,
task,
};
};
if (!task) {
return {
code: 500,
message: `没有找到这个任务`,
task: task,
};
}
let { command, before, after, afterCheck, beforeCheck, type } = task;
if (type === 'npm-install' && !afterCheck) {
afterCheck = 'added';
}
if (before) {
const res = this.runCommand(before);
const checkForContainue = this.checkForContainue(res, beforeCheck);
this.debug('运行前检测', { runCommandResult: res, beforeCheck, checkForContainue });
if (!checkForContainue) {
return end({
code: 200,
message: `当前任务不需要执行, ${command}`,
});
}
}
const res = this.runCommand(command);
this.debug(`执行任务:${command}`, { runCommandResult: res });
if (res.code !== 200) {
this.debug('当前任务执行失败:', { runCommandResult: res });
return end(res);
}
let checkText = res.data || '';
if (after) {
this.debug('执行后检测是否成功:', { after });
const res = this.runCommand(after);
if (res.code !== 200) {
return end(res);
}
checkText = res.data || '';
}
if (afterCheck) {
const isSuccess = checkText?.includes?.(afterCheck);
this.debug('执行后检测是否成功:', { afterCheck, checkText, isSuccess });
return end({
code: isSuccess ? 200 : 500,
output: res.data,
data: 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(),
};
}
}
getTasksArray() {
const tasks = Array.from(this.tasks.values());
return tasks;
}
/**
* 根据标签获取任务
* @param tag
*/
getTasksArrayByTag(tag?: string) {
const tasks = Array.from(this.tasks.values());
return tasks.filter((task) => !tag || task.tags?.includes(tag) || task.meta?.tags?.includes(tag) || task.key === tag);
}
}

View File

@@ -1,29 +0,0 @@
{
"name": "@kevisual/task-command",
"version": "0.0.7",
"description": "",
"types": "mod.d.ts",
"scripts": {
"dts": "dts -i mod.ts -o mod.d.ts -d .",
"build": "bun run bun.config.mjs",
"postbuild": "dts -i mod.ts -o mod.d.ts -d ."
},
"keywords": [],
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"files": [
"mod.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.mjs",
"./mod.ts": "./mod.ts"
}
}

View File

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

View File

@@ -1,34 +0,0 @@
{
"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"
}
}

View File

@@ -1,17 +0,0 @@
{
"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=="
}
}
}

View File

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

View File

@@ -1,4 +0,0 @@
#!/usr/bin/env node
import { runParser } from '../dist/silky.mjs';
runParser(process.argv);

View File

@@ -1,26 +0,0 @@
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('./src/index.ts')],
outdir: w('./dist'),
naming: {
entry: 'silky.mjs',
},
external: ['pm2'],
define: {
ENVISION_VERSION: JSON.stringify(pkg.version),
},
env: 'ENVISION_*',
});

View File

@@ -1,40 +0,0 @@
{
"name": "@kevisual/silky-cli",
"version": "0.0.11",
"description": "",
"main": "index.js",
"scripts": {
"dev": "bun run src/run.ts ",
"build": "bun run bun.config.mjs"
},
"bin": {
"silky": "./bin/silky.js"
},
"keywords": [],
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
"license": "MIT",
"packageManager": "pnpm@10.9.0",
"type": "module",
"publishConfig": {
"access": "public"
},
"files": [
"bin",
"dist"
],
"devDependencies": {
"@kevisual/assistant-cli": "workspace:*",
"@kevisual/task-command": "^0.0.7",
"chalk": "^5.4.1",
"commander": "^13.1.0",
"cross-env": "^7.0.3",
"dayjs": "^1.11.13",
"dotenv": "^16.5.0",
"inquirer": "^12.6.0",
"lodash-es": "^4.17.21",
"nanoid": "^5.1.5"
},
"dependencies": {
"pm2": "^6.0.5"
}
}

View File

@@ -1,46 +0,0 @@
# 初始化搭建模块
base node env node v22.14
## 初始化环境
### 方法1 安装 node 的 @kevisual/silky-cli
```bash
npm i -g @kevisual/silky-cli
# 初始化环境
## 安装pm2和@kevisual/kevisual-cli
silky init-env
## 创建基本文件
silky init
```
### 方法2 使用docker
```bash
docker run -itd --rm -p 51015:51015 --name node_container docker.cnb.cool/kevisual/node22:latest
docker exec -it node_container bash
```
## 项目初始化
```bash
## 安装 应用 root/talkshow-admin 和应用 root/talkshow-code-center
silky init-talkshow
```
## 项目启动
```bash
asst am detect # 检测后端应用 root/talkshow-code-center
asst am start talkshow-code-center
asst server -s # 启动服务
```
## 访问
https://localhost:51015/root/talkshow-admin

View File

@@ -1,2 +0,0 @@
import './init.ts'
import './init-env.ts'

View File

@@ -1,68 +0,0 @@
import { program, Command } from '@/program.ts';
import { TaskKey, silkyCommand } from '@/mdoules/talkshow.ts';
const description = `初始化运行环境,安装
1. @kevisual/cli
2. pm2
可选安装:
deno
bun
`;
const isDev = process.env.NODE_ENV === 'development';
const testEnv = new Command('init-env')
.description(description)
.option('-a --all')
.action((options) => {
let tag = options.all ? 'env' : 'must-env';
silkyCommand.isDebug = isDev ?? false;
const envTask = silkyCommand.getTasksArrayByTag(tag);
for (const value of envTask) {
try {
const res = silkyCommand.runTask(value);
if (res.code === 200) {
console.log('执行结果:', res.code, res.message);
} else {
console.log('执行结果错误:', res.task?.description, res.message);
}
} catch (error) {
console.log('error', error);
continue;
}
}
});
program.addCommand(testEnv);
const appDownloadDesc = `下载安装talkshow的应用模块
1. root/talkshow-admin
2. root/talkshow-code-center
3. root/center
`;
const appDownloadTask = new Command('init-talkshow')
.description(appDownloadDesc)
.option('-a --all', '下载所有应用模块或者只下载talkshow相关的')
.action((options) => {
//
let tag = options.all ? 'app' : 'talkshow';
const appTask = silkyCommand.getTasksArrayByTag(tag);
silkyCommand.isDebug = true;
for (const value of appTask) {
try {
const res = silkyCommand.runTask(value);
if (res.code === 200) {
console.log('执行结果:', res.task?.description, res.code);
} else {
console.log('执行结果错误:', res.task?.description, res.message);
}
} catch (error) {
console.log('error', error);
continue;
}
}
});
program.addCommand(appDownloadTask);

View File

@@ -1,25 +0,0 @@
import { program, Command } from '@/program.ts';
import path from 'node:path';
import { AssistantInit } from '@/services/init/index.ts';
type InitCommandOptions = {
path?: string;
};
const Init = new Command('init')
.description('初始化一个助手客户端,生成配置文件。')
.option('-p --path <path>', '助手路径,默认为执行命令的目录,如果助手路径不存在则创建。')
.action((opts: InitCommandOptions) => {
// 如果path参数存在检测path是否是相对路径如果是相对路径则转换为绝对路径
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 assistantInit = new AssistantInit({
path: configDir,
});
assistantInit.init();
});
program.addCommand(Init);

View File

@@ -1,7 +0,0 @@
import { AssistantConfig } from '@kevisual/assistant-cli/lib';
export const configDir = AssistantConfig.detectConfigDir(null, 1);
export const assistantConfig = new AssistantConfig({
configDir,
init: false,
});

View File

@@ -1,19 +0,0 @@
import { program, runProgram } from '@/program.ts';
/**
* 通过命令行解析器解析参数
* args[0] 是执行的命令, example: node
* args[1] 是执行的脚本, example: index.ts
* @param argv
*/
export const runParser = async (argv: string[]) => {
// program.parse(process.argv);
// console.log('argv', argv);
try {
program.parse(argv);
} catch (error) {
console.error('执行错误:', error.message);
}
};
export { runProgram };

View File

@@ -1,90 +0,0 @@
import { TasksCommand } from '@kevisual/task-command/mod.ts';
export const silkyCommand = new TasksCommand();
export const enum TaskKey {
ev = 1,
pm2,
deno,
bun,
silkyInit,
appCenter,
appTalkshowAdmin,
appTalkshow,
}
export const init = {
description: '安装依赖',
key: TaskKey.ev,
command: 'npm install -g @kevisual/cli --registry=https://registry.npmmirror.com',
type: 'npm-install',
before: 'ev --version',
beforeCheck: '.',
tags: ['env', 'must-env'],
};
silkyCommand.addTask(init);
const init1 = {
description: '安装 pm2',
type: 'npm-install',
key: TaskKey.pm2,
command: 'npm install -g pm2 --registry=https://registry.npmmirror.com',
before: 'pm2 -v',
beforeCheck: '.',
tags: ['env', 'must-env'],
};
silkyCommand.addTask(init1);
const init2 = {
description: '安装 deno',
command: 'npm install -g deno --registry=https://registry.npmmirror.com',
key: TaskKey.deno,
type: 'npm-install',
before: 'deno -v',
beforeCheck: 'deno',
tags: ['env'],
};
silkyCommand.addTask(init2);
const init3 = {
description: '安装 bun',
type: 'npm-install',
key: TaskKey.bun,
command: 'npm install -g bun --registry=https://registry.npmmirror.com',
before: 'bun -v',
beforeCheck: '.',
tags: ['env'],
};
silkyCommand.addTask(init3);
// ===========================
// 安装talkshow的程序到本地
const talkInit = {
description: '初始化一个助手客户端,生成配置文件。',
key: TaskKey.silkyInit,
command: 'silky init',
};
silkyCommand.addTask(talkInit);
const task1 = {
description: '下载前端应用 root/center 应用',
key: TaskKey.appCenter,
command: 'asst app download -i root/center',
tags: ['app', 'root'],
};
silkyCommand.addTask(task1);
const task2 = {
description: '下载前端应用 root/talkshow-admin 应用',
key: TaskKey.appTalkshowAdmin,
command: 'asst app download -i root/talkshow-admin',
tags: ['app', 'talkshow'],
};
silkyCommand.addTask(task2);
const task3 = {
description: '安装后端应用 root/talkshow-code-center 应用',
key: TaskKey.appTalkshow,
command: 'asst app download -i root/talkshow-code-center -t app',
tags: ['app', 'talkshow'],
};
silkyCommand.addTask(task3);

View File

@@ -1,24 +0,0 @@
import { program, Command } from 'commander';
import fs from 'fs';
import './command/check/index.ts';
// 将多个子命令加入主程序中
let version = '0.0.1';
try {
// @ts-ignore
if (ENVISION_VERSION) version = ENVISION_VERSION;
} catch (e) {}
// @ts-ignore
program.name('silky').description('A CLI tool with silky').version(version, '-v, --version', 'output the current version');
export { program, Command };
/**
* 在命令行中运行程序
* 当前命令参数去执行 其他的应用模块
* @param args
*/
export const runProgram = (args: string[]) => {
const [_app, _command] = process.argv;
program.parse([_app, _command, ...args]);
};

View File

@@ -1,6 +0,0 @@
import { runParser } from './index.ts';
/**
* test run parser
*/
runParser(process.argv);

View File

@@ -1,28 +0,0 @@
import { AssistantInit as BaseAssistantInit } from '@kevisual/assistant-cli/lib';
export class AssistantInit extends BaseAssistantInit {
constructor(options: { path?: string }) {
super(options);
}
protected getDefaultInitAssistantConfig() {
const config = super.getDefaultInitAssistantConfig();
config.registry = 'https://kevisual.silkyai.cn';
config.pageApi = 'https://kevisual.silkyai.cn';
config.scripts = {
init: 'silky init',
'init:env': 'silky init-env',
'init:talkshow': 'silky init-talkshow',
'server:start': 'asst server -s',
'app:download': 'asst app download -i root/center',
};
config.apiProxyList = [
...config.apiProxyList,
{
path: '/api/talkshow',
ws: true,
target: 'https://localhost:16000',
},
];
return config;
}
}

View File

@@ -1,14 +0,0 @@
{
"extends": "@kevisual/types/json/backend.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": [
"src/*"
]
},
},
"include": [
"src/**/*",
],
}