@sapphire/cli 1.6.0-next.afa4afb.0 → 1.6.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/CHANGELOG.md +26 -0
- package/dist/commands/generate.js +10 -2
- package/dist/commands/init.js +3 -1
- package/dist/prompts/PromptInit.js +17 -0
- package/dist/prompts/PromptNew.js +0 -1
- package/package.json +5 -1
- package/templates/.sapphirerc.json.sapphire +1 -0
- package/templates/.sapphirerc.yml.sapphire +1 -0
- package/templates/components/autocompleteinteractionhandler.js.sapphire +50 -0
- package/templates/components/autocompleteinteractionhandler.ts.sapphire +32 -0
- package/templates/components/buttoninteractionhandler.js.sapphire +39 -0
- package/templates/components/buttoninteractionhandler.ts.sapphire +24 -0
- package/templates/components/modalinteractionhandler.js.sapphire +39 -0
- package/templates/components/modalinteractionhandler.ts.sapphire +23 -0
- package/templates/components/route.js.sapphire +1 -0
- package/templates/components/selectmenuinteractionhandler.js.sapphire +39 -0
- package/templates/components/selectmenuinteractionhandler.ts.sapphire +23 -0
- package/templates/schemas/.sapphirerc.scheme.json +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
# [1.6.0](https://github.com/sapphiredev/cli/compare/v1.5.0...v1.6.0) - (2023-04-12)
|
|
6
|
+
|
|
7
|
+
## 🏠 Refactor
|
|
8
|
+
|
|
9
|
+
- Remove `with-docker` template ([1b485f8](https://github.com/sapphiredev/cli/commit/1b485f836d656022dd761cc13862fa9a970142a7))
|
|
10
|
+
- Stricter typing for config parsing ([ab0efb3](https://github.com/sapphiredev/cli/commit/ab0efb3c602843b76bf64e135c0a448288227462))
|
|
11
|
+
- **new:** Make yarn v3 the default ([30499ea](https://github.com/sapphiredev/cli/commit/30499ea72a52c31220794f41da695494145c9b08))
|
|
12
|
+
- **CreateFileFromTemplate:** Better internal code naming ([3189772](https://github.com/sapphiredev/cli/commit/3189772a1b85ecc2bad2949ed8d339ff0541cebf))
|
|
13
|
+
- Better error messages for `generate` when template doesn't exist ([dc34e1e](https://github.com/sapphiredev/cli/commit/dc34e1ecda585eeb7024d716fbf401e8e18a9b93))
|
|
14
|
+
|
|
15
|
+
## 🐛 Bug Fixes
|
|
16
|
+
|
|
17
|
+
- Better error messages when creating file ([afa4afb](https://github.com/sapphiredev/cli/commit/afa4afba579f4877eecbe447a9728b71b4042b0c))
|
|
18
|
+
- Fixed JSON config file ([6fe3d0c](https://github.com/sapphiredev/cli/commit/6fe3d0c87a0ba70a802d73c73028832b77c0077b))
|
|
19
|
+
- **templates:** Adhere to strict type checking rules ([b455738](https://github.com/sapphiredev/cli/commit/b455738705d475d99357f758d9eeea505d43c2f2))
|
|
20
|
+
|
|
21
|
+
## 🚀 Features
|
|
22
|
+
|
|
23
|
+
- Add route in prompt (#220) ([60451d6](https://github.com/sapphiredev/cli/commit/60451d6e2c92ef42c07f592d2923177aa9386595))
|
|
24
|
+
- **templates:** Add interaction handler templates (#216) ([650ec76](https://github.com/sapphiredev/cli/commit/650ec76c3c17e2ae5d480994daac4b42bacbfc34))
|
|
25
|
+
- Add `interactive-tools` plugin for yarn v3 installs ([c417d97](https://github.com/sapphiredev/cli/commit/c417d970f139da1827fe914f69903f90df436907))
|
|
26
|
+
|
|
27
|
+
## 🪞 Styling
|
|
28
|
+
|
|
29
|
+
- Add prettierignore file ([2d24595](https://github.com/sapphiredev/cli/commit/2d24595e347a9e4d24ca6926e35fb60945e11725))
|
|
30
|
+
|
|
5
31
|
# [1.5.0](https://github.com/sapphiredev/cli/compare/v1.4.0...v1.5.0) - (2023-04-10)
|
|
6
32
|
|
|
7
33
|
## 🐛 Bug Fixes
|
|
@@ -40,8 +40,16 @@ async function fetchConfig() {
|
|
|
40
40
|
* @returns A string with a hint for the user
|
|
41
41
|
*/
|
|
42
42
|
function parseCommonHints(component) {
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
const newLine = '\n';
|
|
44
|
+
const lowerCaseComponent = component.toLowerCase();
|
|
45
|
+
if (lowerCaseComponent === 'command' || lowerCaseComponent === 'commands') {
|
|
46
|
+
return `${newLine}Hint: You wrote "${component}", instead of "messagecommand", "slashcommand", or "contextmenucommand"`;
|
|
47
|
+
}
|
|
48
|
+
if (lowerCaseComponent === 'interaction-handler' ||
|
|
49
|
+
lowerCaseComponent === 'interaction-handlers' ||
|
|
50
|
+
lowerCaseComponent === 'interactionhandler' ||
|
|
51
|
+
lowerCaseComponent === 'interactionhandlers') {
|
|
52
|
+
return `${newLine}Hint: You wrote "${component}", instead of "buttoninteractionhandler", "autocompleteinteractionhandler", "modalinteractionhandler", or "selectmenuinteractionhandler"`;
|
|
45
53
|
}
|
|
46
54
|
return '';
|
|
47
55
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -20,7 +20,9 @@ export default async () => {
|
|
|
20
20
|
arguments: response.arguments,
|
|
21
21
|
commands: response.commands,
|
|
22
22
|
listeners: response.listeners,
|
|
23
|
-
preconditions: response.preconditions
|
|
23
|
+
preconditions: response.preconditions,
|
|
24
|
+
'interaction-handlers': response['interaction-handlers'],
|
|
25
|
+
routes: response.routes ?? ''
|
|
24
26
|
},
|
|
25
27
|
customFileTemplates: {
|
|
26
28
|
enabled: response.cftEnabled,
|
|
@@ -47,6 +47,23 @@ export const PromptInit = [
|
|
|
47
47
|
message: 'Where do you store your preconditions? (do not include the base)',
|
|
48
48
|
initial: 'preconditions'
|
|
49
49
|
},
|
|
50
|
+
{
|
|
51
|
+
type: 'text',
|
|
52
|
+
name: 'interaction-handlers',
|
|
53
|
+
message: 'Where do you store your interaction handlers? (do not include the base)',
|
|
54
|
+
initial: 'interaction-handlers'
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
type: 'confirm',
|
|
58
|
+
name: 'rEnabled',
|
|
59
|
+
message: 'Would you use the api plugin?'
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
type: (prev) => (prev ? 'text' : null),
|
|
63
|
+
name: 'rLocation',
|
|
64
|
+
message: 'Where do you store your routes? (do not include the base)',
|
|
65
|
+
initial: 'routes'
|
|
66
|
+
},
|
|
50
67
|
{
|
|
51
68
|
type: 'confirm',
|
|
52
69
|
name: 'cftEnabled',
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const tsTemplates = [
|
|
2
2
|
{ title: 'Starter template (Recommended)', value: 'with-typescript-starter' },
|
|
3
3
|
{ title: 'Complete template', value: 'with-typescript-complete' },
|
|
4
|
-
{ title: 'with Docker', value: 'with-docker' },
|
|
5
4
|
{ title: 'with tsup', value: 'with-tsup' },
|
|
6
5
|
{ title: 'with SWC', value: 'with-swc' }
|
|
7
6
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sapphire/cli",
|
|
3
|
-
"version": "1.6.0
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "CLI for Sapphire Framework",
|
|
5
5
|
"author": "@sapphire",
|
|
6
6
|
"license": "MIT",
|
|
@@ -48,7 +48,10 @@
|
|
|
48
48
|
"@commitlint/config-conventional": "^17.4.4",
|
|
49
49
|
"@favware/cliff-jumper": "^2.0.0",
|
|
50
50
|
"@favware/npm-deprecate": "^1.0.7",
|
|
51
|
+
"@sapphire/decorators": "*",
|
|
51
52
|
"@sapphire/eslint-config": "^4.4.0",
|
|
53
|
+
"@sapphire/framework": "*",
|
|
54
|
+
"@sapphire/plugin-api": "*",
|
|
52
55
|
"@sapphire/prettier-config": "^1.4.5",
|
|
53
56
|
"@sapphire/ts-config": "^4.0.0",
|
|
54
57
|
"@types/js-yaml": "^4.0.5",
|
|
@@ -57,6 +60,7 @@
|
|
|
57
60
|
"@typescript-eslint/eslint-plugin": "^5.58.0",
|
|
58
61
|
"@typescript-eslint/parser": "^5.58.0",
|
|
59
62
|
"cz-conventional-changelog": "^3.3.0",
|
|
63
|
+
"discord.js": "*",
|
|
60
64
|
"eslint": "^8.38.0",
|
|
61
65
|
"eslint-config-prettier": "^8.8.0",
|
|
62
66
|
"eslint-plugin-prettier": "^4.2.1",
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{ "category": "interaction-handlers" }
|
|
2
|
+
---
|
|
3
|
+
const { InteractionHandler, InteractionHandlerTypes } = require('@sapphire/framework');
|
|
4
|
+
const { InteractionHandler, InteractionHandlerTypes } = require('@sapphire/framework');
|
|
5
|
+
|
|
6
|
+
class AutocompleteHandler extends InteractionHandler {
|
|
7
|
+
/**
|
|
8
|
+
* @param {InteractionHandler.Context} context
|
|
9
|
+
* @param {InteractionHandler.Options} options
|
|
10
|
+
*/
|
|
11
|
+
constructor(context, options) {
|
|
12
|
+
super(context, {
|
|
13
|
+
...options,
|
|
14
|
+
interactionHandlerType: InteractionHandlerTypes.Autocomplete
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {import('discord.js').AutocompleteInteraction} interaction
|
|
20
|
+
* @param {import('discord.js').ApplicationCommandOptionChoiceData[]} result
|
|
21
|
+
*/
|
|
22
|
+
async run(interaction, result) {
|
|
23
|
+
return interaction.respond(result);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {import('discord.js').AutocompleteInteraction} interaction
|
|
28
|
+
*/
|
|
29
|
+
async parse(interaction) {
|
|
30
|
+
// Only run this interaction for the command with ID '1000000000000000000'
|
|
31
|
+
if (interaction.commandId !== '1000000000000000000') return this.none();
|
|
32
|
+
// Get the focussed (current) option
|
|
33
|
+
const focusedOption = interaction.options.getFocused(true);
|
|
34
|
+
// Ensure that the option name is one that can be autocompleted, or return none if not.
|
|
35
|
+
switch (focusedOption.name) {
|
|
36
|
+
case 'search': {
|
|
37
|
+
// Search your API or similar. This is example code!
|
|
38
|
+
const searchResult = await myApi.searchForSomething(focusedOption.value);
|
|
39
|
+
// Map the search results to the structure required for Autocomplete
|
|
40
|
+
return this.some(searchResult.map((match) => ({ name: match.name, value: match.key })));
|
|
41
|
+
}
|
|
42
|
+
default:
|
|
43
|
+
return this.none();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
AutocompleteHandler
|
|
50
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{ "category": "interaction-handlers" }
|
|
2
|
+
---
|
|
3
|
+
import { ApplyOptions } from '@sapphire/decorators';
|
|
4
|
+
import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework';
|
|
5
|
+
import { AutocompleteInteraction, type ApplicationCommandOptionChoiceData } from 'discord.js';
|
|
6
|
+
|
|
7
|
+
@ApplyOptions<InteractionHandler.Options>({
|
|
8
|
+
interactionHandlerType: InteractionHandlerTypes.Autocomplete
|
|
9
|
+
})
|
|
10
|
+
export class AutocompleteHandler extends InteractionHandler {
|
|
11
|
+
public override async run(interaction: AutocompleteInteraction, result: ApplicationCommandOptionChoiceData[]) {
|
|
12
|
+
return interaction.respond(result);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public override async parse(interaction: AutocompleteInteraction) {
|
|
16
|
+
// Only run this interaction for the command with ID '1000000000000000000'
|
|
17
|
+
if (interaction.commandId !== '1000000000000000000') return this.none();
|
|
18
|
+
// Get the focussed (current) option
|
|
19
|
+
const focusedOption = interaction.options.getFocused(true);
|
|
20
|
+
// Ensure that the option name is one that can be autocompleted, or return none if not.
|
|
21
|
+
switch (focusedOption.name) {
|
|
22
|
+
case 'search': {
|
|
23
|
+
// Search your API or similar. This is example code!
|
|
24
|
+
const searchResult = await myApi.searchForSomething(focusedOption.value);
|
|
25
|
+
// Map the search results to the structure required for Autocomplete
|
|
26
|
+
return this.some(searchResult.map((match) => ({ name: match.name, value: match.key })));
|
|
27
|
+
}
|
|
28
|
+
default:
|
|
29
|
+
return this.none();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{ "category": "interaction-handlers" }
|
|
2
|
+
---
|
|
3
|
+
const { InteractionHandler, InteractionHandlerTypes } = require('@sapphire/framework');
|
|
4
|
+
|
|
5
|
+
class ButtonHandler extends InteractionHandler {
|
|
6
|
+
/**
|
|
7
|
+
* @param {InteractionHandler.Context} context
|
|
8
|
+
* @param {InteractionHandler.Options} options
|
|
9
|
+
*/
|
|
10
|
+
constructor(context, options) {
|
|
11
|
+
super(context, {
|
|
12
|
+
...options,
|
|
13
|
+
interactionHandlerType: InteractionHandlerTypes.Button
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {import('discord.js').ButtonInteraction} interaction
|
|
19
|
+
*/
|
|
20
|
+
async run(interaction) {
|
|
21
|
+
await interaction.reply({
|
|
22
|
+
content: 'Hello from a button interaction handler!',
|
|
23
|
+
// Let's make it so only the person who pressed the button can see this message!
|
|
24
|
+
ephemeral: true
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {import('discord.js').ButtonInteraction} interaction
|
|
30
|
+
*/
|
|
31
|
+
parse(interaction) {
|
|
32
|
+
if (interaction.customId !== 'my-awesome-button') return this.none();
|
|
33
|
+
return this.some();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = {
|
|
38
|
+
ButtonHandler
|
|
39
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{ "category": "interaction-handlers" }
|
|
2
|
+
---
|
|
3
|
+
import { ApplyOptions } from '@sapphire/decorators';
|
|
4
|
+
import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework';
|
|
5
|
+
import type { ButtonInteraction } from 'discord.js';
|
|
6
|
+
|
|
7
|
+
@ApplyOptions<InteractionHandler.Options>({
|
|
8
|
+
interactionHandlerType: InteractionHandlerTypes.Button
|
|
9
|
+
})
|
|
10
|
+
export class ButtonHandler extends InteractionHandler {
|
|
11
|
+
public async run(interaction: ButtonInteraction) {
|
|
12
|
+
await interaction.reply({
|
|
13
|
+
content: 'Hello from a button interaction handler!',
|
|
14
|
+
// Let's make it so only the person who pressed the button can see this message!
|
|
15
|
+
ephemeral: true
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public override parse(interaction: ButtonInteraction) {
|
|
20
|
+
if (interaction.customId !== 'my-awesome-button') return this.none();
|
|
21
|
+
|
|
22
|
+
return this.some();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{ "category": "interaction-handlers" }
|
|
2
|
+
---
|
|
3
|
+
const { InteractionHandler, InteractionHandlerTypes } = require('@sapphire/framework');
|
|
4
|
+
|
|
5
|
+
class ModalHandler extends InteractionHandler {
|
|
6
|
+
/**
|
|
7
|
+
* @param {InteractionHandler.Context} context
|
|
8
|
+
* @param {InteractionHandler.Options} options
|
|
9
|
+
*/
|
|
10
|
+
constructor(context, options) {
|
|
11
|
+
super(context, {
|
|
12
|
+
...options,
|
|
13
|
+
interactionHandlerType: InteractionHandlerTypes.ModalSubmit
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {import('discord.js').ModalSubmitInteraction} interaction
|
|
19
|
+
*/
|
|
20
|
+
async run(interaction) {
|
|
21
|
+
await interaction.reply({
|
|
22
|
+
content: 'Thank you for submitting the form!',
|
|
23
|
+
ephemeral: true
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {import('discord.js').ModalSubmitInteraction} interaction
|
|
29
|
+
*/
|
|
30
|
+
parse(interaction) {
|
|
31
|
+
if (interaction.customId !== 'hello-popup') return this.none();
|
|
32
|
+
|
|
33
|
+
return this.some();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = {
|
|
38
|
+
ModalHandler
|
|
39
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{ "category": "interaction-handlers" }
|
|
2
|
+
---
|
|
3
|
+
import { ApplyOptions } from '@sapphire/decorators';
|
|
4
|
+
import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework';
|
|
5
|
+
import type { ModalSubmitInteraction } from 'discord.js';
|
|
6
|
+
|
|
7
|
+
@ApplyOptions<InteractionHandler.Options>({
|
|
8
|
+
interactionHandlerType: InteractionHandlerTypes.ModalSubmit
|
|
9
|
+
})
|
|
10
|
+
export class ModalHandler extends InteractionHandler {
|
|
11
|
+
public async run(interaction: ModalSubmitInteraction) {
|
|
12
|
+
await interaction.reply({
|
|
13
|
+
content: 'Thank you for submitting the form!',
|
|
14
|
+
ephemeral: true
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public override parse(interaction: ModalSubmitInteraction) {
|
|
19
|
+
if (interaction.customId !== 'hello-popup') return this.none();
|
|
20
|
+
|
|
21
|
+
return this.some();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{ "category": "interaction-handlers" }
|
|
2
|
+
---
|
|
3
|
+
const { InteractionHandler, InteractionHandlerTypes } = require('@sapphire/framework');
|
|
4
|
+
|
|
5
|
+
class MenuHandler extends InteractionHandler {
|
|
6
|
+
/**
|
|
7
|
+
* @param {InteractionHandler.Context} context
|
|
8
|
+
* @param {InteractionHandler.Options} options
|
|
9
|
+
*/
|
|
10
|
+
constructor(context, options) {
|
|
11
|
+
super(context, {
|
|
12
|
+
...options,
|
|
13
|
+
interactionHandlerType: InteractionHandlerTypes.SelectMenu
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {import('discord.js').StringSelectMenuInteraction} interaction
|
|
19
|
+
*/
|
|
20
|
+
async run(interaction) {
|
|
21
|
+
await interaction.reply({
|
|
22
|
+
// Remember how we can have multiple values? Let's get the first one!
|
|
23
|
+
content: `You selected: ${interaction.values[0]}`
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {import('discord.js').StringSelectMenuInteraction} interaction
|
|
29
|
+
*/
|
|
30
|
+
parse(interaction) {
|
|
31
|
+
if (interaction.customId !== 'my-echo-select') return this.none();
|
|
32
|
+
|
|
33
|
+
return this.some();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = {
|
|
38
|
+
MenuHandler
|
|
39
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{ "category": "interaction-handlers" }
|
|
2
|
+
---
|
|
3
|
+
import { ApplyOptions } from '@sapphire/decorators';
|
|
4
|
+
import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework';
|
|
5
|
+
import type { StringSelectMenuInteraction } from 'discord.js';
|
|
6
|
+
|
|
7
|
+
@ApplyOptions<InteractionHandler.Options>({
|
|
8
|
+
interactionHandlerType: InteractionHandlerTypes.SelectMenu
|
|
9
|
+
})
|
|
10
|
+
export class MenuHandler extends InteractionHandler {
|
|
11
|
+
public override async run(interaction: StringSelectMenuInteraction) {
|
|
12
|
+
await interaction.reply({
|
|
13
|
+
// Remember how we can have multiple values? Let's get the first one!
|
|
14
|
+
content: `You selected: ${interaction.values[0]}`
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public override parse(interaction: StringSelectMenuInteraction) {
|
|
19
|
+
if (interaction.customId !== 'my-echo-select') return this.none();
|
|
20
|
+
|
|
21
|
+
return this.some();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -27,11 +27,14 @@
|
|
|
27
27
|
"preconditions": {
|
|
28
28
|
"type": "string"
|
|
29
29
|
},
|
|
30
|
+
"interaction-handlers": {
|
|
31
|
+
"type": "string"
|
|
32
|
+
},
|
|
30
33
|
"routes": {
|
|
31
34
|
"type": "string"
|
|
32
35
|
}
|
|
33
36
|
},
|
|
34
|
-
"required": ["base", "arguments", "commands", "listeners", "preconditions"]
|
|
37
|
+
"required": ["base", "arguments", "commands", "listeners", "preconditions", "interaction-handlers"]
|
|
35
38
|
},
|
|
36
39
|
"customFileTemplates": {
|
|
37
40
|
"description": "Settings about custom component (piece) templates",
|