UNPKG

build-in-public-bot

Version:

AI-powered CLI bot for automating build-in-public tweets with code screenshots

282 lines • 14.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.initCommand = initCommand; const logger_1 = require("../utils/logger"); const config_1 = require("../services/config"); const prompts_1 = require("../utils/prompts"); const chalk_1 = __importDefault(require("chalk")); async function initCommand() { logger_1.logger.info('Welcome to Build-in-Public Bot! 🚀\n'); const configService = config_1.ConfigService.getInstance(); try { let existingConfig = null; let isNewInstall = false; try { existingConfig = await configService.load(); const overwrite = await (0, prompts_1.confirm)('Configuration already exists. Do you want to update it?'); if (!overwrite) { logger_1.logger.info('Using existing configuration.'); } else { isNewInstall = true; } } catch { isNewInstall = true; } let username = existingConfig?.twitter?.username; if (isNewInstall) { console.log(chalk_1.default.bold('\n📝 Let\'s set up your build-in-public bot:\n')); username = await (0, prompts_1.prompt)('Twitter username (without @)', { default: username, validate: (input) => { if (!input) return 'Username is required'; if (input.includes('@')) return 'Please enter username without @ symbol'; return true; } }); } else { console.log(chalk_1.default.bold('\n🔧 Checking your setup:\n')); console.log(chalk_1.default.green(`✅ Twitter username: @${username}`)); } let postingMethod = existingConfig?.twitter?.postingMethod; if (isNewInstall || !postingMethod) { console.log(chalk_1.default.bold('\n🐦 Twitter Posting Method:\n')); console.log('This bot can post to Twitter in two ways:\n'); console.log(chalk_1.default.cyan('1. Browser Automation') + ' (Recommended)'); console.log(' - Uses Chrome to post like a human'); console.log(' - No API keys needed'); console.log(' - Works with personal accounts'); console.log(' - Handles media uploads easily\n'); console.log(chalk_1.default.cyan('2. Twitter API') + ' (Advanced)'); console.log(' - Requires Twitter Developer account'); console.log(' - Need to create an app and get API keys'); console.log(' - Faster but more complex setup'); console.log(' - Subject to API rate limits\n'); const methodChoice = await (0, prompts_1.prompt)('Which method would you like to use? (1 or 2)', { validate: (input) => { if (!['1', '2'].includes(input)) { return 'Please enter 1 or 2'; } return true; } }); postingMethod = methodChoice === '1' ? 'browser' : 'api'; } else { console.log(chalk_1.default.green(`✅ Twitter posting method: ${postingMethod}`)); } if (postingMethod === 'browser') { if (isNewInstall || !existingConfig?.twitter?.postingMethod) { console.log(chalk_1.default.green('\n✅ Great choice! Browser automation is easy to set up.')); console.log(chalk_1.default.dim('When you post your first tweet, a Chrome window will open.')); console.log(chalk_1.default.dim('Just log in to Twitter once, and the bot will remember your session.\n')); } } else if (postingMethod === 'api') { console.log(chalk_1.default.yellow('\n⚠️ Twitter API setup is more complex.')); console.log(chalk_1.default.dim('\nYou\'ll need:')); console.log(chalk_1.default.dim('1. A Twitter Developer account')); console.log(chalk_1.default.dim('2. Create an app at https://developer.twitter.com')); console.log(chalk_1.default.dim('3. Get your API keys and tokens\n')); const setupApiNow = await (0, prompts_1.confirm)('Do you have Twitter API credentials ready?', false); if (setupApiNow) { console.log(chalk_1.default.dim('\nEnter your Twitter API credentials:\n')); const apiKey = await (0, prompts_1.prompt)('API Key', { mask: true, validate: (input) => input.length > 0 || 'API Key is required' }); const apiSecret = await (0, prompts_1.prompt)('API Key Secret', { mask: true, validate: (input) => input.length > 0 || 'API Key Secret is required' }); const accessToken = await (0, prompts_1.prompt)('Access Token', { mask: true, validate: (input) => input.length > 0 || 'Access Token is required' }); const accessSecret = await (0, prompts_1.prompt)('Access Token Secret', { mask: true, validate: (input) => input.length > 0 || 'Access Token Secret is required' }); const fs = await Promise.resolve().then(() => __importStar(require('fs/promises'))); const path = await Promise.resolve().then(() => __importStar(require('path'))); const envPath = path.join(process.cwd(), '.env'); try { let envContent = ''; try { envContent = await fs.readFile(envPath, 'utf-8'); } catch { } const twitterEnvVars = ` TWITTER_API_KEY=${apiKey} TWITTER_API_KEY_SECRET=${apiSecret} TWITTER_ACCESS_TOKEN=${accessToken} TWITTER_ACCESS_TOKEN_SECRET=${accessSecret} `; envContent += twitterEnvVars; await fs.writeFile(envPath, envContent); process.env.TWITTER_API_KEY = apiKey; process.env.TWITTER_API_KEY_SECRET = apiSecret; process.env.TWITTER_ACCESS_TOKEN = accessToken; process.env.TWITTER_ACCESS_TOKEN_SECRET = accessSecret; console.log(chalk_1.default.green('\n✅ Twitter API credentials saved!')); } catch (error) { console.log(chalk_1.default.yellow('\n⚠️ Could not save credentials to .env')); console.log(chalk_1.default.dim('Add these to your .env file manually:')); console.log(chalk_1.default.cyan(`TWITTER_API_KEY=${apiKey}`)); console.log(chalk_1.default.cyan(`TWITTER_API_KEY_SECRET=${apiSecret}`)); console.log(chalk_1.default.cyan(`TWITTER_ACCESS_TOKEN=${accessToken}`)); console.log(chalk_1.default.cyan(`TWITTER_ACCESS_TOKEN_SECRET=${accessSecret}`)); } const config = await configService.load(); config.twitter.postingMethod = 'api'; await configService.save(config); } else { console.log(chalk_1.default.dim('\nYou can set up Twitter API credentials later.')); console.log(chalk_1.default.dim('For now, the bot will use browser automation.\n')); const config = await configService.load(); config.twitter.postingMethod = 'browser'; await configService.save(config); } } console.log(chalk_1.default.bold('\n🤖 AI Configuration:\n')); console.log('This bot uses OpenRouter with GPT-4 for generating tweets.'); if (!process.env.OPENROUTER_API_KEY) { console.log(chalk_1.default.yellow('\n⚠️ No OpenRouter API key detected')); const setupApiKey = await (0, prompts_1.confirm)('Would you like to set up your API key now?', true); if (setupApiKey) { console.log(chalk_1.default.dim('\n1. Sign up at https://openrouter.ai (free)')); console.log(chalk_1.default.dim('2. Copy your API key from the dashboard\n')); const apiKey = await (0, prompts_1.prompt)('Paste your OpenRouter API key', { mask: true, validate: (input) => { if (!input) return 'API key is required'; if (input.length < 20) return 'Invalid API key format'; return true; } }); const fs = await Promise.resolve().then(() => __importStar(require('fs/promises'))); const path = await Promise.resolve().then(() => __importStar(require('path'))); const envPath = path.join(process.cwd(), '.env'); try { let envContent = ''; try { envContent = await fs.readFile(envPath, 'utf-8'); } catch { } if (envContent.includes('OPENROUTER_API_KEY')) { envContent = envContent.replace(/OPENROUTER_API_KEY=.*/, `OPENROUTER_API_KEY=${apiKey}`); } else { envContent += `${envContent ? '\n' : ''}OPENROUTER_API_KEY=${apiKey}\n`; } await fs.writeFile(envPath, envContent); process.env.OPENROUTER_API_KEY = apiKey; console.log(chalk_1.default.green('✅ API key saved to .env file')); } catch (error) { console.log(chalk_1.default.yellow('⚠️ Could not save to .env file')); console.log(chalk_1.default.dim('Add this to your environment manually:')); console.log(chalk_1.default.cyan(`export OPENROUTER_API_KEY="${apiKey}"`)); } } else { console.log(chalk_1.default.dim('\nYou can add it later to your .env file:')); console.log(chalk_1.default.cyan('OPENROUTER_API_KEY=your-key-here')); } } else { console.log(chalk_1.default.green('✅ API key already configured')); } let useEmojis = true; let alwaysUseBuildinpublic = true; if (isNewInstall) { console.log(chalk_1.default.bold('\n✨ Style Preferences:\n')); useEmojis = await (0, prompts_1.confirm)('Do you want to use emojis in your tweets?', true); alwaysUseBuildinpublic = await (0, prompts_1.confirm)('Always include #buildinpublic hashtag?', true); } if (isNewInstall) { await configService.init(); } const config = await configService.load(); if (username) config.twitter.username = username; if (postingMethod) config.twitter.postingMethod = postingMethod; if (isNewInstall) { if (!useEmojis) { config.style.emojis.frequency = 'none'; } if (!alwaysUseBuildinpublic) { config.style.hashtags.always = []; } } await configService.save(config); console.log(chalk_1.default.green('\n✅ Build-in-Public Bot setup complete!\n')); console.log(chalk_1.default.bold('Current Configuration:')); console.log(` Twitter: @${config.twitter.username} (${config.twitter.postingMethod} mode)`); console.log(` AI Key: ${process.env.OPENROUTER_API_KEY ? chalk_1.default.green('✓ Configured') : chalk_1.default.yellow('⚠ Not set')}`); console.log(` Style: ${config.style.tone} tone, ${config.style.emojis.frequency} emojis`); console.log('\n' + chalk_1.default.bold('Next steps:')); if (!process.env.OPENROUTER_API_KEY) { console.log(' 1. Set up your API key:', chalk_1.default.cyan('bip setup-api')); console.log(' 2. Post your first tweet:', chalk_1.default.cyan('bip post "your update"')); } else { console.log(' 1. Post your first tweet:', chalk_1.default.cyan('bip post "your update"')); console.log(' 2. Share code screenshots:', chalk_1.default.cyan('bip code <file>')); } console.log(' 3. Customize your style:', chalk_1.default.cyan('bip style')); console.log(' 4. See all commands:', chalk_1.default.cyan('bip --help')); } catch (error) { logger_1.logger.error('Failed to initialize configuration'); throw error; } } //# sourceMappingURL=init.js.map