Files
chloeclaw/skills/x-api/scripts/x-post.mjs
2026-03-02 20:22:49 +00:00

49 lines
1.4 KiB
JavaScript

#!/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);
}