@koishi-ce/plugin-help 1.0.0 → 1.1.0
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/README.md +120 -0
- package/lib/assets/{en-US-f1RJaaO6.yml → en-US-DRtqxx3I.yml} +3 -0
- package/lib/assets/{zh-CN-DmsdBxOO.yml → zh-CN-DCysH3jk.yml} +3 -0
- package/lib/index.d.ts +6 -7
- package/lib/index.mjs +2 -2
- package/locales/de-DE.yml +19 -16
- package/locales/en-US.yml +3 -0
- package/locales/fr-FR.yml +3 -0
- package/locales/ja-JP.yml +3 -0
- package/locales/ru-RU.yml +19 -16
- package/locales/zh-CN.yml +3 -0
- package/locales/zh-TW.yml +3 -0
- package/package.json +4 -5
- package/src/extra.test.ts +98 -0
- package/src/index.test.ts +41 -10
- package/src/index.ts +173 -45
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# @koishi-ce/plugin-help
|
|
2
|
+
|
|
3
|
+
**简体中文** | [English](#english)
|
|
4
|
+
|
|
5
|
+
帮助指令插件,移植自上游 [koishijs/koishi](https://github.com/koishijs/koishi) 的 `plugins/common/help`。列出当前可用的指令清单,或输出某条指令的详细帮助(描述、别名、用法、选项、示例与子指令),并按权限与隐藏标记过滤展示内容。
|
|
6
|
+
|
|
7
|
+
## 指令
|
|
8
|
+
|
|
9
|
+
| 指令 | 权限 | 说明 |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| `help [command:string]` | 0 | 显示帮助信息,选项 `-H, --showHidden` 查看隐藏的选项和指令 |
|
|
12
|
+
|
|
13
|
+
- 不带参数时列出当前可用的全部指令(按显示名排序),带参数时输出目标指令的详细帮助。
|
|
14
|
+
- 注册全局快捷调用「帮助」(fuzzy 匹配)。
|
|
15
|
+
- 指令参数除指令名外,也可以直接输入某条指令的快捷调用文本来定位指令。
|
|
16
|
+
- 未找到指令时,按相似度给出「您要找的是不是…」建议。
|
|
17
|
+
|
|
18
|
+
## 配置项
|
|
19
|
+
|
|
20
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
21
|
+
| --- | --- | --- | --- |
|
|
22
|
+
| `shortcut` | boolean | `true` | 是否启用快捷调用 |
|
|
23
|
+
| `options` | boolean | `true` | 是否为每个指令添加 `-h, --help` 选项 |
|
|
24
|
+
|
|
25
|
+
### 指令与选项配置扩展
|
|
26
|
+
|
|
27
|
+
本插件经 `ctx.schema.extend` 为每条指令及指令选项追加以下配置(出现在各指令的配置中,而非本插件的配置):
|
|
28
|
+
|
|
29
|
+
| 位置 | 字段 | 类型 | 默认值 | 说明 |
|
|
30
|
+
| --- | --- | --- | --- | --- |
|
|
31
|
+
| 指令 | `hidden` | 计算属性 boolean | `false` | 在帮助菜单中隐藏指令 |
|
|
32
|
+
| 指令 | `hideOptions` | boolean | `false` | 是否隐藏所有选项 |
|
|
33
|
+
| 指令 | `params` | any | — | 帮助信息的本地化参数 |
|
|
34
|
+
| 选项 | `hidden` | 计算属性 boolean | `false` | 在帮助菜单中隐藏选项 |
|
|
35
|
+
| 选项 | `params` | any | — | 帮助信息的本地化参数 |
|
|
36
|
+
|
|
37
|
+
## 用法
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
bun add @koishi-ce/plugin-help
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
也可以在控制台的插件市场中直接安装。随后在配置文件中启用:
|
|
44
|
+
|
|
45
|
+
```yaml
|
|
46
|
+
plugins:
|
|
47
|
+
help: {}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## 备注
|
|
51
|
+
|
|
52
|
+
- 为所有指令注入隐藏的 `-h, --help` 选项;带 `-h` 调用、或调用本身没有 action 的指令时,自动转而输出该指令的帮助。
|
|
53
|
+
- 详细帮助依次输出:指令标题、描述、别名、用法、可用选项、使用示例与子指令列表。
|
|
54
|
+
- 选项的权限要求高于当前用户、或被 `hidden` 标记隐藏时不展示,`-H` 可查看。
|
|
55
|
+
- 指令列表与详情均按 `command:<name>` 权限过滤,无权限的指令不展示。
|
|
56
|
+
- 提供 `help/command` 与 `help/option` 事件,供其他插件改写帮助输出。
|
|
57
|
+
|
|
58
|
+
## 许可证
|
|
59
|
+
|
|
60
|
+
[MIT](https://github.com/Koishi-CE/koishi/blob/main/LICENSE)。本包是上游 [koishijs/koishi](https://github.com/koishijs/koishi) 的社区再分发,版权归属见 [NOTICE](https://github.com/Koishi-CE/koishi/blob/main/NOTICE)。
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## English
|
|
65
|
+
|
|
66
|
+
A help command plugin, ported from `plugins/common/help` of the upstream [koishijs/koishi](https://github.com/koishijs/koishi) repository. It lists the available commands, or shows detailed help for a specific command (description, aliases, usage, options, examples and subcommands), filtered by authority and hidden flags.
|
|
67
|
+
|
|
68
|
+
## Commands
|
|
69
|
+
|
|
70
|
+
| Command | Authority | Description |
|
|
71
|
+
| --- | --- | --- |
|
|
72
|
+
| `help [command:string]` | 0 | Show help; the `-H, --showHidden` option reveals hidden options and commands |
|
|
73
|
+
|
|
74
|
+
- Without arguments it lists all available commands; with an argument it shows detailed help for the target command.
|
|
75
|
+
- Registers the global shortcut "帮助" (Chinese, fuzzy matching).
|
|
76
|
+
- Besides command names, the argument also accepts a command's shortcut text to locate it.
|
|
77
|
+
- When a command is not found, it suggests similar ones.
|
|
78
|
+
|
|
79
|
+
## Configuration
|
|
80
|
+
|
|
81
|
+
| Field | Type | Default | Description |
|
|
82
|
+
| --- | --- | --- | --- |
|
|
83
|
+
| `shortcut` | boolean | `true` | Whether to enable the shortcut |
|
|
84
|
+
| `options` | boolean | `true` | Whether to add a `-h, --help` option to every command |
|
|
85
|
+
|
|
86
|
+
### Command and Option Config Extensions
|
|
87
|
+
|
|
88
|
+
Via `ctx.schema.extend`, the following fields are appended to every command and option config (on each command, not on this plugin):
|
|
89
|
+
|
|
90
|
+
| Scope | Field | Type | Default | Description |
|
|
91
|
+
| --- | --- | --- | --- | --- |
|
|
92
|
+
| Command | `hidden` | computed boolean | `false` | Hide the command from help menus |
|
|
93
|
+
| Command | `hideOptions` | boolean | `false` | Hide all options |
|
|
94
|
+
| Command | `params` | any | — | Localization params for help output |
|
|
95
|
+
| Option | `hidden` | computed boolean | `false` | Hide the option from help menus |
|
|
96
|
+
| Option | `params` | any | — | Localization params for help output |
|
|
97
|
+
|
|
98
|
+
## Usage
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
bun add @koishi-ce/plugin-help
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The plugin can also be installed from the console plugin market, then enabled in the config file:
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
plugins:
|
|
108
|
+
help: {}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Notes
|
|
112
|
+
|
|
113
|
+
- Injects a hidden `-h, --help` option into every command; calling with `-h`, or calling a command without an action, shows its help instead.
|
|
114
|
+
- Options whose authority exceeds the user or marked as `hidden` are not shown unless `-H` is used.
|
|
115
|
+
- Command lists and details are filtered by the `command:<name>` permission.
|
|
116
|
+
- Provides `help/command` and `help/option` events for other plugins to customize the output.
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
[MIT](https://github.com/Koishi-CE/koishi/blob/main/LICENSE). This package is a community redistribution of upstream koishijs/koishi; see [NOTICE](https://github.com/Koishi-CE/koishi/blob/main/NOTICE) for attribution.
|
package/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Computed, Context, Schema, Session } from "@koishi-ce/koishi";
|
|
2
2
|
//#region src/index.d.ts
|
|
3
3
|
declare module "@koishi-ce/koishi" {
|
|
4
4
|
interface Events {
|
|
@@ -25,14 +25,13 @@ declare module "@koishi-ce/koishi" {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
/** 配置项 */
|
|
28
|
-
interface Config {
|
|
28
|
+
export interface Config {
|
|
29
29
|
/** 是否启用“帮助”快捷调用 */
|
|
30
30
|
shortcut?: boolean;
|
|
31
31
|
/** 是否为每个指令注入 `-h, --help` 选项 */
|
|
32
32
|
options?: boolean;
|
|
33
33
|
}
|
|
34
|
-
declare const Config: Schema<Config>;
|
|
35
|
-
declare const name = "help";
|
|
36
|
-
declare function apply(ctx: Context, config: Config): void;
|
|
37
|
-
//#endregion
|
|
38
|
-
export { Config, apply, name };
|
|
34
|
+
export declare const Config: Schema<Config>;
|
|
35
|
+
export declare const name = "help";
|
|
36
|
+
export declare function apply(ctx: Context, config: Config): void;
|
|
37
|
+
//#endregion
|
package/lib/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Context, Schema, h } from "@koishi-ce/koishi";
|
|
2
|
-
import enUS from "./assets/en-US-
|
|
3
|
-
import zhCN from "./assets/zh-CN-
|
|
2
|
+
import enUS from "./assets/en-US-DRtqxx3I.yml";
|
|
3
|
+
import zhCN from "./assets/zh-CN-DCysH3jk.yml";
|
|
4
4
|
//#region src/index.ts
|
|
5
5
|
/**
|
|
6
6
|
* 帮助指令插件(help)。
|
package/locales/de-DE.yml
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2019-present Shigma and Koishijs contributors.
|
|
3
|
+
|
|
1
4
|
commands:
|
|
2
5
|
help:
|
|
3
|
-
description:
|
|
6
|
+
description: Hilfe anzeigen
|
|
4
7
|
shortcuts:
|
|
5
8
|
help: Hilfe
|
|
6
9
|
options:
|
|
7
|
-
help:
|
|
8
|
-
authority:
|
|
9
|
-
showHidden:
|
|
10
|
+
help: Diese Meldung anzeigen
|
|
11
|
+
authority: Berechtigungsanforderungen anzeigen
|
|
12
|
+
showHidden: Versteckte Optionen und Befehle anzeigen
|
|
10
13
|
messages:
|
|
11
|
-
not-found:
|
|
12
|
-
hint-authority:
|
|
13
|
-
hint-subcommand:
|
|
14
|
-
command-title:
|
|
15
|
-
command-aliases:
|
|
16
|
-
command-examples:
|
|
17
|
-
command-authority:
|
|
18
|
-
subcommand-prolog:
|
|
19
|
-
global-prolog:
|
|
20
|
-
global-epilog:
|
|
21
|
-
available-options:
|
|
22
|
-
available-options-with-authority:
|
|
14
|
+
not-found: Befehl nicht gefunden.
|
|
15
|
+
hint-authority: die minimale Berechtigung ist in Klammern angegeben
|
|
16
|
+
hint-subcommand: mit einem Sternchen markierte Befehle besitzen Unterbefehle
|
|
17
|
+
command-title: 'Befehl: {0}'
|
|
18
|
+
command-aliases: 'Aliase: {0}.'
|
|
19
|
+
command-examples: 'Beispiele:'
|
|
20
|
+
command-authority: 'Minimale Berechtigung: {0}.'
|
|
21
|
+
subcommand-prolog: 'Verfügbare Unterbefehle{0}:'
|
|
22
|
+
global-prolog: 'Verfügbare Befehle{0}:'
|
|
23
|
+
global-epilog: Geben Sie „{0}help <Befehl>“ ein, um Syntax und Beispiele für einen bestimmten Befehl anzuzeigen.
|
|
24
|
+
available-options: 'Verfügbare Optionen:'
|
|
25
|
+
available-options-with-authority: 'Verfügbare Optionen (in Klammern angegebene zusätzlich erforderliche Berechtigung):'
|
package/locales/en-US.yml
CHANGED
package/locales/fr-FR.yml
CHANGED
package/locales/ja-JP.yml
CHANGED
package/locales/ru-RU.yml
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2019-present Shigma and Koishijs contributors.
|
|
3
|
+
|
|
1
4
|
commands:
|
|
2
5
|
help:
|
|
3
|
-
description:
|
|
6
|
+
description: Показать справку
|
|
4
7
|
shortcuts:
|
|
5
8
|
help: Справка
|
|
6
9
|
options:
|
|
7
|
-
help:
|
|
8
|
-
authority:
|
|
9
|
-
showHidden:
|
|
10
|
+
help: показать это сообщение
|
|
11
|
+
authority: показать требования к правам
|
|
12
|
+
showHidden: показать скрытые опции и команды
|
|
10
13
|
messages:
|
|
11
|
-
not-found:
|
|
12
|
-
hint-authority:
|
|
13
|
-
hint-subcommand:
|
|
14
|
-
command-title:
|
|
15
|
-
command-aliases:
|
|
16
|
-
command-examples:
|
|
17
|
-
command-authority:
|
|
18
|
-
subcommand-prolog:
|
|
19
|
-
global-prolog:
|
|
20
|
-
global-epilog:
|
|
21
|
-
available-options:
|
|
22
|
-
available-options-with-authority:
|
|
14
|
+
not-found: Команда не найдена.
|
|
15
|
+
hint-authority: минимальный уровень прав указан в скобках
|
|
16
|
+
hint-subcommand: команды, отмеченные звёздочкой, имеют подкоманды
|
|
17
|
+
command-title: 'Команда: {0}'
|
|
18
|
+
command-aliases: 'Псевдонимы: {0}.'
|
|
19
|
+
command-examples: 'Примеры:'
|
|
20
|
+
command-authority: 'Минимальный уровень прав: {0}.'
|
|
21
|
+
subcommand-prolog: 'Доступные подкоманды{0}:'
|
|
22
|
+
global-prolog: 'Доступные команды{0}:'
|
|
23
|
+
global-epilog: Введите "{0}help <команда>", чтобы увидеть синтаксис и примеры для конкретной команды.
|
|
24
|
+
available-options: 'Доступные опции:'
|
|
25
|
+
available-options-with-authority: 'Доступные опции (в скобках указано дополнительное требование к правам):'
|
package/locales/zh-CN.yml
CHANGED
package/locales/zh-TW.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koishi-ce/plugin-help",
|
|
3
3
|
"description": "Help plugin for Koishi",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.1.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.mjs",
|
|
7
7
|
"typings": "lib/index.d.ts",
|
|
@@ -47,13 +47,12 @@
|
|
|
47
47
|
]
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"koishi": "^
|
|
50
|
+
"@koishi-ce/koishi": "^1.0.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
+
"@koishi-ce/koishi": "^1.0.8",
|
|
53
54
|
"@koishi-ce/plugin-mock": "^1.0.0",
|
|
54
|
-
"@
|
|
55
|
-
"@koishi-ce/koishi": "^1.0.0",
|
|
56
|
-
"minato": "^3.7.0"
|
|
55
|
+
"@koishijs/plugin-database-memory": "^3.7.0"
|
|
57
56
|
},
|
|
58
57
|
"exports": {
|
|
59
58
|
".": {
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (c) 2026-present Koishi-CE contributors.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* help 插件补充用例(bun:test 断言):
|
|
6
|
+
* 父指令对当前会话不可见时下钻子指令(getCommands else 分支)、
|
|
7
|
+
* 选项权限不足时从帮助中隐藏、i18n 定义的示例文本逐行展示、
|
|
8
|
+
* 以及快捷调用的模糊命中给出的纠错建议(候选字段收集循环)。
|
|
9
|
+
*
|
|
10
|
+
* 备注:inferCommand 里 session.suggest 的 filter 回调(index.ts 223-225)
|
|
11
|
+
* 经 help 插件路径不可达——suggest 仅在传入 actual 时才调用 filter,
|
|
12
|
+
* 而 help 的 suggest 调用不传 actual(见 core/src/session/interact.ts)。
|
|
13
|
+
*/
|
|
14
|
+
import { beforeAll, describe, expect, it } from "bun:test";
|
|
15
|
+
import { App } from "@koishi-ce/koishi";
|
|
16
|
+
import * as help from "@koishi-ce/plugin-help";
|
|
17
|
+
import mock from "@koishi-ce/plugin-mock";
|
|
18
|
+
import * as memoryModule from "@koishijs/plugin-database-memory";
|
|
19
|
+
|
|
20
|
+
// CJS 实现配 ESM 声明,Bun 互操作视图多包一层 default,穿透取真实驱动
|
|
21
|
+
const memory =
|
|
22
|
+
memoryModule.default as unknown as typeof memoryModule.default.default;
|
|
23
|
+
|
|
24
|
+
const app = new App({
|
|
25
|
+
minSimilarity: 0.64,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
app.plugin(mock);
|
|
29
|
+
app.plugin(help);
|
|
30
|
+
app.plugin(memory);
|
|
31
|
+
|
|
32
|
+
app.i18n.define(
|
|
33
|
+
"$zh-CN",
|
|
34
|
+
"commands.help.messages.global-epilog",
|
|
35
|
+
"",
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const client = app.mock.client("123", "456");
|
|
39
|
+
|
|
40
|
+
beforeAll(async () => {
|
|
41
|
+
await app.start();
|
|
42
|
+
await app.mock.initUser("123", 2);
|
|
43
|
+
await app.mock.initChannel("456");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("@koishi-ce/plugin-help 补充用例", () => {
|
|
47
|
+
it("父指令对当前会话不可见时不进入全局列表", async () => {
|
|
48
|
+
// 限定 telegram 平台的指令对 mock 会话 match 失败,全局列表不展示
|
|
49
|
+
const parent = app
|
|
50
|
+
.platform("telegram")
|
|
51
|
+
.command("tg", "T");
|
|
52
|
+
parent.subcommand("tgc", "C");
|
|
53
|
+
const [reply] = await client.receive("help");
|
|
54
|
+
expect(reply).toContain("help");
|
|
55
|
+
expect(reply).not.toContain("tg");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("选项权限不足时从帮助中隐藏", async () => {
|
|
59
|
+
app
|
|
60
|
+
.command("adv", "D")
|
|
61
|
+
.option("top", "-t", { authority: 3 });
|
|
62
|
+
const [reply] = await client.receive("help adv");
|
|
63
|
+
expect(reply).toBe("指令:adv\nD");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("i18n 定义的示例文本逐行展示", async () => {
|
|
67
|
+
app.command("demo", "D");
|
|
68
|
+
app.i18n.define(
|
|
69
|
+
"$zh-CN",
|
|
70
|
+
"commands.demo.examples",
|
|
71
|
+
"first\nsecond",
|
|
72
|
+
);
|
|
73
|
+
const [reply] = await client.receive("help demo");
|
|
74
|
+
expect(reply).toBe(
|
|
75
|
+
"指令:demo\nD\n使用示例:\n first\n second",
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("快捷调用的模糊命中给出纠错建议", async () => {
|
|
80
|
+
const probe = app.command("probe", "DESCRIPTION");
|
|
81
|
+
probe.shortcut("ask", { i18n: true });
|
|
82
|
+
app.i18n.define(
|
|
83
|
+
"$zh-CN",
|
|
84
|
+
"commands.probe.shortcuts.ask",
|
|
85
|
+
"quickbrownfox",
|
|
86
|
+
);
|
|
87
|
+
// 与快捷调用文本相差一字母:非精确命中,走候选列表与建议流程
|
|
88
|
+
await client.shouldReply(
|
|
89
|
+
"help quickbrownfo",
|
|
90
|
+
"指令未找到。您要找的是不是“probe”?回复句号以使用推测的指令。",
|
|
91
|
+
);
|
|
92
|
+
// 回复句号确认后展示推测指令的帮助
|
|
93
|
+
await client.shouldReply(
|
|
94
|
+
".",
|
|
95
|
+
"指令:probe\nDESCRIPTION",
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
});
|
package/src/index.test.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (c) 2026-present Koishi-CE contributors.
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* help 插件测试:覆盖帮助列表、指令属性(别名 / 用法 / 示例 / 权限)、
|
|
3
6
|
* 选项展示、子指令、无数据库场景与 shortcut / options 配置开关。
|
|
@@ -6,7 +9,11 @@ import { beforeAll, describe, it } from "bun:test";
|
|
|
6
9
|
import { App } from "@koishi-ce/koishi";
|
|
7
10
|
import * as help from "@koishi-ce/plugin-help";
|
|
8
11
|
import mock from "@koishi-ce/plugin-mock";
|
|
9
|
-
import
|
|
12
|
+
import * as memoryModule from "@koishijs/plugin-database-memory";
|
|
13
|
+
|
|
14
|
+
// CJS 实现配 ESM 声明,Bun 互操作视图多包一层 default,穿透取真实驱动
|
|
15
|
+
const memory =
|
|
16
|
+
memoryModule.default as unknown as typeof memoryModule.default.default;
|
|
10
17
|
|
|
11
18
|
const app = new App({
|
|
12
19
|
minSimilarity: 0.64,
|
|
@@ -16,7 +23,11 @@ app.plugin(mock);
|
|
|
16
23
|
app.plugin(help);
|
|
17
24
|
app.plugin(memory);
|
|
18
25
|
|
|
19
|
-
app.i18n.define(
|
|
26
|
+
app.i18n.define(
|
|
27
|
+
"$zh-CN",
|
|
28
|
+
"commands.help.messages.global-epilog",
|
|
29
|
+
"EPILOG",
|
|
30
|
+
);
|
|
20
31
|
|
|
21
32
|
const client = app.mock.client("123", "456");
|
|
22
33
|
|
|
@@ -68,20 +79,30 @@ describe("@koishi-ce/plugin-help", () => {
|
|
|
68
79
|
app.command("foo1", "DESCRIPTION").alias("foo");
|
|
69
80
|
app.command("foo3", "DESCRIPTION").shortcut(/foobar/);
|
|
70
81
|
app.command("foo4", "DESCRIPTION").usage("USAGE TEXT");
|
|
71
|
-
app
|
|
72
|
-
|
|
82
|
+
app
|
|
83
|
+
.command("foo5", "DESCRIPTION")
|
|
84
|
+
.usage(({ userId }) => `${userId}`);
|
|
85
|
+
app
|
|
86
|
+
.command("foo6", "DESCRIPTION")
|
|
87
|
+
.example("EXAMPLE TEXT");
|
|
73
88
|
app.command("foo7", "DESCRIPTION", { authority: 3 });
|
|
74
89
|
|
|
75
90
|
await client.shouldReply(
|
|
76
91
|
"help foo1",
|
|
77
92
|
"指令:foo1\nDESCRIPTION\n别名:foo。",
|
|
78
93
|
);
|
|
79
|
-
await client.shouldReply(
|
|
94
|
+
await client.shouldReply(
|
|
95
|
+
"help foobar",
|
|
96
|
+
"指令:foo3\nDESCRIPTION",
|
|
97
|
+
);
|
|
80
98
|
await client.shouldReply(
|
|
81
99
|
"help foo4",
|
|
82
100
|
"指令:foo4\nDESCRIPTION\nUSAGE TEXT",
|
|
83
101
|
);
|
|
84
|
-
await client.shouldReply(
|
|
102
|
+
await client.shouldReply(
|
|
103
|
+
"help foo5",
|
|
104
|
+
"指令:foo5\nDESCRIPTION\n123",
|
|
105
|
+
);
|
|
85
106
|
await client.shouldReply(
|
|
86
107
|
"help foo6",
|
|
87
108
|
"指令:foo6\nDESCRIPTION\n使用示例:\n EXAMPLE TEXT",
|
|
@@ -92,7 +113,9 @@ describe("@koishi-ce/plugin-help", () => {
|
|
|
92
113
|
// 验证 hideOptions、选项权限与 hidden 选项的过滤,以及 -H 的全量展示
|
|
93
114
|
it("command options", async () => {
|
|
94
115
|
const bar = app
|
|
95
|
-
.command("bar <arg:number>", "DESCRIPTION", {
|
|
116
|
+
.command("bar <arg:number>", "DESCRIPTION", {
|
|
117
|
+
hideOptions: true,
|
|
118
|
+
})
|
|
96
119
|
.option("opt1", "选项1", { authority: 2 })
|
|
97
120
|
.option("opt1", "-n 选项2", { value: false })
|
|
98
121
|
.option("opt2", "[arg:boolean] 选项3")
|
|
@@ -132,7 +155,9 @@ describe("@koishi-ce/plugin-help", () => {
|
|
|
132
155
|
|
|
133
156
|
// 验证多级子指令在父指令帮助中的逐层呈现
|
|
134
157
|
it("subcommand", async () => {
|
|
135
|
-
const foo2 = app.command("foo2", "DESCRIPTION", {
|
|
158
|
+
const foo2 = app.command("foo2", "DESCRIPTION", {
|
|
159
|
+
authority: 0,
|
|
160
|
+
});
|
|
136
161
|
const foo1 = foo2.subcommand("foo1");
|
|
137
162
|
foo1.subcommand("foo3");
|
|
138
163
|
|
|
@@ -163,7 +188,11 @@ describe("@koishi-ce/plugin-help", () => {
|
|
|
163
188
|
const app = new App();
|
|
164
189
|
app.plugin(help);
|
|
165
190
|
app.plugin(mock);
|
|
166
|
-
app.i18n.define(
|
|
191
|
+
app.i18n.define(
|
|
192
|
+
"$zh-CN",
|
|
193
|
+
"commands.help.messages.global-epilog",
|
|
194
|
+
"",
|
|
195
|
+
);
|
|
167
196
|
await app.start();
|
|
168
197
|
|
|
169
198
|
const client = app.mock.client("123");
|
|
@@ -203,7 +232,9 @@ describe("@koishi-ce/plugin-help", () => {
|
|
|
203
232
|
const app = new App();
|
|
204
233
|
app.plugin(help);
|
|
205
234
|
app.plugin(mock);
|
|
206
|
-
app
|
|
235
|
+
app
|
|
236
|
+
.command("test <arg>", { checkArgCount: true })
|
|
237
|
+
.action(() => "pass");
|
|
207
238
|
await app.start();
|
|
208
239
|
|
|
209
240
|
const client = app.mock.client("123");
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (c) 2019-present Shigma and Koishijs contributors.
|
|
3
|
+
// Copyright (c) 2026-present Koishi-CE contributors.
|
|
4
|
+
|
|
1
5
|
/**
|
|
2
6
|
* 帮助指令插件(help)。
|
|
3
7
|
*
|
|
@@ -48,7 +52,9 @@ declare module "@koishi-ce/koishi" {
|
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
namespace Argv {
|
|
51
|
-
interface OptionConfig<
|
|
55
|
+
interface OptionConfig<
|
|
56
|
+
T extends Argv.Type = Argv.Type,
|
|
57
|
+
> {
|
|
52
58
|
/** 在帮助中隐藏此选项 */
|
|
53
59
|
hidden?: Computed<boolean>;
|
|
54
60
|
/** 本地化参数 */
|
|
@@ -72,14 +78,19 @@ export interface Config {
|
|
|
72
78
|
}
|
|
73
79
|
|
|
74
80
|
export const Config: Schema<Config> = Schema.object({
|
|
75
|
-
shortcut: Schema.boolean()
|
|
81
|
+
shortcut: Schema.boolean()
|
|
82
|
+
.default(true)
|
|
83
|
+
.description("是否启用快捷调用。"),
|
|
76
84
|
options: Schema.boolean()
|
|
77
85
|
.default(true)
|
|
78
86
|
.description("是否为每个指令添加 `-h, --help` 选项。"),
|
|
79
87
|
});
|
|
80
88
|
|
|
81
89
|
/** 在当前会话中转执行 help 指令(供 -h 选项与无 action 的指令复用) */
|
|
82
|
-
function executeHelp(
|
|
90
|
+
function executeHelp(
|
|
91
|
+
session: Session<never, never>,
|
|
92
|
+
name: string,
|
|
93
|
+
) {
|
|
83
94
|
if (!session.app.$commander.get("help")) return;
|
|
84
95
|
return session.execute({
|
|
85
96
|
name: "help",
|
|
@@ -114,7 +125,9 @@ export function apply(ctx: Context, config: Config) {
|
|
|
114
125
|
hidden: Schema.computed(Schema.boolean())
|
|
115
126
|
.description("在帮助菜单中隐藏指令。")
|
|
116
127
|
.default(false),
|
|
117
|
-
params: Schema.any()
|
|
128
|
+
params: Schema.any()
|
|
129
|
+
.description("帮助信息的本地化参数。")
|
|
130
|
+
.hidden(),
|
|
118
131
|
}),
|
|
119
132
|
900,
|
|
120
133
|
);
|
|
@@ -125,7 +138,9 @@ export function apply(ctx: Context, config: Config) {
|
|
|
125
138
|
hidden: Schema.computed(Schema.boolean())
|
|
126
139
|
.description("在帮助菜单中隐藏选项。")
|
|
127
140
|
.default(false),
|
|
128
|
-
params: Schema.any()
|
|
141
|
+
params: Schema.any()
|
|
142
|
+
.description("帮助信息的本地化参数。")
|
|
143
|
+
.hidden(),
|
|
129
144
|
}),
|
|
130
145
|
900,
|
|
131
146
|
);
|
|
@@ -139,7 +154,14 @@ export function apply(ctx: Context, config: Config) {
|
|
|
139
154
|
// 指令执行前的拦截:带 -h 或指令本身没有 action 时,转而输出帮助
|
|
140
155
|
ctx.before(
|
|
141
156
|
"command/execute",
|
|
142
|
-
(
|
|
157
|
+
(
|
|
158
|
+
argv: Argv<
|
|
159
|
+
never,
|
|
160
|
+
never,
|
|
161
|
+
unknown[],
|
|
162
|
+
{ help?: boolean }
|
|
163
|
+
>,
|
|
164
|
+
) => {
|
|
143
165
|
const { command, options, session } = argv;
|
|
144
166
|
if (!command || !session || !options) return;
|
|
145
167
|
if (options["help"] && command._options["help"]) {
|
|
@@ -158,16 +180,24 @@ export function apply(ctx: Context, config: Config) {
|
|
|
158
180
|
* @param target 用户输入的指令名或快捷调用文本
|
|
159
181
|
* @returns 指令对象;仅有模糊命中时返回候选列表
|
|
160
182
|
*/
|
|
161
|
-
function findCommand(
|
|
183
|
+
function findCommand(
|
|
184
|
+
target: string,
|
|
185
|
+
session: Session<never, never>,
|
|
186
|
+
) {
|
|
162
187
|
const command = $.resolve(target, session);
|
|
163
188
|
if (command?.ctx.filter(session)) return command;
|
|
164
189
|
|
|
165
190
|
// 指令名未命中:转为在各语言的指令快捷调用文本中检索
|
|
166
191
|
const data = ctx.i18n
|
|
167
192
|
.find("commands.(name).shortcuts.(variant)", target)
|
|
168
|
-
.map((item) => ({
|
|
193
|
+
.map((item) => ({
|
|
194
|
+
...item,
|
|
195
|
+
command: $.resolve(item.data.name, session),
|
|
196
|
+
}))
|
|
169
197
|
.filter((item) => item.command?.match(session));
|
|
170
|
-
const perfect = data.filter(
|
|
198
|
+
const perfect = data.filter(
|
|
199
|
+
(item) => item.similarity === 1,
|
|
200
|
+
);
|
|
171
201
|
if (!perfect.length) return data;
|
|
172
202
|
return perfect[0]?.command;
|
|
173
203
|
}
|
|
@@ -175,7 +205,9 @@ export function apply(ctx: Context, config: Config) {
|
|
|
175
205
|
// 字段收集器:help 指令自身只用 authority,
|
|
176
206
|
// 但被查询的目标指令可能声明了额外的 user / channel 观察字段
|
|
177
207
|
const createCollector =
|
|
178
|
-
<T extends "user" | "channel">(
|
|
208
|
+
<T extends "user" | "channel">(
|
|
209
|
+
key: T,
|
|
210
|
+
): FieldCollector<T> =>
|
|
179
211
|
(argv, fields) => {
|
|
180
212
|
const { args, session } = argv;
|
|
181
213
|
const [target] = args ?? [];
|
|
@@ -186,7 +218,12 @@ export function apply(ctx: Context, config: Config) {
|
|
|
186
218
|
if (result) {
|
|
187
219
|
session.collect(
|
|
188
220
|
key,
|
|
189
|
-
{
|
|
221
|
+
{
|
|
222
|
+
...argv,
|
|
223
|
+
command: result,
|
|
224
|
+
args: [],
|
|
225
|
+
options: { help: true },
|
|
226
|
+
},
|
|
190
227
|
fields,
|
|
191
228
|
);
|
|
192
229
|
}
|
|
@@ -196,14 +233,22 @@ export function apply(ctx: Context, config: Config) {
|
|
|
196
233
|
if (!command) continue;
|
|
197
234
|
session.collect(
|
|
198
235
|
key,
|
|
199
|
-
{
|
|
236
|
+
{
|
|
237
|
+
...argv,
|
|
238
|
+
command,
|
|
239
|
+
args: [],
|
|
240
|
+
options: { help: true },
|
|
241
|
+
},
|
|
200
242
|
fields,
|
|
201
243
|
);
|
|
202
244
|
}
|
|
203
245
|
};
|
|
204
246
|
|
|
205
247
|
/** 推断用户输入对应的指令;仅有模糊命中时发起相似度建议(“您要找的是不是…”) */
|
|
206
|
-
async function inferCommand(
|
|
248
|
+
async function inferCommand(
|
|
249
|
+
target: string,
|
|
250
|
+
session: Session,
|
|
251
|
+
) {
|
|
207
252
|
const result = findCommand(target, session);
|
|
208
253
|
if (!Array.isArray(result)) return result;
|
|
209
254
|
|
|
@@ -223,7 +268,11 @@ export function apply(ctx: Context, config: Config) {
|
|
|
223
268
|
filter: (name) => {
|
|
224
269
|
const command = $.resolve(name, session);
|
|
225
270
|
if (!command) return false;
|
|
226
|
-
return ctx.permissions.test(
|
|
271
|
+
return ctx.permissions.test(
|
|
272
|
+
`command:${command.name}`,
|
|
273
|
+
session,
|
|
274
|
+
cache,
|
|
275
|
+
);
|
|
227
276
|
},
|
|
228
277
|
});
|
|
229
278
|
if (!name) return;
|
|
@@ -232,7 +281,10 @@ export function apply(ctx: Context, config: Config) {
|
|
|
232
281
|
|
|
233
282
|
// 主指令:无参数时列出全局指令清单,带参数时输出目标指令的详细帮助
|
|
234
283
|
const cmd = ctx
|
|
235
|
-
.command("help [command:string]", {
|
|
284
|
+
.command("help [command:string]", {
|
|
285
|
+
authority: 0,
|
|
286
|
+
...config,
|
|
287
|
+
})
|
|
236
288
|
.userFields(["authority"])
|
|
237
289
|
.userFields(createCollector("user"))
|
|
238
290
|
.channelFields(createCollector("channel"))
|
|
@@ -241,25 +293,40 @@ export function apply(ctx: Context, config: Config) {
|
|
|
241
293
|
if (!session || !options) return;
|
|
242
294
|
if (!target) {
|
|
243
295
|
const prefix =
|
|
244
|
-
session.resolve(
|
|
245
|
-
|
|
296
|
+
session.resolve(
|
|
297
|
+
session.app.koishi.config.prefix,
|
|
298
|
+
)?.[0] ?? "";
|
|
299
|
+
const commands = $._commandList.filter(
|
|
300
|
+
(cmd) => cmd.parent === null,
|
|
301
|
+
);
|
|
246
302
|
const output = await formatCommands(
|
|
247
303
|
".global-prolog",
|
|
248
304
|
session,
|
|
249
305
|
commands,
|
|
250
306
|
options as HelpOptions,
|
|
251
307
|
);
|
|
252
|
-
const epilog = session.text(".global-epilog", [
|
|
308
|
+
const epilog = session.text(".global-epilog", [
|
|
309
|
+
prefix,
|
|
310
|
+
]);
|
|
253
311
|
if (epilog) output.push(epilog);
|
|
254
312
|
return output.filter(Boolean).join("\n");
|
|
255
313
|
}
|
|
256
314
|
|
|
257
315
|
const command = await inferCommand(target, session);
|
|
258
316
|
if (!command) return;
|
|
259
|
-
if (
|
|
317
|
+
if (
|
|
318
|
+
!(await ctx.permissions.test(
|
|
319
|
+
`command:${command.name}`,
|
|
320
|
+
session,
|
|
321
|
+
))
|
|
322
|
+
) {
|
|
260
323
|
return session.text("internal.low-authority");
|
|
261
324
|
}
|
|
262
|
-
return showHelp(
|
|
325
|
+
return showHelp(
|
|
326
|
+
command,
|
|
327
|
+
session,
|
|
328
|
+
options as HelpOptions,
|
|
329
|
+
);
|
|
263
330
|
});
|
|
264
331
|
|
|
265
332
|
// 注册全局快捷调用“帮助”(具体文本由各语言的 i18n 文本提供)
|
|
@@ -274,12 +341,23 @@ function* getCommands(
|
|
|
274
341
|
showHidden = false,
|
|
275
342
|
): Generator<Command> {
|
|
276
343
|
for (const command of commands) {
|
|
277
|
-
if (
|
|
344
|
+
if (
|
|
345
|
+
!showHidden &&
|
|
346
|
+
session.resolve(command.config.hidden)
|
|
347
|
+
)
|
|
348
|
+
continue;
|
|
278
349
|
// 自身可用则产出,否则下钻子指令(子指令可能单独可用)
|
|
279
|
-
if (
|
|
350
|
+
if (
|
|
351
|
+
command.match(session) &&
|
|
352
|
+
Object.keys(command._aliases).length
|
|
353
|
+
) {
|
|
280
354
|
yield command;
|
|
281
355
|
} else {
|
|
282
|
-
yield* getCommands(
|
|
356
|
+
yield* getCommands(
|
|
357
|
+
session,
|
|
358
|
+
command.children,
|
|
359
|
+
showHidden,
|
|
360
|
+
);
|
|
283
361
|
}
|
|
284
362
|
}
|
|
285
363
|
}
|
|
@@ -293,7 +371,9 @@ async function formatCommands(
|
|
|
293
371
|
) {
|
|
294
372
|
const cache = new Map<string, Promise<boolean>>();
|
|
295
373
|
// 第一步:按可见性过滤
|
|
296
|
-
children = Array.from(
|
|
374
|
+
children = Array.from(
|
|
375
|
+
getCommands(session, children, options.showHidden),
|
|
376
|
+
);
|
|
297
377
|
// 第二步:按权限过滤(并行检测并缓存结果)
|
|
298
378
|
children = (
|
|
299
379
|
await Promise.all(
|
|
@@ -312,18 +392,27 @@ async function formatCommands(
|
|
|
312
392
|
.filter(([, result]) => result)
|
|
313
393
|
.map(([command]) => command);
|
|
314
394
|
// 第三步:按显示名排序
|
|
315
|
-
children.sort((a, b) =>
|
|
395
|
+
children.sort((a, b) =>
|
|
396
|
+
a.displayName > b.displayName ? 1 : -1,
|
|
397
|
+
);
|
|
316
398
|
if (!children.length) return [];
|
|
317
399
|
|
|
318
|
-
const prefix =
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
400
|
+
const prefix =
|
|
401
|
+
session.resolve(
|
|
402
|
+
session.app.koishi.config.prefix,
|
|
403
|
+
)?.[0] ?? "";
|
|
404
|
+
const output = children.map(
|
|
405
|
+
({ name, displayName, config }) => {
|
|
406
|
+
let output = ` ${prefix}${displayName.replace(/\./g, " ")}`;
|
|
407
|
+
output += ` ${session.text([`commands.${name}.description`, ""], config.params)}`;
|
|
408
|
+
return output;
|
|
409
|
+
},
|
|
410
|
+
);
|
|
324
411
|
const hints: string[] = [];
|
|
325
412
|
const hintText = hints.length
|
|
326
|
-
? session.text("general.paren", [
|
|
413
|
+
? session.text("general.paren", [
|
|
414
|
+
hints.join(session.text("general.comma")),
|
|
415
|
+
])
|
|
327
416
|
: "";
|
|
328
417
|
output.unshift(session.text(path, [hintText]));
|
|
329
418
|
return output;
|
|
@@ -334,7 +423,10 @@ function getOptionVisibility(
|
|
|
334
423
|
option: Argv.OptionConfig,
|
|
335
424
|
session: Session<"authority">,
|
|
336
425
|
) {
|
|
337
|
-
if (
|
|
426
|
+
if (
|
|
427
|
+
session.user &&
|
|
428
|
+
(option.authority ?? 0) > session.user.authority
|
|
429
|
+
) {
|
|
338
430
|
return false;
|
|
339
431
|
}
|
|
340
432
|
return !session.resolve(option.hidden);
|
|
@@ -346,7 +438,8 @@ function getOptions(
|
|
|
346
438
|
session: Session<"authority">,
|
|
347
439
|
config: HelpOptions,
|
|
348
440
|
) {
|
|
349
|
-
if (command.config.hideOptions && !config.showHidden)
|
|
441
|
+
if (command.config.hideOptions && !config.showHidden)
|
|
442
|
+
return [];
|
|
350
443
|
const options = config.showHidden
|
|
351
444
|
? Object.values(command._options)
|
|
352
445
|
: Object.values(command._options).filter((option) =>
|
|
@@ -356,20 +449,37 @@ function getOptions(
|
|
|
356
449
|
|
|
357
450
|
const output: string[] = [];
|
|
358
451
|
Object.values(command._options).forEach((option) => {
|
|
359
|
-
function pushOption(
|
|
360
|
-
|
|
452
|
+
function pushOption(
|
|
453
|
+
option: Argv.OptionVariant,
|
|
454
|
+
name: string,
|
|
455
|
+
) {
|
|
456
|
+
if (
|
|
457
|
+
!config.showHidden &&
|
|
458
|
+
!getOptionVisibility(option, session)
|
|
459
|
+
)
|
|
460
|
+
return;
|
|
361
461
|
let line = `${h.escape(option.syntax)}`;
|
|
362
462
|
const description = session.text(
|
|
363
|
-
option.descPath ?? [
|
|
463
|
+
option.descPath ?? [
|
|
464
|
+
`commands.${command.name}.options.${name}`,
|
|
465
|
+
"",
|
|
466
|
+
],
|
|
364
467
|
option.params,
|
|
365
468
|
);
|
|
366
469
|
if (description) line += ` ${description}`;
|
|
367
|
-
line = command.ctx.chain(
|
|
470
|
+
line = command.ctx.chain(
|
|
471
|
+
"help/option",
|
|
472
|
+
line,
|
|
473
|
+
option,
|
|
474
|
+
command,
|
|
475
|
+
session,
|
|
476
|
+
);
|
|
368
477
|
output.push(` ${line}`);
|
|
369
478
|
}
|
|
370
479
|
|
|
371
480
|
// 无值选项直接输出;带值选项再逐个输出其语法变体
|
|
372
|
-
if (!("value" in option))
|
|
481
|
+
if (!("value" in option))
|
|
482
|
+
pushOption(option, option.name ?? "");
|
|
373
483
|
for (const value in option.variants) {
|
|
374
484
|
const variant = option.variants[value];
|
|
375
485
|
if (!variant) continue;
|
|
@@ -390,7 +500,8 @@ async function showHelp(
|
|
|
390
500
|
) {
|
|
391
501
|
const output = [
|
|
392
502
|
session.text(".command-title", [
|
|
393
|
-
command.displayName.replace(/\./g, " ") +
|
|
503
|
+
command.displayName.replace(/\./g, " ") +
|
|
504
|
+
command.declaration,
|
|
394
505
|
]),
|
|
395
506
|
];
|
|
396
507
|
|
|
@@ -402,11 +513,18 @@ async function showHelp(
|
|
|
402
513
|
|
|
403
514
|
// 有数据库时按目标指令的声明预取 user / channel 字段(usage 等钩子可能用到)
|
|
404
515
|
if (session.app.database) {
|
|
405
|
-
const argv: Argv = {
|
|
516
|
+
const argv: Argv = {
|
|
517
|
+
command,
|
|
518
|
+
args: [],
|
|
519
|
+
options: { help: true },
|
|
520
|
+
};
|
|
406
521
|
const userFields = session.collect("user", argv);
|
|
407
522
|
await session.observeUser(userFields);
|
|
408
523
|
if (!session.isDirect) {
|
|
409
|
-
const channelFields = session.collect(
|
|
524
|
+
const channelFields = session.collect(
|
|
525
|
+
"channel",
|
|
526
|
+
argv,
|
|
527
|
+
);
|
|
410
528
|
await session.observeChannel(channelFields);
|
|
411
529
|
}
|
|
412
530
|
}
|
|
@@ -414,12 +532,20 @@ async function showHelp(
|
|
|
414
532
|
if (Object.keys(command._aliases).length > 1) {
|
|
415
533
|
output.push(
|
|
416
534
|
session.text(".command-aliases", [
|
|
417
|
-
Array.from(
|
|
535
|
+
Array.from(
|
|
536
|
+
Object.keys(command._aliases).slice(1),
|
|
537
|
+
).join(","),
|
|
418
538
|
]),
|
|
419
539
|
);
|
|
420
540
|
}
|
|
421
541
|
|
|
422
|
-
session.app.emit(
|
|
542
|
+
session.app.emit(
|
|
543
|
+
session,
|
|
544
|
+
"help/command",
|
|
545
|
+
output,
|
|
546
|
+
command,
|
|
547
|
+
session,
|
|
548
|
+
);
|
|
423
549
|
|
|
424
550
|
if (command._usage) {
|
|
425
551
|
output.push(
|
|
@@ -441,7 +567,9 @@ async function showHelp(
|
|
|
441
567
|
if (command._examples.length) {
|
|
442
568
|
output.push(
|
|
443
569
|
session.text(".command-examples"),
|
|
444
|
-
...command._examples.map(
|
|
570
|
+
...command._examples.map(
|
|
571
|
+
(example) => ` ${example}`,
|
|
572
|
+
),
|
|
445
573
|
);
|
|
446
574
|
} else {
|
|
447
575
|
const text = session.text(
|