create-seedcord 0.5.0 → 0.6.0-next.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/dist/index.mjs +91 -91
- package/package.json +9 -5
- package/starters/gateway/Event/events/{{pascal name}}.ts.hbs +9 -0
- package/starters/shared/Button/components/{{pascal name}}.ts.hbs +18 -0
- package/starters/shared/Button/handlers/{{pascal name}}.ts.hbs +10 -0
- package/starters/shared/Modal/components/{{pascal name}}.ts.hbs +19 -0
- package/starters/shared/Modal/handlers/{{pascal name}}.ts.hbs +10 -0
- package/starters/shared/Select/components/{{pascal name}}.ts.hbs +16 -0
- package/starters/shared/Select/handlers/{{pascal name}}.ts.hbs +10 -0
- package/starters/shared/Slash/commands/{{pascal name}}.ts.hbs +10 -0
- package/starters/shared/Slash/handlers/{{pascal name}}.ts.hbs +8 -0
- package/templates/.vscode/settings.json.hbs +3 -3
- package/templates/AGENTS.md.hbs +8 -3
- package/templates/README.md.hbs +3 -1
- package/templates/eslint.config.ts.hbs +1 -1
- package/templates/gitattributes.hbs +1 -1
- package/templates/package.json.hbs +1 -0
- package/templates/prettierignore.hbs +2 -1
- package/templates/src/commands/Ping.ts.hbs +1 -1
- package/templates/src/events/Mentioned.ts.hbs +1 -1
- package/templates/src/events/Ready.ts.hbs +1 -1
- package/templates/src/handlers/Ping.ts.hbs +1 -1
- package/templates/src/plugins/Uptime.ts.hbs +2 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-seedcord",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.6.0-next.0",
|
|
5
5
|
"description": "Scaffold a new seedcord bot",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"discord",
|
|
@@ -34,18 +34,22 @@
|
|
|
34
34
|
"files": [
|
|
35
35
|
"bin",
|
|
36
36
|
"dist",
|
|
37
|
+
"starters",
|
|
37
38
|
"templates",
|
|
38
39
|
"package.json",
|
|
39
40
|
"README.md",
|
|
40
41
|
"LICENSE"
|
|
41
42
|
],
|
|
42
43
|
"devDependencies": {
|
|
43
|
-
"@seedcord/
|
|
44
|
-
"@seedcord/
|
|
45
|
-
"@seedcord/
|
|
44
|
+
"@seedcord/brand": "^0.0.0",
|
|
45
|
+
"@seedcord/cli-prompts": "^0.0.3-next.0",
|
|
46
|
+
"@seedcord/cli-templates": "^0.0.1-next.0",
|
|
47
|
+
"@seedcord/core": "^0.12.0-next.0",
|
|
48
|
+
"@seedcord/errors": "^0.15.0-next.0",
|
|
49
|
+
"@seedcord/eslint-config": "^3.0.1-next.0",
|
|
46
50
|
"@seedcord/tsconfig": "^3.0.0",
|
|
47
51
|
"@seedcord/tsdown-config": "^2.0.1",
|
|
48
|
-
"@seedcord/types": "^0.
|
|
52
|
+
"@seedcord/types": "^0.16.0-next.0",
|
|
49
53
|
"@seedcord/vitest-config": "^0.0.1",
|
|
50
54
|
"discord.js": "^14.27.0",
|
|
51
55
|
"handlebars": "^4.7.10",
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EventHandler, RegisterEvent } from '{{ transport }}';
|
|
2
|
+
import { Events } from 'discord.js';
|
|
3
|
+
|
|
4
|
+
@RegisterEvent([Events.{{ event }}])
|
|
5
|
+
export class {{ pascal name }} extends EventHandler<Events.{{ event }}> {
|
|
6
|
+
public async execute(): Promise<void> {
|
|
7
|
+
this.logger.info('{{ pascal name }} ran');
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ButtonBuilder } from '@discordjs/builders';
|
|
2
|
+
import { CustomId, RowComponent } from '{{ transport }}';
|
|
3
|
+
import { ButtonStyle } from 'discord-api-types/v10';
|
|
4
|
+
|
|
5
|
+
export const {{ pascal name }}Id = new CustomId('{{ kebab name }}');
|
|
6
|
+
|
|
7
|
+
export class {{ pascal name }}Row extends RowComponent<'button'> {
|
|
8
|
+
constructor() {
|
|
9
|
+
super('button');
|
|
10
|
+
|
|
11
|
+
this.instance.addComponents(
|
|
12
|
+
new ButtonBuilder()
|
|
13
|
+
.setCustomId({{ pascal name }}Id.encode({}))
|
|
14
|
+
.setLabel({{ quote label }})
|
|
15
|
+
.setStyle(ButtonStyle.Primary)
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ButtonHandler, ButtonRoute } from '{{ transport }}';
|
|
2
|
+
|
|
3
|
+
import { {{ pascal name }}Id } from '{{ importOf "components" }}';
|
|
4
|
+
|
|
5
|
+
@ButtonRoute({{ pascal name }}Id)
|
|
6
|
+
export class {{ pascal name }}Button extends ButtonHandler<[typeof {{ pascal name }}Id]> {
|
|
7
|
+
public async execute(): Promise<void> {
|
|
8
|
+
await this.reply({{ quote reply }});
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BuilderComponent, CustomId } from '{{ transport }}';
|
|
2
|
+
import { TextInputStyle } from 'discord-api-types/v10';
|
|
3
|
+
|
|
4
|
+
export const {{ pascal name }}Id = new CustomId('{{ kebab name }}');
|
|
5
|
+
|
|
6
|
+
export class {{ pascal name }}Modal extends BuilderComponent<'modal'> {
|
|
7
|
+
constructor() {
|
|
8
|
+
super('modal');
|
|
9
|
+
|
|
10
|
+
this.instance
|
|
11
|
+
.setCustomId({{ pascal name }}Id.encode({}))
|
|
12
|
+
.setTitle({{ quote title }})
|
|
13
|
+
.addLabelComponents((label) =>
|
|
14
|
+
label
|
|
15
|
+
.setLabel({{ quote question }})
|
|
16
|
+
.setTextInputComponent((input) => input.setCustomId('answer').setStyle(TextInputStyle.Short))
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ModalHandler, ModalRoute } from '{{ transport }}';
|
|
2
|
+
|
|
3
|
+
import { {{ pascal name }}Id } from '{{ importOf "components" }}';
|
|
4
|
+
|
|
5
|
+
@ModalRoute({{ pascal name }}Id)
|
|
6
|
+
export class {{ pascal name }}Submit extends ModalHandler<[typeof {{ pascal name }}Id]> {
|
|
7
|
+
public async execute(): Promise<void> {
|
|
8
|
+
await this.reply(this.fields.getTextInputValue('answer'));
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { StringSelectMenuBuilder } from '@discordjs/builders';
|
|
2
|
+
import { CustomId, RowComponent } from '{{ transport }}';
|
|
3
|
+
|
|
4
|
+
export const {{ pascal name }}Id = new CustomId('{{ kebab name }}');
|
|
5
|
+
|
|
6
|
+
export class {{ pascal name }}Menu extends RowComponent<'menu_string'> {
|
|
7
|
+
constructor() {
|
|
8
|
+
super('menu_string');
|
|
9
|
+
|
|
10
|
+
this.instance.addComponents(
|
|
11
|
+
new StringSelectMenuBuilder()
|
|
12
|
+
.setCustomId({{ pascal name }}Id.encode({}))
|
|
13
|
+
.addOptions({{#each choices}}{ label: {{ quote this }}, value: '{{ kebab this }}' }{{#unless @last}}, {{/unless}}{{/each}})
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { StringMenuHandler, StringMenuRoute } from '{{ transport }}';
|
|
2
|
+
|
|
3
|
+
import { {{ pascal name }}Id } from '{{ importOf "components" }}';
|
|
4
|
+
|
|
5
|
+
@StringMenuRoute({{ pascal name }}Id)
|
|
6
|
+
export class {{ pascal name }}Select extends StringMenuHandler<[typeof {{ pascal name }}Id]> {
|
|
7
|
+
public async execute(): Promise<void> {
|
|
8
|
+
await this.reply(this.values.join(', '));
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BuilderComponent, RegisterCommand } from '{{ transport }}';
|
|
2
|
+
|
|
3
|
+
@RegisterCommand()
|
|
4
|
+
export class {{ pascal name }} extends BuilderComponent<'command'> {
|
|
5
|
+
constructor() {
|
|
6
|
+
super('command');
|
|
7
|
+
|
|
8
|
+
this.instance.setName('{{ kebab name }}').setDescription({{ quote description }});
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files.watcherExclude": {
|
|
3
|
-
"**/seedcord-gen.
|
|
3
|
+
"**/seedcord-gen.ts": true,
|
|
4
4
|
"**/.seedcord/**": true
|
|
5
5
|
},
|
|
6
6
|
"search.exclude": {
|
|
7
|
-
"**/seedcord-gen.
|
|
7
|
+
"**/seedcord-gen.ts": true
|
|
8
8
|
},
|
|
9
9
|
"files.readonlyInclude": {
|
|
10
|
-
"**/seedcord-gen.
|
|
10
|
+
"**/seedcord-gen.ts": true,
|
|
11
11
|
"**/.seedcord/**": true
|
|
12
12
|
}
|
|
13
13
|
}
|
package/templates/AGENTS.md.hbs
CHANGED
|
@@ -10,13 +10,13 @@ Rules for an AI coding agent working in this repo.
|
|
|
10
10
|
|
|
11
11
|
The API reference is at <https://seedcord.org/docs>, one page per symbol.
|
|
12
12
|
|
|
13
|
-
This project runs on the {{#if isGateway}}gateway{{else}}http{{/if}} transport{{#if isEdge}} on Cloudflare Workers{{/if}} and imports everything from `{{
|
|
13
|
+
This project runs on the {{#if isGateway}}gateway{{else}}http{{/if}} transport{{#if isEdge}} on Cloudflare Workers{{/if}} and imports everything from `{{ transport }}`. A page marks anything that differs between the two transports.
|
|
14
14
|
|
|
15
15
|
## How a command works here
|
|
16
16
|
|
|
17
17
|
A command takes two files. One declares what Discord shows people. The other answers it, as a handler class carrying a route decorator. seedcord reads those decorators at startup and dispatches every interaction itself.
|
|
18
18
|
|
|
19
|
-
Run `{{ pm.run }} codegen` after you add a command or change its options. It writes `src/seedcord-gen.
|
|
19
|
+
Run `{{ pm.run }} codegen` after you add a command or change its options. It writes `src/seedcord-gen.ts`, which types `this.options`. That file is committed.
|
|
20
20
|
|
|
21
21
|
## Where things go
|
|
22
22
|
|
|
@@ -30,6 +30,7 @@ Run `{{ pm.run }} codegen` after you add a command or change its options. It wri
|
|
|
30
30
|
| `src/events/` | handlers for things happening in a server |
|
|
31
31
|
{{/if}}
|
|
32
32
|
| `src/bot.ts` | the config |
|
|
33
|
+
| `templates/` | a template for each kind of file, like a command or a button. Copy its shape when you add one |
|
|
33
34
|
|
|
34
35
|
<!-- prettier-ignore-end -->
|
|
35
36
|
|
|
@@ -41,6 +42,10 @@ Anything that holds a connection, keeps state between interactions, or runs in t
|
|
|
41
42
|
|
|
42
43
|
Never import from a seedcord path ending in `/internal`, like `@seedcord/core/internal`. Those paths wire seedcord's own packages together and change without notice. If the only way to do something is through one of those imports, tell the user so they can open an issue at <https://github.com/seedcord/seedcord/issues>.
|
|
43
44
|
|
|
45
|
+
## Trying a change
|
|
46
|
+
|
|
47
|
+
`{{ pm.run }} dev` runs the bot against Discord and swaps in a handler when you save it. When you start it without a terminal, it prints each log line as JSON and takes commands on stdin, like `{"do":"restart"}`. Run it in the background, ask the user to run the command in Discord, then read the lines it logged. <https://seedcord.org/guide/tooling/dev.md> lists the commands.
|
|
48
|
+
|
|
44
49
|
## Before you call it done
|
|
45
50
|
|
|
46
|
-
Run `{{ pm.run }} tc` and `{{ pm.run }} lint`. A wrong route or a wrong option name is a compile error, so a green type-check catches most of what an invented API gets wrong.
|
|
51
|
+
Run `{{ pm.run }} tc` and `{{ pm.run }} lint`. A wrong route or a wrong option name is a compile error, so a green type-check catches most of what an invented API gets wrong. If the change alters what the bot sends or keeps, try it under `{{ pm.run }} dev` too.
|
package/templates/README.md.hbs
CHANGED
|
@@ -24,7 +24,8 @@ That starts the dev server with hot reload{{#unless isGateway}} and opens a tunn
|
|
|
24
24
|
| `{{ pm.run }} build` | compile to `dist/` |
|
|
25
25
|
| `{{ pm.run }} start` | run the compiled build |
|
|
26
26
|
{{/if}}
|
|
27
|
-
| `{{ pm.run }} codegen` | regenerate `src/seedcord-gen.
|
|
27
|
+
| `{{ pm.run }} codegen` | regenerate `src/seedcord-gen.ts` |
|
|
28
|
+
| `{{ pm.run }} make` | write a new command, button, select menu{{#if isGateway}}, modal, or event{{else}}, or modal{{/if}} from `templates/` |
|
|
28
29
|
{{#if isEdge}}
|
|
29
30
|
| `{{ pm.run }} types` | regenerate the binding types in `.cloudflare/types/` |
|
|
30
31
|
{{/if}}
|
|
@@ -78,6 +79,7 @@ After that, `{{ pm.run }} deploy` is enough. `TESTING_GUILD_IDS` can stay empty
|
|
|
78
79
|
- `src/events/` holds event handlers for the things happening in a server.
|
|
79
80
|
{{/if}}
|
|
80
81
|
- `src/bot.ts` is the config.
|
|
82
|
+
- `templates/` holds the templates `{{ pm.run }} make` writes new files from. [Templates](https://seedcord.org/guide/tooling/make) shows how to change them or add your own.
|
|
81
83
|
|
|
82
84
|
## Docs
|
|
83
85
|
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
seedcord-gen.
|
|
1
|
+
seedcord-gen.ts
|
|
2
|
+
templates/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{{#if isGateway}}
|
|
2
2
|
{{#unless hasMessages}}
|
|
3
|
-
import { EventHandler, RegisterEvent } from '{{
|
|
3
|
+
import { EventHandler, RegisterEvent } from '{{ transport }}';
|
|
4
4
|
import { Events } from 'discord.js';
|
|
5
5
|
|
|
6
6
|
@RegisterEvent([Events.ClientReady, { frequency: 'once' }])
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SlashHandler, SlashRoute, timestampFromSnowflake, toEpochSeconds } from '{{
|
|
1
|
+
import { SlashHandler, SlashRoute, timestampFromSnowflake, toEpochSeconds } from '{{ transport }}';
|
|
2
2
|
|
|
3
3
|
@SlashRoute('ping')
|
|
4
4
|
export class Ping extends SlashHandler<'ping'> {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Plugin } from '{{
|
|
1
|
+
import { Plugin } from '{{ transport }}';
|
|
2
2
|
|
|
3
|
-
import type { EpochMs } from '{{
|
|
3
|
+
import type { EpochMs } from '{{ transport }}';
|
|
4
4
|
|
|
5
5
|
export class Uptime extends Plugin {
|
|
6
6
|
public startedAt = 0 as EpochMs;
|