← back to Goodquestion Ai
scripts/x-retry-pending.cjs
67 lines
/**
* Retry pending X/Twitter operations that were rate-limited
* Run via cron: 0 * * * * node /root/Projects/goodquestion-ai/scripts/x-retry-pending.cjs
*/
require('dotenv').config({ path: require('path').join(__dirname, '..', '.env') });
const fs = require('fs');
const { TwitterApi } = require('twitter-api-v2');
const client = new TwitterApi({
appKey: process.env.TWITTER_API_KEY,
appSecret: process.env.TWITTER_API_SECRET,
accessToken: process.env.TWITTER_ACCESS_TOKEN,
accessSecret: process.env.TWITTER_ACCESS_TOKEN_SECRET,
});
const PENDING_LISTS = '/tmp/x-create-good-question.json';
const PENDING_REMAINING = '/tmp/x-pending-lists.json';
async function run() {
// Create "Good Question" list if pending
if (fs.existsSync(PENDING_LISTS)) {
try {
const data = JSON.parse(fs.readFileSync(PENDING_LISTS, 'utf-8'));
const result = await client.v2.createList({ name: data.name, description: data.description, private: false });
console.log(`Created "${data.name}" → ID: ${result.data.id}`);
fs.unlinkSync(PENDING_LISTS);
} catch (e) {
if (e.message.includes('429')) {
console.log('Still rate limited, will retry next hour');
return;
}
console.error('Error:', e.message);
}
}
// Create remaining lists from x-create-lists if pending
const remaining = [
{ name: 'Claude & Anthropic', description: 'Anthropic team, Claude ecosystem builders, and Claude Code power users.' },
{ name: 'Dev Tools & Infra', description: 'Developer tools, infrastructure, DevOps, and the people making developers more productive.' },
{ name: 'Open Source Leaders', description: 'Open source maintainers, contributors, and advocates building in public.' },
{ name: 'Build In Public', description: 'Founders and devs sharing their journey — code, revenue, mistakes, and wins.' },
];
// Check which lists exist
const me = await client.v2.me();
const existing = await client.v2.listsOwned(me.data.id);
const existingNames = new Set((existing.data || []).map(l => l.name));
for (const list of remaining) {
if (existingNames.has(list.name)) continue;
try {
const result = await client.v2.createList({ name: list.name, description: list.description, private: false });
console.log(`Created "${list.name}" → ID: ${result.data.id}`);
} catch (e) {
if (e.message.includes('429')) {
console.log(`Rate limited on "${list.name}", stopping. Will retry next hour.`);
return;
}
console.error(`Failed "${list.name}":`, e.message);
}
}
console.log('All pending lists created!');
}
run().catch(e => console.error('Fatal:', e.message));