alemonjs 2.1.74 → 2.1.76
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/lib/app/router/dsl.d.ts
CHANGED
package/lib/app/router/dsl.js
CHANGED
|
@@ -53,6 +53,7 @@ function normalizeRouteConfig(config) {
|
|
|
53
53
|
}
|
|
54
54
|
return {
|
|
55
55
|
path: normalizeRoutePath(path),
|
|
56
|
+
description: config.description,
|
|
56
57
|
events: config.events,
|
|
57
58
|
platforms: config.platforms,
|
|
58
59
|
schema: config.schema
|
|
@@ -68,6 +69,94 @@ function normalizeResConfig(config, defaults) {
|
|
|
68
69
|
function getImporterLabel(importer, index) {
|
|
69
70
|
return importer.name || `anonymous_${index + 1}`;
|
|
70
71
|
}
|
|
72
|
+
function formatRouteDescription(description) {
|
|
73
|
+
return typeof description === 'string' && description.trim() ? description.trim() : undefined;
|
|
74
|
+
}
|
|
75
|
+
function formatArgRuleHint(arg, displayIndex) {
|
|
76
|
+
const rules = arg.rules ?? [];
|
|
77
|
+
const parts = [];
|
|
78
|
+
const typeRule = rules.find(rule => rule.type);
|
|
79
|
+
const requiredRule = rules.find(rule => rule.required);
|
|
80
|
+
if (requiredRule) {
|
|
81
|
+
parts.push('必填');
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
parts.push('可选');
|
|
85
|
+
}
|
|
86
|
+
if (typeRule?.type === 'number') {
|
|
87
|
+
parts.push('数字');
|
|
88
|
+
}
|
|
89
|
+
else if (typeRule?.type === 'enum') {
|
|
90
|
+
parts.push(`枚举: ${(typeRule.enum ?? []).join(' / ')}`);
|
|
91
|
+
}
|
|
92
|
+
else if (typeRule?.type === 'range') {
|
|
93
|
+
parts.push('区间');
|
|
94
|
+
}
|
|
95
|
+
else if (typeRule?.type === 'rest') {
|
|
96
|
+
parts.push('剩余文本');
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
parts.push('文本');
|
|
100
|
+
}
|
|
101
|
+
if (typeof typeRule?.min === 'number') {
|
|
102
|
+
parts.push(`最小 ${typeRule.min}`);
|
|
103
|
+
}
|
|
104
|
+
if (typeof typeRule?.max === 'number') {
|
|
105
|
+
parts.push(`最大 ${typeRule.max}`);
|
|
106
|
+
}
|
|
107
|
+
const suffix = arg.description ? `,${arg.description}` : '';
|
|
108
|
+
return `参数${displayIndex} \`${arg.name}\`:${parts.join(',')}${suffix}`;
|
|
109
|
+
}
|
|
110
|
+
function buildSchemaHints(schema) {
|
|
111
|
+
const args = schema?.args ?? [];
|
|
112
|
+
if (args.length === 0) {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
return args.map((arg, index) => formatArgRuleHint(arg, index + 1));
|
|
116
|
+
}
|
|
117
|
+
function quoteCommand(command) {
|
|
118
|
+
return command ? `\`${command}\`` : '';
|
|
119
|
+
}
|
|
120
|
+
function buildFallbackReply(params) {
|
|
121
|
+
const lines = [];
|
|
122
|
+
const commandText = quoteCommand(params.suggestedKey);
|
|
123
|
+
if (commandText) {
|
|
124
|
+
lines.push(`我猜你想用的是 ${commandText}。`);
|
|
125
|
+
lines.push(`可以直接输入:${commandText}`);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
lines.push('我还没完全认出你这条指令。');
|
|
129
|
+
}
|
|
130
|
+
if (params.description) {
|
|
131
|
+
lines.push(params.description);
|
|
132
|
+
}
|
|
133
|
+
if (params.usage && params.usage !== params.suggestedKey) {
|
|
134
|
+
lines.push(`如果你想继续,可以这样写:\`${params.usage}\``);
|
|
135
|
+
}
|
|
136
|
+
return lines;
|
|
137
|
+
}
|
|
138
|
+
function buildValidationReply(params) {
|
|
139
|
+
const lines = [];
|
|
140
|
+
const commandText = quoteCommand(params.commandKey);
|
|
141
|
+
if (commandText) {
|
|
142
|
+
lines.push(`我已经识别到你想用的是 ${commandText}。`);
|
|
143
|
+
}
|
|
144
|
+
lines.push(params.error || '这条指令的参数还不完整。');
|
|
145
|
+
if (params.description) {
|
|
146
|
+
lines.push(params.description);
|
|
147
|
+
}
|
|
148
|
+
if (params.usage) {
|
|
149
|
+
lines.push(`你可以这样输入:\`${params.usage}\``);
|
|
150
|
+
}
|
|
151
|
+
else if (commandText) {
|
|
152
|
+
lines.push(`请继续补全 ${commandText} 所需的参数。`);
|
|
153
|
+
}
|
|
154
|
+
if (params.schemaHints && params.schemaHints.length > 0) {
|
|
155
|
+
lines.push('参数说明:');
|
|
156
|
+
lines.push(...params.schemaHints);
|
|
157
|
+
}
|
|
158
|
+
return lines;
|
|
159
|
+
}
|
|
71
160
|
function normalizeInteractionKey(messageText) {
|
|
72
161
|
return String(messageText ?? '')
|
|
73
162
|
.trim()
|
|
@@ -345,6 +434,7 @@ class Router {
|
|
|
345
434
|
eventName,
|
|
346
435
|
routes: [...routes.two.values(), ...routes.one.values()].map(route => ({
|
|
347
436
|
path: route.config.path,
|
|
437
|
+
description: route?.config?.description,
|
|
348
438
|
importerCount: route.importers.length
|
|
349
439
|
}))
|
|
350
440
|
}));
|
|
@@ -542,14 +632,14 @@ class Router {
|
|
|
542
632
|
return;
|
|
543
633
|
}
|
|
544
634
|
const eventName = String(event.name ?? '');
|
|
545
|
-
const
|
|
635
|
+
const routeMetas = this.inspect()
|
|
546
636
|
.filter(item => item.eventName === eventName)
|
|
547
637
|
.flatMap(item => item.routes)
|
|
548
638
|
.filter(route => {
|
|
549
639
|
const routeEntry = this.routes.get(eventName)?.one.get(route.path) ?? this.routes.get(eventName)?.two.get(route.path);
|
|
550
640
|
return routeEntry ? applicableScopeIds.includes(routeEntry.scopeId) : false;
|
|
551
|
-
})
|
|
552
|
-
|
|
641
|
+
});
|
|
642
|
+
const routeKeys = routeMetas.map(route => route.path);
|
|
553
643
|
const fallback = checkFallbackHint(typeof event.MessageText === 'string' ? event.MessageText : undefined, routeKeys, fallbackOptions);
|
|
554
644
|
if (!fallback.matched) {
|
|
555
645
|
await next();
|
|
@@ -558,7 +648,18 @@ class Router {
|
|
|
558
648
|
const [message] = useMessage();
|
|
559
649
|
const md = Format.createMarkdown();
|
|
560
650
|
const format = Format.create();
|
|
561
|
-
|
|
651
|
+
const suggestedRoute = fallback.suggestedKey ? routeMetas.find(route => route.path === fallback.suggestedKey) : undefined;
|
|
652
|
+
const replyLines = buildFallbackReply({
|
|
653
|
+
suggestedKey: fallback.suggestedKey,
|
|
654
|
+
description: formatRouteDescription(suggestedRoute?.description),
|
|
655
|
+
usage: suggestedRoute?.path
|
|
656
|
+
});
|
|
657
|
+
replyLines.forEach((line, index) => {
|
|
658
|
+
if (index > 0) {
|
|
659
|
+
md.addNewline();
|
|
660
|
+
}
|
|
661
|
+
md.addText(line);
|
|
662
|
+
});
|
|
562
663
|
format.addMarkdown(md);
|
|
563
664
|
void message.send({ format });
|
|
564
665
|
}
|
|
@@ -570,15 +671,24 @@ class Router {
|
|
|
570
671
|
const [message] = useMessage();
|
|
571
672
|
const md = Format.createMarkdown();
|
|
572
673
|
const format = Format.create();
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
674
|
+
const routeEntry = (result.eventName && result.matchedPath
|
|
675
|
+
? (this.routes.get(result.eventName)?.one.get(result.matchedPath) ?? this.routes.get(result.eventName)?.two.get(result.matchedPath))
|
|
676
|
+
: undefined) ?? undefined;
|
|
677
|
+
const description = formatRouteDescription(routeEntry?.config.description);
|
|
678
|
+
const schemaHints = buildSchemaHints(routeEntry?.config.schema);
|
|
679
|
+
const replyLines = buildValidationReply({
|
|
680
|
+
error: validation && !validation.valid ? validation.error : '参数校验失败',
|
|
681
|
+
commandKey: result.commandKey,
|
|
682
|
+
description,
|
|
683
|
+
usage: validation && !validation.valid ? validation.usage : undefined,
|
|
684
|
+
schemaHints
|
|
685
|
+
});
|
|
686
|
+
replyLines.forEach((line, index) => {
|
|
687
|
+
if (index > 0) {
|
|
688
|
+
md.addNewline();
|
|
689
|
+
}
|
|
690
|
+
md.addText(line);
|
|
691
|
+
});
|
|
582
692
|
format.addMarkdown(md);
|
|
583
693
|
void message.send({ format });
|
|
584
694
|
}
|
|
@@ -21,6 +21,12 @@ function levenshteinDistance(a, b) {
|
|
|
21
21
|
function normalizeForCompare(text) {
|
|
22
22
|
return text.replace(/^([!!/##])\s*/, '').trim();
|
|
23
23
|
}
|
|
24
|
+
function shouldCheckCandidate(messageText, candidate) {
|
|
25
|
+
if (!messageText || !candidate) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return messageText.startsWith(candidate);
|
|
29
|
+
}
|
|
24
30
|
function getAdaptiveMaxDistance(input) {
|
|
25
31
|
if (input.length <= 2) {
|
|
26
32
|
return 1;
|
|
@@ -44,6 +50,10 @@ function checkFallbackHint(messageText, routeKeys, options = {}) {
|
|
|
44
50
|
if (options.suggest === false) {
|
|
45
51
|
return { matched: false };
|
|
46
52
|
}
|
|
53
|
+
const normalizedMessage = normalizeForCompare(String(messageText ?? ''));
|
|
54
|
+
if (!normalizedMessage) {
|
|
55
|
+
return { matched: false };
|
|
56
|
+
}
|
|
47
57
|
const parsed = parseMessageText(messageText);
|
|
48
58
|
if (!parsed) {
|
|
49
59
|
return { matched: false };
|
|
@@ -60,6 +70,9 @@ function checkFallbackHint(messageText, routeKeys, options = {}) {
|
|
|
60
70
|
let bestMatch = null;
|
|
61
71
|
for (const routeKey of routeKeys) {
|
|
62
72
|
const normalizedKey = normalizeForCompare(routeKey);
|
|
73
|
+
if (!shouldCheckCandidate(normalizedMessage, normalizedKey)) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
63
76
|
const distance = levenshteinDistance(attemptedKey, normalizedKey);
|
|
64
77
|
if (!bestMatch || distance < bestMatch.distance) {
|
|
65
78
|
bestMatch = {
|
|
@@ -20,6 +20,7 @@ export type RouteNext = () => Promise<void> | undefined;
|
|
|
20
20
|
export type RouteExecutable = (event: Record<string, unknown>, next: RouteNext) => Promise<boolean | undefined> | boolean | undefined;
|
|
21
21
|
export type RouteHandlerConfig<P extends string = string, E extends string = string> = {
|
|
22
22
|
path?: string;
|
|
23
|
+
description?: string;
|
|
23
24
|
events?: readonly E[];
|
|
24
25
|
platforms?: readonly P[];
|
|
25
26
|
schema?: RouteSchema;
|
|
@@ -52,6 +53,7 @@ export type RouteDefinition<P extends string = string, E extends string = string
|
|
|
52
53
|
export type RouteDefinitions<P extends string = string, E extends string = string> = RouteDefinition<P, E> | RouteDefinition<P, E>[];
|
|
53
54
|
export type NormalizedRouteConfig<P extends string = string, E extends string = string> = {
|
|
54
55
|
path?: string;
|
|
56
|
+
description?: string;
|
|
55
57
|
events?: readonly E[];
|
|
56
58
|
platforms?: readonly P[];
|
|
57
59
|
schema?: RouteSchema;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alemonjs",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.76",
|
|
4
4
|
"description": "bot script",
|
|
5
5
|
"author": "lemonade",
|
|
6
6
|
"license": "MIT",
|
|
@@ -72,4 +72,4 @@
|
|
|
72
72
|
"url": "https://github.com/lemonade-lab/alemonjs.git"
|
|
73
73
|
},
|
|
74
74
|
"gitHead": "c6aa5616afe091a37610dad22fbb2d2618d943b8"
|
|
75
|
-
}
|
|
75
|
+
}
|