@2byte/tgbot-framework 1.0.6 → 1.0.8

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.
Files changed (59) hide show
  1. package/README.md +300 -300
  2. package/bin/2byte-cli.ts +97 -97
  3. package/package.json +55 -55
  4. package/src/cli/CreateBotCommand.ts +181 -181
  5. package/src/cli/GenerateCommand.ts +195 -195
  6. package/src/cli/InitCommand.ts +107 -107
  7. package/src/cli/TgAccountManager.ts +50 -50
  8. package/src/console/migrate.ts +82 -82
  9. package/src/core/ApiService.ts +20 -20
  10. package/src/core/ApiServiceManager.ts +63 -63
  11. package/src/core/App.ts +1157 -1143
  12. package/src/core/BotArtisan.ts +79 -79
  13. package/src/core/BotMigration.ts +30 -30
  14. package/src/core/BotSeeder.ts +66 -66
  15. package/src/core/Model.ts +84 -84
  16. package/src/core/utils.ts +2 -2
  17. package/src/illumination/Artisan.ts +149 -149
  18. package/src/illumination/InlineKeyboard.ts +61 -61
  19. package/src/illumination/Message2Byte.ts +255 -255
  20. package/src/illumination/Message2ByteLiveProgressive.ts +278 -278
  21. package/src/illumination/Message2bytePool.ts +107 -107
  22. package/src/illumination/Migration.ts +186 -186
  23. package/src/illumination/RunSectionRoute.ts +85 -85
  24. package/src/illumination/Section.ts +410 -410
  25. package/src/illumination/SectionComponent.ts +64 -64
  26. package/src/illumination/Telegraf2byteContext.ts +32 -32
  27. package/src/index.ts +42 -42
  28. package/src/libs/TelegramAccountControl.ts +1140 -1140
  29. package/src/libs/TgSender.ts +53 -53
  30. package/src/models/Model.ts +67 -67
  31. package/src/models/Proxy.ts +217 -217
  32. package/src/models/TgAccount.ts +362 -362
  33. package/src/models/index.ts +2 -2
  34. package/src/types.ts +191 -191
  35. package/src/user/UserModel.ts +297 -297
  36. package/src/user/UserStore.ts +119 -119
  37. package/src/workflow/services/MassSendApiService.ts +83 -80
  38. package/templates/bot/.env.example +33 -33
  39. package/templates/bot/artisan.ts +8 -8
  40. package/templates/bot/bot.ts +82 -82
  41. package/templates/bot/database/dbConnector.ts +4 -4
  42. package/templates/bot/database/migrate.ts +9 -9
  43. package/templates/bot/database/migrations/001_create_users.sql +18 -18
  44. package/templates/bot/database/migrations/007_proxy.sql +27 -27
  45. package/templates/bot/database/migrations/008_tg_accounts.sql +32 -32
  46. package/templates/bot/database/seed.ts +14 -14
  47. package/templates/bot/docs/CLI_SERVICES.md +536 -536
  48. package/templates/bot/docs/INPUT_SYSTEM.md +211 -211
  49. package/templates/bot/docs/MASS_SEND_SERVICE.md +327 -0
  50. package/templates/bot/docs/SERVICE_EXAMPLES.md +384 -384
  51. package/templates/bot/docs/TASK_SYSTEM.md +156 -156
  52. package/templates/bot/models/Model.ts +7 -7
  53. package/templates/bot/models/index.ts +1 -1
  54. package/templates/bot/package.json +30 -30
  55. package/templates/bot/sectionList.ts +9 -9
  56. package/templates/bot/sections/ExampleInputSection.ts +85 -85
  57. package/templates/bot/sections/ExampleLiveTaskerSection.ts +60 -60
  58. package/templates/bot/sections/HomeSection.ts +63 -63
  59. package/templates/bot/workflow/services/ExampleService.ts +23 -23
@@ -1,196 +1,196 @@
1
- import * as fs from 'fs-extra';
2
- import * as path from 'path';
3
- import chalk from 'chalk';
4
-
5
- export class GenerateCommand {
6
- async generateSection(name: string): Promise<void> {
7
- console.log(chalk.blue(`🎯 Generating section: ${name}`));
8
-
9
- const currentDir = process.cwd();
10
- const sectionsDir = path.join(currentDir, 'sections');
11
- const sectionName = this.formatSectionName(name);
12
- const sectionPath = path.join(sectionsDir, `${sectionName}Section.ts`);
13
-
14
- // Ensure sections directory exists
15
- await fs.ensureDir(sectionsDir);
16
-
17
- // Check if section already exists
18
- if (await fs.pathExists(sectionPath)) {
19
- console.log(chalk.red(`❌ Section ${sectionName} already exists at ${sectionPath}`));
20
- return;
21
- }
22
-
23
- // Generate section content
24
- const template = this.getSectionTemplate(sectionName);
25
- await fs.writeFile(sectionPath, template);
26
-
27
- console.log(chalk.green(`✅ Created section ${sectionName} at ${sectionPath}`));
28
- }
29
-
30
- async generateService(name: string): Promise<void> {
31
- console.log(chalk.blue(`⚙️ Generating service: ${name}`));
32
-
33
- const currentDir = process.cwd();
34
- const servicesDir = path.join(currentDir, 'workflow', 'services');
35
- const serviceName = this.formatServiceName(name);
36
- const servicePath = path.join(servicesDir, `${serviceName}.ts`);
37
-
38
- // Ensure services directory exists
39
- await fs.ensureDir(servicesDir);
40
-
41
- // Check if service already exists
42
- if (await fs.pathExists(servicePath)) {
43
- console.log(chalk.red(`❌ Service ${serviceName} already exists at ${servicePath}`));
44
- return;
45
- }
46
-
47
- // Generate service content
48
- const template = this.getServiceTemplate(serviceName);
49
- await fs.writeFile(servicePath, template);
50
-
51
- console.log(chalk.green(`✅ Created service ${serviceName} at ${servicePath}`));
52
- console.log(chalk.yellow(`💡 Service will be automatically loaded from workflow/services directory`));
53
- }
54
-
55
- async generateMigration(name: string): Promise<void> {
56
- console.log(chalk.blue(`🗃️ Generating migration: ${name}`));
57
-
58
- const currentDir = process.cwd();
59
- const migrationsDir = path.join(currentDir, 'database', 'migrations');
60
-
61
- // Ensure migrations directory exists
62
- await fs.ensureDir(migrationsDir);
63
-
64
- // Get next migration ID
65
- const files = await fs.readdir(migrationsDir);
66
- const migrationFiles = files
67
- .filter(file => file.endsWith('.sql'))
68
- .map(file => parseInt(file.split('_')[0]))
69
- .filter(id => !isNaN(id));
70
-
71
- const nextId = (Math.max(0, ...migrationFiles) + 1).toString().padStart(3, '0');
72
- const fileName = `${nextId}_${name}.sql`;
73
- const filePath = path.join(migrationsDir, fileName);
74
-
75
- const template = this.getMigrationTemplate(name);
76
- await fs.writeFile(filePath, template);
77
-
78
- console.log(chalk.green(`✅ Created migration: ${fileName}`));
79
- }
80
-
81
- private formatSectionName(name: string): string {
82
- return name.charAt(0).toUpperCase() + name.slice(1);
83
- }
84
-
85
- private formatServiceName(name: string): string {
86
- // Convert to PascalCase and add "Service" suffix if not present
87
- const pascalName = name.charAt(0).toUpperCase() + name.slice(1);
88
- return pascalName.endsWith('Service') ? pascalName : `${pascalName}Service`;
89
- }
90
-
91
- private getSectionTemplate(name: string): string {
92
- return `import { Section } from "@2byte/tgbot-framework";
93
- import { SectionOptions } from "@2byte/tgbot-framework";
94
- import { InlineKeyboard } from "@2byte/tgbot-framework";
95
-
96
- export default class ${name}Section extends Section {
97
- static command = "${name.toLowerCase()}";
98
- static description = "${name} section";
99
- static actionRoutes = {
100
- "${name}.index": "index",
101
- };
102
-
103
- public sectionId = "${name}";
104
- private mainInlineKeyboard: InlineKeyboard;
105
-
106
- constructor(options: SectionOptions) {
107
- super(options);
108
-
109
- this.mainInlineKeyboard = this.makeInlineKeyboard().addFootFixedButtons(this.btnHome);
110
- }
111
-
112
- public async up(): Promise<void> {}
113
- public async down(): Promise<void> {}
114
- public async setup(): Promise<void> {}
115
- public async unsetup(): Promise<void> {}
116
-
117
- async index() {
118
- const message = \`
119
- 👋 Welcome to ${name} Section
120
- \`;
121
-
122
- await this.message(message)
123
- .inlineKeyboard(this.mainInlineKeyboard)
124
- .send();
125
- }
126
- }
127
- `;
128
- }
129
-
130
- private getServiceTemplate(name: string): string {
131
- return `import { App } from "@2byte/tgbot-framework";
132
- import { ApiService } from "@2byte/tgbot-framework";
133
-
134
- export default class ${name} extends ApiService {
135
-
136
- constructor(
137
- protected app: App,
138
- public name: string = "${name}"
139
- ) {
140
- super(app, name);
141
- }
142
-
143
- /**
144
- * Setup method called when service is registered
145
- * Use this for initialization tasks like setting up connections,
146
- * loading configurations, etc.
147
- */
148
- public async setup(): Promise<void> {
149
- // TODO: Add setup logic here
150
- this.app.debugLog(\`[\${this.name}] Service setup completed\`);
151
- return Promise.resolve();
152
- }
153
-
154
- /**
155
- * Cleanup method called when service is being destroyed
156
- * Use this for cleanup tasks like closing connections,
157
- * releasing resources, etc.
158
- */
159
- public async unsetup(): Promise<void> {
160
- // TODO: Add cleanup logic here
161
- this.app.debugLog(\`[\${this.name}] Service cleanup completed\`);
162
- return Promise.resolve();
163
- }
164
-
165
- /**
166
- * Main run method for the service
167
- * This is where your service's main logic should be implemented
168
- */
169
- public async run(): Promise<void> {
170
- // TODO: Add your service logic here
171
- this.app.debugLog(\`[\${this.name}] Service running\`);
172
- return Promise.resolve();
173
- }
174
-
175
- /**
176
- * Example method - you can add your own methods here
177
- */
178
- // public async exampleMethod(): Promise<void> {
179
- // // Your custom logic
180
- // }
181
- }
182
- `;
183
- }
184
-
185
- private getMigrationTemplate(name: string): string {
186
- return `-- UP
187
- CREATE TABLE IF NOT EXISTS ${name} (
188
- id INTEGER PRIMARY KEY AUTOINCREMENT,
189
- created_at DATETIME DEFAULT CURRENT_TIMESTAMP
190
- );
191
-
192
- -- DOWN
193
- DROP TABLE IF EXISTS ${name};
194
- `;
195
- }
1
+ import * as fs from 'fs-extra';
2
+ import * as path from 'path';
3
+ import chalk from 'chalk';
4
+
5
+ export class GenerateCommand {
6
+ async generateSection(name: string): Promise<void> {
7
+ console.log(chalk.blue(`🎯 Generating section: ${name}`));
8
+
9
+ const currentDir = process.cwd();
10
+ const sectionsDir = path.join(currentDir, 'sections');
11
+ const sectionName = this.formatSectionName(name);
12
+ const sectionPath = path.join(sectionsDir, `${sectionName}Section.ts`);
13
+
14
+ // Ensure sections directory exists
15
+ await fs.ensureDir(sectionsDir);
16
+
17
+ // Check if section already exists
18
+ if (await fs.pathExists(sectionPath)) {
19
+ console.log(chalk.red(`❌ Section ${sectionName} already exists at ${sectionPath}`));
20
+ return;
21
+ }
22
+
23
+ // Generate section content
24
+ const template = this.getSectionTemplate(sectionName);
25
+ await fs.writeFile(sectionPath, template);
26
+
27
+ console.log(chalk.green(`✅ Created section ${sectionName} at ${sectionPath}`));
28
+ }
29
+
30
+ async generateService(name: string): Promise<void> {
31
+ console.log(chalk.blue(`⚙️ Generating service: ${name}`));
32
+
33
+ const currentDir = process.cwd();
34
+ const servicesDir = path.join(currentDir, 'workflow', 'services');
35
+ const serviceName = this.formatServiceName(name);
36
+ const servicePath = path.join(servicesDir, `${serviceName}.ts`);
37
+
38
+ // Ensure services directory exists
39
+ await fs.ensureDir(servicesDir);
40
+
41
+ // Check if service already exists
42
+ if (await fs.pathExists(servicePath)) {
43
+ console.log(chalk.red(`❌ Service ${serviceName} already exists at ${servicePath}`));
44
+ return;
45
+ }
46
+
47
+ // Generate service content
48
+ const template = this.getServiceTemplate(serviceName);
49
+ await fs.writeFile(servicePath, template);
50
+
51
+ console.log(chalk.green(`✅ Created service ${serviceName} at ${servicePath}`));
52
+ console.log(chalk.yellow(`💡 Service will be automatically loaded from workflow/services directory`));
53
+ }
54
+
55
+ async generateMigration(name: string): Promise<void> {
56
+ console.log(chalk.blue(`🗃️ Generating migration: ${name}`));
57
+
58
+ const currentDir = process.cwd();
59
+ const migrationsDir = path.join(currentDir, 'database', 'migrations');
60
+
61
+ // Ensure migrations directory exists
62
+ await fs.ensureDir(migrationsDir);
63
+
64
+ // Get next migration ID
65
+ const files = await fs.readdir(migrationsDir);
66
+ const migrationFiles = files
67
+ .filter(file => file.endsWith('.sql'))
68
+ .map(file => parseInt(file.split('_')[0]))
69
+ .filter(id => !isNaN(id));
70
+
71
+ const nextId = (Math.max(0, ...migrationFiles) + 1).toString().padStart(3, '0');
72
+ const fileName = `${nextId}_${name}.sql`;
73
+ const filePath = path.join(migrationsDir, fileName);
74
+
75
+ const template = this.getMigrationTemplate(name);
76
+ await fs.writeFile(filePath, template);
77
+
78
+ console.log(chalk.green(`✅ Created migration: ${fileName}`));
79
+ }
80
+
81
+ private formatSectionName(name: string): string {
82
+ return name.charAt(0).toUpperCase() + name.slice(1);
83
+ }
84
+
85
+ private formatServiceName(name: string): string {
86
+ // Convert to PascalCase and add "Service" suffix if not present
87
+ const pascalName = name.charAt(0).toUpperCase() + name.slice(1);
88
+ return pascalName.endsWith('Service') ? pascalName : `${pascalName}Service`;
89
+ }
90
+
91
+ private getSectionTemplate(name: string): string {
92
+ return `import { Section } from "@2byte/tgbot-framework";
93
+ import { SectionOptions } from "@2byte/tgbot-framework";
94
+ import { InlineKeyboard } from "@2byte/tgbot-framework";
95
+
96
+ export default class ${name}Section extends Section {
97
+ static command = "${name.toLowerCase()}";
98
+ static description = "${name} section";
99
+ static actionRoutes = {
100
+ "${name}.index": "index",
101
+ };
102
+
103
+ public sectionId = "${name}";
104
+ private mainInlineKeyboard: InlineKeyboard;
105
+
106
+ constructor(options: SectionOptions) {
107
+ super(options);
108
+
109
+ this.mainInlineKeyboard = this.makeInlineKeyboard().addFootFixedButtons(this.btnHome);
110
+ }
111
+
112
+ public async up(): Promise<void> {}
113
+ public async down(): Promise<void> {}
114
+ public async setup(): Promise<void> {}
115
+ public async unsetup(): Promise<void> {}
116
+
117
+ async index() {
118
+ const message = \`
119
+ 👋 Welcome to ${name} Section
120
+ \`;
121
+
122
+ await this.message(message)
123
+ .inlineKeyboard(this.mainInlineKeyboard)
124
+ .send();
125
+ }
126
+ }
127
+ `;
128
+ }
129
+
130
+ private getServiceTemplate(name: string): string {
131
+ return `import { App } from "@2byte/tgbot-framework";
132
+ import { ApiService } from "@2byte/tgbot-framework";
133
+
134
+ export default class ${name} extends ApiService {
135
+
136
+ constructor(
137
+ protected app: App,
138
+ public name: string = "${name}"
139
+ ) {
140
+ super(app, name);
141
+ }
142
+
143
+ /**
144
+ * Setup method called when service is registered
145
+ * Use this for initialization tasks like setting up connections,
146
+ * loading configurations, etc.
147
+ */
148
+ public async setup(): Promise<void> {
149
+ // TODO: Add setup logic here
150
+ this.app.debugLog(\`[\${this.name}] Service setup completed\`);
151
+ return Promise.resolve();
152
+ }
153
+
154
+ /**
155
+ * Cleanup method called when service is being destroyed
156
+ * Use this for cleanup tasks like closing connections,
157
+ * releasing resources, etc.
158
+ */
159
+ public async unsetup(): Promise<void> {
160
+ // TODO: Add cleanup logic here
161
+ this.app.debugLog(\`[\${this.name}] Service cleanup completed\`);
162
+ return Promise.resolve();
163
+ }
164
+
165
+ /**
166
+ * Main run method for the service
167
+ * This is where your service's main logic should be implemented
168
+ */
169
+ public async run(): Promise<void> {
170
+ // TODO: Add your service logic here
171
+ this.app.debugLog(\`[\${this.name}] Service running\`);
172
+ return Promise.resolve();
173
+ }
174
+
175
+ /**
176
+ * Example method - you can add your own methods here
177
+ */
178
+ // public async exampleMethod(): Promise<void> {
179
+ // // Your custom logic
180
+ // }
181
+ }
182
+ `;
183
+ }
184
+
185
+ private getMigrationTemplate(name: string): string {
186
+ return `-- UP
187
+ CREATE TABLE IF NOT EXISTS ${name} (
188
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
189
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
190
+ );
191
+
192
+ -- DOWN
193
+ DROP TABLE IF EXISTS ${name};
194
+ `;
195
+ }
196
196
  }
@@ -1,108 +1,108 @@
1
- import * as fs from 'fs-extra';
2
- import * as path from 'path';
3
- import chalk from 'chalk';
4
-
5
- export class InitCommand {
6
- async execute(options: any): Promise<void> {
7
- const currentDir = process.cwd();
8
- const packageJsonPath = path.join(currentDir, 'package.json');
9
-
10
- console.log(chalk.blue('🔧 Initializing 2byte bot in current directory...'));
11
-
12
- // Check if already a 2byte bot
13
- if (await fs.pathExists(packageJsonPath)) {
14
- const packageJson = await fs.readJson(packageJsonPath);
15
-
16
- if (packageJson.dependencies && packageJson.dependencies['2bytetgbot']) {
17
- if (!options.force) {
18
- console.log(chalk.yellow('⚠️ This directory already contains a 2byte bot.'));
19
- console.log(chalk.yellow(' Use --force to override existing files.'));
20
- return;
21
- }
22
- }
23
- }
24
-
25
- // Create basic bot structure
26
- await this.createBotStructure(currentDir, options);
27
-
28
- console.log(chalk.green('✅ 2byte bot initialized successfully!'));
29
- console.log(chalk.blue('📋 Next steps:'));
30
- console.log(' bun install # Install dependencies');
31
- console.log(' bun run migrate # Run migrations');
32
- console.log(' bun run seed # Seed database');
33
- console.log(' bun run dev # Start bot');
34
- }
35
-
36
- private async createBotStructure(targetPath: string, options: any): Promise<void> {
37
- const templatesPath = path.join(__dirname, '../../templates/bot');
38
-
39
- // Copy essential files
40
- const essentialFiles = [
41
- 'package.json',
42
- 'artisan.ts',
43
- 'bot.ts',
44
- 'sections.ts',
45
- '.env.example',
46
- 'database/migrate.ts',
47
- 'database/seed.ts',
48
- ];
49
-
50
- for (const file of essentialFiles) {
51
- const sourcePath = path.join(templatesPath, file);
52
- const targetFilePath = path.join(targetPath, file);
53
-
54
- if (await fs.pathExists(sourcePath)) {
55
- if (!options.force && await fs.pathExists(targetFilePath)) {
56
- console.log(chalk.yellow(`⚠️ Skipping ${file} (already exists)`));
57
- continue;
58
- }
59
-
60
- await fs.ensureDir(path.dirname(targetFilePath));
61
-
62
- // Read and process template
63
- let content = await fs.readFile(sourcePath, 'utf-8');
64
-
65
- // For now, use current directory name as bot name
66
- const botName = path.basename(targetPath);
67
- const config = {
68
- botName,
69
- className: this.toPascalCase(botName),
70
- kebabName: this.toKebabCase(botName),
71
- description: `A telegram bot created with 2byte framework`,
72
- author: '',
73
- useDatabase: true,
74
- };
75
-
76
- // Simple template replacement
77
- content = this.processTemplate(content, config);
78
-
79
- await fs.writeFile(targetFilePath, content);
80
- console.log(chalk.green(`✅ Created ${file}`));
81
- }
82
- }
83
- }
84
-
85
- private processTemplate(content: string, config: any): string {
86
- // Simple mustache-style replacement
87
- return content
88
- .replace(/\{\{botName\}\}/g, config.botName)
89
- .replace(/\{\{className\}\}/g, config.className)
90
- .replace(/\{\{kebabName\}\}/g, config.kebabName)
91
- .replace(/\{\{description\}\}/g, config.description)
92
- .replace(/\{\{author\}\}/g, config.author);
93
- }
94
-
95
- private toPascalCase(str: string): string {
96
- return str
97
- .split(/[-_\s]+/)
98
- .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
99
- .join('');
100
- }
101
-
102
- private toKebabCase(str: string): string {
103
- return str
104
- .replace(/([a-z])([A-Z])/g, '$1-$2')
105
- .replace(/[\s_]+/g, '-')
106
- .toLowerCase();
107
- }
1
+ import * as fs from 'fs-extra';
2
+ import * as path from 'path';
3
+ import chalk from 'chalk';
4
+
5
+ export class InitCommand {
6
+ async execute(options: any): Promise<void> {
7
+ const currentDir = process.cwd();
8
+ const packageJsonPath = path.join(currentDir, 'package.json');
9
+
10
+ console.log(chalk.blue('🔧 Initializing 2byte bot in current directory...'));
11
+
12
+ // Check if already a 2byte bot
13
+ if (await fs.pathExists(packageJsonPath)) {
14
+ const packageJson = await fs.readJson(packageJsonPath);
15
+
16
+ if (packageJson.dependencies && packageJson.dependencies['2bytetgbot']) {
17
+ if (!options.force) {
18
+ console.log(chalk.yellow('⚠️ This directory already contains a 2byte bot.'));
19
+ console.log(chalk.yellow(' Use --force to override existing files.'));
20
+ return;
21
+ }
22
+ }
23
+ }
24
+
25
+ // Create basic bot structure
26
+ await this.createBotStructure(currentDir, options);
27
+
28
+ console.log(chalk.green('✅ 2byte bot initialized successfully!'));
29
+ console.log(chalk.blue('📋 Next steps:'));
30
+ console.log(' bun install # Install dependencies');
31
+ console.log(' bun run migrate # Run migrations');
32
+ console.log(' bun run seed # Seed database');
33
+ console.log(' bun run dev # Start bot');
34
+ }
35
+
36
+ private async createBotStructure(targetPath: string, options: any): Promise<void> {
37
+ const templatesPath = path.join(__dirname, '../../templates/bot');
38
+
39
+ // Copy essential files
40
+ const essentialFiles = [
41
+ 'package.json',
42
+ 'artisan.ts',
43
+ 'bot.ts',
44
+ 'sections.ts',
45
+ '.env.example',
46
+ 'database/migrate.ts',
47
+ 'database/seed.ts',
48
+ ];
49
+
50
+ for (const file of essentialFiles) {
51
+ const sourcePath = path.join(templatesPath, file);
52
+ const targetFilePath = path.join(targetPath, file);
53
+
54
+ if (await fs.pathExists(sourcePath)) {
55
+ if (!options.force && await fs.pathExists(targetFilePath)) {
56
+ console.log(chalk.yellow(`⚠️ Skipping ${file} (already exists)`));
57
+ continue;
58
+ }
59
+
60
+ await fs.ensureDir(path.dirname(targetFilePath));
61
+
62
+ // Read and process template
63
+ let content = await fs.readFile(sourcePath, 'utf-8');
64
+
65
+ // For now, use current directory name as bot name
66
+ const botName = path.basename(targetPath);
67
+ const config = {
68
+ botName,
69
+ className: this.toPascalCase(botName),
70
+ kebabName: this.toKebabCase(botName),
71
+ description: `A telegram bot created with 2byte framework`,
72
+ author: '',
73
+ useDatabase: true,
74
+ };
75
+
76
+ // Simple template replacement
77
+ content = this.processTemplate(content, config);
78
+
79
+ await fs.writeFile(targetFilePath, content);
80
+ console.log(chalk.green(`✅ Created ${file}`));
81
+ }
82
+ }
83
+ }
84
+
85
+ private processTemplate(content: string, config: any): string {
86
+ // Simple mustache-style replacement
87
+ return content
88
+ .replace(/\{\{botName\}\}/g, config.botName)
89
+ .replace(/\{\{className\}\}/g, config.className)
90
+ .replace(/\{\{kebabName\}\}/g, config.kebabName)
91
+ .replace(/\{\{description\}\}/g, config.description)
92
+ .replace(/\{\{author\}\}/g, config.author);
93
+ }
94
+
95
+ private toPascalCase(str: string): string {
96
+ return str
97
+ .split(/[-_\s]+/)
98
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
99
+ .join('');
100
+ }
101
+
102
+ private toKebabCase(str: string): string {
103
+ return str
104
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
105
+ .replace(/[\s_]+/g, '-')
106
+ .toLowerCase();
107
+ }
108
108
  }