@kevisual/router 0.0.86 → 0.0.87
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +1 -1
- package/dist/commander.d.ts +815 -0
- package/dist/commander.js +2243 -0
- package/package.json +3 -1
- package/src/commander.ts +115 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@kevisual/router",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.87",
|
|
5
5
|
"description": "",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/router.js",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"@types/send": "^1.2.1",
|
|
36
36
|
"@types/ws": "^8.18.1",
|
|
37
37
|
"@types/xml2js": "^0.4.14",
|
|
38
|
+
"commander": "^14.0.3",
|
|
38
39
|
"eventemitter3": "^5.0.4",
|
|
39
40
|
"fast-glob": "^3.3.3",
|
|
40
41
|
"hono": "^4.12.5",
|
|
@@ -59,6 +60,7 @@
|
|
|
59
60
|
"exports": {
|
|
60
61
|
".": "./dist/router.js",
|
|
61
62
|
"./browser": "./dist/router-browser.js",
|
|
63
|
+
"./commander": "./dist/commander.js",
|
|
62
64
|
"./simple": "./dist/router-simple.js",
|
|
63
65
|
"./opencode": "./dist/opencode.js",
|
|
64
66
|
"./skill": "./dist/app.js",
|
package/src/commander.ts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { program } from 'commander';
|
|
2
|
+
import { App } from './app.ts';
|
|
3
|
+
|
|
4
|
+
export const groupByPath = (routes: App['routes']) => {
|
|
5
|
+
return routes.reduce((acc, route) => {
|
|
6
|
+
const path = route.path || 'default';
|
|
7
|
+
if (!acc[path]) {
|
|
8
|
+
acc[path] = [];
|
|
9
|
+
}
|
|
10
|
+
acc[path].push(route);
|
|
11
|
+
return acc;
|
|
12
|
+
}, {} as Record<string, typeof routes>);
|
|
13
|
+
}
|
|
14
|
+
export const parseArgs = (args: string) => {
|
|
15
|
+
try {
|
|
16
|
+
return JSON.parse(args);
|
|
17
|
+
} catch {
|
|
18
|
+
// 尝试解析 a=b b=c 格式
|
|
19
|
+
const result: Record<string, string> = {};
|
|
20
|
+
const pairs = args.match(/(\S+?)=(\S+)/g);
|
|
21
|
+
if (pairs && pairs.length > 0) {
|
|
22
|
+
for (const pair of pairs) {
|
|
23
|
+
const idx = pair.indexOf('=');
|
|
24
|
+
const key = pair.slice(0, idx);
|
|
25
|
+
const value = pair.slice(idx + 1);
|
|
26
|
+
result[key] = value;
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
throw new Error('Invalid arguments: expected JSON or key=value pairs (e.g. a=b c=d)');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export const parseDescription = (route: App['routes'][number]) => {
|
|
34
|
+
let desc = '';
|
|
35
|
+
if (route.metadata?.skill) {
|
|
36
|
+
desc += `\n\t=====${route.metadata.skill}=====\n`;
|
|
37
|
+
}
|
|
38
|
+
let hasSummary = false;
|
|
39
|
+
if (route.metadata?.summary) {
|
|
40
|
+
desc += `\t${route.metadata.summary}`;
|
|
41
|
+
hasSummary = true;
|
|
42
|
+
}
|
|
43
|
+
if (route.metadata?.args) {
|
|
44
|
+
const argsLines = Object.entries(route.metadata.args).map(([key, schema]: [string, any]) => {
|
|
45
|
+
const defType: string = schema?._def?.type ?? schema?.type ?? '';
|
|
46
|
+
const isOptional = defType === 'optional';
|
|
47
|
+
const innerType: string = isOptional
|
|
48
|
+
? (schema?._def?.innerType?.type ?? schema?._def?.innerType?._def?.type ?? '')
|
|
49
|
+
: defType;
|
|
50
|
+
const description: string =
|
|
51
|
+
schema?.description ??
|
|
52
|
+
schema?._def?.description ??
|
|
53
|
+
'';
|
|
54
|
+
const optionalMark = isOptional ? '?' : '';
|
|
55
|
+
const descPart = description ? ` ${description}` : '';
|
|
56
|
+
return `\t - ${key}${optionalMark}: ${innerType}${descPart}`;
|
|
57
|
+
});
|
|
58
|
+
desc += '\n\targs:\n' + argsLines.join('\n');
|
|
59
|
+
}
|
|
60
|
+
if (route.description && !hasSummary) {
|
|
61
|
+
desc += `\t - ${route.description}`;
|
|
62
|
+
}
|
|
63
|
+
return desc;
|
|
64
|
+
}
|
|
65
|
+
export const createCommand = (opts: { app: App, program: typeof program }) => {
|
|
66
|
+
const { app, program } = opts;
|
|
67
|
+
const routes = app.routes;
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
const groupRoutes = groupByPath(routes);
|
|
71
|
+
for (const path in groupRoutes) {
|
|
72
|
+
const routeList = groupRoutes[path];
|
|
73
|
+
const keys = routeList.map(route => route.key).filter(Boolean);
|
|
74
|
+
const subProgram = program.command(path).description(`路由《${path}》 ${keys.length > 0 ? ': ' + keys.join(', ') : ''}`);
|
|
75
|
+
routeList.forEach(route => {
|
|
76
|
+
if (!route.key) return;
|
|
77
|
+
const description = parseDescription(route);
|
|
78
|
+
subProgram.command(route.key)
|
|
79
|
+
.description(description || '')
|
|
80
|
+
.option('--args <args>', 'JSON字符串参数,传递给命令执行')
|
|
81
|
+
.action(async (options) => {
|
|
82
|
+
const output = (data: any) => {
|
|
83
|
+
if (typeof data === 'object') {
|
|
84
|
+
process.stdout.write(JSON.stringify(data, null, 2) + '\n');
|
|
85
|
+
} else {
|
|
86
|
+
process.stdout.write(String(data) + '\n');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
const args = options.args ? parseArgs(options.args) : {};
|
|
91
|
+
// 这里可以添加实际的命令执行逻辑,例如调用对应的路由处理函数
|
|
92
|
+
const res = await app.run({ path, key: route.key, payload: args }, { appId: app.appId });
|
|
93
|
+
if (res.code === 200) {
|
|
94
|
+
output(res.data);
|
|
95
|
+
} else {
|
|
96
|
+
output(`Error: ${res.message}`);
|
|
97
|
+
}
|
|
98
|
+
} catch (error) {
|
|
99
|
+
output(`Execution error: ${error instanceof Error ? error.message : String(error)}`);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
program.parse(process.argv);
|
|
107
|
+
|
|
108
|
+
export const parse = (opts: { app: App, description?: string, parse?: boolean }) => {
|
|
109
|
+
const { app, description, parse } = opts;
|
|
110
|
+
program.description(description || 'Router 命令行工具');
|
|
111
|
+
createCommand({ app: app as App, program });
|
|
112
|
+
if (parse) {
|
|
113
|
+
program.parse(process.argv);
|
|
114
|
+
}
|
|
115
|
+
}
|