UNPKG

build-in-public-bot

Version:

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

203 lines • 9.25 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const commander_1 = require("commander"); const chalk_1 = __importDefault(require("chalk")); const ora_1 = __importDefault(require("ora")); const twitter_1 = require("../services/twitter"); const config_1 = require("../services/config"); const errors_1 = require("../utils/errors"); const prompts_1 = require("../utils/prompts"); const logger_1 = require("../utils/logger"); const setupCommand = new commander_1.Command('setup') .description('Set up authentication and API keys'); setupCommand .command('browser') .description('Authenticate with Twitter using browser automation') .option('--headless', 'Run browser in headless mode (not recommended for first setup)') .option('--no-save', 'Don\'t save credentials after authentication') .action(async (options) => { try { const configService = config_1.ConfigService.getInstance(); const config = await configService.load(); if (config.twitter?.sessionData && !options.force) { const overwrite = await (0, prompts_1.confirm)(`Already authenticated as @${config.twitter.username}. Re-authenticate?`, false); if (!overwrite) { logger_1.logger.info('Using existing authentication.'); return; } } console.log(chalk_1.default.cyan('\n🐦 Twitter Browser Authentication\n')); console.log('This will open a Chrome browser window where you can log in to Twitter.'); console.log('Your session will be saved securely for future use.\n'); const username = await (0, prompts_1.prompt)('Twitter username (without @)', { default: config.twitter?.username, validate: (input) => { if (!input) return 'Username is required'; if (input.includes('@')) return 'Please enter username without @ symbol'; return true; } }); const password = await (0, prompts_1.prompt)('Twitter password', { mask: true, validate: (input) => input ? true : 'Password is required' }); console.log(chalk_1.default.yellow('\nāš ļø Important:')); console.log('1. A Chrome window will open'); console.log('2. You may need to complete 2FA if enabled'); console.log('3. The browser will close automatically after login\n'); const ready = await (0, prompts_1.confirm)('Ready to proceed?', true); if (!ready) { logger_1.logger.info('Authentication cancelled.'); return; } const spinner = (0, ora_1.default)('Opening browser...').start(); try { const twitterService = twitter_1.TwitterService.getInstance(); if (options.headless) { logger_1.logger.warn('Running in headless mode - this may fail if 2FA is required'); } spinner.text = 'Authenticating with Twitter...'; await twitterService.authenticate(username, password); spinner.succeed('Successfully authenticated!'); console.log(chalk_1.default.green('\nāœ… Authentication successful!')); console.log(`You are now logged in as @${username}`); console.log('\nYou can now use commands like:'); console.log(chalk_1.default.gray(' bip post "Just shipped a new feature!"')); console.log(chalk_1.default.gray(' bip code app.js "Check out this clean code"')); const testConnection = await (0, prompts_1.confirm)('\nWould you like to test the connection with a draft tweet?', true); if (testConnection) { console.log(chalk_1.default.gray('\nRun: bip draft "Hello from build-in-public bot!"')); } } catch (error) { spinner.fail('Authentication failed'); if (error instanceof Error) { if (error.message.includes('2FA')) { console.log(chalk_1.default.yellow('\nāš ļø Two-factor authentication detected')); console.log('Please try again with --no-headless flag to complete 2FA manually'); } else if (error.message.includes('rate limit')) { console.log(chalk_1.default.red('\nāŒ Twitter rate limit detected')); console.log('Please wait a few minutes before trying again'); } else { console.log(chalk_1.default.red(`\nāŒ Error: ${error.message}`)); } } throw error; } } catch (error) { (0, errors_1.handleError)(error); } }); setupCommand .command('api') .alias('openrouter') .description('Set up or update your OpenRouter API key') .option('--key <key>', 'API key (if not provided, will prompt)') .action(async (options) => { try { const configService = config_1.ConfigService.getInstance(); const config = await configService.load(); console.log(chalk_1.default.cyan('\nšŸ¤– AI API Setup\n')); console.log('This bot uses AI to generate tweet suggestions.'); console.log('You can use either OpenAI or Anthropic via OpenRouter.\n'); let apiKey = options.key; if (!apiKey) { apiKey = await (0, prompts_1.prompt)('Enter your OpenRouter API key', { mask: true, validate: (input) => input ? true : 'API key is required' }); } config.ai = config.ai || { provider: 'openrouter', model: 'anthropic/claude-3-sonnet', apiKey: '' }; config.ai.apiKey = apiKey; config.ai.provider = 'openrouter'; await configService.save(config); logger_1.logger.success('API key saved successfully!'); console.log(chalk_1.default.gray('\nYou can now use AI-powered features.')); } catch (error) { (0, errors_1.handleError)(error); } }); setupCommand .command('logout') .description('Remove stored authentication') .action(async () => { try { const configService = config_1.ConfigService.getInstance(); const config = await configService.load(); if (!config.twitter?.sessionData) { logger_1.logger.info('No Twitter authentication found.'); return; } const confirm_ = await (0, prompts_1.confirm)(`Remove authentication for @${config.twitter.username}?`, false); if (!confirm_) { logger_1.logger.info('Logout cancelled.'); return; } config.twitter.sessionData = null; await configService.save(config); logger_1.logger.success('Successfully logged out from Twitter.'); } catch (error) { (0, errors_1.handleError)(error); } }); setupCommand .command('status') .description('Check authentication status') .action(async () => { try { const configService = config_1.ConfigService.getInstance(); const config = await configService.load(); console.log(chalk_1.default.cyan('\nšŸ” Authentication Status\n')); console.log(chalk_1.default.bold('Twitter:')); if (config.twitter?.sessionData) { console.log(chalk_1.default.green(' āœ… Authenticated')); console.log(` Username: @${config.twitter.username}`); console.log(` Method: ${config.twitter.postingMethod || 'browser'}`); const twitterService = twitter_1.TwitterService.getInstance(); const spinner = (0, ora_1.default)(' Verifying session...').start(); try { const isValid = await twitterService.loadSession(); if (isValid) { spinner.succeed(' Session is valid'); } else { spinner.warn(' Session may have expired'); console.log(chalk_1.default.yellow('\n Run "bip setup browser" to re-authenticate')); } } catch (error) { spinner.fail(' Could not verify session'); } } else { console.log(chalk_1.default.red(' āŒ Not authenticated')); console.log(chalk_1.default.gray(' Run "bip setup browser" to authenticate')); } console.log(chalk_1.default.bold('\nAI API:')); if (config.ai?.apiKey || process.env.OPENAI_API_KEY || process.env.ANTHROPIC_API_KEY) { console.log(chalk_1.default.green(' āœ… Configured')); if (config.ai?.provider) { console.log(` Provider: ${config.ai.provider}`); } } else { console.log(chalk_1.default.red(' āŒ Not configured')); console.log(chalk_1.default.gray(' Run "bip setup api" or set OPENAI_API_KEY')); } } catch (error) { (0, errors_1.handleError)(error); } }); exports.default = setupCommand; //# sourceMappingURL=setup.js.map