build-in-public-bot
Version:
AI-powered CLI bot for automating build-in-public tweets with code screenshots
203 lines ⢠9.25 kB
JavaScript
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
;