← back to Goodquestion Ai

scripts/bsky-post.cjs

81 lines

#!/usr/bin/env node
/**
 * Post to Bluesky (@agentabrams.bsky.social)
 * Usage: node bsky-post.cjs --text "Post text" [--url "https://..."] [--link-text "Click here"]
 */
const { BskyAgent, RichText } = require('@atproto/api');

const BSKY_SERVICE = 'https://bsky.social';
const BSKY_HANDLE = 'agentabrams.bsky.social';
const BSKY_PASSWORD = process.env.BSKY_PASSWORD || '*Blueaccess911*';

function parseArgs() {
  const args = process.argv.slice(2);
  const result = {};
  for (let i = 0; i < args.length; i++) {
    if (args[i] === '--text' && args[i + 1]) result.text = args[++i];
    if (args[i] === '--url' && args[i + 1]) result.url = args[++i];
    if (args[i] === '--link-text' && args[i + 1]) result.linkText = args[++i];
  }
  return result;
}

async function post() {
  const opts = parseArgs();
  if (!opts.text) {
    console.error('Usage: node bsky-post.cjs --text "Post text" [--url "https://..."]');
    process.exit(1);
  }

  const agent = new BskyAgent({ service: BSKY_SERVICE });
  console.log('Logging in as', BSKY_HANDLE, '...');
  await agent.login({ identifier: BSKY_HANDLE, password: BSKY_PASSWORD });
  console.log('Logged in successfully.');

  // Build post text with optional URL appended
  let fullText = opts.text;
  if (opts.url && !fullText.includes(opts.url)) {
    fullText += '\n\n' + opts.url;
  }

  // Truncate to 300 chars (Bluesky limit)
  if (fullText.length > 300) {
    fullText = fullText.substring(0, 297) + '...';
  }

  // Use RichText to auto-detect links, mentions, tags
  const rt = new RichText({ text: fullText });
  await rt.detectFacets(agent);

  // Build embed card if URL provided
  let embed = undefined;
  if (opts.url) {
    embed = {
      $type: 'app.bsky.embed.external',
      external: {
        uri: opts.url,
        title: opts.linkText || opts.text.substring(0, 60),
        description: 'Read more at goodquestion.ai',
      },
    };
  }

  const result = await agent.post({
    text: rt.text,
    facets: rt.facets,
    embed: embed,
    createdAt: new Date().toISOString(),
  });

  console.log('Posted to Bluesky!');
  console.log('URI:', result.uri);
  console.log('CID:', result.cid);
  const postId = result.uri.split('/').pop();
  console.log('URL: https://bsky.app/profile/' + BSKY_HANDLE + '/post/' + postId);
}

post().catch(e => {
  console.error('Error posting to Bluesky:', e.message);
  process.exit(1);
});