yuzuha 0.1.7 → 0.2.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 +44 -0
- package/README.md +21 -4
- package/VERSIONING.md +78 -6
- package/assets/canvas/Inter-Bold.ttf +0 -0
- package/assets/canvas/Inter-Regular.ttf +0 -0
- package/assets/canvas/OFL.txt +92 -0
- package/assets/canvas/ORIGIN.md +8 -0
- package/benchmarks/rate-limits.mjs +138 -0
- package/benchmarks/results/rate-limits-comparison.json +273 -0
- package/bridges/lavalink/README.md +2 -2
- package/dist/canvas.d.ts +10 -0
- package/dist/canvas.d.ts.map +1 -0
- package/dist/canvas.js +11 -0
- package/dist/canvas.js.map +1 -0
- package/dist/cli/arguments.d.ts +5 -0
- package/dist/cli/arguments.d.ts.map +1 -1
- package/dist/cli/arguments.js +31 -6
- package/dist/cli/arguments.js.map +1 -1
- package/dist/cli/bot-template-catalog.d.ts +33 -0
- package/dist/cli/bot-template-catalog.d.ts.map +1 -0
- package/dist/cli/bot-template-catalog.js +20 -0
- package/dist/cli/bot-template-catalog.js.map +1 -0
- package/dist/cli/bot-template-commands.d.ts +2 -0
- package/dist/cli/bot-template-commands.d.ts.map +1 -0
- package/dist/cli/bot-template-commands.js +358 -0
- package/dist/cli/bot-template-commands.js.map +1 -0
- package/dist/cli/bot-template-content.d.ts +13 -0
- package/dist/cli/bot-template-content.d.ts.map +1 -0
- package/dist/cli/bot-template-content.js +69 -0
- package/dist/cli/bot-template-content.js.map +1 -0
- package/dist/cli/bot-template-feature-tests.d.ts +2 -0
- package/dist/cli/bot-template-feature-tests.d.ts.map +1 -0
- package/dist/cli/bot-template-feature-tests.js +165 -0
- package/dist/cli/bot-template-feature-tests.js.map +1 -0
- package/dist/cli/bot-template-tests.d.ts +3 -0
- package/dist/cli/bot-template-tests.d.ts.map +1 -0
- package/dist/cli/bot-template-tests.js +67 -0
- package/dist/cli/bot-template-tests.js.map +1 -0
- package/dist/cli/bot-templates.d.ts +3 -0
- package/dist/cli/bot-templates.d.ts.map +1 -0
- package/dist/cli/bot-templates.js +154 -0
- package/dist/cli/bot-templates.js.map +1 -0
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +7 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/scaffold.d.ts +3 -1
- package/dist/cli/scaffold.d.ts.map +1 -1
- package/dist/cli/scaffold.js +26 -8
- package/dist/cli/scaffold.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/arguments.js +2 -2
- package/dist/commands/arguments.js.map +1 -1
- package/dist/commands/context.d.ts +11 -0
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +13 -0
- package/dist/commands/context.js.map +1 -1
- package/dist/contracts.d.ts +1 -1
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/domain/canvas.d.ts +240 -0
- package/dist/domain/canvas.d.ts.map +1 -0
- package/dist/domain/canvas.js +226 -0
- package/dist/domain/canvas.js.map +1 -0
- package/dist/domain/embeds.d.ts +36 -0
- package/dist/domain/embeds.d.ts.map +1 -0
- package/dist/domain/embeds.js +259 -0
- package/dist/domain/embeds.js.map +1 -0
- package/dist/domain/message-query.d.ts +39 -0
- package/dist/domain/message-query.d.ts.map +1 -0
- package/dist/domain/message-query.js +108 -0
- package/dist/domain/message-query.js.map +1 -0
- package/dist/domain/messages.d.ts +89 -13
- package/dist/domain/messages.d.ts.map +1 -1
- package/dist/domain/messages.js.map +1 -1
- package/dist/framework/bot.d.ts +2 -1
- package/dist/framework/bot.d.ts.map +1 -1
- package/dist/framework/bot.js +34 -3
- package/dist/framework/bot.js.map +1 -1
- package/dist/framework/events.d.ts +12 -0
- package/dist/framework/events.d.ts.map +1 -1
- package/dist/framework/events.js.map +1 -1
- package/dist/framework/options.d.ts +2 -0
- package/dist/framework/options.d.ts.map +1 -1
- package/dist/framework/options.js.map +1 -1
- package/dist/framework/rate-limits.d.ts +1 -0
- package/dist/framework/rate-limits.d.ts.map +1 -1
- package/dist/framework/rate-limits.js +18 -8
- package/dist/framework/rate-limits.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/canvas/render.d.ts +3 -0
- package/dist/infrastructure/canvas/render.d.ts.map +1 -0
- package/dist/infrastructure/canvas/render.js +118 -0
- package/dist/infrastructure/canvas/render.js.map +1 -0
- package/dist/infrastructure/canvas/worker.mjs +286 -0
- package/dist/infrastructure/fluxer/payload.d.ts +6 -1
- package/dist/infrastructure/fluxer/payload.d.ts.map +1 -1
- package/dist/infrastructure/fluxer/payload.js +58 -19
- package/dist/infrastructure/fluxer/payload.js.map +1 -1
- package/dist/infrastructure/fluxer/resources/messages.d.ts.map +1 -1
- package/dist/infrastructure/fluxer/resources/messages.js +61 -4
- package/dist/infrastructure/fluxer/resources/messages.js.map +1 -1
- package/dist/infrastructure/fluxer/resources/threads.d.ts.map +1 -1
- package/dist/infrastructure/fluxer/resources/threads.js +9 -0
- package/dist/infrastructure/fluxer/resources/threads.js.map +1 -1
- package/dist/infrastructure/fluxer/transport.d.ts.map +1 -1
- package/dist/infrastructure/fluxer/transport.js +9 -5
- package/dist/infrastructure/fluxer/transport.js.map +1 -1
- package/dist/infrastructure/images/transform.d.ts.map +1 -1
- package/dist/infrastructure/images/transform.js +14 -9
- package/dist/infrastructure/images/transform.js.map +1 -1
- package/dist/infrastructure/process-budget.d.ts +3 -0
- package/dist/infrastructure/process-budget.d.ts.map +1 -0
- package/dist/infrastructure/process-budget.js +17 -0
- package/dist/infrastructure/process-budget.js.map +1 -0
- package/dist/ports/canvas.d.ts +5 -0
- package/dist/ports/canvas.d.ts.map +1 -0
- package/dist/ports/canvas.js +2 -0
- package/dist/ports/canvas.js.map +1 -0
- package/dist/ports/resources/messages.d.ts +17 -7
- package/dist/ports/resources/messages.d.ts.map +1 -1
- package/dist/ports/resources/messages.js.map +1 -1
- package/dist/ports/resources/threads.d.ts +6 -0
- package/dist/ports/resources/threads.d.ts.map +1 -1
- package/dist/ports/resources/threads.js.map +1 -1
- package/dist/scripting/builtins/canvas.d.ts +2 -0
- package/dist/scripting/builtins/canvas.d.ts.map +1 -0
- package/dist/scripting/builtins/canvas.js +118 -0
- package/dist/scripting/builtins/canvas.js.map +1 -0
- package/dist/scripting/builtins/embeds.d.ts +1 -2
- package/dist/scripting/builtins/embeds.d.ts.map +1 -1
- package/dist/scripting/builtins/embeds.js +90 -35
- package/dist/scripting/builtins/embeds.js.map +1 -1
- package/dist/scripting/builtins/index.d.ts.map +1 -1
- package/dist/scripting/builtins/index.js +4 -1
- package/dist/scripting/builtins/index.js.map +1 -1
- package/dist/scripting/builtins/language/objects.d.ts.map +1 -1
- package/dist/scripting/builtins/language/objects.js +2 -1
- package/dist/scripting/builtins/language/objects.js.map +1 -1
- package/dist/scripting/builtins/language/state.d.ts.map +1 -1
- package/dist/scripting/builtins/language/state.js +14 -9
- package/dist/scripting/builtins/language/state.js.map +1 -1
- package/dist/scripting/builtins/messages.js +3 -3
- package/dist/scripting/builtins/messages.js.map +1 -1
- package/dist/scripting/builtins/native-expressions.d.ts.map +1 -1
- package/dist/scripting/builtins/native-expressions.js +3 -1
- package/dist/scripting/builtins/native-expressions.js.map +1 -1
- package/dist/scripting/builtins/native-messages.d.ts.map +1 -1
- package/dist/scripting/builtins/native-messages.js +17 -0
- package/dist/scripting/builtins/native-messages.js.map +1 -1
- package/dist/scripting/builtins/native-threads.d.ts.map +1 -1
- package/dist/scripting/builtins/native-threads.js +8 -0
- package/dist/scripting/builtins/native-threads.js.map +1 -1
- package/dist/scripting/builtins/payload.d.ts +4 -1
- package/dist/scripting/builtins/payload.d.ts.map +1 -1
- package/dist/scripting/builtins/payload.js +127 -5
- package/dist/scripting/builtins/payload.js.map +1 -1
- package/dist/scripting/builtins/resource-extras.d.ts.map +1 -1
- package/dist/scripting/builtins/resource-extras.js +10 -2
- package/dist/scripting/builtins/resource-extras.js.map +1 -1
- package/dist/scripting/canvas-execution.d.ts +12 -0
- package/dist/scripting/canvas-execution.d.ts.map +1 -0
- package/dist/scripting/canvas-execution.js +14 -0
- package/dist/scripting/canvas-execution.js.map +1 -0
- package/dist/scripting/evaluator.d.ts +3 -0
- package/dist/scripting/evaluator.d.ts.map +1 -1
- package/dist/scripting/evaluator.js +45 -25
- package/dist/scripting/evaluator.js.map +1 -1
- package/dist/services/attachments.d.ts.map +1 -1
- package/dist/services/attachments.js +6 -4
- package/dist/services/attachments.js.map +1 -1
- package/dist/services/canvas.d.ts +43 -0
- package/dist/services/canvas.d.ts.map +1 -0
- package/dist/services/canvas.js +587 -0
- package/dist/services/canvas.js.map +1 -0
- package/dist/services/http.d.ts.map +1 -1
- package/dist/services/http.js +34 -44
- package/dist/services/http.js.map +1 -1
- package/dist/services/resource-authorization.d.ts.map +1 -1
- package/dist/services/resource-authorization.js +37 -6
- package/dist/services/resource-authorization.js.map +1 -1
- package/docs/API.md +13 -2
- package/docs/ARCHITECTURE.md +1 -1
- package/docs/BENCHMARKS.md +35 -0
- package/docs/BOT-BASES.md +168 -0
- package/docs/CANVAS.md +274 -0
- package/docs/CLI.md +26 -3
- package/docs/EMBEDS.md +153 -0
- package/docs/FUNCTION-GAPS.md +7 -6
- package/docs/FUNCTIONS.md +41 -6
- package/docs/HTTP.md +18 -0
- package/docs/IMAGES.md +13 -8
- package/docs/LANGUAGE.md +37 -0
- package/docs/MUSIC.md +3 -3
- package/docs/NATIVE.md +36 -3
- package/docs/PARITY-MATRIX.md +952 -0
- package/docs/PARITY.md +26 -10
- package/docs/PLAN.md +40 -1
- package/docs/QUICKSTART.md +18 -2
- package/docs/README.md +7 -2
- package/docs/STORAGE.md +3 -1
- package/docs/VALIDATION.md +55 -0
- package/editors/vscode/functions.json +248 -8
- package/editors/vscode/package.json +1 -1
- package/examples/canvas/fixtures/avatar.png +0 -0
- package/examples/canvas/functions/profile.yuzuha +15 -0
- package/examples/canvas/functions/ranking.yuzuha +46 -0
- package/examples/canvas/functions/welcome.yuzuha +10 -0
- package/examples/canvas/output/function-profile.png +0 -0
- package/examples/canvas/output/function-ranking.png +0 -0
- package/examples/canvas/output/function-welcome.png +0 -0
- package/examples/canvas/output/js-profile.png +0 -0
- package/examples/canvas/output/js-ranking.png +0 -0
- package/examples/canvas/output/js-welcome.png +0 -0
- package/examples/canvas/output/profile.png +0 -0
- package/examples/canvas/output/ranking.png +0 -0
- package/examples/canvas/output/welcome.png +0 -0
- package/examples/canvas/profile.d.mts +3 -0
- package/examples/canvas/profile.mjs +20 -0
- package/examples/canvas/profile.ts +34 -0
- package/examples/canvas/ranking.d.mts +5 -0
- package/examples/canvas/ranking.mjs +25 -0
- package/examples/canvas/ranking.ts +40 -0
- package/examples/canvas/render.ts +48 -0
- package/examples/canvas/welcome.d.mts +3 -0
- package/examples/canvas/welcome.mjs +14 -0
- package/examples/canvas/welcome.ts +27 -0
- package/examples/embeds/complete-embed-functions.ts +31 -0
- package/examples/embeds/complete-embed.ts +33 -0
- package/package.json +16 -5
- package/src/canvas.ts +20 -0
- package/src/cli/arguments.ts +26 -7
- package/src/cli/bot-template-catalog.ts +23 -0
- package/src/cli/bot-template-commands.ts +357 -0
- package/src/cli/bot-template-content.ts +66 -0
- package/src/cli/bot-template-feature-tests.ts +159 -0
- package/src/cli/bot-template-tests.ts +68 -0
- package/src/cli/bot-templates.ts +155 -0
- package/src/cli/main.ts +7 -1
- package/src/cli/scaffold.ts +29 -8
- package/src/cli.ts +1 -1
- package/src/commands/arguments.ts +3 -3
- package/src/commands/context.ts +15 -0
- package/src/contracts.ts +1 -1
- package/src/domain/canvas.ts +259 -0
- package/src/domain/embeds.ts +218 -0
- package/src/domain/message-query.ts +142 -0
- package/src/domain/messages.ts +89 -4
- package/src/framework/bot.ts +30 -5
- package/src/framework/events.ts +12 -0
- package/src/framework/options.ts +2 -0
- package/src/framework/rate-limits.ts +16 -7
- package/src/index.ts +5 -3
- package/src/infrastructure/canvas/render.ts +100 -0
- package/src/infrastructure/canvas/worker.mjs +286 -0
- package/src/infrastructure/fluxer/payload.ts +54 -13
- package/src/infrastructure/fluxer/resources/messages.ts +62 -5
- package/src/infrastructure/fluxer/resources/threads.ts +9 -0
- package/src/infrastructure/fluxer/transport.ts +9 -5
- package/src/infrastructure/images/transform.ts +13 -8
- package/src/infrastructure/process-budget.ts +17 -0
- package/src/ports/canvas.ts +5 -0
- package/src/ports/resources/messages.ts +17 -7
- package/src/ports/resources/threads.ts +7 -0
- package/src/scripting/builtins/canvas.ts +117 -0
- package/src/scripting/builtins/embeds.ts +87 -28
- package/src/scripting/builtins/index.ts +4 -1
- package/src/scripting/builtins/language/objects.ts +2 -1
- package/src/scripting/builtins/language/state.ts +14 -7
- package/src/scripting/builtins/messages.ts +3 -3
- package/src/scripting/builtins/native-expressions.ts +3 -1
- package/src/scripting/builtins/native-messages.ts +17 -0
- package/src/scripting/builtins/native-threads.ts +7 -0
- package/src/scripting/builtins/payload.ts +121 -6
- package/src/scripting/builtins/resource-extras.ts +9 -2
- package/src/scripting/canvas-execution.ts +23 -0
- package/src/scripting/evaluator.ts +25 -9
- package/src/services/attachments.ts +6 -4
- package/src/services/canvas.ts +498 -0
- package/src/services/http.ts +26 -33
- package/src/services/resource-authorization.ts +37 -6
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
export const extraCommands = {
|
|
2
|
+
'moderation/kick': `import { arg, defineCommand } from 'yuzuha';
|
|
3
|
+
|
|
4
|
+
export default defineCommand({
|
|
5
|
+
name: 'kick',
|
|
6
|
+
description: 'Expulsa um membro e registra um caso.',
|
|
7
|
+
guildOnly: true,
|
|
8
|
+
args: {
|
|
9
|
+
membro: arg.user().required(),
|
|
10
|
+
motivo: arg.text().rest().min(1).max(400).required(),
|
|
11
|
+
},
|
|
12
|
+
async run(ctx) {
|
|
13
|
+
const record = await ctx.mod.kick(ctx.args.get('membro'), {
|
|
14
|
+
reason: ctx.args.get('motivo'),
|
|
15
|
+
});
|
|
16
|
+
await ctx.reply({ embeds: [{ title: 'Caso #' + record.id, color: 0x5865F2,
|
|
17
|
+
fields: [
|
|
18
|
+
{ name: 'Ação', value: record.action, inline: true },
|
|
19
|
+
{ name: 'Usuário (ID)', value: record.targetID, inline: true },
|
|
20
|
+
{ name: 'Motivo', value: record.reason, inline: false },
|
|
21
|
+
],
|
|
22
|
+
}] });
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
`,
|
|
26
|
+
'moderation/timeout': `import { arg, defineCommand } from 'yuzuha';
|
|
27
|
+
|
|
28
|
+
export default defineCommand({
|
|
29
|
+
name: 'timeout',
|
|
30
|
+
description: 'Aplica timeout a um membro e registra um caso.',
|
|
31
|
+
guildOnly: true,
|
|
32
|
+
args: {
|
|
33
|
+
membro: arg.user().required(),
|
|
34
|
+
duracao: arg.duration().min(1000).max(2419200000).required(),
|
|
35
|
+
motivo: arg.text().rest().min(1).max(400).required(),
|
|
36
|
+
},
|
|
37
|
+
async run(ctx) {
|
|
38
|
+
const record = await ctx.mod.timeout(ctx.args.get('membro'), {
|
|
39
|
+
reason: ctx.args.get('motivo'),
|
|
40
|
+
duration: ctx.args.get('duracao'),
|
|
41
|
+
});
|
|
42
|
+
await ctx.reply({ embeds: [{ title: 'Caso #' + record.id, color: 0x5865F2,
|
|
43
|
+
fields: [
|
|
44
|
+
{ name: 'Ação', value: record.action, inline: true },
|
|
45
|
+
{ name: 'Usuário (ID)', value: record.targetID, inline: true },
|
|
46
|
+
{ name: 'Motivo', value: record.reason, inline: false },
|
|
47
|
+
],
|
|
48
|
+
}] });
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
`,
|
|
52
|
+
'moderation/unban': `import { arg, defineCommand } from 'yuzuha';
|
|
53
|
+
|
|
54
|
+
export default defineCommand({
|
|
55
|
+
name: 'unban',
|
|
56
|
+
description: 'Remove um banimento e registra um caso.',
|
|
57
|
+
guildOnly: true,
|
|
58
|
+
args: {
|
|
59
|
+
membro: arg.user().required(),
|
|
60
|
+
motivo: arg.text().rest().min(1).max(400).required(),
|
|
61
|
+
},
|
|
62
|
+
async run(ctx) {
|
|
63
|
+
const record = await ctx.mod.unban(ctx.args.get('membro'), {
|
|
64
|
+
reason: ctx.args.get('motivo'),
|
|
65
|
+
});
|
|
66
|
+
await ctx.reply({ embeds: [{ title: 'Caso #' + record.id, color: 0x5865F2,
|
|
67
|
+
fields: [
|
|
68
|
+
{ name: 'Ação', value: record.action, inline: true },
|
|
69
|
+
{ name: 'Usuário (ID)', value: record.targetID, inline: true },
|
|
70
|
+
{ name: 'Motivo', value: record.reason, inline: false },
|
|
71
|
+
],
|
|
72
|
+
}] });
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
`,
|
|
76
|
+
'moderation/case': `import { arg, defineCommand } from 'yuzuha';
|
|
77
|
+
|
|
78
|
+
export default defineCommand({
|
|
79
|
+
name: 'caso', description: 'Consulta um caso de moderação deste servidor.',
|
|
80
|
+
guildOnly: true, permissions: ['ManageGuild'],
|
|
81
|
+
args: { numero: arg.integer().min(1).required() },
|
|
82
|
+
async run(ctx) {
|
|
83
|
+
const record = await ctx.case(ctx.args.get('numero'));
|
|
84
|
+
if (!record) { await ctx.reply('Caso não encontrado neste servidor.'); return; }
|
|
85
|
+
await ctx.reply({ embeds: [{ title: 'Caso #' + record.id, color: 0x5865F2,
|
|
86
|
+
fields: [
|
|
87
|
+
{ name: 'Ação', value: record.action, inline: true },
|
|
88
|
+
{ name: 'Usuário (ID)', value: record.targetID, inline: true },
|
|
89
|
+
{ name: 'Moderador (ID)', value: record.moderatorID, inline: true },
|
|
90
|
+
{ name: 'Motivo', value: record.reason || 'Sem motivo informado.', inline: false },
|
|
91
|
+
],
|
|
92
|
+
}] });
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
`,
|
|
96
|
+
'community/rules': `import { arg, assert, defineCommand } from 'yuzuha';
|
|
97
|
+
|
|
98
|
+
export default defineCommand({
|
|
99
|
+
name: 'regras', description: 'Consulta ou configura as regras do servidor.', guildOnly: true,
|
|
100
|
+
subcommands: [
|
|
101
|
+
{ name: 'ver', description: 'Mostra as regras.', async run(ctx) {
|
|
102
|
+
const text = await ctx.data.guild.get('regras', 'As regras ainda não foram configuradas.');
|
|
103
|
+
assert(typeof text === 'string' && text.length <= 3000, 'As regras salvas são inválidas.');
|
|
104
|
+
await ctx.reply({ embeds: [{ title: 'Regras do servidor', description: text, color: 0x5865F2 }] });
|
|
105
|
+
} },
|
|
106
|
+
defineCommand({ name: 'definir', description: 'Define as regras (ManageGuild).', permissions: ['ManageGuild'],
|
|
107
|
+
args: { texto: arg.text().rest().min(1).max(3000).required() },
|
|
108
|
+
async run(ctx) { await ctx.data.guild.set('regras', ctx.args.get('texto')); await ctx.reply('Regras atualizadas.'); },
|
|
109
|
+
}),
|
|
110
|
+
],
|
|
111
|
+
});
|
|
112
|
+
`,
|
|
113
|
+
'community/suggestions': `import { arg, defineCommand } from 'yuzuha';
|
|
114
|
+
import { readStrings } from '../../helpers/state.js';
|
|
115
|
+
|
|
116
|
+
export default defineCommand({
|
|
117
|
+
name: 'sugestao', description: 'Envia e consulta as últimas 10 sugestões públicas.', guildOnly: true,
|
|
118
|
+
subcommands: [
|
|
119
|
+
defineCommand({ name: 'enviar', description: 'Envia uma sugestão pública.', cooldown: '30s',
|
|
120
|
+
args: { texto: arg.text().rest().min(1).max(250).required() },
|
|
121
|
+
async run(ctx) {
|
|
122
|
+
const line = ctx.authorID + ': ' + ctx.args.get('texto');
|
|
123
|
+
await ctx.data.guild.update('sugestoes', current => [...readStrings(current), line].slice(-10), []);
|
|
124
|
+
await ctx.reply('Sugestão registrada. Use sugestao listar para consultar.');
|
|
125
|
+
},
|
|
126
|
+
}),
|
|
127
|
+
{ name: 'listar', description: 'Lista as sugestões públicas mais recentes.', async run(ctx) {
|
|
128
|
+
const lines = readStrings(await ctx.data.guild.get('sugestoes', []));
|
|
129
|
+
await ctx.reply({ embeds: [{ title: 'Sugestões da comunidade', color: 0x5865F2,
|
|
130
|
+
description: lines.join('\\n') || 'Ainda não há sugestões.',
|
|
131
|
+
}] });
|
|
132
|
+
} },
|
|
133
|
+
],
|
|
134
|
+
});
|
|
135
|
+
`,
|
|
136
|
+
'community/poll': `import { arg, assert, defineCommand } from 'yuzuha';
|
|
137
|
+
import { readPoll } from '../../helpers/state.js';
|
|
138
|
+
|
|
139
|
+
export default defineCommand({
|
|
140
|
+
name: 'enquete', description: 'Enquete de sim ou não por canal; votos podem ser alterados.', guildOnly: true,
|
|
141
|
+
subcommands: [
|
|
142
|
+
defineCommand({ name: 'criar', description: 'Abre uma enquete (ManageGuild).', permissions: ['ManageGuild'],
|
|
143
|
+
args: { pergunta: arg.text().rest().min(1).max(500).required() },
|
|
144
|
+
async run(ctx) {
|
|
145
|
+
await ctx.data.guild.update('enquete:' + ctx.channelID, current => {
|
|
146
|
+
if (current !== null) assert(readPoll(current).closed, 'Feche a enquete atual antes de criar outra.');
|
|
147
|
+
return { question: ctx.args.get('pergunta'), authorID: ctx.authorID, closed: false, votes: [] };
|
|
148
|
+
});
|
|
149
|
+
await ctx.reply('Enquete aberta. Vote com enquete votar sim ou enquete votar nao.');
|
|
150
|
+
},
|
|
151
|
+
}),
|
|
152
|
+
defineCommand({ name: 'votar', description: 'Registra ou altera seu voto.',
|
|
153
|
+
args: { voto: arg.text().choices(['sim', 'nao']).required() },
|
|
154
|
+
async run(ctx) {
|
|
155
|
+
await ctx.data.guild.update('enquete:' + ctx.channelID, current => {
|
|
156
|
+
const poll = readPoll(current);
|
|
157
|
+
assert(!poll.closed, 'Esta enquete já foi encerrada.');
|
|
158
|
+
const votes = poll.votes.filter(vote => vote.id !== ctx.authorID);
|
|
159
|
+
assert(votes.length < 1000, 'Esta enquete atingiu o limite de participantes.');
|
|
160
|
+
return { ...poll, votes: [...votes, { id: ctx.authorID, choice: ctx.args.get('voto') }] };
|
|
161
|
+
});
|
|
162
|
+
await ctx.reply('Voto registrado.');
|
|
163
|
+
},
|
|
164
|
+
}),
|
|
165
|
+
{ name: 'resultado', description: 'Mostra o resultado atual.', async run(ctx) {
|
|
166
|
+
const poll = readPoll(await ctx.data.guild.get('enquete:' + ctx.channelID));
|
|
167
|
+
await ctx.reply({ embeds: [{ title: poll.closed ? 'Enquete encerrada' : 'Enquete aberta',
|
|
168
|
+
description: poll.question, color: 0x5865F2,
|
|
169
|
+
fields: ['sim', 'nao'].map(choice => ({ name: choice === 'sim' ? 'Sim' : 'Não',
|
|
170
|
+
value: String(poll.votes.filter(vote => vote.choice === choice).length), inline: true })),
|
|
171
|
+
}] });
|
|
172
|
+
} },
|
|
173
|
+
{ name: 'fechar', description: 'Encerra sua enquete.', async run(ctx) {
|
|
174
|
+
await ctx.data.guild.update('enquete:' + ctx.channelID, current => {
|
|
175
|
+
const poll = readPoll(current);
|
|
176
|
+
assert(poll.authorID === ctx.authorID, 'Somente o criador pode encerrar esta enquete.');
|
|
177
|
+
assert(!poll.closed, 'Esta enquete já foi encerrada.');
|
|
178
|
+
return { ...poll, closed: true };
|
|
179
|
+
});
|
|
180
|
+
await ctx.reply('Enquete encerrada. O resultado continua disponível.');
|
|
181
|
+
} },
|
|
182
|
+
],
|
|
183
|
+
});
|
|
184
|
+
`,
|
|
185
|
+
'economy/balance': `import { arg, defineCommand } from 'yuzuha';
|
|
186
|
+
import { readBalance } from '../../helpers/state.js';
|
|
187
|
+
|
|
188
|
+
export default defineCommand({
|
|
189
|
+
name: 'saldo', description: 'Consulta moedas virtuais neste servidor.', guildOnly: true,
|
|
190
|
+
args: { usuario: arg.user() },
|
|
191
|
+
async run(ctx) {
|
|
192
|
+
const id = ctx.args.get('usuario') ?? ctx.authorID;
|
|
193
|
+
const balance = readBalance(await ctx.data.guild.get('saldo:' + id, 0));
|
|
194
|
+
await ctx.reply({ embeds: [{ title: 'Carteira', color: 0x5865F2, fields: [
|
|
195
|
+
{ name: 'Usuário (ID)', value: id, inline: true },
|
|
196
|
+
{ name: 'Moedas', value: String(balance), inline: true },
|
|
197
|
+
] }] });
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
`,
|
|
201
|
+
'economy/daily': `import { assert, defineCommand } from 'yuzuha';
|
|
202
|
+
import { readBalance } from '../../helpers/state.js';
|
|
203
|
+
|
|
204
|
+
export default defineCommand({
|
|
205
|
+
name: 'diario', description: 'Recebe 100 moedas a cada 24 horas.', guildOnly: true,
|
|
206
|
+
async run(ctx) {
|
|
207
|
+
const balance = await ctx.data.transaction(data => {
|
|
208
|
+
const claim = 'diario:' + ctx.authorID;
|
|
209
|
+
assert(data.guild.get(claim) === null, 'Você já recebeu esta recompensa. Aguarde o prazo.');
|
|
210
|
+
const key = 'saldo:' + ctx.authorID;
|
|
211
|
+
const next = readBalance(readBalance(data.guild.get(key, 0)) + 100);
|
|
212
|
+
data.guild.set(key, next);
|
|
213
|
+
data.guild.set(claim, true, { ttlMs: 86400000 });
|
|
214
|
+
return next;
|
|
215
|
+
});
|
|
216
|
+
await ctx.reply({ embeds: [{ title: 'Recompensa recebida', color: 0x5865F2,
|
|
217
|
+
description: '100 moedas adicionadas.', fields: [{ name: 'Saldo', value: String(balance), inline: true }],
|
|
218
|
+
}] });
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
`,
|
|
222
|
+
'economy/work': `import { assert, defineCommand } from 'yuzuha';
|
|
223
|
+
import { readBalance } from '../../helpers/state.js';
|
|
224
|
+
|
|
225
|
+
export default defineCommand({
|
|
226
|
+
name: 'trabalhar', description: 'Recebe 25 moedas a cada hora.', guildOnly: true,
|
|
227
|
+
async run(ctx) {
|
|
228
|
+
const balance = await ctx.data.transaction(data => {
|
|
229
|
+
const claim = 'trabalhar:' + ctx.authorID;
|
|
230
|
+
assert(data.guild.get(claim) === null, 'Você já recebeu esta recompensa. Aguarde o prazo.');
|
|
231
|
+
const key = 'saldo:' + ctx.authorID;
|
|
232
|
+
const next = readBalance(readBalance(data.guild.get(key, 0)) + 25);
|
|
233
|
+
data.guild.set(key, next);
|
|
234
|
+
data.guild.set(claim, true, { ttlMs: 3600000 });
|
|
235
|
+
return next;
|
|
236
|
+
});
|
|
237
|
+
await ctx.reply({ embeds: [{ title: 'Recompensa recebida', color: 0x5865F2,
|
|
238
|
+
description: '25 moedas adicionadas.', fields: [{ name: 'Saldo', value: String(balance), inline: true }],
|
|
239
|
+
}] });
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
`,
|
|
243
|
+
'economy/pay': `import { arg, assert, defineCommand } from 'yuzuha';
|
|
244
|
+
import { readBalance } from '../../helpers/state.js';
|
|
245
|
+
|
|
246
|
+
export default defineCommand({
|
|
247
|
+
name: 'pagar', description: 'Transfere moedas virtuais para outra pessoa neste servidor.', guildOnly: true,
|
|
248
|
+
args: { usuario: arg.user().required(), quantidade: arg.integer().min(1).max(1000000).required() },
|
|
249
|
+
async run(ctx) {
|
|
250
|
+
const id = ctx.args.get('usuario');
|
|
251
|
+
const amount = ctx.args.get('quantidade');
|
|
252
|
+
assert(id !== ctx.authorID, 'Escolha outra pessoa.');
|
|
253
|
+
const user = await ctx.resources.users.user(id);
|
|
254
|
+
assert(!user.bot, 'Transferências para bots não são permitidas.');
|
|
255
|
+
await ctx.data.transaction(data => {
|
|
256
|
+
const fromKey = 'saldo:' + ctx.authorID;
|
|
257
|
+
const toKey = 'saldo:' + id;
|
|
258
|
+
const balance = readBalance(data.guild.get(fromKey, 0));
|
|
259
|
+
assert(balance >= amount, 'Saldo insuficiente.');
|
|
260
|
+
const received = readBalance(readBalance(data.guild.get(toKey, 0)) + amount);
|
|
261
|
+
data.guild.set(fromKey, balance - amount);
|
|
262
|
+
data.guild.set(toKey, received);
|
|
263
|
+
});
|
|
264
|
+
await ctx.reply('Transferência concluída: ' + amount + ' moedas para ' + id + '.');
|
|
265
|
+
},
|
|
266
|
+
});
|
|
267
|
+
`,
|
|
268
|
+
'fun/choose': `import { randomInt } from 'node:crypto';
|
|
269
|
+
import { arg, assert, defineCommand } from 'yuzuha';
|
|
270
|
+
|
|
271
|
+
export default defineCommand({
|
|
272
|
+
name: 'escolher', description: 'Escolhe entre 2 a 20 opções separadas por |.',
|
|
273
|
+
args: { opcoes: arg.text().rest().max(1500).required() },
|
|
274
|
+
async run(ctx) {
|
|
275
|
+
const options = ctx.args.get('opcoes').split('|').map(option => option.trim());
|
|
276
|
+
assert(options.length >= 2 && options.length <= 20 && options.every(option => option.length > 0 && option.length <= 100),
|
|
277
|
+
'Informe de 2 a 20 opções não vazias de até 100 caracteres, separadas por |.');
|
|
278
|
+
await ctx.reply({ embeds: [{ title: 'Minha escolha', description: options[randomInt(options.length)], color: 0x5865F2 }] });
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
`,
|
|
282
|
+
'fun/eightball': `import { randomInt } from 'node:crypto';
|
|
283
|
+
import { arg, defineCommand } from 'yuzuha';
|
|
284
|
+
|
|
285
|
+
const answers = ['Sim.', 'Não.', 'Talvez.', 'Pergunte outra vez.', 'Tudo indica que sim.', 'Melhor esperar.'];
|
|
286
|
+
|
|
287
|
+
export default defineCommand({
|
|
288
|
+
name: 'bola8', aliases: ['8ball'], description: 'Responde uma pergunta por diversão.',
|
|
289
|
+
args: { pergunta: arg.text().rest().min(1).max(500).required() },
|
|
290
|
+
async run(ctx) {
|
|
291
|
+
await ctx.reply({ embeds: [{ title: 'Bola 8', description: ctx.args.get('pergunta'), color: 0x5865F2,
|
|
292
|
+
fields: [{ name: 'Resposta', value: answers[randomInt(answers.length)], inline: false }],
|
|
293
|
+
footer: { text: 'Resposta aleatória, só por diversão.' },
|
|
294
|
+
}] });
|
|
295
|
+
},
|
|
296
|
+
});
|
|
297
|
+
`,
|
|
298
|
+
'utilities/notes': `import { arg, assert, defineCommand } from 'yuzuha';
|
|
299
|
+
import { readStrings } from '../../helpers/state.js';
|
|
300
|
+
|
|
301
|
+
export default defineCommand({
|
|
302
|
+
name: 'notas', description: 'Notas pessoais, disponíveis apenas em mensagens diretas.',
|
|
303
|
+
checks: [ctx => !ctx.guildID || 'Use notas em uma mensagem direta com o bot.'],
|
|
304
|
+
subcommands: [
|
|
305
|
+
defineCommand({ name: 'adicionar', description: 'Adiciona uma nota (até 10 notas).',
|
|
306
|
+
args: { texto: arg.text().rest().min(1).max(300).required() },
|
|
307
|
+
async run(ctx) {
|
|
308
|
+
const count = await ctx.data.user.update('notas', current => {
|
|
309
|
+
const notes = readStrings(current);
|
|
310
|
+
assert(notes.length < 10, 'Você atingiu o limite de 10 notas. Apague uma antes de adicionar outra.');
|
|
311
|
+
return [...notes, ctx.args.get('texto')];
|
|
312
|
+
}, []);
|
|
313
|
+
await ctx.reply('Nota #' + count.length + ' salva.');
|
|
314
|
+
},
|
|
315
|
+
}),
|
|
316
|
+
{ name: 'listar', description: 'Lista suas notas.', async run(ctx) {
|
|
317
|
+
const notes = readStrings(await ctx.data.user.get('notas', []));
|
|
318
|
+
await ctx.reply({ embeds: [{ title: 'Suas notas', color: 0x5865F2,
|
|
319
|
+
description: notes.map((note, index) => (index + 1) + '. ' + note).join('\\n') || 'Nenhuma nota salva.',
|
|
320
|
+
}] });
|
|
321
|
+
} },
|
|
322
|
+
defineCommand({ name: 'apagar', description: 'Apaga uma nota pelo número atual.',
|
|
323
|
+
args: { numero: arg.integer().min(1).max(10).required() },
|
|
324
|
+
async run(ctx) {
|
|
325
|
+
const index = ctx.args.get('numero') - 1;
|
|
326
|
+
await ctx.data.user.update('notas', current => {
|
|
327
|
+
const notes = readStrings(current);
|
|
328
|
+
assert(index < notes.length, 'Nota não encontrada.');
|
|
329
|
+
return notes.filter((_, position) => position !== index);
|
|
330
|
+
}, []);
|
|
331
|
+
await ctx.reply('Nota apagada. Os números das notas seguintes foram atualizados.');
|
|
332
|
+
},
|
|
333
|
+
}),
|
|
334
|
+
],
|
|
335
|
+
});
|
|
336
|
+
`,
|
|
337
|
+
'utilities/timestamp': `import { arg, assert, defineCommand } from 'yuzuha';
|
|
338
|
+
|
|
339
|
+
export default defineCommand({
|
|
340
|
+
name: 'data', description: 'Converte uma data ISO com fuso para UTC e Unix em segundos.',
|
|
341
|
+
args: { iso: arg.text().max(35).required() },
|
|
342
|
+
async run(ctx) {
|
|
343
|
+
const iso = ctx.args.get('iso');
|
|
344
|
+
assert(/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:Z|[+-]\\d{2}:\\d{2})$/.test(iso),
|
|
345
|
+
'Use ISO com fuso, por exemplo 2026-01-20T18:30:00-03:00.');
|
|
346
|
+
const date = new Date(iso);
|
|
347
|
+
assert(Number.isFinite(date.getTime()), 'Data inválida.');
|
|
348
|
+
assert(new Date(iso.slice(0, 10) + 'T00:00:00Z').toISOString().slice(0, 10) === iso.slice(0, 10)
|
|
349
|
+
&& Number(iso.slice(11, 13)) < 24, 'Data inválida.');
|
|
350
|
+
await ctx.reply({ embeds: [{ title: 'Data convertida', color: 0x5865F2, fields: [
|
|
351
|
+
{ name: 'UTC', value: date.toISOString(), inline: false },
|
|
352
|
+
{ name: 'Unix (segundos)', value: String(Math.floor(date.getTime() / 1000)), inline: false },
|
|
353
|
+
] }] });
|
|
354
|
+
},
|
|
355
|
+
});
|
|
356
|
+
`,
|
|
357
|
+
};
|
|
358
|
+
//# sourceMappingURL=bot-template-commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot-template-commands.js","sourceRoot":"","sources":["../../src/cli/bot-template-commands.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAA2B;IACnD,iBAAiB,EAAE;;;;;;;;;;;;;;;;;;;;;;;CAuBpB;IACC,oBAAoB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;CAyBvB;IACC,kBAAkB,EAAE;;;;;;;;;;;;;;;;;;;;;;;CAuBrB;IACC,iBAAiB,EAAE;;;;;;;;;;;;;;;;;;;CAmBpB;IACC,iBAAiB,EAAE;;;;;;;;;;;;;;;;CAgBpB;IACC,uBAAuB,EAAE;;;;;;;;;;;;;;;;;;;;;;CAsB1B;IACC,gBAAgB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDnB;IACC,iBAAiB,EAAE;;;;;;;;;;;;;;;CAepB;IACC,eAAe,EAAE;;;;;;;;;;;;;;;;;;;;CAoBlB;IACC,cAAc,EAAE;;;;;;;;;;;;;;;;;;;;CAoBjB;IACC,aAAa,EAAE;;;;;;;;;;;;;;;;;;;;;;;;CAwBhB;IACC,YAAY,EAAE;;;;;;;;;;;;;CAaf;IACC,eAAe,EAAE;;;;;;;;;;;;;;;CAelB;IACC,iBAAiB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCpB;IACC,qBAAqB,EAAE;;;;;;;;;;;;;;;;;;;CAmBxB;CACA,CAAC","sourcesContent":["export const extraCommands: Record<string, string> = {\n 'moderation/kick': `import { arg, defineCommand } from 'yuzuha';\n\nexport default defineCommand({\n name: 'kick',\n description: 'Expulsa um membro e registra um caso.',\n guildOnly: true,\n args: {\n membro: arg.user().required(),\n motivo: arg.text().rest().min(1).max(400).required(),\n },\n async run(ctx) {\n const record = await ctx.mod.kick(ctx.args.get('membro'), {\n reason: ctx.args.get('motivo'),\n });\n await ctx.reply({ embeds: [{ title: 'Caso #' + record.id, color: 0x5865F2,\n fields: [\n { name: 'Ação', value: record.action, inline: true },\n { name: 'Usuário (ID)', value: record.targetID, inline: true },\n { name: 'Motivo', value: record.reason, inline: false },\n ],\n }] });\n },\n});\n`,\n 'moderation/timeout': `import { arg, defineCommand } from 'yuzuha';\n\nexport default defineCommand({\n name: 'timeout',\n description: 'Aplica timeout a um membro e registra um caso.',\n guildOnly: true,\n args: {\n membro: arg.user().required(),\n duracao: arg.duration().min(1000).max(2419200000).required(),\n motivo: arg.text().rest().min(1).max(400).required(),\n },\n async run(ctx) {\n const record = await ctx.mod.timeout(ctx.args.get('membro'), {\n reason: ctx.args.get('motivo'),\n duration: ctx.args.get('duracao'),\n });\n await ctx.reply({ embeds: [{ title: 'Caso #' + record.id, color: 0x5865F2,\n fields: [\n { name: 'Ação', value: record.action, inline: true },\n { name: 'Usuário (ID)', value: record.targetID, inline: true },\n { name: 'Motivo', value: record.reason, inline: false },\n ],\n }] });\n },\n});\n`,\n 'moderation/unban': `import { arg, defineCommand } from 'yuzuha';\n\nexport default defineCommand({\n name: 'unban',\n description: 'Remove um banimento e registra um caso.',\n guildOnly: true,\n args: {\n membro: arg.user().required(),\n motivo: arg.text().rest().min(1).max(400).required(),\n },\n async run(ctx) {\n const record = await ctx.mod.unban(ctx.args.get('membro'), {\n reason: ctx.args.get('motivo'),\n });\n await ctx.reply({ embeds: [{ title: 'Caso #' + record.id, color: 0x5865F2,\n fields: [\n { name: 'Ação', value: record.action, inline: true },\n { name: 'Usuário (ID)', value: record.targetID, inline: true },\n { name: 'Motivo', value: record.reason, inline: false },\n ],\n }] });\n },\n});\n`,\n 'moderation/case': `import { arg, defineCommand } from 'yuzuha';\n\nexport default defineCommand({\n name: 'caso', description: 'Consulta um caso de moderação deste servidor.',\n guildOnly: true, permissions: ['ManageGuild'],\n args: { numero: arg.integer().min(1).required() },\n async run(ctx) {\n const record = await ctx.case(ctx.args.get('numero'));\n if (!record) { await ctx.reply('Caso não encontrado neste servidor.'); return; }\n await ctx.reply({ embeds: [{ title: 'Caso #' + record.id, color: 0x5865F2,\n fields: [\n { name: 'Ação', value: record.action, inline: true },\n { name: 'Usuário (ID)', value: record.targetID, inline: true },\n { name: 'Moderador (ID)', value: record.moderatorID, inline: true },\n { name: 'Motivo', value: record.reason || 'Sem motivo informado.', inline: false },\n ],\n }] });\n },\n});\n`,\n 'community/rules': `import { arg, assert, defineCommand } from 'yuzuha';\n\nexport default defineCommand({\n name: 'regras', description: 'Consulta ou configura as regras do servidor.', guildOnly: true,\n subcommands: [\n { name: 'ver', description: 'Mostra as regras.', async run(ctx) {\n const text = await ctx.data.guild.get('regras', 'As regras ainda não foram configuradas.');\n assert(typeof text === 'string' && text.length <= 3000, 'As regras salvas são inválidas.');\n await ctx.reply({ embeds: [{ title: 'Regras do servidor', description: text, color: 0x5865F2 }] });\n } },\n defineCommand({ name: 'definir', description: 'Define as regras (ManageGuild).', permissions: ['ManageGuild'],\n args: { texto: arg.text().rest().min(1).max(3000).required() },\n async run(ctx) { await ctx.data.guild.set('regras', ctx.args.get('texto')); await ctx.reply('Regras atualizadas.'); },\n }),\n ],\n});\n`,\n 'community/suggestions': `import { arg, defineCommand } from 'yuzuha';\nimport { readStrings } from '../../helpers/state.js';\n\nexport default defineCommand({\n name: 'sugestao', description: 'Envia e consulta as últimas 10 sugestões públicas.', guildOnly: true,\n subcommands: [\n defineCommand({ name: 'enviar', description: 'Envia uma sugestão pública.', cooldown: '30s',\n args: { texto: arg.text().rest().min(1).max(250).required() },\n async run(ctx) {\n const line = ctx.authorID + ': ' + ctx.args.get('texto');\n await ctx.data.guild.update('sugestoes', current => [...readStrings(current), line].slice(-10), []);\n await ctx.reply('Sugestão registrada. Use sugestao listar para consultar.');\n },\n }),\n { name: 'listar', description: 'Lista as sugestões públicas mais recentes.', async run(ctx) {\n const lines = readStrings(await ctx.data.guild.get('sugestoes', []));\n await ctx.reply({ embeds: [{ title: 'Sugestões da comunidade', color: 0x5865F2,\n description: lines.join('\\\\n') || 'Ainda não há sugestões.',\n }] });\n } },\n ],\n});\n`,\n 'community/poll': `import { arg, assert, defineCommand } from 'yuzuha';\nimport { readPoll } from '../../helpers/state.js';\n\nexport default defineCommand({\n name: 'enquete', description: 'Enquete de sim ou não por canal; votos podem ser alterados.', guildOnly: true,\n subcommands: [\n defineCommand({ name: 'criar', description: 'Abre uma enquete (ManageGuild).', permissions: ['ManageGuild'],\n args: { pergunta: arg.text().rest().min(1).max(500).required() },\n async run(ctx) {\n await ctx.data.guild.update('enquete:' + ctx.channelID, current => {\n if (current !== null) assert(readPoll(current).closed, 'Feche a enquete atual antes de criar outra.');\n return { question: ctx.args.get('pergunta'), authorID: ctx.authorID, closed: false, votes: [] };\n });\n await ctx.reply('Enquete aberta. Vote com enquete votar sim ou enquete votar nao.');\n },\n }),\n defineCommand({ name: 'votar', description: 'Registra ou altera seu voto.',\n args: { voto: arg.text().choices(['sim', 'nao']).required() },\n async run(ctx) {\n await ctx.data.guild.update('enquete:' + ctx.channelID, current => {\n const poll = readPoll(current);\n assert(!poll.closed, 'Esta enquete já foi encerrada.');\n const votes = poll.votes.filter(vote => vote.id !== ctx.authorID);\n assert(votes.length < 1000, 'Esta enquete atingiu o limite de participantes.');\n return { ...poll, votes: [...votes, { id: ctx.authorID, choice: ctx.args.get('voto') }] };\n });\n await ctx.reply('Voto registrado.');\n },\n }),\n { name: 'resultado', description: 'Mostra o resultado atual.', async run(ctx) {\n const poll = readPoll(await ctx.data.guild.get('enquete:' + ctx.channelID));\n await ctx.reply({ embeds: [{ title: poll.closed ? 'Enquete encerrada' : 'Enquete aberta',\n description: poll.question, color: 0x5865F2,\n fields: ['sim', 'nao'].map(choice => ({ name: choice === 'sim' ? 'Sim' : 'Não',\n value: String(poll.votes.filter(vote => vote.choice === choice).length), inline: true })),\n }] });\n } },\n { name: 'fechar', description: 'Encerra sua enquete.', async run(ctx) {\n await ctx.data.guild.update('enquete:' + ctx.channelID, current => {\n const poll = readPoll(current);\n assert(poll.authorID === ctx.authorID, 'Somente o criador pode encerrar esta enquete.');\n assert(!poll.closed, 'Esta enquete já foi encerrada.');\n return { ...poll, closed: true };\n });\n await ctx.reply('Enquete encerrada. O resultado continua disponível.');\n } },\n ],\n});\n`,\n 'economy/balance': `import { arg, defineCommand } from 'yuzuha';\nimport { readBalance } from '../../helpers/state.js';\n\nexport default defineCommand({\n name: 'saldo', description: 'Consulta moedas virtuais neste servidor.', guildOnly: true,\n args: { usuario: arg.user() },\n async run(ctx) {\n const id = ctx.args.get('usuario') ?? ctx.authorID;\n const balance = readBalance(await ctx.data.guild.get('saldo:' + id, 0));\n await ctx.reply({ embeds: [{ title: 'Carteira', color: 0x5865F2, fields: [\n { name: 'Usuário (ID)', value: id, inline: true },\n { name: 'Moedas', value: String(balance), inline: true },\n ] }] });\n },\n});\n`,\n 'economy/daily': `import { assert, defineCommand } from 'yuzuha';\nimport { readBalance } from '../../helpers/state.js';\n\nexport default defineCommand({\n name: 'diario', description: 'Recebe 100 moedas a cada 24 horas.', guildOnly: true,\n async run(ctx) {\n const balance = await ctx.data.transaction(data => {\n const claim = 'diario:' + ctx.authorID;\n assert(data.guild.get(claim) === null, 'Você já recebeu esta recompensa. Aguarde o prazo.');\n const key = 'saldo:' + ctx.authorID;\n const next = readBalance(readBalance(data.guild.get(key, 0)) + 100);\n data.guild.set(key, next);\n data.guild.set(claim, true, { ttlMs: 86400000 });\n return next;\n });\n await ctx.reply({ embeds: [{ title: 'Recompensa recebida', color: 0x5865F2,\n description: '100 moedas adicionadas.', fields: [{ name: 'Saldo', value: String(balance), inline: true }],\n }] });\n },\n});\n`,\n 'economy/work': `import { assert, defineCommand } from 'yuzuha';\nimport { readBalance } from '../../helpers/state.js';\n\nexport default defineCommand({\n name: 'trabalhar', description: 'Recebe 25 moedas a cada hora.', guildOnly: true,\n async run(ctx) {\n const balance = await ctx.data.transaction(data => {\n const claim = 'trabalhar:' + ctx.authorID;\n assert(data.guild.get(claim) === null, 'Você já recebeu esta recompensa. Aguarde o prazo.');\n const key = 'saldo:' + ctx.authorID;\n const next = readBalance(readBalance(data.guild.get(key, 0)) + 25);\n data.guild.set(key, next);\n data.guild.set(claim, true, { ttlMs: 3600000 });\n return next;\n });\n await ctx.reply({ embeds: [{ title: 'Recompensa recebida', color: 0x5865F2,\n description: '25 moedas adicionadas.', fields: [{ name: 'Saldo', value: String(balance), inline: true }],\n }] });\n },\n});\n`,\n 'economy/pay': `import { arg, assert, defineCommand } from 'yuzuha';\nimport { readBalance } from '../../helpers/state.js';\n\nexport default defineCommand({\n name: 'pagar', description: 'Transfere moedas virtuais para outra pessoa neste servidor.', guildOnly: true,\n args: { usuario: arg.user().required(), quantidade: arg.integer().min(1).max(1000000).required() },\n async run(ctx) {\n const id = ctx.args.get('usuario');\n const amount = ctx.args.get('quantidade');\n assert(id !== ctx.authorID, 'Escolha outra pessoa.');\n const user = await ctx.resources.users.user(id);\n assert(!user.bot, 'Transferências para bots não são permitidas.');\n await ctx.data.transaction(data => {\n const fromKey = 'saldo:' + ctx.authorID;\n const toKey = 'saldo:' + id;\n const balance = readBalance(data.guild.get(fromKey, 0));\n assert(balance >= amount, 'Saldo insuficiente.');\n const received = readBalance(readBalance(data.guild.get(toKey, 0)) + amount);\n data.guild.set(fromKey, balance - amount);\n data.guild.set(toKey, received);\n });\n await ctx.reply('Transferência concluída: ' + amount + ' moedas para ' + id + '.');\n },\n});\n`,\n 'fun/choose': `import { randomInt } from 'node:crypto';\nimport { arg, assert, defineCommand } from 'yuzuha';\n\nexport default defineCommand({\n name: 'escolher', description: 'Escolhe entre 2 a 20 opções separadas por |.',\n args: { opcoes: arg.text().rest().max(1500).required() },\n async run(ctx) {\n const options = ctx.args.get('opcoes').split('|').map(option => option.trim());\n assert(options.length >= 2 && options.length <= 20 && options.every(option => option.length > 0 && option.length <= 100),\n 'Informe de 2 a 20 opções não vazias de até 100 caracteres, separadas por |.');\n await ctx.reply({ embeds: [{ title: 'Minha escolha', description: options[randomInt(options.length)], color: 0x5865F2 }] });\n },\n});\n`,\n 'fun/eightball': `import { randomInt } from 'node:crypto';\nimport { arg, defineCommand } from 'yuzuha';\n\nconst answers = ['Sim.', 'Não.', 'Talvez.', 'Pergunte outra vez.', 'Tudo indica que sim.', 'Melhor esperar.'];\n\nexport default defineCommand({\n name: 'bola8', aliases: ['8ball'], description: 'Responde uma pergunta por diversão.',\n args: { pergunta: arg.text().rest().min(1).max(500).required() },\n async run(ctx) {\n await ctx.reply({ embeds: [{ title: 'Bola 8', description: ctx.args.get('pergunta'), color: 0x5865F2,\n fields: [{ name: 'Resposta', value: answers[randomInt(answers.length)], inline: false }],\n footer: { text: 'Resposta aleatória, só por diversão.' },\n }] });\n },\n});\n`,\n 'utilities/notes': `import { arg, assert, defineCommand } from 'yuzuha';\nimport { readStrings } from '../../helpers/state.js';\n\nexport default defineCommand({\n name: 'notas', description: 'Notas pessoais, disponíveis apenas em mensagens diretas.',\n checks: [ctx => !ctx.guildID || 'Use notas em uma mensagem direta com o bot.'],\n subcommands: [\n defineCommand({ name: 'adicionar', description: 'Adiciona uma nota (até 10 notas).',\n args: { texto: arg.text().rest().min(1).max(300).required() },\n async run(ctx) {\n const count = await ctx.data.user.update('notas', current => {\n const notes = readStrings(current);\n assert(notes.length < 10, 'Você atingiu o limite de 10 notas. Apague uma antes de adicionar outra.');\n return [...notes, ctx.args.get('texto')];\n }, []);\n await ctx.reply('Nota #' + count.length + ' salva.');\n },\n }),\n { name: 'listar', description: 'Lista suas notas.', async run(ctx) {\n const notes = readStrings(await ctx.data.user.get('notas', []));\n await ctx.reply({ embeds: [{ title: 'Suas notas', color: 0x5865F2,\n description: notes.map((note, index) => (index + 1) + '. ' + note).join('\\\\n') || 'Nenhuma nota salva.',\n }] });\n } },\n defineCommand({ name: 'apagar', description: 'Apaga uma nota pelo número atual.',\n args: { numero: arg.integer().min(1).max(10).required() },\n async run(ctx) {\n const index = ctx.args.get('numero') - 1;\n await ctx.data.user.update('notas', current => {\n const notes = readStrings(current);\n assert(index < notes.length, 'Nota não encontrada.');\n return notes.filter((_, position) => position !== index);\n }, []);\n await ctx.reply('Nota apagada. Os números das notas seguintes foram atualizados.');\n },\n }),\n ],\n});\n`,\n 'utilities/timestamp': `import { arg, assert, defineCommand } from 'yuzuha';\n\nexport default defineCommand({\n name: 'data', description: 'Converte uma data ISO com fuso para UTC e Unix em segundos.',\n args: { iso: arg.text().max(35).required() },\n async run(ctx) {\n const iso = ctx.args.get('iso');\n assert(/^\\\\d{4}-\\\\d{2}-\\\\d{2}T\\\\d{2}:\\\\d{2}:\\\\d{2}(?:Z|[+-]\\\\d{2}:\\\\d{2})$/.test(iso),\n 'Use ISO com fuso, por exemplo 2026-01-20T18:30:00-03:00.');\n const date = new Date(iso);\n assert(Number.isFinite(date.getTime()), 'Data inválida.');\n assert(new Date(iso.slice(0, 10) + 'T00:00:00Z').toISOString().slice(0, 10) === iso.slice(0, 10)\n && Number(iso.slice(11, 13)) < 24, 'Data inválida.');\n await ctx.reply({ embeds: [{ title: 'Data convertida', color: 0x5865F2, fields: [\n { name: 'UTC', value: date.toISOString(), inline: false },\n { name: 'Unix (segundos)', value: String(Math.floor(date.getTime() / 1000)), inline: false },\n ] }] });\n },\n});\n`,\n};\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BotTemplate } from './bot-template-catalog.js';
|
|
2
|
+
export declare const templateExamples: {
|
|
3
|
+
simple: string[];
|
|
4
|
+
multifunctional: string[];
|
|
5
|
+
moderation: string[];
|
|
6
|
+
community: string[];
|
|
7
|
+
economy: string[];
|
|
8
|
+
entertainment: string[];
|
|
9
|
+
utility: string[];
|
|
10
|
+
};
|
|
11
|
+
export declare function templateReadme(template: BotTemplate): string;
|
|
12
|
+
export declare function templateHelpers(template: BotTemplate, language: 'js' | 'ts'): Record<string, string>;
|
|
13
|
+
//# sourceMappingURL=bot-template-content.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot-template-content.d.ts","sourceRoot":"","sources":["../../src/cli/bot-template-content.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,eAAO,MAAM,gBAAgB;;;;;;;;CAQY,CAAC;AAE1C,wBAAgB,cAAc,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,CAc5D;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAoCpG"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { botTemplates } from './bot-template-catalog.js';
|
|
2
|
+
export const templateExamples = {
|
|
3
|
+
simple: ['!ping', '!ajuda', '!sobre', '!avatar @usuario'],
|
|
4
|
+
multifunctional: ['!ajuda', '!regras definir Respeite os membros.', '!enquete criar Vamos jogar hoje?', '!enquete votar sim', '!diario', '!pagar @usuario 25', '!notas listar', '!caso 1'],
|
|
5
|
+
moderation: ['!ban @usuario spam', '!kick @usuario spam', '!timeout @usuario 10m spam', '!unban 123456789 revisão', '!caso 1'],
|
|
6
|
+
community: ['!regras definir Respeite os membros.', '!regras ver', '!sugestao enviar Adicionar um canal de jogos', '!sugestao listar', '!enquete criar Vamos jogar hoje?', '!enquete votar sim', '!enquete resultado', '!enquete fechar'],
|
|
7
|
+
economy: ['!saldo', '!saldo @usuario', '!diario', '!trabalhar', '!pagar @usuario 25'],
|
|
8
|
+
entertainment: ['!dado 20', '!moeda', '!escolher pizza | sushi | massa', '!bola8 Vai chover?'],
|
|
9
|
+
utility: ['!perfil @usuario', '!servidor', '!data 2026-01-20T18:30:00-03:00', '!notas adicionar Comprar café', '!notas listar', '!notas apagar 1'],
|
|
10
|
+
};
|
|
11
|
+
export function templateReadme(template) {
|
|
12
|
+
const paths = botTemplates[template].paths;
|
|
13
|
+
const paragraphs = [
|
|
14
|
+
`Base: **${template}**. ${botTemplates[template].description}`,
|
|
15
|
+
'Todas as bases incluem `!ping`, `!ajuda` (aliases `help`, `comandos`), `!sobre` e `!avatar [@usuario]`. Ajuda e consultas de informações usam embeds. As pastas de commands são carregadas recursivamente.',
|
|
16
|
+
`Exemplos:\n\n${templateExamples[template].map(value => `- \`${value}\``).join('\n')}`,
|
|
17
|
+
];
|
|
18
|
+
if (paths.includes('moderation/ban'))
|
|
19
|
+
paragraphs.push('Moderação exige permissões de autor e bot e hierarquia sobre o alvo. `caso` exige ManageGuild. Kick, timeout e unban exigem motivo; timeout aceita de 1 segundo a 28 dias. Falha depois da ação é parcial: não repita a ação para tentar salvar o caso.');
|
|
20
|
+
if (paths.includes('community/rules'))
|
|
21
|
+
paragraphs.push('Regras e criação de enquetes exigem ManageGuild. Há uma enquete de sim/não por canal, até 1000 participantes, com alteração de voto. Somente o criador encerra; o resultado permanece disponível. Sugestões são públicas, limitadas às 10 mais recentes, com cooldown de 30 segundos por autor/canal.');
|
|
22
|
+
if (paths.includes('economy/daily'))
|
|
23
|
+
paragraphs.push('Moedas são virtuais e isoladas por servidor. Diário concede 100 a cada 24 horas; trabalho, 25 a cada hora. Prazos persistem após reinício. Transferências de 1 a 1000000 moedas são atômicas, não permitem saldo negativo, autoenvio ou bots. Não há dinheiro real ou pagamentos externos.');
|
|
24
|
+
if (paths.includes('utilities/notes'))
|
|
25
|
+
paragraphs.push('Notas funcionam somente em DM, são isoladas por usuário e limitadas a 10 entradas de 300 caracteres. Apagar uma nota renumera as seguintes. `data` exige ISO com fuso explícito e retorna UTC e Unix em segundos.');
|
|
26
|
+
if (paths.includes('fun/choose'))
|
|
27
|
+
paragraphs.push('`escolher` aceita de 2 a 20 opções não vazias de até 100 caracteres, separadas por |. `dado` aceita de 2 a 100 lados. `bola8` responde aleatoriamente, apenas por diversão.');
|
|
28
|
+
paragraphs.push('Os testes usam MockTransport, recursos simulados e store em memória. `check` valida sem login; `npm test` exercita comandos e guards. Dados reais usam o store configurado pela CLI; reinicie o processo após mudar helpers fora de commands/.');
|
|
29
|
+
return paragraphs.join('\n\n');
|
|
30
|
+
}
|
|
31
|
+
export function templateHelpers(template, language) {
|
|
32
|
+
const paths = botTemplates[template].paths;
|
|
33
|
+
if (!paths.some(path => path.startsWith('community/') || path.startsWith('economy/') || path === 'utilities/notes'))
|
|
34
|
+
return {};
|
|
35
|
+
const input = language === 'ts' ? ': unknown' : '';
|
|
36
|
+
return { [`helpers/state.${language}`]: `import { assert } from 'yuzuha';
|
|
37
|
+
|
|
38
|
+
export function readStrings(value${input}) {
|
|
39
|
+
assert(Array.isArray(value) && value.length <= 10, 'A lista salva é inválida.');
|
|
40
|
+
return value.map(item => {
|
|
41
|
+
assert(typeof item === 'string' && item.length <= 400, 'A entrada salva é inválida.');
|
|
42
|
+
return item;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function readBalance(value${input}) {
|
|
47
|
+
assert(typeof value === 'number' && Number.isSafeInteger(value) && value >= 0, 'O saldo salvo é inválido ou atingiu o limite.');
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function readVote(value${input}) {
|
|
52
|
+
assert(value !== null && typeof value === 'object' && 'id' in value && 'choice' in value, 'Voto salvo inválido.');
|
|
53
|
+
assert(typeof value.id === 'string' && (value.choice === 'sim' || value.choice === 'nao'), 'Voto salvo inválido.');
|
|
54
|
+
return { id: value.id, choice: value.choice };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function readPoll(value${input}) {
|
|
58
|
+
assert(value !== null && typeof value === 'object' && 'question' in value && 'authorID' in value && 'closed' in value && 'votes' in value,
|
|
59
|
+
'Nenhuma enquete válida neste canal.');
|
|
60
|
+
assert(typeof value.question === 'string' && value.question.length <= 500 && typeof value.authorID === 'string'
|
|
61
|
+
&& typeof value.closed === 'boolean' && Array.isArray(value.votes) && value.votes.length <= 1000,
|
|
62
|
+
'A enquete salva é inválida.');
|
|
63
|
+
const votes = value.votes.map(readVote);
|
|
64
|
+
assert(new Set(votes.map(vote => vote.id)).size === votes.length, 'Há votos duplicados na enquete salva.');
|
|
65
|
+
return { question: value.question, authorID: value.authorID, closed: value.closed, votes };
|
|
66
|
+
}
|
|
67
|
+
` };
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=bot-template-content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot-template-content.js","sourceRoot":"","sources":["../../src/cli/bot-template-content.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGzD,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,MAAM,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,kBAAkB,CAAC;IACzD,eAAe,EAAE,CAAC,QAAQ,EAAE,sCAAsC,EAAE,kCAAkC,EAAE,oBAAoB,EAAE,SAAS,EAAE,oBAAoB,EAAE,eAAe,EAAE,SAAS,CAAC;IAC1L,UAAU,EAAE,CAAC,oBAAoB,EAAE,qBAAqB,EAAE,4BAA4B,EAAE,0BAA0B,EAAE,SAAS,CAAC;IAC9H,SAAS,EAAE,CAAC,sCAAsC,EAAE,aAAa,EAAE,8CAA8C,EAAE,kBAAkB,EAAE,kCAAkC,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,iBAAiB,CAAC;IACzO,OAAO,EAAE,CAAC,QAAQ,EAAE,iBAAiB,EAAE,SAAS,EAAE,YAAY,EAAE,oBAAoB,CAAC;IACrF,aAAa,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,iCAAiC,EAAE,oBAAoB,CAAC;IAC9F,OAAO,EAAE,CAAC,kBAAkB,EAAE,WAAW,EAAE,iCAAiC,EAAE,+BAA+B,EAAE,eAAe,EAAE,iBAAiB,CAAC;CAC3G,CAAC;AAE1C,MAAM,UAAU,cAAc,CAAC,QAAqB;IAClD,MAAM,KAAK,GAAsB,YAAY,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC;IAC9D,MAAM,UAAU,GAAG;QACjB,WAAW,QAAQ,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE;QAC9D,4MAA4M;QAC5M,gBAAgB,gBAAgB,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;KACvF,CAAC;IACF,IAAI,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QAAE,UAAU,CAAC,IAAI,CAAC,yPAAyP,CAAC,CAAC;IACjT,IAAI,KAAK,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAAE,UAAU,CAAC,IAAI,CAAC,uSAAuS,CAAC,CAAC;IAChW,IAAI,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC;QAAE,UAAU,CAAC,IAAI,CAAC,4RAA4R,CAAC,CAAC;IACnV,IAAI,KAAK,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAAE,UAAU,CAAC,IAAI,CAAC,mNAAmN,CAAC,CAAC;IAC5Q,IAAI,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC;QAAE,UAAU,CAAC,IAAI,CAAC,6KAA6K,CAAC,CAAC;IACjO,UAAU,CAAC,IAAI,CAAC,gPAAgP,CAAC,CAAC;IAClQ,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAqB,EAAE,QAAqB;IAC1E,MAAM,KAAK,GAAsB,YAAY,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC;IAC9D,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,IAAI,KAAK,iBAAiB,CAAC;QAAE,OAAO,EAAE,CAAC;IAC/H,MAAM,KAAK,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;IACnD,OAAO,EAAE,CAAC,iBAAiB,QAAQ,EAAE,CAAC,EAAE;;mCAEP,KAAK;;;;;;;;mCAQL,KAAK;;;;;yBAKf,KAAK;;;;;;gCAME,KAAK;;;;;;;;;;CAUpC,EAAE,CAAC;AACJ,CAAC","sourcesContent":["import { botTemplates } from './bot-template-catalog.js';\nimport type { BotTemplate } from './bot-template-catalog.js';\n\nexport const templateExamples = {\n simple: ['!ping', '!ajuda', '!sobre', '!avatar @usuario'],\n multifunctional: ['!ajuda', '!regras definir Respeite os membros.', '!enquete criar Vamos jogar hoje?', '!enquete votar sim', '!diario', '!pagar @usuario 25', '!notas listar', '!caso 1'],\n moderation: ['!ban @usuario spam', '!kick @usuario spam', '!timeout @usuario 10m spam', '!unban 123456789 revisão', '!caso 1'],\n community: ['!regras definir Respeite os membros.', '!regras ver', '!sugestao enviar Adicionar um canal de jogos', '!sugestao listar', '!enquete criar Vamos jogar hoje?', '!enquete votar sim', '!enquete resultado', '!enquete fechar'],\n economy: ['!saldo', '!saldo @usuario', '!diario', '!trabalhar', '!pagar @usuario 25'],\n entertainment: ['!dado 20', '!moeda', '!escolher pizza | sushi | massa', '!bola8 Vai chover?'],\n utility: ['!perfil @usuario', '!servidor', '!data 2026-01-20T18:30:00-03:00', '!notas adicionar Comprar café', '!notas listar', '!notas apagar 1'],\n} satisfies Record<BotTemplate, string[]>;\n\nexport function templateReadme(template: BotTemplate): string {\n const paths: readonly string[] = botTemplates[template].paths;\n const paragraphs = [\n `Base: **${template}**. ${botTemplates[template].description}`,\n 'Todas as bases incluem `!ping`, `!ajuda` (aliases `help`, `comandos`), `!sobre` e `!avatar [@usuario]`. Ajuda e consultas de informações usam embeds. As pastas de commands são carregadas recursivamente.',\n `Exemplos:\\n\\n${templateExamples[template].map(value => `- \\`${value}\\``).join('\\n')}`,\n ];\n if (paths.includes('moderation/ban')) paragraphs.push('Moderação exige permissões de autor e bot e hierarquia sobre o alvo. `caso` exige ManageGuild. Kick, timeout e unban exigem motivo; timeout aceita de 1 segundo a 28 dias. Falha depois da ação é parcial: não repita a ação para tentar salvar o caso.');\n if (paths.includes('community/rules')) paragraphs.push('Regras e criação de enquetes exigem ManageGuild. Há uma enquete de sim/não por canal, até 1000 participantes, com alteração de voto. Somente o criador encerra; o resultado permanece disponível. Sugestões são públicas, limitadas às 10 mais recentes, com cooldown de 30 segundos por autor/canal.');\n if (paths.includes('economy/daily')) paragraphs.push('Moedas são virtuais e isoladas por servidor. Diário concede 100 a cada 24 horas; trabalho, 25 a cada hora. Prazos persistem após reinício. Transferências de 1 a 1000000 moedas são atômicas, não permitem saldo negativo, autoenvio ou bots. Não há dinheiro real ou pagamentos externos.');\n if (paths.includes('utilities/notes')) paragraphs.push('Notas funcionam somente em DM, são isoladas por usuário e limitadas a 10 entradas de 300 caracteres. Apagar uma nota renumera as seguintes. `data` exige ISO com fuso explícito e retorna UTC e Unix em segundos.');\n if (paths.includes('fun/choose')) paragraphs.push('`escolher` aceita de 2 a 20 opções não vazias de até 100 caracteres, separadas por |. `dado` aceita de 2 a 100 lados. `bola8` responde aleatoriamente, apenas por diversão.');\n paragraphs.push('Os testes usam MockTransport, recursos simulados e store em memória. `check` valida sem login; `npm test` exercita comandos e guards. Dados reais usam o store configurado pela CLI; reinicie o processo após mudar helpers fora de commands/.');\n return paragraphs.join('\\n\\n');\n}\n\nexport function templateHelpers(template: BotTemplate, language: 'js' | 'ts'): Record<string, string> {\n const paths: readonly string[] = botTemplates[template].paths;\n if (!paths.some(path => path.startsWith('community/') || path.startsWith('economy/') || path === 'utilities/notes')) return {};\n const input = language === 'ts' ? ': unknown' : '';\n return { [`helpers/state.${language}`]: `import { assert } from 'yuzuha';\n\nexport function readStrings(value${input}) {\n assert(Array.isArray(value) && value.length <= 10, 'A lista salva é inválida.');\n return value.map(item => {\n assert(typeof item === 'string' && item.length <= 400, 'A entrada salva é inválida.');\n return item;\n });\n}\n\nexport function readBalance(value${input}) {\n assert(typeof value === 'number' && Number.isSafeInteger(value) && value >= 0, 'O saldo salvo é inválido ou atingiu o limite.');\n return value;\n}\n\nfunction readVote(value${input}) {\n assert(value !== null && typeof value === 'object' && 'id' in value && 'choice' in value, 'Voto salvo inválido.');\n assert(typeof value.id === 'string' && (value.choice === 'sim' || value.choice === 'nao'), 'Voto salvo inválido.');\n return { id: value.id, choice: value.choice };\n}\n\nexport function readPoll(value${input}) {\n assert(value !== null && typeof value === 'object' && 'question' in value && 'authorID' in value && 'closed' in value && 'votes' in value,\n 'Nenhuma enquete válida neste canal.');\n assert(typeof value.question === 'string' && value.question.length <= 500 && typeof value.authorID === 'string'\n && typeof value.closed === 'boolean' && Array.isArray(value.votes) && value.votes.length <= 1000,\n 'A enquete salva é inválida.');\n const votes = value.votes.map(readVote);\n assert(new Set(votes.map(vote => vote.id)).size === votes.length, 'Há votos duplicados na enquete salva.');\n return { question: value.question, authorID: value.authorID, closed: value.closed, votes };\n}\n` };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot-template-feature-tests.d.ts","sourceRoot":"","sources":["../../src/cli/bot-template-feature-tests.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CA8J7D"}
|