#!/usr/bin/env node import { TwitterApi } from 'twitter-api-v2'; import { readFileSync, existsSync } from 'fs'; import { join } from 'path'; import { homedir } from 'os'; function getCredentials() { if (process.env.X_API_KEY && process.env.X_API_SECRET && process.env.X_ACCESS_TOKEN && process.env.X_ACCESS_SECRET) { return { appKey: process.env.X_API_KEY, appSecret: process.env.X_API_SECRET, accessToken: process.env.X_ACCESS_TOKEN, accessSecret: process.env.X_ACCESS_SECRET, }; } const configPath = join(homedir(), '.clawdbot', 'secrets', 'x-api.json'); if (existsSync(configPath)) { const config = JSON.parse(readFileSync(configPath, 'utf-8')); return { appKey: config.consumerKey, appSecret: config.consumerSecret, accessToken: config.accessToken, accessSecret: config.accessTokenSecret, }; } console.error('No credentials found.'); process.exit(1); } const text = process.argv.slice(2).join(' '); if (!text) { console.error('Usage: x-post "text"'); process.exit(1); } const creds = getCredentials(); const client = new TwitterApi({ appKey: creds.appKey, appSecret: creds.appSecret, accessToken: creds.accessToken, accessSecret: creds.accessSecret, }); try { const { data } = await client.v2.tweet(text); console.log(`✅ Posted: https://x.com/i/status/${data.id}`); } catch (err) { console.error('❌ Error:', err.data || err.message || err); process.exit(1); }