codebakers 1.0.45 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +275 -60
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3999 -0
- package/install.bat +9 -0
- package/package.json +71 -115
- package/src/channels/discord.ts +5 -0
- package/src/channels/slack.ts +5 -0
- package/src/channels/sms.ts +4 -0
- package/src/channels/telegram.ts +5 -0
- package/src/channels/whatsapp.ts +7 -0
- package/src/commands/check.ts +365 -0
- package/src/commands/code.ts +684 -0
- package/src/commands/connect.ts +12 -0
- package/src/commands/deploy.ts +414 -0
- package/src/commands/fix.ts +20 -0
- package/src/commands/gateway.ts +604 -0
- package/src/commands/generate.ts +178 -0
- package/src/commands/init.ts +574 -0
- package/src/commands/learn.ts +36 -0
- package/src/commands/security.ts +102 -0
- package/src/commands/setup.ts +448 -0
- package/src/commands/status.ts +56 -0
- package/src/index.ts +268 -0
- package/src/patterns/loader.ts +337 -0
- package/src/services/github.ts +61 -0
- package/src/services/supabase.ts +147 -0
- package/src/services/vercel.ts +61 -0
- package/src/utils/claude-md.ts +287 -0
- package/src/utils/config.ts +282 -0
- package/src/utils/updates.ts +27 -0
- package/tsconfig.json +17 -10
- package/.vscodeignore +0 -18
- package/LICENSE +0 -21
- package/codebakers-1.0.0.vsix +0 -0
- package/codebakers-1.0.10.vsix +0 -0
- package/codebakers-1.0.11.vsix +0 -0
- package/codebakers-1.0.12.vsix +0 -0
- package/codebakers-1.0.13.vsix +0 -0
- package/codebakers-1.0.14.vsix +0 -0
- package/codebakers-1.0.15.vsix +0 -0
- package/codebakers-1.0.16.vsix +0 -0
- package/codebakers-1.0.17.vsix +0 -0
- package/codebakers-1.0.18.vsix +0 -0
- package/codebakers-1.0.19.vsix +0 -0
- package/codebakers-1.0.20.vsix +0 -0
- package/codebakers-1.0.21.vsix +0 -0
- package/codebakers-1.0.22.vsix +0 -0
- package/codebakers-1.0.23.vsix +0 -0
- package/codebakers-1.0.24.vsix +0 -0
- package/codebakers-1.0.25.vsix +0 -0
- package/codebakers-1.0.26.vsix +0 -0
- package/codebakers-1.0.27.vsix +0 -0
- package/codebakers-1.0.28.vsix +0 -0
- package/codebakers-1.0.29.vsix +0 -0
- package/codebakers-1.0.30.vsix +0 -0
- package/codebakers-1.0.31.vsix +0 -0
- package/codebakers-1.0.32.vsix +0 -0
- package/codebakers-1.0.35.vsix +0 -0
- package/codebakers-1.0.36.vsix +0 -0
- package/codebakers-1.0.37.vsix +0 -0
- package/codebakers-1.0.38.vsix +0 -0
- package/codebakers-1.0.39.vsix +0 -0
- package/codebakers-1.0.40.vsix +0 -0
- package/codebakers-1.0.41.vsix +0 -0
- package/codebakers-1.0.42.vsix +0 -0
- package/codebakers-1.0.43.vsix +0 -0
- package/codebakers-1.0.44.vsix +0 -0
- package/codebakers-1.0.45.vsix +0 -0
- package/dist/extension.js +0 -1394
- package/esbuild.js +0 -63
- package/media/icon.png +0 -0
- package/media/icon.svg +0 -7
- package/nul +0 -1
- package/preview.html +0 -547
- package/src/ChatPanelProvider.ts +0 -1815
- package/src/ChatViewProvider.ts +0 -749
- package/src/CodeBakersClient.ts +0 -1146
- package/src/CodeValidator.ts +0 -645
- package/src/FileOperations.ts +0 -410
- package/src/ProjectContext.ts +0 -526
- package/src/extension.ts +0 -332
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { Config } from '../utils/config.js';
|
|
4
|
+
import { WhatsAppChannel } from '../channels/whatsapp.js';
|
|
5
|
+
import { TelegramChannel } from '../channels/telegram.js';
|
|
6
|
+
import { DiscordChannel } from '../channels/discord.js';
|
|
7
|
+
import { SlackChannel } from '../channels/slack.js';
|
|
8
|
+
import { SMSChannel } from '../channels/sms.js';
|
|
9
|
+
|
|
10
|
+
interface GatewayOptions {
|
|
11
|
+
start?: boolean;
|
|
12
|
+
stop?: boolean;
|
|
13
|
+
status?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface ChannelInfo {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
description: string;
|
|
20
|
+
icon: string;
|
|
21
|
+
connected: boolean;
|
|
22
|
+
status: 'running' | 'stopped' | 'error' | 'connecting';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function gatewayCommand(options: GatewayOptions = {}): Promise<void> {
|
|
26
|
+
const config = new Config();
|
|
27
|
+
|
|
28
|
+
p.intro(chalk.bgCyan.black(' Channel Gateway '));
|
|
29
|
+
|
|
30
|
+
// Quick actions
|
|
31
|
+
if (options.start) {
|
|
32
|
+
await startAllChannels(config);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (options.stop) {
|
|
37
|
+
await stopAllChannels(config);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (options.status) {
|
|
42
|
+
await showGatewayStatus(config);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Interactive menu
|
|
47
|
+
const action = await p.select({
|
|
48
|
+
message: 'What do you want to do?',
|
|
49
|
+
options: [
|
|
50
|
+
{ value: 'status', label: '📊 View status', hint: 'see all channels' },
|
|
51
|
+
{ value: 'connect', label: '🔗 Connect channel', hint: 'add WhatsApp, Telegram, etc.' },
|
|
52
|
+
{ value: 'start', label: '▶️ Start gateway', hint: 'start receiving messages' },
|
|
53
|
+
{ value: 'stop', label: '⏹️ Stop gateway', hint: 'pause all channels' },
|
|
54
|
+
{ value: 'deploy', label: '🚀 Deploy to cloud', hint: 'always-on hosting' },
|
|
55
|
+
{ value: 'back', label: '← Back' },
|
|
56
|
+
],
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
if (p.isCancel(action) || action === 'back') {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
switch (action) {
|
|
64
|
+
case 'status':
|
|
65
|
+
await showGatewayStatus(config);
|
|
66
|
+
break;
|
|
67
|
+
case 'connect':
|
|
68
|
+
await connectChannelWizard(config);
|
|
69
|
+
break;
|
|
70
|
+
case 'start':
|
|
71
|
+
await startAllChannels(config);
|
|
72
|
+
break;
|
|
73
|
+
case 'stop':
|
|
74
|
+
await stopAllChannels(config);
|
|
75
|
+
break;
|
|
76
|
+
case 'deploy':
|
|
77
|
+
await deployGatewayWizard(config);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function showGatewayStatus(config: Config): Promise<void> {
|
|
83
|
+
const channels = await getChannelStatuses(config);
|
|
84
|
+
|
|
85
|
+
console.log(chalk.bold('\n📱 Channel Gateway Status\n'));
|
|
86
|
+
|
|
87
|
+
for (const channel of channels) {
|
|
88
|
+
const statusIcon = {
|
|
89
|
+
running: chalk.green('●'),
|
|
90
|
+
stopped: chalk.gray('○'),
|
|
91
|
+
error: chalk.red('✗'),
|
|
92
|
+
connecting: chalk.yellow('◐'),
|
|
93
|
+
}[channel.status];
|
|
94
|
+
|
|
95
|
+
const statusText = {
|
|
96
|
+
running: chalk.green('Running'),
|
|
97
|
+
stopped: chalk.gray('Stopped'),
|
|
98
|
+
error: chalk.red('Error'),
|
|
99
|
+
connecting: chalk.yellow('Connecting...'),
|
|
100
|
+
}[channel.status];
|
|
101
|
+
|
|
102
|
+
console.log(` ${channel.icon} ${channel.name.padEnd(15)} ${statusIcon} ${statusText}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
console.log('');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function getChannelStatuses(config: Config): Promise<ChannelInfo[]> {
|
|
109
|
+
const channels: ChannelInfo[] = [
|
|
110
|
+
{
|
|
111
|
+
id: 'whatsapp',
|
|
112
|
+
name: 'WhatsApp',
|
|
113
|
+
description: 'WhatsApp via Baileys',
|
|
114
|
+
icon: '💬',
|
|
115
|
+
connected: !!config.getChannelConfig('whatsapp')?.enabled,
|
|
116
|
+
status: config.getChannelConfig('whatsapp')?.enabled ? 'stopped' : 'stopped',
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: 'telegram',
|
|
120
|
+
name: 'Telegram',
|
|
121
|
+
description: 'Telegram Bot API',
|
|
122
|
+
icon: '✈️',
|
|
123
|
+
connected: !!config.getChannelConfig('telegram')?.enabled,
|
|
124
|
+
status: config.getChannelConfig('telegram')?.enabled ? 'stopped' : 'stopped',
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: 'discord',
|
|
128
|
+
name: 'Discord',
|
|
129
|
+
description: 'Discord.js bot',
|
|
130
|
+
icon: '🎮',
|
|
131
|
+
connected: !!config.getChannelConfig('discord')?.enabled,
|
|
132
|
+
status: config.getChannelConfig('discord')?.enabled ? 'stopped' : 'stopped',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: 'slack',
|
|
136
|
+
name: 'Slack',
|
|
137
|
+
description: 'Slack Bot API',
|
|
138
|
+
icon: '💼',
|
|
139
|
+
connected: !!config.getChannelConfig('slack')?.enabled,
|
|
140
|
+
status: config.getChannelConfig('slack')?.enabled ? 'stopped' : 'stopped',
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: 'sms',
|
|
144
|
+
name: 'SMS',
|
|
145
|
+
description: 'Twilio SMS',
|
|
146
|
+
icon: '📱',
|
|
147
|
+
connected: !!config.getCredentials('twilio')?.accountSid,
|
|
148
|
+
status: config.getCredentials('twilio')?.accountSid ? 'stopped' : 'stopped',
|
|
149
|
+
},
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
return channels;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function connectChannelWizard(config: Config): Promise<void> {
|
|
156
|
+
const channel = await p.select({
|
|
157
|
+
message: 'Which channel do you want to connect?',
|
|
158
|
+
options: [
|
|
159
|
+
{ value: 'whatsapp', label: '💬 WhatsApp', hint: 'Personal or Business' },
|
|
160
|
+
{ value: 'telegram', label: '✈️ Telegram', hint: 'Create a bot' },
|
|
161
|
+
{ value: 'discord', label: '🎮 Discord', hint: 'Server bot' },
|
|
162
|
+
{ value: 'slack', label: '💼 Slack', hint: 'Workspace app' },
|
|
163
|
+
{ value: 'sms', label: '📱 SMS', hint: 'via Twilio' },
|
|
164
|
+
{ value: 'imessage', label: '🍎 iMessage', hint: 'Mac only' },
|
|
165
|
+
],
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
if (p.isCancel(channel)) return;
|
|
169
|
+
|
|
170
|
+
switch (channel) {
|
|
171
|
+
case 'whatsapp':
|
|
172
|
+
await connectWhatsApp(config);
|
|
173
|
+
break;
|
|
174
|
+
case 'telegram':
|
|
175
|
+
await connectTelegram(config);
|
|
176
|
+
break;
|
|
177
|
+
case 'discord':
|
|
178
|
+
await connectDiscord(config);
|
|
179
|
+
break;
|
|
180
|
+
case 'slack':
|
|
181
|
+
await connectSlack(config);
|
|
182
|
+
break;
|
|
183
|
+
case 'sms':
|
|
184
|
+
await connectSMS(config);
|
|
185
|
+
break;
|
|
186
|
+
case 'imessage':
|
|
187
|
+
await connectiMessage(config);
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async function connectWhatsApp(config: Config): Promise<void> {
|
|
193
|
+
p.log.info(chalk.bold('WhatsApp Setup'));
|
|
194
|
+
p.log.info(chalk.dim(`
|
|
195
|
+
WhatsApp uses QR code authentication via Baileys library.
|
|
196
|
+
Your phone needs to scan a QR code to connect.
|
|
197
|
+
|
|
198
|
+
Note: This is for personal accounts. For WhatsApp Business API,
|
|
199
|
+
you'll need a Meta Business account.
|
|
200
|
+
`));
|
|
201
|
+
|
|
202
|
+
const proceed = await p.confirm({
|
|
203
|
+
message: 'Ready to scan QR code?',
|
|
204
|
+
initialValue: true,
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
if (!proceed || p.isCancel(proceed)) return;
|
|
208
|
+
|
|
209
|
+
const spinner = p.spinner();
|
|
210
|
+
spinner.start('Generating QR code...');
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
// In real implementation, this would:
|
|
214
|
+
// 1. Initialize Baileys
|
|
215
|
+
// 2. Generate QR code
|
|
216
|
+
// 3. Wait for scan
|
|
217
|
+
// 4. Save session
|
|
218
|
+
|
|
219
|
+
// Simulated QR code display
|
|
220
|
+
spinner.stop('');
|
|
221
|
+
|
|
222
|
+
console.log(chalk.cyan(`
|
|
223
|
+
╔════════════════════════════════════╗
|
|
224
|
+
║ ║
|
|
225
|
+
║ ▄▄▄▄▄▄▄ ▄▄▄▄▄ ▄▄▄▄▄▄▄ ║
|
|
226
|
+
║ █ ▄▄▄ █ ▀█▀▄█ █ ▄▄▄ █ ║
|
|
227
|
+
║ █ ███ █ ▄▀ ▀▄ █ ███ █ ║
|
|
228
|
+
║ █▄▄▄▄▄█ █ ▄▀█ █▄▄▄▄▄█ ║
|
|
229
|
+
║ ▄▄▄▄▄ ▄▄▄██▀▀▄ ▄ ▄ ▄ ║
|
|
230
|
+
║ ██▀▀▀▄▄▀▄▀▄▄█▀██▀▄█▄▄ ║
|
|
231
|
+
║ ▄▄▄▄▄▄▄ █▄▀▄▀ ▄██▄█▄ ║
|
|
232
|
+
║ █ ▄▄▄ █ █▀▀▄▄▄▄▀▄ ║
|
|
233
|
+
║ █ ███ █ ▄███▄█▀█▄▄▄█ ║
|
|
234
|
+
║ █▄▄▄▄▄█ ██▀▄▀▀▄█▄▀█ ║
|
|
235
|
+
║ ║
|
|
236
|
+
╚════════════════════════════════════╝
|
|
237
|
+
|
|
238
|
+
Scan this QR code with WhatsApp:
|
|
239
|
+
1. Open WhatsApp on your phone
|
|
240
|
+
2. Go to Settings > Linked Devices
|
|
241
|
+
3. Tap "Link a Device"
|
|
242
|
+
4. Scan the QR code above
|
|
243
|
+
`));
|
|
244
|
+
|
|
245
|
+
const connected = await p.confirm({
|
|
246
|
+
message: 'Did you scan the QR code successfully?',
|
|
247
|
+
initialValue: false,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
if (connected && !p.isCancel(connected)) {
|
|
251
|
+
config.setChannelConfig('whatsapp', { enabled: true });
|
|
252
|
+
p.log.success('WhatsApp connected!');
|
|
253
|
+
}
|
|
254
|
+
} catch (error) {
|
|
255
|
+
spinner.stop('Error connecting WhatsApp');
|
|
256
|
+
p.log.error(error instanceof Error ? error.message : 'Unknown error');
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async function connectTelegram(config: Config): Promise<void> {
|
|
261
|
+
p.log.info(chalk.bold('Telegram Bot Setup'));
|
|
262
|
+
p.log.info(chalk.dim(`
|
|
263
|
+
To create a Telegram bot:
|
|
264
|
+
1. Open Telegram and search for @BotFather
|
|
265
|
+
2. Send /newbot
|
|
266
|
+
3. Follow the prompts to name your bot
|
|
267
|
+
4. Copy the API token
|
|
268
|
+
`));
|
|
269
|
+
|
|
270
|
+
const openBotFather = await p.confirm({
|
|
271
|
+
message: 'Open BotFather in browser?',
|
|
272
|
+
initialValue: true,
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
if (openBotFather && !p.isCancel(openBotFather)) {
|
|
276
|
+
const open = (await import('open')).default;
|
|
277
|
+
await open('https://t.me/botfather');
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const token = await p.text({
|
|
281
|
+
message: 'Paste your bot token:',
|
|
282
|
+
placeholder: '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11',
|
|
283
|
+
validate: (value) => {
|
|
284
|
+
if (!value) return 'Token is required';
|
|
285
|
+
if (!value.includes(':')) return 'Invalid token format';
|
|
286
|
+
return undefined;
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
if (p.isCancel(token)) return;
|
|
291
|
+
|
|
292
|
+
const spinner = p.spinner();
|
|
293
|
+
spinner.start('Verifying bot token...');
|
|
294
|
+
|
|
295
|
+
try {
|
|
296
|
+
// Verify token by calling getMe
|
|
297
|
+
const response = await fetch(`https://api.telegram.org/bot${token}/getMe`);
|
|
298
|
+
const data = await response.json();
|
|
299
|
+
|
|
300
|
+
if (!data.ok) {
|
|
301
|
+
throw new Error(data.description || 'Invalid token');
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
spinner.stop('Bot verified!');
|
|
305
|
+
|
|
306
|
+
config.setChannelConfig('telegram', {
|
|
307
|
+
enabled: true,
|
|
308
|
+
botToken: token,
|
|
309
|
+
botUsername: data.result.username,
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
p.log.success(`Connected to @${data.result.username}`);
|
|
313
|
+
} catch (error) {
|
|
314
|
+
spinner.stop('Verification failed');
|
|
315
|
+
p.log.error(error instanceof Error ? error.message : 'Invalid token');
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async function connectDiscord(config: Config): Promise<void> {
|
|
320
|
+
p.log.info(chalk.bold('Discord Bot Setup'));
|
|
321
|
+
p.log.info(chalk.dim(`
|
|
322
|
+
To create a Discord bot:
|
|
323
|
+
1. Go to Discord Developer Portal
|
|
324
|
+
2. Create a new application
|
|
325
|
+
3. Go to Bot section
|
|
326
|
+
4. Create a bot and copy the token
|
|
327
|
+
5. Enable necessary intents (Message Content)
|
|
328
|
+
`));
|
|
329
|
+
|
|
330
|
+
const openPortal = await p.confirm({
|
|
331
|
+
message: 'Open Discord Developer Portal?',
|
|
332
|
+
initialValue: true,
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
if (openPortal && !p.isCancel(openPortal)) {
|
|
336
|
+
const open = (await import('open')).default;
|
|
337
|
+
await open('https://discord.com/developers/applications');
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const token = await p.text({
|
|
341
|
+
message: 'Paste your bot token:',
|
|
342
|
+
placeholder: 'MTIzNDU2Nzg5MDEyMzQ1Njc4.Gg1234.abc...',
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
if (p.isCancel(token) || !token) return;
|
|
346
|
+
|
|
347
|
+
const clientId = await p.text({
|
|
348
|
+
message: 'Paste your application (client) ID:',
|
|
349
|
+
placeholder: '123456789012345678',
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
if (p.isCancel(clientId) || !clientId) return;
|
|
353
|
+
|
|
354
|
+
config.setChannelConfig('discord', {
|
|
355
|
+
enabled: true,
|
|
356
|
+
botToken: token,
|
|
357
|
+
clientId: clientId,
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
// Generate invite URL
|
|
361
|
+
const inviteUrl = `https://discord.com/api/oauth2/authorize?client_id=${clientId}&permissions=2048&scope=bot`;
|
|
362
|
+
|
|
363
|
+
p.log.success('Discord bot configured!');
|
|
364
|
+
p.log.info(`Add bot to server: ${inviteUrl}`);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
async function connectSlack(config: Config): Promise<void> {
|
|
368
|
+
p.log.info(chalk.bold('Slack App Setup'));
|
|
369
|
+
p.log.info(chalk.dim(`
|
|
370
|
+
To create a Slack app:
|
|
371
|
+
1. Go to Slack API portal
|
|
372
|
+
2. Create a new app
|
|
373
|
+
3. Add bot scopes (chat:write, app_mentions:read, etc.)
|
|
374
|
+
4. Install to workspace
|
|
375
|
+
5. Copy the Bot Token
|
|
376
|
+
`));
|
|
377
|
+
|
|
378
|
+
const openSlack = await p.confirm({
|
|
379
|
+
message: 'Open Slack API portal?',
|
|
380
|
+
initialValue: true,
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
if (openSlack && !p.isCancel(openSlack)) {
|
|
384
|
+
const open = (await import('open')).default;
|
|
385
|
+
await open('https://api.slack.com/apps');
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const token = await p.text({
|
|
389
|
+
message: 'Paste your Bot User OAuth Token:',
|
|
390
|
+
placeholder: 'xoxb-...',
|
|
391
|
+
validate: (value) => {
|
|
392
|
+
if (!value) return 'Token is required';
|
|
393
|
+
if (!value.startsWith('xoxb-')) return 'Should start with xoxb-';
|
|
394
|
+
return undefined;
|
|
395
|
+
},
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
if (p.isCancel(token)) return;
|
|
399
|
+
|
|
400
|
+
config.setChannelConfig('slack', {
|
|
401
|
+
enabled: true,
|
|
402
|
+
botToken: token,
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
p.log.success('Slack app configured!');
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
async function connectSMS(config: Config): Promise<void> {
|
|
409
|
+
p.log.info(chalk.bold('SMS via Twilio'));
|
|
410
|
+
|
|
411
|
+
const twilioConfig = config.getCredentials('twilio');
|
|
412
|
+
|
|
413
|
+
if (twilioConfig?.accountSid) {
|
|
414
|
+
p.log.info('Twilio is already configured.');
|
|
415
|
+
|
|
416
|
+
const reconfigure = await p.confirm({
|
|
417
|
+
message: 'Reconfigure Twilio?',
|
|
418
|
+
initialValue: false,
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
if (!reconfigure || p.isCancel(reconfigure)) {
|
|
422
|
+
config.setChannelConfig('sms', { enabled: true });
|
|
423
|
+
p.log.success('SMS channel enabled!');
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const openTwilio = await p.confirm({
|
|
429
|
+
message: 'Open Twilio Console?',
|
|
430
|
+
initialValue: true,
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
if (openTwilio && !p.isCancel(openTwilio)) {
|
|
434
|
+
const open = (await import('open')).default;
|
|
435
|
+
await open('https://console.twilio.com/');
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const accountSid = await p.text({
|
|
439
|
+
message: 'Account SID:',
|
|
440
|
+
placeholder: 'AC...',
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
if (p.isCancel(accountSid)) return;
|
|
444
|
+
|
|
445
|
+
const authToken = await p.text({
|
|
446
|
+
message: 'Auth Token:',
|
|
447
|
+
placeholder: '...',
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
if (p.isCancel(authToken)) return;
|
|
451
|
+
|
|
452
|
+
const phoneNumber = await p.text({
|
|
453
|
+
message: 'Twilio phone number:',
|
|
454
|
+
placeholder: '+1234567890',
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
if (p.isCancel(phoneNumber)) return;
|
|
458
|
+
|
|
459
|
+
config.setCredentials('twilio', {
|
|
460
|
+
accountSid: accountSid as string,
|
|
461
|
+
authToken: authToken as string,
|
|
462
|
+
phoneNumber: phoneNumber as string,
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
config.setChannelConfig('sms', { enabled: true });
|
|
466
|
+
p.log.success('SMS channel configured!');
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
async function connectiMessage(config: Config): Promise<void> {
|
|
470
|
+
p.log.warn('iMessage support requires macOS and additional setup.');
|
|
471
|
+
p.log.info(chalk.dim(`
|
|
472
|
+
iMessage integration uses AppleScript on macOS.
|
|
473
|
+
This requires:
|
|
474
|
+
1. macOS with Messages app
|
|
475
|
+
2. iCloud signed in
|
|
476
|
+
3. Terminal with accessibility permissions
|
|
477
|
+
`));
|
|
478
|
+
|
|
479
|
+
const isMac = process.platform === 'darwin';
|
|
480
|
+
|
|
481
|
+
if (!isMac) {
|
|
482
|
+
p.log.error('iMessage is only available on macOS.');
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Would check for accessibility permissions and configure
|
|
487
|
+
p.log.info('iMessage support coming soon.');
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
async function startAllChannels(config: Config): Promise<void> {
|
|
491
|
+
const spinner = p.spinner();
|
|
492
|
+
spinner.start('Starting channel gateway...');
|
|
493
|
+
|
|
494
|
+
// In real implementation, this would start all enabled channels
|
|
495
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
496
|
+
|
|
497
|
+
spinner.stop('Gateway started');
|
|
498
|
+
|
|
499
|
+
console.log(chalk.green(`
|
|
500
|
+
╔═══════════════════════════════════════╗
|
|
501
|
+
║ Gateway is running! ║
|
|
502
|
+
║ ║
|
|
503
|
+
║ You can now receive messages from: ║
|
|
504
|
+
║ • WhatsApp • Telegram • Discord ║
|
|
505
|
+
║ • Slack • SMS ║
|
|
506
|
+
║ ║
|
|
507
|
+
║ Press Ctrl+C to stop ║
|
|
508
|
+
╚═══════════════════════════════════════╝
|
|
509
|
+
`));
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
async function stopAllChannels(config: Config): Promise<void> {
|
|
513
|
+
const spinner = p.spinner();
|
|
514
|
+
spinner.start('Stopping gateway...');
|
|
515
|
+
|
|
516
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
517
|
+
|
|
518
|
+
spinner.stop('Gateway stopped');
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
async function deployGatewayWizard(config: Config): Promise<void> {
|
|
522
|
+
p.log.info(chalk.bold('Deploy Gateway to Cloud'));
|
|
523
|
+
|
|
524
|
+
const platform = await p.select({
|
|
525
|
+
message: 'Where do you want to deploy?',
|
|
526
|
+
options: [
|
|
527
|
+
{ value: 'codebakers', label: '☁️ CodeBakers Cloud', hint: '$29/mo - We handle everything' },
|
|
528
|
+
{ value: 'vps', label: '🖥️ VPS', hint: '$5/mo - DigitalOcean, etc.' },
|
|
529
|
+
{ value: 'local', label: '🏠 Home server', hint: 'Raspberry Pi, etc.' },
|
|
530
|
+
],
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
if (p.isCancel(platform)) return;
|
|
534
|
+
|
|
535
|
+
switch (platform) {
|
|
536
|
+
case 'codebakers':
|
|
537
|
+
p.log.info('CodeBakers Cloud coming soon!');
|
|
538
|
+
p.log.info(chalk.dim('Sign up at https://codebakers.dev/cloud'));
|
|
539
|
+
break;
|
|
540
|
+
|
|
541
|
+
case 'vps':
|
|
542
|
+
await deployToVPS(config);
|
|
543
|
+
break;
|
|
544
|
+
|
|
545
|
+
case 'local':
|
|
546
|
+
p.log.info('Local deployment guide:');
|
|
547
|
+
p.log.info(chalk.dim(`
|
|
548
|
+
1. Install Node.js on your server
|
|
549
|
+
2. Clone your project
|
|
550
|
+
3. Run: npm install
|
|
551
|
+
4. Run: pm2 start codebakers -- gateway --start
|
|
552
|
+
5. Configure firewall to allow outbound connections
|
|
553
|
+
`));
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
async function deployToVPS(config: Config): Promise<void> {
|
|
559
|
+
const provider = await p.select({
|
|
560
|
+
message: 'Which VPS provider?',
|
|
561
|
+
options: [
|
|
562
|
+
{ value: 'digitalocean', label: 'DigitalOcean' },
|
|
563
|
+
{ value: 'vultr', label: 'Vultr' },
|
|
564
|
+
{ value: 'linode', label: 'Linode' },
|
|
565
|
+
{ value: 'hetzner', label: 'Hetzner' },
|
|
566
|
+
{ value: 'other', label: 'Other' },
|
|
567
|
+
],
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
if (p.isCancel(provider)) return;
|
|
571
|
+
|
|
572
|
+
if (provider === 'digitalocean') {
|
|
573
|
+
p.log.info('DigitalOcean auto-deploy:');
|
|
574
|
+
p.log.info(chalk.dim(`
|
|
575
|
+
1. Opening DigitalOcean login...
|
|
576
|
+
2. We'll create a $6/mo droplet
|
|
577
|
+
3. Install CodeBakers gateway
|
|
578
|
+
4. Connect all your channels
|
|
579
|
+
`));
|
|
580
|
+
|
|
581
|
+
const proceed = await p.confirm({
|
|
582
|
+
message: 'Open DigitalOcean?',
|
|
583
|
+
initialValue: true,
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
if (proceed && !p.isCancel(proceed)) {
|
|
587
|
+
const open = (await import('open')).default;
|
|
588
|
+
await open('https://cloud.digitalocean.com/');
|
|
589
|
+
}
|
|
590
|
+
} else {
|
|
591
|
+
p.log.info(chalk.dim(`
|
|
592
|
+
Manual VPS setup:
|
|
593
|
+
|
|
594
|
+
1. Create a VPS (Ubuntu 22.04 recommended)
|
|
595
|
+
2. SSH into your server
|
|
596
|
+
3. Run these commands:
|
|
597
|
+
|
|
598
|
+
curl -fsSL https://codebakers.dev/install.sh | bash
|
|
599
|
+
codebakers gateway --start
|
|
600
|
+
|
|
601
|
+
4. Your gateway will start automatically on boot
|
|
602
|
+
`));
|
|
603
|
+
}
|
|
604
|
+
}
|